Source: lib/ads/media_tailor_ad.js

  1. /*! @license
  2. * Shaka Player
  3. * Copyright 2016 Google LLC
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. goog.provide('shaka.ads.MediaTailorAd');
  7. goog.require('shaka.util.TextParser');
  8. /**
  9. * @implements {shaka.extern.IAd}
  10. * @export
  11. */
  12. shaka.ads.MediaTailorAd = class {
  13. /**
  14. * @param {mediaTailor.Ad} mediaTailorAd
  15. * @param {number} adPosition
  16. * @param {number} totalAds
  17. * @param {HTMLMediaElement} video
  18. */
  19. constructor(mediaTailorAd, adPosition, totalAds, isLinear, video) {
  20. /** @private {?mediaTailor.Ad} */
  21. this.ad_ = mediaTailorAd;
  22. /** @private {?number} */
  23. this.skipOffset_ = this.parseTime_(this.ad_.skipOffset);
  24. /** @private {HTMLMediaElement} */
  25. this.video_ = video;
  26. /** @private {?number} */
  27. this.adPosition_ = adPosition;
  28. /** @private {?number} */
  29. this.totalAds_ = totalAds;
  30. /** @private {boolean} */
  31. this.isLinear_ = isLinear;
  32. /** @private {boolean} */
  33. this.isSkipped_ = false;
  34. }
  35. /**
  36. * @override
  37. * @export
  38. */
  39. needsSkipUI() {
  40. return true;
  41. }
  42. /**
  43. * @override
  44. * @export
  45. */
  46. getDuration() {
  47. return this.ad_.durationInSeconds;
  48. }
  49. /**
  50. * @override
  51. * @export
  52. */
  53. getMinSuggestedDuration() {
  54. return this.getDuration();
  55. }
  56. /**
  57. * @override
  58. * @export
  59. */
  60. getRemainingTime() {
  61. const endTime = this.ad_.startTimeInSeconds + this.ad_.durationInSeconds;
  62. return endTime - this.video_.currentTime;
  63. }
  64. /**
  65. * @override
  66. * @export
  67. */
  68. isPaused() {
  69. return this.video_.paused;
  70. }
  71. /**
  72. * @override
  73. * @export
  74. */
  75. isSkippable() {
  76. if (typeof this.skipOffset_ == 'number') {
  77. return true;
  78. }
  79. return false;
  80. }
  81. /**
  82. * @override
  83. * @export
  84. */
  85. getTimeUntilSkippable() {
  86. if (typeof this.skipOffset_ != 'number') {
  87. return this.getRemainingTime();
  88. }
  89. const canSkipIn =
  90. this.getRemainingTime() + this.skipOffset_ - this.getDuration();
  91. return Math.max(canSkipIn, 0);
  92. }
  93. /**
  94. * @override
  95. * @export
  96. */
  97. canSkipNow() {
  98. return this.getTimeUntilSkippable() == 0;
  99. }
  100. /**
  101. * @override
  102. * @export
  103. */
  104. skip() {
  105. this.isSkipped_ = true;
  106. this.video_.currentTime += this.getRemainingTime();
  107. }
  108. /**
  109. * @override
  110. * @export
  111. */
  112. pause() {
  113. return this.video_.pause();
  114. }
  115. /**
  116. * @override
  117. * @export
  118. */
  119. play() {
  120. return this.video_.play();
  121. }
  122. /**
  123. * @override
  124. * @export
  125. */
  126. getVolume() {
  127. return this.video_.volume;
  128. }
  129. /**
  130. * @override
  131. * @export
  132. */
  133. setVolume(volume) {
  134. this.video_.volume = volume;
  135. }
  136. /**
  137. * @override
  138. * @export
  139. */
  140. isMuted() {
  141. return this.video_.muted;
  142. }
  143. /**
  144. * @override
  145. * @export
  146. */
  147. isLinear() {
  148. return this.isLinear_;
  149. }
  150. /**
  151. * @override
  152. * @export
  153. */
  154. resize(width, height) {
  155. // Nothing
  156. }
  157. /**
  158. * @override
  159. * @export
  160. */
  161. setMuted(muted) {
  162. this.video_.muted = muted;
  163. }
  164. /**
  165. * @override
  166. * @export
  167. */
  168. getSequenceLength() {
  169. if (!this.totalAds_) {
  170. return 1;
  171. }
  172. return this.totalAds_;
  173. }
  174. /**
  175. * @override
  176. * @export
  177. */
  178. getPositionInSequence() {
  179. if (!this.adPosition_) {
  180. return 1;
  181. }
  182. return this.adPosition_;
  183. }
  184. /**
  185. * @override
  186. * @export
  187. */
  188. getTitle() {
  189. return this.ad_.adTitle;
  190. }
  191. /**
  192. * @override
  193. * @export
  194. */
  195. getDescription() {
  196. return '';
  197. }
  198. /**
  199. * @override
  200. * @export
  201. */
  202. getVastMediaBitrate() {
  203. return 0;
  204. }
  205. /**
  206. * @override
  207. * @export
  208. */
  209. getVastMediaHeight() {
  210. return 0;
  211. }
  212. /**
  213. * @override
  214. * @export
  215. */
  216. getVastMediaWidth() {
  217. return 0;
  218. }
  219. /**
  220. * @override
  221. * @export
  222. */
  223. getAdId() {
  224. return this.ad_.adId;
  225. }
  226. /**
  227. * @override
  228. * @export
  229. */
  230. getCreativeAdId() {
  231. return this.ad_.creativeId;
  232. }
  233. /**
  234. * @override
  235. * @export
  236. */
  237. getAdvertiserName() {
  238. return '';
  239. }
  240. /**
  241. * @override
  242. * @export
  243. */
  244. getMediaUrl() {
  245. return null;
  246. }
  247. /**
  248. * @override
  249. * @export
  250. */
  251. getTimeOffset() {
  252. return 0;
  253. }
  254. /**
  255. * @override
  256. * @export
  257. */
  258. getPodIndex() {
  259. return 0;
  260. }
  261. /**
  262. * @override
  263. * @export
  264. */
  265. release() {
  266. this.ad_ = null;
  267. this.video_ = null;
  268. this.adPosition_ = null;
  269. this.totalAds_ = null;
  270. }
  271. /**
  272. * @return {boolean}
  273. */
  274. isSkipped() {
  275. return this.isSkipped_;
  276. }
  277. /**
  278. * Parses a time from string.
  279. *
  280. * @param {?string} time
  281. * @return {?number}
  282. * @private
  283. */
  284. parseTime_(time) {
  285. if (!time) {
  286. return null;
  287. }
  288. const parser = new shaka.util.TextParser(time);
  289. const results = parser.readRegex(shaka.ads.MediaTailorAd.timeFormat_);
  290. if (results == null) {
  291. return null;
  292. }
  293. // This capture is optional, but will still be in the array as undefined,
  294. // in which case it is 0.
  295. const hours = Number(results[1]) || 0;
  296. const minutes = Number(results[2]);
  297. const seconds = Number(results[3]);
  298. const milliseconds = Number(results[4]) || 0;
  299. if (minutes > 59 || seconds > 59) {
  300. return null;
  301. }
  302. return (milliseconds / 1000) + seconds + (minutes * 60) + (hours * 3600);
  303. }
  304. };
  305. /**
  306. * @const
  307. * @private {!RegExp}
  308. * @example 00:00.000 or 00:00:00.000 or 0:00:00.000 or
  309. * 00:00.00 or 00:00:00.00 or 0:00:00.00 or 00:00:00
  310. */
  311. shaka.ads.MediaTailorAd.timeFormat_ =
  312. /(?:(\d{1,}):)?(\d{2}):(\d{2})((\.(\d{1,3})))?/g;