From 6500ee746c29f19838ad891a7a748b7f583a9174 Mon Sep 17 00:00:00 2001 From: Andrew S Date: Sun, 17 Dec 2023 21:08:52 -0600 Subject: [PATCH] Custom source pattern support --- chrome/_locales/en/messages.json | 6 +++ chrome/_locales/es/messages.json | 6 +++ chrome/_locales/ja/messages.json | 6 +++ chrome/background/background.mjs | 46 ++++++++++++++++--- .../options/defaults/DefaultOptions.mjs | 1 + chrome/player/options/index.html | 4 ++ chrome/player/options/options.css | 6 ++- chrome/player/options/options.mjs | 7 +++ 8 files changed, 74 insertions(+), 8 deletions(-) diff --git a/chrome/_locales/en/messages.json b/chrome/_locales/en/messages.json index 250a5491..308cbf6e 100644 --- a/chrome/_locales/en/messages.json +++ b/chrome/_locales/en/messages.json @@ -768,6 +768,12 @@ "options_autourl_hint": { "message": "Hint: Test regex on" }, + "options_pattern_header": { + "message": "Custom Source Patterns" + }, + "options_pattern_body": { + "message": "These patterns are used to detect custom video sources on webpages. They are applied in order, and the first match is used. For advanced users only." + }, "options_help_header": { "message": "Help" }, diff --git a/chrome/_locales/es/messages.json b/chrome/_locales/es/messages.json index 938acd4c..d155b636 100644 --- a/chrome/_locales/es/messages.json +++ b/chrome/_locales/es/messages.json @@ -767,6 +767,12 @@ "options_autourl_hint": { "message": "Sugerencia: Prueba regex en" }, + "options_pattern_header": { + "message": "Patrones de Fuente Personalizados" + }, + "options_pattern_body": { + "message": "Estos patrones se utilizan para detectar fuentes de video personalizadas en páginas web. Se aplican en orden y se usa la primera coincidencia. Solo para usuarios avanzados." + }, "options_help_header": { "message": "Ayuda" }, diff --git a/chrome/_locales/ja/messages.json b/chrome/_locales/ja/messages.json index e292e86c..214a3e58 100644 --- a/chrome/_locales/ja/messages.json +++ b/chrome/_locales/ja/messages.json @@ -768,6 +768,12 @@ "options_autourl_hint": { "message": "ヒント: 正規表現のテストができます" }, + "options_pattern_header": { + "message": "カスタムソースパターン" + }, + "options_pattern_body": { + "message": "これらのパターンは、Web ページ上のカスタム動画ソースを検出するために使用されます。順番に適用され、最初に一致したものが使用されます。上級者向け。" + }, "options_help_header": { "message": "ヘルプ" }, diff --git a/chrome/background/background.mjs b/chrome/background/background.mjs index a0e637e1..96ec7e44 100644 --- a/chrome/background/background.mjs +++ b/chrome/background/background.mjs @@ -12,6 +12,7 @@ import {StreamSaverBackend} from './StreamSaverBackend.mjs'; let Options = {}; const AutoEnableList = []; +const CustomSourcePatterns = []; const ExtensionVersion = chrome.runtime.getManifest().version; const Logging = false; const PlayerURL = chrome.runtime.getURL('player/index.html'); @@ -425,11 +426,37 @@ async function loadOptions(newOptions) { } if (urlStr[0] === '~') { - AutoEnableList.push(new RegExp(urlStr.substring(1))); + try { + AutoEnableList.push(new RegExp(urlStr.substring(1))); + } catch (e) { + } } else { AutoEnableList.push(urlStr); } }); + + CustomSourcePatterns.length = 0; + Options.customSourcePatterns.split('\n') .forEach((line)=>{ + line = line.trim(); + if (line.length === 0) return; + if (line.startsWith('#') || line.startsWith('//')) return; + + const args = line.split(' '); + const extStr = args[0]; + const regexStr = args.slice(1).join(' '); + + // parse regex and flags + const regex = regexStr.substring(1, regexStr.lastIndexOf('/')); + const flags = regexStr.substring(regexStr.lastIndexOf('/') + 1); + try { + CustomSourcePatterns.push({ + regex: new RegExp(regex, flags), + ext: extStr, + }); + } catch (e) { + + } + }); } async function setupRedirectRule(ruleID, filetypes) { @@ -762,10 +789,21 @@ function frameHasPlayer(frame) { chrome.webRequest.onHeadersReceived.addListener( (details) => { const url = details.url; - const ext = URLUtils.get_url_extension(url); + let ext = URLUtils.get_url_extension(url); const frame = getOrCreateFrame(details); if (frameHasPlayer(frame)) return; + if ((details.statusCode >= 400 && details.statusCode < 600) || details.statusCode === 204) { + return; // Client or server error. Ignore it + } + + const customSourcePattern = CustomSourcePatterns.find((item)=>{ + return item.regex.test(url); + }); + if (customSourcePattern) { + ext = customSourcePattern.ext; + } + if (isSubtitles(ext)) { return handleSubtitles(url, frame, frame.requestHeaders[details.requestId]); } @@ -778,10 +816,6 @@ chrome.webRequest.onHeadersReceived.addListener( } } - if ((details.statusCode >= 400 && details.statusCode < 600) || details.statusCode === 204) { - return; // Client or server error. Ignore it - } - onSourceRecieved(details, frame, mode); }, { urls: [''], diff --git a/chrome/player/options/defaults/DefaultOptions.mjs b/chrome/player/options/defaults/DefaultOptions.mjs index a5544a2b..3863a324 100644 --- a/chrome/player/options/defaults/DefaultOptions.mjs +++ b/chrome/player/options/defaults/DefaultOptions.mjs @@ -11,6 +11,7 @@ export const DefaultOptions = { autoEnableBestSubtitles: false, autoplayYoutube: true, autoEnableURLs: [], + customSourcePatterns: ``, keybinds: DefaultKeybinds, videoBrightness: 1, videoContrast: 1, diff --git a/chrome/player/options/index.html b/chrome/player/options/index.html index 8c26e60d..ead89dda 100644 --- a/chrome/player/options/index.html +++ b/chrome/player/options/index.html @@ -187,6 +187,10 @@

Regex101

+

+

+ +

diff --git a/chrome/player/options/options.css b/chrome/player/options/options.css index 8e55ddcb..630ef5f1 100644 --- a/chrome/player/options/options.css +++ b/chrome/player/options/options.css @@ -110,7 +110,8 @@ p.hint { color: rgb(0, 0, 255); } -#autoEnableURLs { +#autoEnableURLs, +#customSourcePatterns { color: black; background-color: transparent; font-size: 12px; @@ -124,7 +125,8 @@ p.hint { resize: none; } -#autoEnableURLs:focus { +#autoEnableURLs:focus, +#customSourcePatterns:focus { border: 1px solid blue; } diff --git a/chrome/player/options/options.mjs b/chrome/player/options/options.mjs index 8d68e54c..306c0e5c 100644 --- a/chrome/player/options/options.mjs +++ b/chrome/player/options/options.mjs @@ -28,6 +28,7 @@ const exportButton = document.getElementById('export'); const clickAction = document.getElementById('clickaction'); const dblclickAction = document.getElementById('dblclickaction'); const tplclickAction = document.getElementById('tplclickaction'); +const customSourcePatterns = document.getElementById('customSourcePatterns'); autoEnableURLSInput.setAttribute('autocapitalize', 'off'); autoEnableURLSInput.setAttribute('autocomplete', 'off'); autoEnableURLSInput.setAttribute('autocorrect', 'off'); @@ -60,6 +61,7 @@ async function loadOptions(newOptions) { seekStepSize.value = Math.round(Options.seekStepSize * 100) / 100; playbackRate.value = Options.playbackRate; qualityMultiplier.value = Options.qualityMultiplier; + customSourcePatterns.value = Options.customSourcePatterns || ''; setSelectMenuValue(clickAction, Options.singleClickAction); setSelectMenuValue(dblclickAction, Options.doubleClickAction); @@ -296,6 +298,11 @@ autoEnableURLSInput.addEventListener('input', (e) => { optionChanged(); }); +customSourcePatterns.addEventListener('input', (e) => { + Options.customSourcePatterns = customSourcePatterns.value; + optionChanged(); +}); + importButton.addEventListener('click', () => { const picker = document.createElement('input'); picker.type = 'file';