- // ==UserScript==
- // @name Youtube exact upload
- // @name:de YouTube exakter Hochladezeitpunkt
- // @description Adds exact upload time to youtube videos
- // @description:de Fügt YouTube-Videos den exakten Hochladezeitpunkt mit Uhrzeit hinzu
- // @require https://cdn.jsdelivr.net/npm/hacktimer@1.1.3/HackTimer.min.js
- // @require http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js
- // @version 0.3
- // @match https://www.youtube.com/*
- // @grant none
- // @namespace https://greasyfork.org/users/94906
- // @license WTFPL
- // ==/UserScript==
-
- // HackTimer is for making setInterval work in background tabs
- // moment is for formatting and comparing dates and times
-
- (function() {
- 'use strict';
- console.log("YT EXACT UPLOAD LOADED");
- var DATE_PATTERN = "DD.MM.YYYY"; // https://momentjs.com/docs/#/parsing/string-format/
- var TIME_PATTERN = "HH:mm:ss [Uhr]"; // https://momentjs.com/docs/#/parsing/string-format/
- var DATETIME_COMBINE_PATTERN = " [um] ";
- var SCHEDULED_LIVESTREAM_START = "Livestream geplant für: ";
- var SCHEDULED_PREMIERE_START = "Premiere geplant für: ";
- var ONGOING_LIVESTREAM_START = "Aktiver Livestream seit ";
- var ONGOING_PREMIERE_START = "Aktive Premiere seit ";
- var ENDED_LIVESTREAM_START = "Livestream von ";
- var ENDED_PREMIERE_START = "Premiere von ";
- var DATETIME_UNTIL_PATTERN = " bis ";
- var SINCE = "Seit";
- var YT_API_KEY = "AIzaSyCuVr_6gb-vkfbtp6rM0qwWnRQKJXw167c";
- var BASE_URL = "https://www.googleapis.com/youtube/v3/videos?part=snippet,liveStreamingDetails,contentDetails,localizations,player,statistics,status&key=" + YT_API_KEY;
- var interval = null;
- var changeCheckTimer = null;
- var currentVideoId = null;
- //console.log("Language:" + document.getElementsByTagName("html")[0].getAttribute("lang"));
- function genUrl(){
- const urlParams = new URLSearchParams(window.location.search);
-
- if(urlParams.get("v") != null){
- return BASE_URL + "&id=" + urlParams.get("v");
- }else {
- return "";
- }
- }
- function isUndefinedOrNull(obj) {
- return obj == undefined || obj == null;
- }
- function sleep(milliseconds) {
- return new Promise(resolve => setTimeout(resolve, milliseconds));
- }
- function formatMilliseconds(milliseconds, joinString, showDays, showHours, showMinutes, showSeconds, showMilliseconds, pad, hideDaysOnNull) {
- let result = '';
- let days = Math.floor(milliseconds / (1000 * 60 * 60 * 24));
- let hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24);
- let minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
- let seconds = Math.floor((milliseconds / 1000) % 60);
- milliseconds = milliseconds % 1000;
- if (showDays) {
- if (days < 1 && hideDaysOnNull) {
- } else {
- if (result != '')
- result += joinString;
- if (pad) {
- if (days < 10)
- result += '0' + days;
- else
- result += days;
- } else
- result += days;
- }
- }
- if (showHours) {
- if (result != '')
- result += joinString;
- if (pad)
- result += ('0' + hours).slice(-2);
- else
- result += hours;
- }
- if (showMinutes) {
- if (result != '')
- result += joinString;
- if (pad)
- result += ('0' + minutes).slice(-2);
- else
- result += minutes;
- }
- if (showSeconds) {
- if (result != '')
- result += joinString;
- if (pad)
- result += ('0' + seconds).slice(-2);
- else
- result += seconds;
- }
- if (showMilliseconds) {
- if (result != '')
- result += joinString;
- if (pad)
- result += ('00' + milliseconds).slice(-3);
- else
- result += milliseconds;
- }
- return result;
- }
- function updateOngoing(durationInMilliseconds) {
- if (!isUndefinedOrNull(interval)) {
- clearInterval(interval);
- interval = null;
- }
- let duration = durationInMilliseconds;
- interval = setInterval(function() {
- duration += 500;
- document.getElementById("ongoing-video-duration").innerHTML = formatMilliseconds(duration, ':', true, true, true, true, false, true, true);
- }, 500);
- }
- async function updateLiveContent(premiere, livestream, data, mom) {
- var element = null;
- while (isUndefinedOrNull(element)) {
- element = document.getElementById("date");
- await sleep(200);
- }
- var durationInMilliseconds = null;
- var ongoing = false;
- var innerHTML = "<span id=\"dot\" class=\"style-scope ytd-video-primary-info-renderer\">•</span>";
- if (!premiere && !livestream) { // normal video
- if (mom.isSame(moment(), 'day')) // today
- innerHTML += mom.format(TIME_PATTERN);
- else
- innerHTML += mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- } else {
- if (isUndefinedOrNull(data.items[0].liveStreamingDetails.actualStartTime)) { // planned
- mom = moment(data.items[0].liveStreamingDetails.scheduledStartTime);
- if (mom.isSame(moment(), 'day')) { // today
- if (livestream)
- innerHTML += SCHEDULED_LIVESTREAM_START + mom.format(TIME_PATTERN);
- else if (premiere)
- innerHTML += SCHEDULED_PREMIERE_START + mom.format(TIME_PATTERN);
- else
- innerHTML += mom.format(TIME_PATTERN);
- } else {
- if (livestream)
- innerHTML += SCHEDULED_LIVESTREAM_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- else if (premiere)
- innerHTML += SCHEDULED_PREMIERE_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- else
- innerHTML += mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- }
- } else { // ongoing / ended
- mom = moment(data.items[0].liveStreamingDetails.actualStartTime);
- var endTime = null;
- if (!isUndefinedOrNull(data.items[0].liveStreamingDetails.actualEndTime))
- endTime = moment(data.items[0].liveStreamingDetails.actualEndTime);
- if (endTime == null) { // ongoing
- ongoing = true;
- durationInMilliseconds = moment.duration(moment().diff(mom)).asMilliseconds();
- if (mom.isSame(moment(), 'day')) { // today
- if (livestream)
- innerHTML += ONGOING_LIVESTREAM_START + mom.format(TIME_PATTERN) + " (<span id=\"ongoing-video-duration\">" + formatMilliseconds(durationInMilliseconds, ':', true, true, true, true, false, true, true) + "</span>)";
- else if (premiere)
- innerHTML += ONGOING_PREMIERE_START + mom.format(TIME_PATTERN) + " (<span id=\"ongoing-video-duration\">" + formatMilliseconds(durationInMilliseconds, ':', true, true, true, true, false, true, true) + "</span>)";
- else
- innerHTML += SINCE + " " + mom.format(TIME_PATTERN) + " (<span id=\"ongoing-video-duration\">" + formatMilliseconds(durationInMilliseconds, ':', true, true, true, true, false, true, true) + "</span>)";
- } else {
- if (livestream)
- innerHTML += ONGOING_LIVESTREAM_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + " (<span id=\"ongoing-video-duration\">" + formatMilliseconds(durationInMilliseconds, ':', true, true, true, true, false, true, true) + "</span>)";
- else if (premiere)
- innerHTML += ONGOING_PREMIERE_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + " (<span id=\"ongoing-video-duration\">" + formatMilliseconds(durationInMilliseconds, ':', true, true, true, true, false, true, true) + "</span>)";
- else
- innerHTML += SINCE + " " + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + " (<span id=\"ongoing-video-duration\">" + formatMilliseconds(durationInMilliseconds, ':', true, true, true, true, false, true, true) + "</span>)";
- }
- } else { // ended
- if (mom.isSame(endTime, 'day')) { // start date and end date are the same
- if (mom.isSame(moment(), 'day')) { // today
- if (livestream)
- innerHTML += ENDED_LIVESTREAM_START + mom.format(TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(TIME_PATTERN);
- else if (premiere)
- innerHTML += ENDED_PREMIERE_START + mom.format(TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(TIME_PATTERN);
- else
- innerHTML += mom.format(TIME_PATTERN);
- } else {
- if (livestream)
- innerHTML += ENDED_LIVESTREAM_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(TIME_PATTERN);
- else if (premiere)
- innerHTML += ENDED_PREMIERE_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(TIME_PATTERN);
- else
- innerHTML += mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(TIME_PATTERN);
- }
- } else {
- if (mom.isSame(moment(), 'day')) { // today
- if (livestream)
- innerHTML += ENDED_LIVESTREAM_START + mom.format(TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- else if (premiere)
- innerHTML += ENDED_PREMIERE_START + mom.format(TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- else
- innerHTML += mom.format(TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- } else {
- if (livestream)
- innerHTML += ENDED_LIVESTREAM_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- else if (premiere)
- innerHTML += ENDED_PREMIERE_START + mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- else
- innerHTML += mom.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN) + DATETIME_UNTIL_PATTERN + endTime.format(DATE_PATTERN + DATETIME_COMBINE_PATTERN + TIME_PATTERN);
- }
- }
- }
- }
- }
- var contentRating = data.items[0].contentDetails.contentRating;
- if (!isUndefinedOrNull(contentRating.ytRating) && contentRating.ytRating == 'ytAgeRestricted')
- innerHTML += " - FSK 18";
- element.innerHTML = innerHTML;
- if (ongoing)
- updateOngoing(durationInMilliseconds);
- return ongoing;
- }
- function updateLiveContentWithChangeCheck(premiere, livestream, data, mom) {
- var ongoing = updateLiveContent(premiere, livestream, data, mom);
- /*document.getElementsByClassName('html5-main-video')[0].addEventListener('ended', function() {
- fetch('https://www.youtube.com/get_video_info?video_id=' + currentVideoId).then(function(response) {
- return response.text();
- }).then(function(video_info) {
- try {
- let player_response = decodeURIComponent(video_info);
- let urlParams = new URLSearchParams(player_response);
- if (urlParams.get("player_response") != null) {
- player_response = urlParams.get("player_response");
- }
- player_response = JSON.parse(player_response);
- var premiere = !isUndefinedOrNull(player_response) && !player_response.videoDetails.isLiveContent;
- premiere = premiere && !isUndefinedOrNull(data.items[0].liveStreamingDetails);
- var livestream = !isUndefinedOrNull(player_response) && player_response.videoDetails.isLiveContent;
- var live = !isUndefinedOrNull(player_response) && player_response.videoDetails.isLive;
- if (ongoing)
- updateLiveContent(premiere, livestream, data, mom);
- } catch (ex) {
- console.error(ex);
- }
- }).catch(error => console.error("YOUTUBE EXACT UPLOAD ERROR: " + error, "\nget_video_info doesn't seem to work"));
- });*/
- }
- function getExactUploadDate() {
- var abort = false;
- const processEvent = async () => {
- await sleep(500);
- const urlParams = new URLSearchParams(window.location.search);
- if (urlParams.get("v") != null){
- let videoId = urlParams.get("v");
- if (videoId == currentVideoId) {
- abort = true;
- } else {
- currentVideoId = videoId;
- }
- }
- if ((YT_API_KEY != "" || typeof YT_API_KEY != "undefined") && !abort) {
- var url = genUrl();
- if (url != "") {
- fetch(url).then(function(response) {
- return response.json();
- }).then(function(data) {
- if (data.pageInfo.totalResults > 0) {
- const addTime = async () => {
-
- var mom = moment(data.items[0].snippet.publishedAt);
- console.log(mom);
- fetch('https://www.youtube.com/get_video_info?video_id=' + currentVideoId).then(function(response) {
- return response.text();
- }).then(function(video_info) {
- if (!isUndefinedOrNull(interval)) {
- clearInterval(interval);
- interval = null;
- }
- if (!isUndefinedOrNull(changeCheckTimer)) {
- clearInterval(changeCheckTimer);
- changeCheckTimer = null;
- }
- try {
- let player_response = decodeURIComponent(video_info);
- let urlParams = new URLSearchParams(player_response);
- if (urlParams.get("player_response") != null) {
- player_response = urlParams.get("player_response");
- }
- player_response = JSON.parse(player_response);// data.items[0].status.privacyStatus = "public" -> Öffentliches Video
- var premiere = !isUndefinedOrNull(player_response) && !player_response.videoDetails.isLiveContent;
- premiere = premiere && !isUndefinedOrNull(data.items[0].liveStreamingDetails);
- var livestream = !isUndefinedOrNull(player_response) && player_response.videoDetails.isLiveContent;
- var innerHTML = "<span id=\"dot\" class=\"style-scope ytd-video-primary-info-renderer\">•</span>";
- updateLiveContentWithChangeCheck(premiere, livestream, data, mom);
- } catch (ex) {
- console.error(ex);
- }
- }).catch(error => console.error("YOUTUBE EXACT UPLOAD ERROR: " + error, "\nget_video_info doesn't seem to work"));
- }
- addTime();
- }
- }).catch(error => console.error("YOUTUBE EXACT UPLOAD ERROR: " + error, "\nINVALID API KEY?"));
- }
- } else {
- if(!abort)
- console.error("YOUTUBE EXACT UPLOAD ERROR: Undefined api key");
- }
- }
- processEvent();
- }
- //getExactUploadDate();
- //document.addEventListener('click', getExactUploadDate);
- //document.addEventListener('yt-page-data-updated', getExactUploadDate);
- document.addEventListener('yt-navigate-finish', getExactUploadDate);
- })();