diff --git a/.tmp-update-check/update_check.json b/.tmp-update-check/update_check.json new file mode 100644 index 0000000..2ec89ce --- /dev/null +++ b/.tmp-update-check/update_check.json @@ -0,0 +1 @@ +{"timestamp": "2026-03-12T10:57:42.150570", "release": {"tag_name": "v0.8.4", "name": "WebDropBridge v0.8.4", "version": "0.8.4", "body": "Shared branded release for WebDrop Bridge v0.8.4", "assets": [{"id": 49, "name": "AgravityBridge-0.8.4-win-x64.msi", "size": 214445231, "download_count": 2, "created_at": "2026-03-12T08:25:03Z", "uuid": "7ffcd98a-99a9-4100-8e71-3ebe63534b8f", "browser_download_url": "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/AgravityBridge-0.8.4-win-x64.msi", "type": "attachment"}, {"id": 50, "name": "AgravityBridge-0.8.4-win-x64.msi.sha256", "size": 64, "download_count": 2, "created_at": "2026-03-12T08:25:03Z", "uuid": "ddd00072-a5bc-422f-93c0-7cc3bc3408d3", "browser_download_url": "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/AgravityBridge-0.8.4-win-x64.msi.sha256", "type": "attachment"}, {"id": 47, "name": "WebDropBridge-0.8.4-win-x64.msi", "size": 214445229, "download_count": 0, "created_at": "2026-03-12T08:24:20Z", "uuid": "5a20eef9-b77d-4e04-be06-d85c3ebd3f6e", "browser_download_url": "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/WebDropBridge-0.8.4-win-x64.msi", "type": "attachment"}, {"id": 48, "name": "WebDropBridge-0.8.4-win-x64.msi.sha256", "size": 64, "download_count": 0, "created_at": "2026-03-12T08:24:21Z", "uuid": "9972b3bb-7c4b-4b26-951a-5a8dfc1a1f27", "browser_download_url": "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/WebDropBridge-0.8.4-win-x64.msi.sha256", "type": "attachment"}, {"id": 51, "name": "release-manifest.json", "size": 931, "download_count": 0, "created_at": "2026-03-12T08:25:03Z", "uuid": "e3c13ccd-cbc6-4eb1-988e-7f465a75eca6", "browser_download_url": "https://git.him-tools.de/HIM-public/webdrop-bridge/releases/download/v0.8.4/release-manifest.json", "type": "attachment"}], "published_at": "2026-03-12T08:23:40Z"}} \ No newline at end of file diff --git a/.tmp_check_update.py b/.tmp_check_update.py new file mode 100644 index 0000000..51e5e8c --- /dev/null +++ b/.tmp_check_update.py @@ -0,0 +1,14 @@ +import asyncio +from pathlib import Path +from webdrop_bridge.core.updater import UpdateManager + +async def main(): + manager = UpdateManager(current_version='0.8.3', config_dir=Path('.tmp-update-check')) + release = await manager.check_for_updates() + print('release:', None if not release else (release.tag_name, release.version, len(release.assets))) + if release: + installer, checksum = await manager._resolve_release_assets(release) + print('installer:', None if not installer else installer.get('name')) + print('checksum:', None if not checksum else checksum.get('name')) + +asyncio.run(main()) diff --git a/build/scripts/create_release.ps1 b/build/scripts/create_release.ps1 index 49de30d..488c9bb 100644 --- a/build/scripts/create_release.ps1 +++ b/build/scripts/create_release.ps1 @@ -80,7 +80,8 @@ if ($artifactPaths.Count -eq 0) { exit 1 } -$localData.manifest | ConvertTo-Json -Depth 10 | Set-Content -Path $localManifestPath -Encoding utf8 +$localManifestJson = $localData.manifest | ConvertTo-Json -Depth 10 +[System.IO.File]::WriteAllText($localManifestPath, $localManifestJson, (New-Object System.Text.UTF8Encoding($false))) if ($DryRun) { Copy-Item $localManifestPath $manifestOutput -Force @@ -155,6 +156,12 @@ else { Copy-Item $localManifestPath $manifestOutput -Force } +# Ensure uploaded manifest is UTF-8 without BOM (for strict JSON parsers) +if (Test-Path $manifestOutput) { + $manifestText = Get-Content -Raw -Path $manifestOutput + [System.IO.File]::WriteAllText($manifestOutput, $manifestText, (New-Object System.Text.UTF8Encoding($false))) +} + $artifactPaths.Add($manifestOutput) $assetMap = Get-AssetMap -Assets $releaseInfo.assets diff --git a/src/webdrop_bridge/core/updater.py b/src/webdrop_bridge/core/updater.py index 92fe794..c235caa 100644 --- a/src/webdrop_bridge/core/updater.py +++ b/src/webdrop_bridge/core/updater.py @@ -93,7 +93,9 @@ class UpdateManager: """Download and parse a JSON asset from a release.""" try: with urlopen(url, timeout=10) as response: - return json.loads(response.read().decode("utf-8")) + # Some release pipelines may upload JSON files with UTF-8 BOM. + # Use utf-8-sig to transparently handle both BOM and non-BOM files. + return json.loads(response.read().decode("utf-8-sig")) except (URLError, json.JSONDecodeError) as e: logger.error(f"Failed to download JSON asset: {e}") return None @@ -148,8 +150,28 @@ class UpdateManager: brand_prefix = f"{self.brand_id}-*" installer_asset = None + + # Prefer brand-specific naming when possible. + if self.brand_id == "webdrop_bridge": + preferred_patterns = ["webdropbridge-*.msi", "webdropbridge*.msi"] + else: + preferred_patterns = [f"{self.brand_id.lower()}-*.msi", f"{self.brand_id.lower()}*.msi"] + + # 1) Try strict brand-pattern match first for asset in release.assets: asset_name = asset.get("name", "") + asset_name_lower = asset_name.lower() + if not asset_name_lower.endswith(extension): + continue + if any(fnmatch.fnmatch(asset_name_lower, pattern) for pattern in preferred_patterns): + installer_asset = asset + break + + # 2) Fallback: preserve previous behavior (first installer for platform) + for asset in release.assets: + if installer_asset: + break + asset_name = asset.get("name", "") if not asset_name.endswith(extension): continue