Publish Source Available licenses and remove Mutagen in YouTubeDL 1.4.7 / helper 1.3.3

This commit is contained in:
DepressedCat committed 2026-10-11 23:51:30 +03:00
1 parent 71a808b298
commit 50457bc35b
27 files changed
+201 -58

No files matched your search

+6 -6
View File
@@ -55,19 +55,19 @@ test("brief missing speed samples do not flicker, expire and reset between track
assert.equal(stabilizeDownloadSpeed({ ...sample, stage: "merging", speed: "8x" }, previous, 1200).speedUpdatedAt, null);
});
test("helper compatibility detects outdated, newer and unidentifiable versions in both directions", () => {
assert.equal(checkHelperCompatibility({ version: "1.3.2" }, "1.4.5").compatible, true);
assert.equal(checkHelperCompatibility({ bundle: { version: "1.3.2" } }, "1.4.5").compatible, true);
assert.equal(checkHelperCompatibility({ version: "1.3.2.0" }, "1.4.5").compatible, true);
assert.equal(checkHelperCompatibility({ version: "1.3.3" }, "1.4.5").compatible, true);
assert.equal(checkHelperCompatibility({ bundle: { version: "1.3.3" } }, "1.4.5").compatible, true);
assert.equal(checkHelperCompatibility({ version: "1.3.3.0" }, "1.4.5").compatible, true);
for (const version of ["1.3.0", "1.2.10", undefined, "unknown"]) {
const result = checkHelperCompatibility({ version }, "1.4.5");
assert.equal(result.compatible, false);
assert.equal(result.update, "helper");
}
for (const version of ["1.3.3", "1.3.20", "2.0.0"]) {
for (const version of ["1.3.4", "1.3.30", "2.0.0"]) {
const result = checkHelperCompatibility({ version }, "1.4.5");
assert.equal(result.compatible, false);
assert.equal(result.update, "extension");
}
assert.equal(checkHelperCompatibility({ version: "1.3.2" }, "1.4.2").update, "extension");
assert.equal(checkHelperCompatibility({ version: "1.3.2", minimumExtensionVersion: "1.4.6" }, "1.4.5").update, "extension");
assert.equal(checkHelperCompatibility({ version: "1.3.3" }, "1.4.2").update, "extension");
assert.equal(checkHelperCompatibility({ version: "1.3.3", minimumExtensionVersion: "1.4.7" }, "1.4.5").update, "extension");
});
+1 -1
View File
@@ -16,7 +16,7 @@ test("history connects without a helper, opens a tab, and retains failures befor
return { onMessage: { addListener: listener => { receive = listener; } }, onDisconnect: noEvent, disconnect() {},
postMessage(message) {
nativeRequests.push(message);
queueMicrotask(() => receive({ id: message.id, ok: message.action !== "inspect", result: message.action === "hello" ? { version: "1.3.2" } : { alive: true }, error: "Видео недоступно" }));
queueMicrotask(() => receive({ id: message.id, ok: message.action !== "inspect", result: message.action === "hello" ? { version: "1.3.3" } : { alive: true }, error: "Видео недоступно" }));
} };
} };
globalThis.chrome = { runtime, storage: { local: { get: async () => structuredClone(storage), set: async data => Object.assign(storage, structuredClone(data)) } },
+3 -3
View File
@@ -4,7 +4,7 @@ import assert from "node:assert/strict";
test("native lifecycle recovers stale ports and publishes install/remove/update state to all menus", async () => {
const ports = [], listeners = {}, storage = {}, pending = new Map(), updates = [];
let installed = false;
let helperVersion = "1.3.2";
let helperVersion = "1.3.3";
let componentsReady = true;
const noEvent = { addListener() {} };
const runtime = { id: "test-id", getManifest: () => ({ version: "1.4.5" }), getURL: name => `chrome-extension://test-id/${name}`,
@@ -94,7 +94,7 @@ test("native lifecycle recovers stale ports and publishes install/remove/update
await new Promise(resolve => setTimeout(resolve, 20));
assert.equal((await call("state")).result.helper.hardware.ready, true, "Restoring a component refreshes readiness without reload");
assert.ok(fresh.sent.some(message => message.action === "helper_uninstall"));
for (const [version, update] of [["1.3.0", "helper"], ["1.3.3", "extension"]]) {
for (const [version, update] of [["1.3.0", "helper"], ["1.3.4", "extension"]]) {
helperVersion = version;
ports.at(-1).disconnect();
await new Promise(resolve => setImmediate(resolve));
@@ -107,6 +107,6 @@ test("native lifecycle recovers stale ports and publishes install/remove/update
assert.equal((await call("download", { url: "https://youtu.be/jNQXAC9IVRw" })).ok, false, 'Incompatible versions cannot launch a download');
assert.ok(!port.sent.some(message => message.action === "download"));
}
helperVersion = "1.3.2";
helperVersion = "1.3.3";
assert.equal((await call("helper_status")).result.status, "running", 'Version repair is detected by the Check button without reloading');
});
+1 -1
View File
@@ -38,7 +38,7 @@ test("background passes fresh YouTube cookies to both worker actions and never p
onMessage: { addListener(listener) { nativeListener = listener; } }, onDisconnect: noEvent, disconnect() {},
postMessage(message) {
requests.push(message);
const result = message.action === "hello" ? { version: "1.3.2", ready: true, supportsBrowserCookies: true } : message.action === "ping" ? { alive: true }
const result = message.action === "hello" ? { version: "1.3.3", ready: true, supportsBrowserCookies: true } : message.action === "ping" ? { alive: true }
: message.action === "download" ? { jobId: "auth-test-job" } : { title: "Synthetic video", videos: [], audios: [] };
queueMicrotask(() => nativeListener({ id: message.id, ok: true, result }));
},
+1 -1
View File
@@ -35,7 +35,7 @@ try {
assert.equal(new URL(page.url()).hash,"#install");
assert.ok(await page.locator(".download-grid").isVisible());
assert.equal(await page.locator('[data-download="extension"]').getAttribute("href"),`https://git.lonarpgproxy.space/DepressedCat/YouTubeDL/releases/download/v${version}/YouTubeDL-${version}.zip`);
assert.equal(await page.locator('[data-download="helper"]').getAttribute("href"),"https://git.lonarpgproxy.space/DepressedCat/YouTubeDL/releases/download/v1.4.6/YouTubeDL-Helper-Setup.exe");
assert.equal(await page.locator('[data-download="helper"]').getAttribute("href"),"https://git.lonarpgproxy.space/DepressedCat/YouTubeDL/releases/download/v1.4.7/YouTubeDL-Helper-Setup.exe");
await page.locator('[data-screenshot="light"]').click();
await page.locator("#menu-screenshot").evaluate(image => image.decode());
assert.match(await page.locator("#menu-screenshot").getAttribute("src"), /menu-light\.png$/);
+53
View File
@@ -0,0 +1,53 @@
import json
import tempfile
import unittest
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch
from host.python_packages import validate_metadata
from host.updates import resolve_packages
class PythonPackageLicenseTests(unittest.TestCase):
def test_permissive_and_weak_copyleft_metadata_is_accepted(self):
validate_metadata([{"name": "yt-dlp", "license_expression": "Unlicense"},
{"name": "certifi", "license_expression": "MPL-2.0"},
{"name": "library", "license_expression": "MIT"},
{"name": "library", "license_expression": "LGPL-2.1-or-later"}])
def test_strong_copyleft_is_rejected_using_expression_or_classifiers(self):
for metadata in [{"name": "mutagen"},
{"name": "dependency", "license_expression": "GPL-3.0-or-later"},
{"name": "dependency", "license_expression": "AGPL-3.0-only"},
{"name": "dependency", "classifier": ["License :: OSI Approved :: GNU General Public License v2 (GPLv2)"]}]:
with self.subTest(metadata=metadata), self.assertRaises(ValueError):
validate_metadata([metadata])
def test_incompatible_resolution_does_not_delete_the_existing_packages(self):
with tempfile.TemporaryDirectory() as temporary:
stage = Path(temporary) / "stage"
packages = stage / "runtime/python/Lib/site-packages"
packages.mkdir(parents=True)
sentinel = packages / "existing.py"
sentinel.write_text("original package", encoding="utf8")
work = Path(temporary) / "work"
work.mkdir()
def resolve(command, **kwargs):
report = Path(command[command.index("--report") + 1])
report.write_text(json.dumps({"install": [{"metadata": {
"name": "mutagen", "license_expression": "GPL-2.0-or-later"}}]}), encoding="utf8")
self.assertNotIn("yt-dlp[default]", command)
return SimpleNamespace(returncode=0)
response = {"urls": [{"filename": "pip-1-py3-none-any.whl", "url": "https://files.pythonhosted.org/pip.whl", "digests": {"sha256": "a" * 64}}]}
with patch("host.updates.get", return_value=SimpleNamespace(json=lambda: response)), \
patch("host.updates.fetch"), patch("host.updates.subprocess.run", side_effect=resolve):
with self.assertRaisesRegex(ValueError, "mutagen"):
resolve_packages(stage, work, lambda *args: None)
self.assertEqual(sentinel.read_text(), "original package")
if __name__ == "__main__":
unittest.main()
+2 -2
View File
@@ -18,7 +18,7 @@
window.__contentMessage = message => contentListeners.forEach(listener => listener(message));
let autoUpdate = true;
window.__updateRequests = [];
const hardware = () => ({ version: window.__helperVersion || "1.3.2", bundle: { mode: "autonomous", version: window.__helperVersion || "1.3.2", updateTogether: true }, supportsComponentUpdates: true, supportsWorkFolder: true, updateSettings: { enabled: autoUpdate },
const hardware = () => ({ version: window.__helperVersion || "1.3.3", bundle: { mode: "autonomous", version: window.__helperVersion || "1.3.3", updateTogether: true }, supportsComponentUpdates: true, supportsWorkFolder: true, updateSettings: { enabled: autoUpdate },
gpu: window.__amdOnly ? "AMD Radeon RX 7900 XTX" : "NVIDIA GeForce RTX 5080", nvenc: window.__dependencyMissing || window.__amdOnly ? [] : ["h264", "hevc", "av1"],
amf: window.__amdOnly ? ["h264", "hevc", "av1"] : [], amf10bit: window.__amdOnly ? ["hevc", "av1"] : [], defaultFolder: "D:\\Videos", ready: !window.__dependencyMissing,
dependencies: ["python", "yt_dlp", "ejs", "node", "ffmpeg"].map(id => ({ id, status: window.__dependencyMissing && id === "ffmpeg" ? "missing" : "installed", version: "test-version" })) });
@@ -31,7 +31,7 @@
], audios: [{ id: "251", codec: "opus", extension: "webm", bitrate: 160, language: "en", note: "English", size: 5000000 }] };
window.chrome = {
runtime: {
getManifest: () => ({ version: window.__extensionVersion || "1.4.6" }),
getManifest: () => ({ version: window.__extensionVersion || "1.4.7" }),
getURL: file => `https://ui.ytdl.test/${file}`,
sendMessage: async message => {
if (message.type === "QUICK_DOWNLOAD") { window.__quickRequests.push(message.url); return { ok: true, jobId: "fixture-job" }; }
+7 -7
View File
@@ -20,8 +20,8 @@ try {
page.on("pageerror", error => errors.push(error.message));
await page.goto("https://ui.ytdl.test/downloader.html?theme=dark&url=https://www.youtube.com/watch?v=aircAruvnKk");
await page.locator('#helper-panel[data-state="incompatible"]').waitFor();
assert.match(await page.locator('#helper-message').textContent(), /1\.3\.0.*1\.4\.6/);
assert.match(await page.locator('#helper-versions').textContent(), /Расширение 1\.4\.6.*Помощник 1\.3\.0/);
assert.match(await page.locator('#helper-message').textContent(), /1\.3\.0.*1\.4\.7/);
assert.match(await page.locator('#helper-versions').textContent(), /Расширение 1\.4\.7.*Помощник 1\.3\.0/);
assert.equal(await page.locator('#helper-install').textContent(), 'Обновить помощник');
assert.equal(await page.locator('#download').isDisabled(), true);
assert.equal(await page.locator('#download-form').isVisible(), false);
@@ -30,13 +30,13 @@ try {
await page.locator('#setup-helper[data-state="incompatible"]').waitFor();
assert.equal(await page.locator('#setup-next').isDisabled(), true);
assert.equal(await page.locator('#setup-install').textContent(), 'Обновить помощник');
assert.match(await page.locator('#setup-versions').textContent(), /1\.4\.6.*1\.3\.0/);
await page.evaluate(() => { window.__helperVersion = '1.3.2'; });
assert.match(await page.locator('#setup-versions').textContent(), /1\.4\.7.*1\.3\.0/);
await page.evaluate(() => { window.__helperVersion = '1.3.3'; });
await page.locator('#setup-check').click();
await page.locator('#setup-helper[data-state="running"]').waitFor();
assert.match(await page.locator('#setup-versions').textContent(), /Версии совместимы/);
await page.locator('#setup-next:not([disabled])').waitFor();
await page.evaluate(() => { window.__helperVersion = '1.3.3'; });
await page.evaluate(() => { window.__helperVersion = '1.3.4'; });
await page.locator('#setup-check').click();
await page.locator('#setup-helper[data-state="incompatible"]').waitFor();
assert.equal(await page.locator('#setup-next').isDisabled(), true);
@@ -44,9 +44,9 @@ try {
assert.equal(await page.locator('#setup-install-steps').isVisible(), false);
await page.locator('#setup-close').click();
assert.equal(await page.locator('#helper-install').textContent(), 'Обновить расширение');
assert.match(await page.locator('#helper-message').textContent(), /Помощник 1\.3\.3.*расширением 1\.4\.6/);
assert.match(await page.locator('#helper-message').textContent(), /Помощник 1\.3\.4.*расширением 1\.4\.7/);
assert.equal(await page.locator('#download').isDisabled(), true);
await page.evaluate(() => { window.__helperVersion = '1.3.2'; });
await page.evaluate(() => { window.__helperVersion = '1.3.3'; });
await page.locator('#helper-start').click();
await page.locator('#helper-panel[data-state="running"]').waitFor();
await page.locator('#download:not([disabled])').waitFor();