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