date-ranges.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. export default class DateRangesStorage {
  2. constructor() {
  3. this.offset_ = null;
  4. this.pendingDateRanges_ = new Map();
  5. this.processedDateRanges_ = new Map();
  6. }
  7. setOffset(segments = []) {
  8. // already set
  9. if (this.offset_ !== null) {
  10. return;
  11. }
  12. // no segment to process
  13. if (!segments.length) {
  14. return;
  15. }
  16. const [firstSegment] = segments;
  17. // no program date time
  18. if (firstSegment.programDateTime === undefined) {
  19. return;
  20. }
  21. // Set offset as ProgramDateTime for the very first segment of the very first playlist load:
  22. this.offset_ = firstSegment.programDateTime / 1000;
  23. }
  24. setPendingDateRanges(dateRanges = []) {
  25. if (!dateRanges.length) {
  26. return;
  27. }
  28. const [dateRange] = dateRanges;
  29. const startTime = dateRange.startDate.getTime();
  30. this.trimProcessedDateRanges_(startTime);
  31. this.pendingDateRanges_ = dateRanges.reduce((map, pendingDateRange) => {
  32. map.set(pendingDateRange.id, pendingDateRange);
  33. return map;
  34. }, new Map());
  35. }
  36. processDateRange(dateRange) {
  37. this.pendingDateRanges_.delete(dateRange.id);
  38. this.processedDateRanges_.set(dateRange.id, dateRange);
  39. }
  40. getDateRangesToProcess() {
  41. if (this.offset_ === null) {
  42. return [];
  43. }
  44. const dateRangeClasses = {};
  45. const dateRangesToProcess = [];
  46. this.pendingDateRanges_.forEach((dateRange, id) => {
  47. if (this.processedDateRanges_.has(id)) {
  48. return;
  49. }
  50. dateRange.startTime = (dateRange.startDate.getTime() / 1000) - this.offset_;
  51. dateRange.processDateRange = () => this.processDateRange(dateRange);
  52. dateRangesToProcess.push(dateRange);
  53. if (!dateRange.class) {
  54. return;
  55. }
  56. if (dateRangeClasses[dateRange.class]) {
  57. const length = dateRangeClasses[dateRange.class].push(dateRange);
  58. dateRange.classListIndex = length - 1;
  59. } else {
  60. dateRangeClasses[dateRange.class] = [dateRange];
  61. dateRange.classListIndex = 0;
  62. }
  63. });
  64. for (const dateRange of dateRangesToProcess) {
  65. const classList = dateRangeClasses[dateRange.class] || [];
  66. if (dateRange.endDate) {
  67. dateRange.endTime = (dateRange.endDate.getTime() / 1000) - this.offset_;
  68. } else if (dateRange.endOnNext && classList[dateRange.classListIndex + 1]) {
  69. dateRange.endTime = classList[dateRange.classListIndex + 1].startTime;
  70. } else if (dateRange.duration) {
  71. dateRange.endTime = dateRange.startTime + dateRange.duration;
  72. } else if (dateRange.plannedDuration) {
  73. dateRange.endTime = dateRange.startTime + dateRange.plannedDuration;
  74. } else {
  75. dateRange.endTime = dateRange.startTime;
  76. }
  77. }
  78. return dateRangesToProcess;
  79. }
  80. trimProcessedDateRanges_(startTime) {
  81. const copy = new Map(this.processedDateRanges_);
  82. copy.forEach((dateRange, id) => {
  83. if (dateRange.startDate.getTime() < startTime) {
  84. this.processedDateRanges_.delete(id);
  85. }
  86. });
  87. }
  88. }