From a0c74c117d86516f856cd8859a2277a0592737da Mon Sep 17 00:00:00 2001 From: Andrew S Date: Mon, 4 Mar 2024 17:51:39 -0600 Subject: [PATCH] Implement #91 --- chrome/_locales/en/messages.json | 3 + chrome/_locales/es/messages.json | 3 + chrome/_locales/ja/messages.json | 3 + chrome/_locales/ru/messages.json | 3 + chrome/player/FastStreamClient.mjs | 9 ++- .../options/defaults/DefaultOptions.mjs | 1 + chrome/player/options/index.html | 5 ++ chrome/player/options/options.mjs | 9 +++ chrome/player/utils/StringUtils.mjs | 57 +++++++++++++++++++ 9 files changed, 92 insertions(+), 1 deletion(-) diff --git a/chrome/_locales/en/messages.json b/chrome/_locales/en/messages.json index 0ec6d1fd..00cd08c0 100644 --- a/chrome/_locales/en/messages.json +++ b/chrome/_locales/en/messages.json @@ -756,6 +756,9 @@ "options_general_targetspeed": { "message": "Target download speed of predownloader" }, + "options_general_maxsize": { + "message": "Maximum size of predownloaded video" + }, "options_general_freeunused": { "message": "Free unused channel buffers when switching quality levels" }, diff --git a/chrome/_locales/es/messages.json b/chrome/_locales/es/messages.json index 71f8e460..ae7ab360 100644 --- a/chrome/_locales/es/messages.json +++ b/chrome/_locales/es/messages.json @@ -755,6 +755,9 @@ "options_general_targetspeed": { "message": "Velocidad de descarga objetivo del predescargador" }, + "options_general_maxsize": { + "message": "Tamaño máximo de video predescargado" + }, "options_general_freeunused": { "message": "Libera los búferes de canal no utilizados al cambiar los niveles de calidad" }, diff --git a/chrome/_locales/ja/messages.json b/chrome/_locales/ja/messages.json index c762232c..b2c991ec 100644 --- a/chrome/_locales/ja/messages.json +++ b/chrome/_locales/ja/messages.json @@ -756,6 +756,9 @@ "options_general_targetspeed": { "message": "プリダウンローダーのターゲット速度" }, + "options_general_maxsize": { + "message": "プリダウンローダーの最大サイズ" + }, "options_general_freeunused": { "message": "品質レベル切り替え時に未使用のチャンネルバッファーを解放する" }, diff --git a/chrome/_locales/ru/messages.json b/chrome/_locales/ru/messages.json index 74c71082..ed5ccfef 100644 --- a/chrome/_locales/ru/messages.json +++ b/chrome/_locales/ru/messages.json @@ -756,6 +756,9 @@ "options_general_targetspeed": { "message": "Целевая скорость предзагрузки" }, + "options_general_maxsize": { + "message": "Максимальный размер предзагружаемого видео" + }, "options_general_freeunused": { "message": "Выгружать неиспользуемые буферы каналов при изменении качества видео" }, diff --git a/chrome/player/FastStreamClient.mjs b/chrome/player/FastStreamClient.mjs index 2f10933e..df5c98a6 100644 --- a/chrome/player/FastStreamClient.mjs +++ b/chrome/player/FastStreamClient.mjs @@ -30,6 +30,7 @@ export class FastStreamClient extends EventEmitter { this.options = { autoPlay: false, maxSpeed: -1, + maxSize: -1, introCutoff: 5 * 60, outroCutoff: 5 * 60, bufferAhead: 120, @@ -170,6 +171,7 @@ export class FastStreamClient extends EventEmitter { this.options.freeUnusedChannels = options.freeUnusedChannels; this.options.autoEnableBestSubtitles = options.autoEnableBestSubtitles; this.options.maxSpeed = options.maxSpeed; + this.options.maxSize = options.maxSize; this.options.seekStepSize = options.seekStepSize; this.options.singleClickAction = options.singleClickAction; this.options.doubleClickAction = options.doubleClickAction; @@ -214,6 +216,8 @@ export class FastStreamClient extends EventEmitter { this.options.toolSettings = options.toolSettings; this.interfaceController.updateToolVisibility(); } + + this.updateHasDownloadSpace(); } updateCSSFilters() { @@ -351,7 +355,10 @@ export class FastStreamClient extends EventEmitter { this.hasDownloadSpace = false; } else { if (level.bitrate && this.duration) { - const storageAvailable = (this.storageAvailable * 8) * 0.6; + let storageAvailable = (this.storageAvailable * 8) * 0.6; + if (this.options.maxSize > 0) { + storageAvailable = Math.min(storageAvailable, this.options.maxSize * 8); + } this.hasDownloadSpace = (level.bitrate * this.duration) < storageAvailable; } else { this.hasDownloadSpace = true; diff --git a/chrome/player/options/defaults/DefaultOptions.mjs b/chrome/player/options/defaults/DefaultOptions.mjs index dc5f7954..b10fca0c 100644 --- a/chrome/player/options/defaults/DefaultOptions.mjs +++ b/chrome/player/options/defaults/DefaultOptions.mjs @@ -27,6 +27,7 @@ export const DefaultOptions = { videoDaltonizerType: DaltonizerTypes.NONE, videoDaltonizerStrength: 1, maxSpeed: -1, + maxSize: -1, seekStepSize: 2, playbackRate: 1, qualityMultiplier: 1.1, diff --git a/chrome/player/options/index.html b/chrome/player/options/index.html index 1d0f7223..01b43dea 100644 --- a/chrome/player/options/index.html +++ b/chrome/player/options/index.html @@ -109,6 +109,11 @@

+
+
+ +
+
diff --git a/chrome/player/options/options.mjs b/chrome/player/options/options.mjs index b2dea4bf..791466a6 100644 --- a/chrome/player/options/options.mjs +++ b/chrome/player/options/options.mjs @@ -24,6 +24,7 @@ const keybindsList = document.getElementById('keybindslist'); const autoEnableURLSInput = document.getElementById('autoEnableURLs'); const autoSub = document.getElementById('autosub'); const maxSpeed = document.getElementById('maxspeed'); +const maxSize = document.getElementById('maxsize'); const seekStepSize = document.getElementById('seekstepsize'); const playbackRate = document.getElementById('playbackrate'); const autoplayYoutube = document.getElementById('autoplayyt'); @@ -79,6 +80,7 @@ async function loadOptions(newOptions) { autoSub.checked = !!Options.autoEnableBestSubtitles; autoplayYoutube.checked = !!Options.autoplayYoutube; maxSpeed.value = StringUtils.getSpeedString(Options.maxSpeed, true); + maxSize.value = StringUtils.getSizeString(Options.maxSize); seekStepSize.value = Math.round(Options.seekStepSize * 100) / 100; playbackRate.value = Options.playbackRate; qualityMultiplier.value = Options.qualityMultiplier; @@ -341,6 +343,13 @@ maxSpeed.addEventListener('change', () => { optionChanged(); }); +maxSize.addEventListener('change', () => { + // parse value, number unit + Options.maxSize = StringUtils.getSizeValue(maxSize.value); + maxSize.value = StringUtils.getSizeString(Options.maxSize); + optionChanged(); +}); + seekStepSize.addEventListener('change', () => { Options.seekStepSize = parseFloat(seekStepSize.value); optionChanged(); diff --git a/chrome/player/utils/StringUtils.mjs b/chrome/player/utils/StringUtils.mjs index 68109b77..7bd83696 100644 --- a/chrome/player/utils/StringUtils.mjs +++ b/chrome/player/utils/StringUtils.mjs @@ -194,6 +194,63 @@ export class StringUtils { return Math.round(value * 100) / 100 + ' ' + unit; } + static getSizeString(size) { + if (size=== -1) { + return '∞ GB'; + } + + let unit = 'B'; + if (size >= 1000) { + unit = 'KB'; + size /= 1000; + } + if (size >= 1000) { + unit = 'MB'; + size /= 1000; + } + if (size >= 1000) { + unit = 'GB'; + size /= 1000; + } + if (size >= 1000) { + unit = 'TB'; + size /= 1000; + } + return Math.round(size * 100) / 100 + ' ' + unit; + } + + static getSizeValue(sizeStr) { + const float = parseFloat(sizeStr); + const unit = sizeStr.replace(float, '').trim(); + if ( + isNaN(float) || + float < 0 || + float === Infinity + ) { + return -1; + } + + // Unit can be MB, Mb, etc... + const match = unit.match(/([a-oq-zA-Z]+)/); + const unit1 = match?.[1]; + + let multiplier = 1; + + // Convert to bytes + if (unit1) { + const sci = ['b', 'k', 'm', 'g', 't', 'p', 'e', 'z', 'y']; + const split = unit1.split(''); + if (sci.includes(split[0].toLowerCase())) { + multiplier *= 1000 ** sci.indexOf(split[0].toLowerCase()); + } else { + // M default + multiplier *= 1000 ** 2; + } + } + + return float * multiplier; + } + static parseHTTPRange(range) { const match = range.match(/(\d+)-(\d+)?/); if (!match) return [undefined, undefined];