Home Reference Source

src/loader/date-range.ts

  1. import { AttrList } from '../utils/attr-list';
  2. import { logger } from '../utils/logger';
  3.  
  4. export enum DateRangeAttribute {
  5. ID = 'ID',
  6. CLASS = 'CLASS',
  7. START_DATE = 'START-DATE',
  8. DURATION = 'DURATION',
  9. END_DATE = 'END-DATE',
  10. END_ON_NEXT = 'END-ON-NEXT',
  11. PLANNED_DURATION = 'PLANNED-DURATION',
  12. SCTE35_OUT = 'SCTE35-OUT',
  13. SCTE35_IN = 'SCTE35-IN',
  14. }
  15.  
  16. export class DateRange {
  17. public attr: AttrList;
  18. private _startDate: Date;
  19. private _endDate?: Date;
  20. private _badValueForSameId?: string;
  21.  
  22. constructor(dateRangeAttr: AttrList, dateRangeWithSameId?: DateRange) {
  23. if (dateRangeWithSameId) {
  24. const previousAttr = dateRangeWithSameId.attr;
  25. for (const key in previousAttr) {
  26. if (
  27. Object.prototype.hasOwnProperty.call(dateRangeAttr, key) &&
  28. dateRangeAttr[key] !== previousAttr[key]
  29. ) {
  30. logger.warn(
  31. `DATERANGE tag attribute: "${key}" does not match for tags with ID: "${dateRangeAttr.ID}"`
  32. );
  33. this._badValueForSameId = key;
  34. break;
  35. }
  36. }
  37. // Merge DateRange tags with the same ID
  38. dateRangeAttr = Object.assign(
  39. new AttrList({}),
  40. previousAttr,
  41. dateRangeAttr
  42. );
  43. }
  44. this.attr = dateRangeAttr;
  45. this._startDate = new Date(dateRangeAttr[DateRangeAttribute.START_DATE]);
  46. if (DateRangeAttribute.END_DATE in this.attr) {
  47. const endDate = new Date(this.attr[DateRangeAttribute.END_DATE]);
  48. if (Number.isFinite(endDate.getTime())) {
  49. this._endDate = endDate;
  50. }
  51. }
  52. }
  53.  
  54. get id(): string {
  55. return this.attr.ID;
  56. }
  57.  
  58. get class(): string {
  59. return this.attr.CLASS;
  60. }
  61.  
  62. get startDate(): Date {
  63. return this._startDate;
  64. }
  65.  
  66. get endDate(): Date | null {
  67. if (this._endDate) {
  68. return this._endDate;
  69. }
  70. const duration = this.duration;
  71. if (duration !== null) {
  72. return new Date(this._startDate.getTime() + duration * 1000);
  73. }
  74. return null;
  75. }
  76.  
  77. get duration(): number | null {
  78. if (DateRangeAttribute.DURATION in this.attr) {
  79. const duration = this.attr.decimalFloatingPoint(
  80. DateRangeAttribute.DURATION
  81. );
  82. if (Number.isFinite(duration)) {
  83. return duration;
  84. }
  85. } else if (this._endDate) {
  86. return (this._endDate.getTime() - this._startDate.getTime()) / 1000;
  87. }
  88. return null;
  89. }
  90.  
  91. get plannedDuration(): number | null {
  92. if (DateRangeAttribute.PLANNED_DURATION in this.attr) {
  93. return this.attr.decimalFloatingPoint(
  94. DateRangeAttribute.PLANNED_DURATION
  95. );
  96. }
  97. return null;
  98. }
  99.  
  100. get endOnNext(): boolean {
  101. return this.attr.bool(DateRangeAttribute.END_ON_NEXT);
  102. }
  103.  
  104. get isValid(): boolean {
  105. return (
  106. !!this.id &&
  107. !this._badValueForSameId &&
  108. Number.isFinite(this.startDate.getTime()) &&
  109. (this.duration === null || this.duration >= 0) &&
  110. (!this.endOnNext || !!this.class)
  111. );
  112. }
  113. }