/* @since 2024-03-05 NicoCache_nl シス?ファイル. Domand用にURLインジェクションする. * 2023年11月に部??され2024年2月から本格導?された?動画配信仕?(Domand,CMAF,DMS)では? * 要求URLに動画ID(smXXX)が乗らな??jsonにも現れな?. リファラにも乗らな?. * nicocache_nlのサーバ?側に伝えるために、要?APIを乗っ取ってURLに動画IDなど??を乗せ?. * searchに乗った情報はニコ動サーバ?に伝わる前にDefaultRequestFilter.javaで消す. * ?onRequestではrequestHeader.getParameter("nicocachenl_XXX")の形式で値を取れる. */ // Web Workerでも動くよ?window変数ではなくself変数を使?. // こ?コード? NicoCache_nl.watch, NicoCache_nl.watch.apiData.video.id を使? // とを??して??. 使った方が綺麗かど?の検証をして??. (function() { 'use strict'; /* * - threadId: コメントスレ?idの意味. /watch/以降に現れることがある数字???id. * - videoId: sm,nm,soで始まるよ?id. * - 他JSがこれを読みたい場合あるか?. */ const threadIdToVideoId = {}; // - 2024-09-03: 機?して??. js-initial-watch-dataと?idを持つhtml elementは // jsが実行される前?htmlにも、jsが実行された後?htmlにも存在しな?. /* jsonから上記連想配?を追?. */ function initThreadIdToVideoId() { /* 「お探し?動画は視?できません」ではnull. */ const watch_data = document.getElementById("js-initial-watch-data"); if (watch_data === null) { return; }; const api_data = watch_data.getAttribute("data-api-data"); if (api_data == null) { return; /* 異常. */ }; let api_json; try { api_json = JSON.parse(api_data); } catch (e) { return; /* 異常. */ }; if (api_json === null || api_json.comment === undefined || api_json.comment === null || api_json.comment.threads === undefined || api_json.comment.threads === null || !(api_json.comment.threads instanceof Array)) { return; /* 正常 | 異常. */ }; for (const thread of api_json.comment.threads) { if (thread.id !== undefined && thread.videoId !== undefined) { threadIdToVideoId[thread.id] = thread.videoId; }; }; }; function log_bottom(s) { const div = document.createElement("div"); const br = document.createElement("br"); div.textContent = s; if (document.body != null) { document.body.appendChild(div); document.body.appendChild(br); }; }; function add_search(url, search) { if (url.includes('?')) { return url + '&' + search; }; return url + '?' + search; }; function domain_starts_with(url, x) { if (url.startsWith("https://" + x + "/")) { return true; }; return url.startsWith("//" + x + "/"); }; /* * - [NicoCacheのjava側]に伝える情報を付け足したurlを返す. * - 動作非対象のurlはそ?まま返す. */ function might_add_video_info(url) { /* * if (url.includes(".key")) {log_bottom(url);}; */ /* インジェクション動作対象URL. ??なのはマスターm3u8を示すURL. */ if (domain_starts_with(url, 'asset.domand.nicovideo.jp')) { /* * - "CMAF付与情報取得失?"エラーの出力を抑制する. */ return add_search(url, 'nicocachenl_noerror=true'); }; if (! domain_starts_with(url, 'delivery.domand.nicovideo.jp')) { return url; }; /* * embed.nicovideo.jpなどを除外す?. */ if (location.host === 'www.nicovideo.jp' && location.pathname.startsWith('/watch/')) { // do nothing. } else { return add_search(url, 'nicocachenl_noerror=true'); }; const [video_type, video_id] = (() => { let rest = location.pathname.substring("/watch/".length); if (rest.match(/^[0-9]/)) { /* - restはコメントスレ?ID. */ /* - それをsmXXXへ. */ if (undefined === threadIdToVideoId[rest]) { return [null, null]; /* 失?. 異常. */ }; rest = threadIdToVideoId[rest]; }; /* 英字部と数字部に??. */ const m = rest.match(/^(nm|sm|so)([0-9]+)/); if (m === null) { return [null, null]; }; return [m[1], m[2]]; })(); if (video_id === null) { return url; }; const asearch = 'nicocachenl_video_id=' + video_id + '&nicocachenl_video_type=' + video_type; return add_search(url, asearch); }; function wrap_fetch() { const original_fetch = self.fetch; const fetch = function fetch(input, ...rest) { if (input === undefined || input === null || input.constructor === undefined) { // do nothing. } else if (input.constructor.name === 'Request') { // console.log('fetch req url "' + input.url + '"'); // do nothing. } else { /* タイ?シフト予?そ?削除がここを通る */ // console.log('fetch txt url "' + input + '"'); input = might_add_video_info(`${input}`); }; return original_fetch(input, ...rest); }; self.fetch = fetch; }; function wrap_XMLHttpRequest_open() { const original_open = XMLHttpRequest.prototype.open; const open = function open(method, url, ...rest) { /* * - 2024年8月時点、ここを通ってdelivery.domand.nicovideo.jpへのリクエスト?実行される. */ url = might_add_video_info(url); // console.log(`xml url "${url}"`); return original_open.call(this, method, url, ...rest); }; XMLHttpRequest.prototype.open = open; }; function wrap_Request() { const original_Request = self.Request; // 2024-08 watchペ?ジはRequestを使って取得される. self.Request = new Proxy(Request, { construct: function(target, argumentsList, newTarget) { // console.log("//Request.[[constructor]]"); if (0 !== argumentsList.length) { const url = argumentsList[0]; // console.log(`Req url "${url}"`); if (null !== url && undefined === url) { // do nothing. } else if(url.constructor === String) { argumentsList[0] = might_add_video_info(url); }; }; return new target(...argumentsList); } }); }; if (location.pathname.startsWith("/watch/") && location.host === 'www.nicovideo.jp') { // do nothing } else { // Request?fetchの例で予想外?エラーを引き起こして?. // 被害縮小?ためにwatchペ?ジ以外では動作させな?. return; }; wrap_Request(); wrap_XMLHttpRequest_open(); wrap_fetch(); if (document.readyState === 'complete') { initThreadIdToVideoId(); } else { document.addEventListener("DOMContentLoaded", initThreadIdToVideoId); }; })();