Get Page Title

Extract web video title

// ==UserScript==
// @name           Get Page Title
// @description    Extract web video title
// @namespace https://greasyfork.org/users/3920
// @match http://*/*
// @match https://*/*
// @version 0.0.1.20251006121143
// ==/UserScript==

(function () {
let GetJson = function (url, options = {}) {
  return fetch(url, options)
  .then((response) => {
    return response.json();
  })
  .then((data) => {
    return data;
  });
};

	copyToClipboard = function(val) {
		let t = document.createElement("textarea");
		document.body.appendChild(t);
		t.value = val;
		t.select();
		document.execCommand('copy');
		document.body.removeChild(t);
	}

	function CreateTable(col, row, color = "") {
		if (color === "")
			color = "white";

		let row_dom = document.createElement('div');
		row_dom.setAttribute('id', row);
		row_dom.setAttribute('style', 'color:' + color + ';font:12px Meiryo;');
		row_dom.setAttribute('onclick', 'copyToClipboard(this.getAttribute("value"));');

		let col_dom = document.getElementById(col);
		if(col_dom === null) {
			col_dom = document.createElement('div');
			col_dom.setAttribute('id', col);
			col_dom.setAttribute('style', 'display:table-cell;padding:0px 10px 0px 10px; vertical-align:middle;');

			let table_dom = document.getElementById('resulttable');
			if(table_dom === null)
				CreateLayout();
			table_dom = document.getElementById('resulttable');
			if(table_dom !== null)
				table_dom.appendChild(col_dom);
		}

		col_dom.appendChild(row_dom);
	}

	function CreateLayout(color) {
		let trends_dom = document.getElementById('extractresult');
		if (trends_dom !== null)
			trends_dom.outerHTML = "";
		trends_dom = document.createElement('div');
		trends_dom.setAttribute('id', 'extractresult');
		let title_dom = document.createElement('strong');
		title_dom.innerHTML = [
			'<div style="display: block; text-align:center; width: 100%; padding: 0px; margin: auto; vertical-align: middle; border-spacing: 0px"><div id="resulttable" style="display: inline-table;">',
			'</div></div>'
		].join(' ');

		trends_dom.appendChild(title_dom);
		trends_dom.style.cssText = [
			'background: rgba(55, 55, 55, 0.5);',
			'color: #fff;',
			'padding: 0px;',
			'position: fixed;',
			'z-index:102400;',
			'width:100%;',
			'font: 12px Meiryo;',
			'vertical-align: middle;',
		].join(' ');
		document.body.style.cssText = 'position: relative; margin-top: 0px';
		document.body.insertBefore(trends_dom, document.body.firstElementChild);
	}

	function SetResult(name, value, col_id, row_id, color = "") {
		let elem = document.getElementById(row_id);
		if (elem === null)
			CreateTable(col_id, row_id, color);

		elem = document.getElementById(row_id);
		if (elem !== null) {
			elem.setAttribute('value', value);
			elem.innerHTML = name;
		}
	}

	function Convert(title) {
		return title.replace(/\//g, "/").replace(/!/g, "!").replace(/\?/g, "?").replace(/&/g, "&").replace(/\^/g, "^").replace(/:/g, ":").replace(/%/g, "%").replace(/\</g, "〈").replace(/\>/g, "〉");
	}

  function TverVideo(filename) {
    if (!window.videojs) return;
    for (let src of window.videojs.players[Object.keys(window.videojs.players)[0]].mediainfo.sources) {
      if (/mpegurl/.test(src.type)) {
        //console.log(src);
        SetResult(`Video : ${filename}`, `${src.src}\n${filename}\n`, "right", "video");
        break;
      }
    }
  }
function TverKey() {
  /**
   * 주어진 시간만큼 현재 시간에서 더한 값을 밀리초 단위의 타임스탬프로 반환합니다.
   * @param {object} options - 더할 시간을 나타내는 객체입니다. 예: { hours: 9 }
   * @returns {number} - 1970-01-01T00:00:00Z부터 경과한 시간을 밀리초로 나타낸 타임스탬프입니다.
   */
  function timeMilliseconds(options = {}) {
    const { days = 0, hours = 0, minutes = 0, seconds = 0 } = options;
    const future = new Date();
    future.setDate(future.getDate() + days);
    future.setHours(future.getHours() + hours);
    future.setMinutes(future.getMinutes() + minutes);
    future.setSeconds(future.getSeconds() + seconds);
    return future.getTime();
  }

  const futureTimestamp = timeMilliseconds({ hours: 9 });
  const date = new Date(futureTimestamp);

  // UTC 기준 월을 가져옵니다 (0 = 1월, 1 = 2월, ...). 1을 더해 1-12 범위로 맞춥니다.
  const month = date.getUTCMonth() + 1;

  // 파이썬의 'or'와 동일한 기능을 하는 논리 연산자 '||'를 사용합니다.
  // month % 6의 결과가 0 (falsy)이면 6을 할당합니다.
  const key_idx = (month % 6) || 6;
  return key_idx;
}

  async function TverVideoDownload(pid, vid) {
    let _STREAKS_API_INFO = await GetJson('https://player.tver.jp/player/streaks_info_v2.json');
    let info = await GetJson(`https://mocho.pp.ua/tver/info.php?pid=${pid}&vid=${vid}&key=${_STREAKS_API_INFO[pid]['api_key'][`key0${TverKey()}`]}`);
    if (undefined === info.sources) return '';
    for (let src of info.sources) {
      if ('1920x1080' == src.resolution) return src.src;
    }
    return '';
/*
    a=document.createElement('a');
    a.href=`ytdlp:tver@_@${filename}@_@null@_@${window.location.href}`;
    a.click();
    a.remove();
*/
  }

	async function TverInfo(json) {
		let filename = "";

		if (json.broadcastDateLabel !== undefined) {
			let date = /((\d+)[^\d]+(\d+)|(\d{4})).+/gm.exec(json.broadcastDateLabel);
			if(date !== null) {
				if(date[4] === undefined) {
					let today = new Date();
					let yyyy = today.getFullYear();
					let mm = (date[2].length > 1 ? "" : "0") + date[2];
					let dd = (date[3].length > 1 ? "" : "0") + date[3];
					filename = yyyy + mm + dd;
				} else {
					filename = date[4];
				}
			}
		}

		if (json.share !== undefined && json.share.text !== undefined && json.share.text.match(/([^\n]+)/)) {
			filename += (filename.length === 0 ? "" : " ") + RegExp.$1;
		}

		let episode = document.querySelectorAll('span[class^="titles_title"]');
		if(json.title !== undefined && json.title !== "")
			filename += " " + json.title;

/*
		let onair = document.querySelectorAll('div[class^="description_metaDetail"]');
		if(onair.length > 0 && onair[0].innerText !== "") {
			onair = onair[0].getElementsByTagName("span");
			if(onair.length > 1 && onair[1].innerText !== "") {
				let date = /((\d+)[^\d]+(\d+)|(\d{4})).+/gm.exec(onair[1].innerText);
				if(date !== null) {
					if(date[4] === undefined) {
						let today = new Date();
						let yyyy = today.getFullYear();
						let mm = (date[2].length > 1 ? "" : "0") + date[2];
						let dd = (date[3].length > 1 ? "" : "0") + date[3];
						filename = yyyy + mm + dd;
					} else {
						filename = date[4];
					}
				}
			}
		}

		let title = document.querySelectorAll('span[class^="titles_seriesTitle"]');
		if(title.length > 0 && title[0].innerText !== "")
			filename += (filename.length === 0 ? "" : " ") + title[0].innerText;

		let episode = document.querySelectorAll('span[class^="titles_title"]');
		if(episode.length > 0 && episode[0].innerText !== "")
			filename += " " + episode[0].innerText;
*/

		filename = Convert(filename);
		let hls = await TverVideoDownload(json.streaks.projectID, json.streaks.videoRefID);
		if ('' !== hls)
			SetResult('HLS copy', `${hls}\n${filename}\n`, "right", "video");
		else
			SetResult('error', '', "right", "video");
		SetResult(filename, filename, "right", "title");
		TverVideo(filename);

		if(json.id !== undefined) {
			let img = `https://statics.tver.jp/images/content/thumbnail/episode/xlarge/${json.id}.jpg`;
			SetResult('<a href="' + img + '" download="' + filename + '"><img src="' + img + '" width="300px"></a>', img, "right", "thum");
		}

		console.log(filename);
	}

	function Tver() {
		let id = document.location.href;
		if (id.match(/([^\/\?$]+)(?:$|\?)/))
			id = RegExp.$1;
		else
			id = "";

		if (id === "") {
			console.log("not detected");
		}

		let xmlhttp = new XMLHttpRequest();
		let url = `https://statics.tver.jp/content/episode/${id}.json`;

		xmlhttp.onreadystatechange = function () {
			if (xmlhttp.readyState == XMLHttpRequest.DONE) {
				if (xmlhttp.status == 200) {
					TverInfo(JSON.parse(xmlhttp.responseText));
				} else if (xmlhttp.status == 400) {
					console.log('There was an error 400');
				} else {
					console.log('something else other than 200 was returned');
				}
			}
		};
		xmlhttp.open("GET", url, true);
		xmlhttp.send();
	}

	function NicoLive() {
		let onair = $("*[class^='___onair-time___']")[0].getAttribute("datetime").replace(/(\d+)-(\d+)-(\d+).*/g, "$1$2$3");
		let title = document.getElementsByTagName("h1");
		if(title.length == 1)
			title = title[0].innerText;
		else
			title = $("*[class^='___title___']")[0].innerText;
		title = Convert(onair + " " + title);
		SetResult(title, title, "right", "title");
	}

	function NicoArchive() {
		let onair = document.querySelector('time').getAttribute("datetime").replace(/(\d+)-(\d+)-(\d+).*/g, "$1$2$3");
		let title = document.querySelector('.fs_xl.fw_bold').textContent;

		title = Convert(onair + " " + title);
		SetResult(title, title, "right", "title");
	}

	function Main() {
		if(typeof(jQuery) == 'undefined') {
			let jquery = document.createElement('script');
			jquery.src = 'https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js';
			document.body.appendChild(jquery);
			setTimeout(Main, 100);
			return;
		}

		let url = document.location.href;
		let extractFunc = null;
		if (/tver.jp/gi.test(url))
			extractFunc = Tver;
		else if (/live2?\.nicovideo\.jp/gi.test(url))
			extractFunc = NicoLive;
		else if (/nicovideo\.jp\/watch/.test(url))
			extractFunc = NicoArchive;

		extractFunc();
	}
	Main();
})();