Youtube exact upload

Adds exact upload time to youtube videos

  1. // ==UserScript==
  2. // @name Youtube exact upload
  3. // @name:de YouTube exakter Hochladezeitpunkt
  4. // @description Adds exact upload time to youtube videos
  5. // @description:de Fügt YouTube-Videos den exakten Hochladezeitpunkt mit Uhrzeit hinzu
  6. // @require https://cdnjs.cloudflare.com/ajax/libs/luxon/3.4.4/luxon.min.js
  7. // @version 0.18
  8. // @match https://www.youtube.com/*
  9. // @grant none
  10. // @namespace https://greasyfork.org/users/94906
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. // luxon is for formatting and comparing dates and times
  15.  
  16. (function () {
  17. "use strict";
  18. console.log("YT EXACT UPLOAD LOADED");
  19. //Pre-Define Variables to prevent warning of redaclaration of variables
  20. var DATE_PATTERN,
  21. TIME_PATTERN,
  22. DATETIME_COMBINE_PATTERN,
  23. SCHEDULED_LIVESTREAM_START,
  24. SCHEDULED_PREMIERE_START,
  25. ONGOING_LIVESTREAM_START;
  26. var ONGOING_PREMIERE_START,
  27. ENDED_LIVESTREAM_START,
  28. ENDED_PREMIERE_START,
  29. DATETIME_UNTIL_PATTERN,
  30. SINCE,
  31. TODAY_AT;
  32. var YT_API_KEY = "YouTube API-Key";
  33. var AGE_RESTRICTED = " - FSK 18";
  34. var SHOW_REFRESH = true;
  35. var REFRESH_TIMESTAMP = "⟳";
  36. var SHOW_UNDERLINE_ON_TIMESTAMP = false;
  37. var BASE_URL =
  38. "https://www.googleapis.com/youtube/v3/videos?part=snippet,liveStreamingDetails,contentDetails,localizations,player,statistics,status&key=" +
  39. YT_API_KEY;
  40. var lang = document.getElementsByTagName("html")[0].getAttribute("lang");
  41. luxon.Settings.defaultLocale = lang;
  42. if (lang.startsWith("de")) {
  43. DATE_PATTERN = "dd.MM.yyyy"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  44. TIME_PATTERN = "HH:mm:ss 'Uhr'"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  45. DATETIME_COMBINE_PATTERN = " 'um' "; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  46. SCHEDULED_LIVESTREAM_START = "Livestream geplant für: ";
  47. SCHEDULED_PREMIERE_START = "Premiere geplant für: ";
  48. ONGOING_LIVESTREAM_START = "Aktiver Livestream seit ";
  49. ONGOING_PREMIERE_START = "Aktive Premiere seit ";
  50. ENDED_LIVESTREAM_START = "Livestream von ";
  51. ENDED_PREMIERE_START = "Premiere von ";
  52. DATETIME_UNTIL_PATTERN = " bis ";
  53. SINCE = "Seit";
  54. TODAY_AT = "Heute um ";
  55. } else if (lang.startsWith("fr")) {
  56. DATE_PATTERN = "dd MMMM yyyy"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  57. TIME_PATTERN = "HH:mm:ss"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  58. DATETIME_COMBINE_PATTERN = " 'de' "; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  59. SCHEDULED_LIVESTREAM_START = "Direct planifié pour le ";
  60. SCHEDULED_PREMIERE_START = "Première planifiée pour le ";
  61. ONGOING_LIVESTREAM_START = "Direct en cours depuis ";
  62. ONGOING_PREMIERE_START = "Première en cours depuis ";
  63. ENDED_LIVESTREAM_START = "Direct diffusé le ";
  64. ENDED_PREMIERE_START = "Première diffusée le ";
  65. DATETIME_UNTIL_PATTERN = " à ";
  66. SINCE = "Depuis";
  67. TODAY_AT = "Aujourd'hui à ";
  68. } else if (lang.startsWith("it")) {
  69. DATE_PATTERN = "dd MMMM yyyy"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  70. TIME_PATTERN = "HH:mm:ss"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  71. DATETIME_COMBINE_PATTERN = " 'alle' "; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  72. SCHEDULED_LIVESTREAM_START = "Diretta pianificata per il: ";
  73. SCHEDULED_PREMIERE_START = "Premiere pianificata per il: ";
  74. ONGOING_LIVESTREAM_START = "Diretta attiva dalle ";
  75. ONGOING_PREMIERE_START = "Premiere attiva dalle ";
  76. ENDED_LIVESTREAM_START = "Diretta del ";
  77. ENDED_PREMIERE_START = " Premiere del ";
  78. DATETIME_UNTIL_PATTERN = " fino ";
  79. SINCE = "Dalle";
  80. TODAY_AT = "Oggi alle ";
  81. } else {
  82. DATE_PATTERN = "dd.MM.yyyy"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  83. TIME_PATTERN = "HH:mm:ss"; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  84. DATETIME_COMBINE_PATTERN = " 'at' "; // https://moment.github.io/luxon/#/formatting?id=table-of-tokens
  85. SCHEDULED_LIVESTREAM_START = "Livestream scheduled for: ";
  86. SCHEDULED_PREMIERE_START = "Premiere scheduled for: ";
  87. ONGOING_LIVESTREAM_START = "Active Livestream since ";
  88. ONGOING_PREMIERE_START = "Active Premiere since ";
  89. ENDED_LIVESTREAM_START = "Livestream from ";
  90. ENDED_PREMIERE_START = "Premiere from ";
  91. DATETIME_UNTIL_PATTERN = " until ";
  92. SINCE = "Since";
  93. TODAY_AT = "Today at ";
  94. }
  95. var interval = null;
  96. var changeCheckTimer = null;
  97. var currentVideoId = null;
  98. function genUrl() {
  99. const urlParams = new URLSearchParams(window.location.search);
  100.  
  101. if (urlParams.get("v") != null) {
  102. return BASE_URL + "&id=" + urlParams.get("v");
  103. } else {
  104. return "";
  105. }
  106. }
  107. function sleep(milliseconds) {
  108. return new Promise((resolve) => setTimeout(resolve, milliseconds));
  109. }
  110. function formatMilliseconds(
  111. milliseconds,
  112. joinString,
  113. showDays,
  114. showHours,
  115. showMinutes,
  116. showSeconds,
  117. showMilliseconds,
  118. pad,
  119. hideDaysOnNull,
  120. ) {
  121. let result = "";
  122. let days = Math.floor(milliseconds / (1000 * 60 * 60 * 24));
  123. let hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);
  124. let minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
  125. let seconds = Math.floor((milliseconds / 1000) % 60);
  126. milliseconds = milliseconds % 1000;
  127. if (showDays) {
  128. if (days < 1 && hideDaysOnNull) {
  129. } else {
  130. if (result != "") result += joinString;
  131. if (pad) {
  132. if (days < 10) result += "0" + days;
  133. else result += days;
  134. } else result += days;
  135. }
  136. }
  137. if (showHours) {
  138. if (result != "") result += joinString;
  139. if (pad) result += ("0" + hours).slice(-2);
  140. else result += hours;
  141. }
  142. if (showMinutes) {
  143. if (result != "") result += joinString;
  144. if (pad) result += ("0" + minutes).slice(-2);
  145. else result += minutes;
  146. }
  147. if (showSeconds) {
  148. if (result != "") result += joinString;
  149. if (pad) result += ("0" + seconds).slice(-2);
  150. else result += seconds;
  151. }
  152. if (showMilliseconds) {
  153. if (result != "") result += joinString;
  154. if (pad) result += ("00" + milliseconds).slice(-3);
  155. else result += milliseconds;
  156. }
  157. return result;
  158. }
  159. function updateOngoing(startTime) {
  160. if (interval) {
  161. clearInterval(interval);
  162. interval = null;
  163. }
  164. interval = setInterval(function () {
  165. let durationInMilliseconds = luxon.Interval.fromDateTimes(
  166. startTime,
  167. luxon.DateTime.now(),
  168. ).length("milliseconds");
  169. var ongoingVideoDuration = document.getElementById(
  170. "ongoing-video-duration",
  171. );
  172. ongoingVideoDuration.innerHTML = formatMilliseconds(
  173. durationInMilliseconds,
  174. ":",
  175. true,
  176. true,
  177. true,
  178. true,
  179. false,
  180. true,
  181. true,
  182. );
  183. if (ongoingVideoDuration.parentNode) {
  184. ongoingVideoDuration.parentNode.title =
  185. ongoingVideoDuration.parentNode.innerText;
  186. }
  187. }, 500);
  188. }
  189. async function updateLiveContent(premiere, livestream, data, dt) {
  190. var element = null;
  191. while (!element) {
  192. element = document.getElementById("primary-inner");
  193. await sleep(200);
  194. }
  195. var durationInMilliseconds = null;
  196. var ongoing = false;
  197. var innerHTML = "";
  198. if (!premiere && !livestream) {
  199. // normal video
  200. if (dt.hasSame(luxon.DateTime.now(), "day"))
  201. // today
  202. innerHTML += TODAY_AT + dt.toFormat(TIME_PATTERN);
  203. else
  204. innerHTML += dt.toFormat(
  205. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  206. );
  207. } else {
  208. if (!data.items[0].liveStreamingDetails.actualStartTime) {
  209. // planned
  210. dt = luxon.DateTime.fromISO(
  211. data.items[0].liveStreamingDetails.scheduledStartTime,
  212. );
  213. if (dt.hasSame(luxon.DateTime.now(), "day")) {
  214. // today
  215. if (livestream)
  216. innerHTML += SCHEDULED_LIVESTREAM_START + dt.toFormat(TIME_PATTERN);
  217. else if (premiere)
  218. innerHTML += SCHEDULED_PREMIERE_START + dt.toFormat(TIME_PATTERN);
  219. else innerHTML += TODAY_AT + dt.toFormat(TIME_PATTERN);
  220. } else {
  221. if (livestream)
  222. innerHTML +=
  223. SCHEDULED_LIVESTREAM_START +
  224. dt.toFormat(
  225. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  226. );
  227. else if (premiere)
  228. innerHTML +=
  229. SCHEDULED_PREMIERE_START +
  230. dt.toFormat(
  231. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  232. );
  233. else
  234. innerHTML +=
  235. TODAY_AT +
  236. dt.toFormat(
  237. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  238. );
  239. }
  240. } else {
  241. // ongoing / ended
  242. dt = luxon.DateTime.fromISO(
  243. data.items[0].liveStreamingDetails.actualStartTime,
  244. );
  245. var endTime = null;
  246. if (data.items[0].liveStreamingDetails.actualEndTime)
  247. endTime = luxon.DateTime.fromISO(
  248. data.items[0].liveStreamingDetails.actualEndTime,
  249. );
  250. if (endTime == null) {
  251. // ongoing
  252. ongoing = true;
  253. durationInMilliseconds = luxon.Interval.fromDateTimes(
  254. dt,
  255. luxon.DateTime.now(),
  256. ).length("milliseconds");
  257. if (dt.hasSame(luxon.DateTime.now(), "day")) {
  258. // today
  259. if (livestream)
  260. innerHTML +=
  261. ONGOING_LIVESTREAM_START +
  262. dt.toFormat(TIME_PATTERN) +
  263. ' (<span id="ongoing-video-duration">' +
  264. formatMilliseconds(
  265. durationInMilliseconds,
  266. ":",
  267. true,
  268. true,
  269. true,
  270. true,
  271. false,
  272. true,
  273. true,
  274. ) +
  275. "</span>)";
  276. else if (premiere)
  277. innerHTML +=
  278. ONGOING_PREMIERE_START +
  279. dt.toFormat(TIME_PATTERN) +
  280. ' (<span id="ongoing-video-duration">' +
  281. formatMilliseconds(
  282. durationInMilliseconds,
  283. ":",
  284. true,
  285. true,
  286. true,
  287. true,
  288. false,
  289. true,
  290. true,
  291. ) +
  292. "</span>)";
  293. else
  294. innerHTML +=
  295. SINCE +
  296. " " +
  297. dt.toFormat(TIME_PATTERN) +
  298. ' (<span id="ongoing-video-duration">' +
  299. formatMilliseconds(
  300. durationInMilliseconds,
  301. ":",
  302. true,
  303. true,
  304. true,
  305. true,
  306. false,
  307. true,
  308. true,
  309. ) +
  310. "</span>)";
  311. } else {
  312. if (livestream)
  313. innerHTML +=
  314. ONGOING_LIVESTREAM_START +
  315. dt.toFormat(
  316. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  317. ) +
  318. ' (<span id="ongoing-video-duration">' +
  319. formatMilliseconds(
  320. durationInMilliseconds,
  321. ":",
  322. true,
  323. true,
  324. true,
  325. true,
  326. false,
  327. true,
  328. true,
  329. ) +
  330. "</span>)";
  331. else if (premiere)
  332. innerHTML +=
  333. ONGOING_PREMIERE_START +
  334. dt.toFormat(
  335. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  336. ) +
  337. ' (<span id="ongoing-video-duration">' +
  338. formatMilliseconds(
  339. durationInMilliseconds,
  340. ":",
  341. true,
  342. true,
  343. true,
  344. true,
  345. false,
  346. true,
  347. true,
  348. ) +
  349. "</span>)";
  350. else
  351. innerHTML +=
  352. SINCE +
  353. " " +
  354. dt.toFormat(
  355. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  356. ) +
  357. ' (<span id="ongoing-video-duration">' +
  358. formatMilliseconds(
  359. durationInMilliseconds,
  360. ":",
  361. true,
  362. true,
  363. true,
  364. true,
  365. false,
  366. true,
  367. true,
  368. ) +
  369. "</span>)";
  370. }
  371. } else {
  372. // ended
  373. if (dt.hasSame(endTime, "day")) {
  374. // start date and end date are the same
  375. if (dt.hasSame(luxon.DateTime.now(), "day")) {
  376. // today
  377. if (livestream)
  378. innerHTML +=
  379. ENDED_LIVESTREAM_START +
  380. dt.toFormat(TIME_PATTERN) +
  381. DATETIME_UNTIL_PATTERN +
  382. endTime.toFormat(TIME_PATTERN);
  383. else if (premiere)
  384. innerHTML +=
  385. ENDED_PREMIERE_START +
  386. dt.toFormat(TIME_PATTERN) +
  387. DATETIME_UNTIL_PATTERN +
  388. endTime.toFormat(TIME_PATTERN);
  389. else innerHTML += TODAY_AT + dt.toFormat(TIME_PATTERN);
  390. } else {
  391. if (livestream)
  392. innerHTML +=
  393. ENDED_LIVESTREAM_START +
  394. dt.toFormat(
  395. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  396. ) +
  397. DATETIME_UNTIL_PATTERN +
  398. endTime.toFormat(TIME_PATTERN);
  399. else if (premiere)
  400. innerHTML +=
  401. ENDED_PREMIERE_START +
  402. dt.toFormat(
  403. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  404. ) +
  405. DATETIME_UNTIL_PATTERN +
  406. endTime.toFormat(TIME_PATTERN);
  407. else
  408. innerHTML +=
  409. dt.toFormat(
  410. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  411. ) +
  412. DATETIME_UNTIL_PATTERN +
  413. endTime.toFormat(TIME_PATTERN);
  414. }
  415. } else {
  416. if (dt.hasSame(luxon.DateTime.now(), "day")) {
  417. // today
  418. if (livestream)
  419. innerHTML +=
  420. ENDED_LIVESTREAM_START +
  421. dt.toFormat(TIME_PATTERN) +
  422. DATETIME_UNTIL_PATTERN +
  423. endTime.toFormat(
  424. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  425. );
  426. else if (premiere)
  427. innerHTML +=
  428. ENDED_PREMIERE_START +
  429. dt.toFormat(TIME_PATTERN) +
  430. DATETIME_UNTIL_PATTERN +
  431. endTime.toFormat(
  432. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  433. );
  434. else
  435. innerHTML +=
  436. TODAY_AT +
  437. dt.toFormat(TIME_PATTERN) +
  438. DATETIME_UNTIL_PATTERN +
  439. endTime.toFormat(
  440. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  441. );
  442. } else {
  443. if (livestream)
  444. innerHTML +=
  445. ENDED_LIVESTREAM_START +
  446. dt.toFormat(
  447. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  448. ) +
  449. DATETIME_UNTIL_PATTERN +
  450. endTime.toFormat(
  451. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  452. );
  453. else if (premiere)
  454. innerHTML +=
  455. ENDED_PREMIERE_START +
  456. dt.toFormat(
  457. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  458. ) +
  459. DATETIME_UNTIL_PATTERN +
  460. endTime.toFormat(
  461. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  462. );
  463. else
  464. innerHTML +=
  465. dt.toFormat(
  466. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  467. ) +
  468. DATETIME_UNTIL_PATTERN +
  469. endTime.toFormat(
  470. DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN,
  471. );
  472. }
  473. }
  474. }
  475. }
  476. }
  477. var contentRating = data.items[0].contentDetails.contentRating;
  478. if (contentRating.ytRating && contentRating.ytRating == "ytAgeRestricted")
  479. innerHTML += AGE_RESTRICTED;
  480. if (SHOW_REFRESH) {
  481. if (SHOW_UNDERLINE_ON_TIMESTAMP)
  482. innerHTML +=
  483. ' <span id="dot" class="style-scope ytd-video-primary-info-renderer"></span> <span style="color: var(--yt-spec-text-secondary); text-decoration: underline var(--yt-spec-text-secondary); cursor: pointer;" onclick="document.dispatchEvent(new Event(\'refresh-clicked\'));">' +
  484. REFRESH_TIMESTAMP +
  485. "</span>";
  486. else
  487. innerHTML +=
  488. ' <span id="dot" class="style-scope ytd-video-primary-info-renderer"></span> <span style="color: var(--yt-spec-text-secondary); cursor: pointer;" onclick="document.dispatchEvent(new Event(\'refresh-clicked\'));">' +
  489. REFRESH_TIMESTAMP +
  490. "</span>";
  491. }
  492. if (ongoing) updateOngoing(dt);
  493. let primaryInner = document.getElementById("primary-inner");
  494. let dateTimeValueElem = document.getElementById("exact-date-time");
  495. if (!dateTimeValueElem) {
  496. dateTimeValueElem = document.createElement("span");
  497. dateTimeValueElem.id = "exact-date-time";
  498. primaryInner.insertBefore(dateTimeValueElem, primaryInner.firstChild);
  499. }
  500. dateTimeValueElem.style.color = "white";
  501. dateTimeValueElem.style.position = "absolute";
  502. dateTimeValueElem.style.zIndex = "999";
  503. dateTimeValueElem.innerHTML = innerHTML;
  504. dateTimeValueElem.title = dateTimeValueElem.innerText;
  505. return ongoing;
  506. }
  507. function getExactUploadDate(forceRefresh = false) {
  508. var abort = false;
  509. const processEvent = async () => {
  510. await sleep(500);
  511. const urlParams = new URLSearchParams(window.location.search);
  512. if (urlParams.get("v") != null) {
  513. let videoId = urlParams.get("v");
  514. if (videoId == currentVideoId) {
  515. abort = true;
  516. } else {
  517. currentVideoId = videoId;
  518. }
  519. }
  520. if (forceRefresh) abort = false;
  521. if ((YT_API_KEY != "" || typeof YT_API_KEY != "undefined") && !abort) {
  522. var url = genUrl();
  523. if (url != "") {
  524. fetch(url)
  525. .then(function (response) {
  526. return response.json();
  527. })
  528. .then(function (data) {
  529. if (data.pageInfo.totalResults > 0) {
  530. const addTime = async () => {
  531. var dt = luxon.DateTime.fromISO(
  532. data.items[0].snippet.publishedAt,
  533. );
  534. console.log(dt);
  535. let payload = {
  536. context: {
  537. client: {
  538. clientName: "WEB",
  539. clientVersion: "2.20210614.06.00",
  540. originalUrl: window.location.href,
  541. platform: "DESKTOP",
  542. clientFormFactor: "UNKNOWN_FORM_FACTOR",
  543. mainAppWebInfo: {
  544. graftUrl: "/watch?v=" + currentVideoId,
  545. webDisplayMode: "WEB_DISPLAY_MODE_BROWSER",
  546. isWebNativeShareAvailable: false,
  547. },
  548. },
  549. user: {
  550. lockedSafetyMode: false,
  551. },
  552. request: {
  553. useSsl: true,
  554. },
  555. },
  556. videoId: currentVideoId,
  557. racyCheckOk: false,
  558. contentCheckOk: false,
  559. };
  560. fetch(
  561. "https://www.youtube.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8" /*InnerTube-API-Key*/,
  562. {
  563. method: "POST",
  564. headers: {
  565. "Content-Type": "application/json",
  566. },
  567. body: JSON.stringify(payload),
  568. },
  569. )
  570. .then(function (response) {
  571. return response.text();
  572. })
  573. .then(function (video_info) {
  574. if (interval) {
  575. clearInterval(interval);
  576. interval = null;
  577. }
  578. if (changeCheckTimer) {
  579. clearInterval(changeCheckTimer);
  580. changeCheckTimer = null;
  581. }
  582. try {
  583. /*let player_response = decodeURIComponent(video_info);
  584. let urlParams = new URLSearchParams(player_response);
  585. if (urlParams.get("player_response") != null) {
  586. player_response = urlParams.get("player_response");
  587. }
  588. player_response = JSON.parse(player_response);// data.items[0].status.privacyStatus = "public" -> Öffentliches Video*/
  589. let player_response = JSON.parse(video_info);
  590. var premiere =
  591. player_response &&
  592. !player_response.videoDetails.isLiveContent;
  593. premiere =
  594. premiere && data.items[0].liveStreamingDetails;
  595. var livestream =
  596. player_response &&
  597. player_response.videoDetails.isLiveContent;
  598. var innerHTML =
  599. '<span id="dot" class="style-scope ytd-video-primary-info-renderer">•</span>';
  600. updateLiveContent(premiere, livestream, data, dt);
  601. } catch (ex) {
  602. console.error(ex);
  603. }
  604. })
  605. .catch((error) =>
  606. console.error(
  607. "YOUTUBE EXACT UPLOAD ERROR: " + error,
  608. "\nget_video_info doesn't seem to work",
  609. ),
  610. );
  611. };
  612. addTime();
  613. }
  614. })
  615. .catch((error) =>
  616. console.error(
  617. "YOUTUBE EXACT UPLOAD ERROR: " + error,
  618. "\nINVALID API KEY?",
  619. ),
  620. );
  621. }
  622. } else {
  623. if (!abort)
  624. console.error("YOUTUBE EXACT UPLOAD ERROR: Undefined api key");
  625. }
  626. };
  627. processEvent();
  628. }
  629. function refreshEventListener() {
  630. getExactUploadDate(true);
  631. }
  632. //getExactUploadDate();
  633. //document.addEventListener('click', getExactUploadDate);
  634. //document.addEventListener('yt-page-data-updated', getExactUploadDate);
  635. //document.addEventListener('yt-navigate-finish', getExactUploadDate);
  636. document.addEventListener("refresh-clicked", refreshEventListener);
  637. //<video style="width: 853px; height: 480px; left: 0px; top: 0px;" tabindex="-1" class="video-stream html5-main-video" src="blob:https://www.youtube.com/0976da77-cfd4-4922-ad9e-383d88a12200"></video>
  638. /*function main() {
  639. let videoStream = document.getElementsByClassName('video-stream');
  640. if (videoStream.length < 1) {
  641. setTimeout(() => main(), 500);
  642. } else {
  643. console.log('video-stream:', videoStream[0]);
  644. // videoStream[0].addEventListener('loadeddata', (event) => console.log(`Loaded ${event.target.src}`));
  645. //videoStream[0].addEventListener('loadeddata', (event) => getExactUploadDate());
  646. videoStream[0].addEventListener('durationchange', (event) => getExactUploadDate());
  647. }
  648. }*/
  649. function main() {
  650. let ytdPlayer = document.getElementById("ytd-player");
  651. if (!ytdPlayer) {
  652. setTimeout(() => main(), 500);
  653. } else {
  654. ytdPlayer.addEventListener("yt-player-updated", (event) =>
  655. getExactUploadDate(),
  656. );
  657. }
  658. }
  659. main();
  660. if (new URLSearchParams(window.location.search).get("v") != null) {
  661. getExactUploadDate();
  662. }
  663. })();