Clarify local provider update status
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## 0.52.19 - 2026-09-01
|
||||
|
||||
- Changed the provider update check to report newer local provider patches separately from upstream updates, avoiding false update warnings for the patched Anikoto module.
|
||||
- Updated the Config page provider badge list to show local provider patch versions.
|
||||
|
||||
## 0.52.18 - 2026-08-30
|
||||
|
||||
- Fixed Anikoto dub availability detection when episode-list flags report sub-only episodes but the episode server list exposes dub streams.
|
||||
|
||||
@@ -116,4 +116,4 @@ The Anikoto, AniNeko, and AnimePahe parser modules in `providers/extensions/Anim
|
||||
- AniNeko `3.0.3`
|
||||
- AnimePahe `4.0.1`
|
||||
|
||||
The Config page checks the bundled JavaScript against the upstream `main` branch and reports whether local provider files differ. Kaizoku acts as a local client-side parser/downloader wrapper and does not host media.
|
||||
The Config page checks the bundled JavaScript against the upstream `main` branch and reports whether upstream updates are available. If Kaizoku carries a newer local provider patch than upstream, such as the patched Anikoto module, the Config page reports it separately as a local change. Kaizoku acts as a local client-side parser/downloader wrapper and does not host media.
|
||||
|
||||
@@ -1101,6 +1101,7 @@ CONFIG_HTML = r"""<!doctype html>
|
||||
|
||||
function providerUpdateBadgeClass(status) {
|
||||
if (status === "up_to_date") return "ok";
|
||||
if (status === "local_changes") return "ok";
|
||||
if (status === "updates_available") return "warn";
|
||||
if (status === "error") return "bad";
|
||||
return "";
|
||||
@@ -1117,6 +1118,7 @@ CONFIG_HTML = r"""<!doctype html>
|
||||
|
||||
const files = [
|
||||
...(data.updated_files || []).map((item) => item.path),
|
||||
...(data.locally_modified_files || []).map((item) => `${item.path} local ${item.local_version || "modified"}`),
|
||||
...(data.missing_upstream_files || [])
|
||||
];
|
||||
if (!files.length && status !== "checking") {
|
||||
|
||||
+36
-5
@@ -4,6 +4,7 @@
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from datetime import datetime, timezone
|
||||
@@ -36,6 +37,7 @@ def default_status(status="idle", message="Provider update check has not run yet
|
||||
"upstream_tree_sha": "",
|
||||
"checked_files": 0,
|
||||
"updated_files": [],
|
||||
"locally_modified_files": [],
|
||||
"missing_upstream_files": [],
|
||||
}
|
||||
|
||||
@@ -55,6 +57,25 @@ def sha256_bytes(content):
|
||||
return hashlib.sha256(content).hexdigest()
|
||||
|
||||
|
||||
def provider_module_version(content):
|
||||
match = re.search(rb'version:\s*["\']([^"\']+)["\']', content)
|
||||
if not match:
|
||||
return ""
|
||||
return match.group(1).decode("utf-8", errors="replace")
|
||||
|
||||
|
||||
def compare_versions(left, right):
|
||||
left_parts = [int(part) for part in re.findall(r"\d+", left or "")]
|
||||
right_parts = [int(part) for part in re.findall(r"\d+", right or "")]
|
||||
length = max(len(left_parts), len(right_parts))
|
||||
for index in range(length):
|
||||
left_value = left_parts[index] if index < len(left_parts) else 0
|
||||
right_value = right_parts[index] if index < len(right_parts) else 0
|
||||
if left_value != right_value:
|
||||
return 1 if left_value > right_value else -1
|
||||
return 0
|
||||
|
||||
|
||||
def fetch_json(url, timeout=10):
|
||||
request = urllib.request.Request(
|
||||
url,
|
||||
@@ -100,6 +121,7 @@ def check_provider_updates(local_root=LOCAL_PROVIDER_ROOT, timeout=10):
|
||||
|
||||
upstream_paths, upstream_tree_sha = upstream_provider_js_paths(timeout=timeout)
|
||||
updated_files = []
|
||||
locally_modified_files = []
|
||||
missing_upstream_files = []
|
||||
checked_files = 0
|
||||
|
||||
@@ -114,19 +136,27 @@ def check_provider_updates(local_root=LOCAL_PROVIDER_ROOT, timeout=10):
|
||||
local_hash = sha256_bytes(local_content)
|
||||
remote_hash = sha256_bytes(remote_content)
|
||||
if local_hash != remote_hash:
|
||||
updated_files.append(
|
||||
{
|
||||
local_version = provider_module_version(local_content)
|
||||
upstream_version = provider_module_version(remote_content)
|
||||
item = {
|
||||
"path": relative_path,
|
||||
"local_sha256": local_hash,
|
||||
"upstream_sha256": remote_hash,
|
||||
"upstream_url": remote_url,
|
||||
"local_version": local_version,
|
||||
"upstream_version": upstream_version,
|
||||
}
|
||||
)
|
||||
if local_version and upstream_version and compare_versions(local_version, upstream_version) > 0:
|
||||
locally_modified_files.append(item)
|
||||
else:
|
||||
updated_files.append(item)
|
||||
|
||||
has_updates = bool(updated_files or missing_upstream_files)
|
||||
if has_updates:
|
||||
if updated_files or missing_upstream_files:
|
||||
message = "Provider updates are available from TheYogMehta/extensions."
|
||||
status_name = "updates_available"
|
||||
elif locally_modified_files:
|
||||
message = "Bundled provider JavaScript includes local changes ahead of upstream."
|
||||
status_name = "local_changes"
|
||||
else:
|
||||
message = "Bundled provider JavaScript is up to date."
|
||||
status_name = "up_to_date"
|
||||
@@ -140,6 +170,7 @@ def check_provider_updates(local_root=LOCAL_PROVIDER_ROOT, timeout=10):
|
||||
"upstream_tree_sha": upstream_tree_sha,
|
||||
"checked_files": checked_files,
|
||||
"updated_files": updated_files,
|
||||
"locally_modified_files": locally_modified_files,
|
||||
"missing_upstream_files": missing_upstream_files,
|
||||
}
|
||||
|
||||
|
||||
+20
@@ -3479,6 +3479,26 @@ class ProviderUpdateTests(unittest.TestCase):
|
||||
self.assertEqual(status["checked_files"], 1)
|
||||
self.assertEqual([item["path"] for item in status["updated_files"]], ["Anime/pahe.js"])
|
||||
|
||||
def test_provider_update_check_reports_local_provider_patch(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
provider_file = root / "Anime" / "anikoto.js"
|
||||
provider_file.parent.mkdir(parents=True)
|
||||
provider_file.write_text('module.exports = { version: "5.0.3" };\n', encoding="utf-8")
|
||||
|
||||
with mock.patch.object(
|
||||
provider_updates, "upstream_provider_js_paths", return_value=({"Anime/anikoto.js"}, "tree-sha")
|
||||
), mock.patch.object(
|
||||
provider_updates, "fetch_bytes", return_value=b'module.exports = { version: "5.0.2" };\n'
|
||||
):
|
||||
status = provider_updates.check_provider_updates(local_root=root)
|
||||
|
||||
self.assertEqual(status["status"], "local_changes")
|
||||
self.assertEqual(status["updated_files"], [])
|
||||
self.assertEqual([item["path"] for item in status["locally_modified_files"]], ["Anime/anikoto.js"])
|
||||
self.assertEqual(status["locally_modified_files"][0]["local_version"], "5.0.3")
|
||||
self.assertEqual(status["locally_modified_files"][0]["upstream_version"], "5.0.2")
|
||||
|
||||
def test_provider_update_api_returns_current_status(self):
|
||||
status = provider_updates.default_status("updates_available", "Providers changed.")
|
||||
status["checked_files"] = 3
|
||||
|
||||
Reference in New Issue
Block a user