Switch updater and docs from GitHub to Codeberg
This commit is contained in:
parent
fe59e064f0
commit
43bc95b7fc
@ -43,17 +43,17 @@ Desktop downloader for **Real-Debrid, Mega-Debrid, BestDebrid, and AllDebrid** w
|
||||
- Minimize-to-tray with tray menu controls.
|
||||
- Speed limits globally or per download.
|
||||
- Bandwidth schedules for time-based speed profiles.
|
||||
- Built-in update checks via GitHub Releases.
|
||||
- Built-in update checks via Codeberg Releases.
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A: prebuilt releases (recommended)
|
||||
|
||||
1. Download a release from the GitHub Releases page.
|
||||
1. Download a release from the Codeberg Releases page.
|
||||
2. Run the installer or portable build.
|
||||
3. Add your debrid tokens in Settings.
|
||||
|
||||
Releases: `https://github.com/Sucukdeluxe/real-debrid-downloader/releases`
|
||||
Releases: `https://codeberg.org/Sucukdeluxe/real-debrid-downloader/releases`
|
||||
|
||||
### Option B: build from source
|
||||
|
||||
@ -113,7 +113,7 @@ The app stores runtime files in Electron's `userData` directory, including:
|
||||
|
||||
## Changelog
|
||||
|
||||
Release history is available in `CHANGELOG.md` and on GitHub Releases.
|
||||
Release history is available in `CHANGELOG.md` and on Codeberg Releases.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ function createWindow(): BrowserWindow {
|
||||
responseHeaders: {
|
||||
...details.responseHeaders,
|
||||
"Content-Security-Policy": [
|
||||
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://api.real-debrid.com https://api.github.com https://bestdebrid.com https://api.alldebrid.com https://www.mega-debrid.eu"
|
||||
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://api.real-debrid.com https://codeberg.org https://bestdebrid.com https://api.alldebrid.com https://www.mega-debrid.eu"
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
@ -17,6 +17,8 @@ const DOWNLOAD_BODY_IDLE_TIMEOUT_MS = 45000;
|
||||
const RETRIES_PER_CANDIDATE = 3;
|
||||
const RETRY_DELAY_MS = 1500;
|
||||
const UPDATE_USER_AGENT = `RD-Node-Downloader/${APP_VERSION}`;
|
||||
const UPDATE_WEB_BASE = "https://codeberg.org";
|
||||
const UPDATE_API_BASE = "https://codeberg.org/api/v1";
|
||||
|
||||
let activeUpdateAbortController: AbortController | null = null;
|
||||
|
||||
@ -45,9 +47,9 @@ export function normalizeUpdateRepo(repo: string): string {
|
||||
|
||||
const normalizeParts = (input: string): string => {
|
||||
const cleaned = input
|
||||
.replace(/^https?:\/\/(?:www\.)?github\.com\//i, "")
|
||||
.replace(/^(?:www\.)?github\.com\//i, "")
|
||||
.replace(/^git@github\.com:/i, "")
|
||||
.replace(/^https?:\/\/(?:www\.)?(?:codeberg\.org|github\.com)\//i, "")
|
||||
.replace(/^(?:www\.)?(?:codeberg\.org|github\.com)\//i, "")
|
||||
.replace(/^git@(?:codeberg\.org|github\.com):/i, "")
|
||||
.replace(/\.git$/i, "")
|
||||
.replace(/^\/+|\/+$/g, "");
|
||||
const parts = cleaned.split("/").filter(Boolean);
|
||||
@ -64,7 +66,7 @@ export function normalizeUpdateRepo(repo: string): string {
|
||||
try {
|
||||
const url = new URL(raw);
|
||||
const host = url.hostname.toLowerCase();
|
||||
if (host === "github.com" || host === "www.github.com") {
|
||||
if (host === "codeberg.org" || host === "www.codeberg.org" || host === "github.com" || host === "www.github.com") {
|
||||
const normalized = normalizeParts(url.pathname);
|
||||
if (normalized) {
|
||||
return normalized;
|
||||
@ -158,7 +160,7 @@ function createFallbackResult(repo: string): UpdateCheckResult {
|
||||
currentVersion: APP_VERSION,
|
||||
latestVersion: APP_VERSION,
|
||||
latestTag: `v${APP_VERSION}`,
|
||||
releaseUrl: `https://github.com/${safeRepo}/releases/latest`
|
||||
releaseUrl: `${UPDATE_WEB_BASE}/${safeRepo}/releases/latest`
|
||||
};
|
||||
}
|
||||
|
||||
@ -210,7 +212,7 @@ async function fetchReleasePayload(safeRepo: string, endpoint: string): Promise<
|
||||
const timeout = timeoutController(RELEASE_FETCH_TIMEOUT_MS);
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(`https://api.github.com/repos/${safeRepo}/${endpoint}`, {
|
||||
response = await fetch(`${UPDATE_API_BASE}/repos/${safeRepo}/${endpoint}`, {
|
||||
headers: {
|
||||
Accept: "application/vnd.github+json",
|
||||
"User-Agent": UPDATE_USER_AGENT
|
||||
@ -250,9 +252,9 @@ function buildDownloadCandidates(safeRepo: string, check: UpdateCheckResult): st
|
||||
const candidates = [setupAssetUrl];
|
||||
if (setupAssetName) {
|
||||
const encodedName = encodeURIComponent(setupAssetName);
|
||||
candidates.push(`https://github.com/${safeRepo}/releases/latest/download/${encodedName}`);
|
||||
candidates.push(`${UPDATE_WEB_BASE}/${safeRepo}/releases/latest/download/${encodedName}`);
|
||||
if (latestTag) {
|
||||
candidates.push(`https://github.com/${safeRepo}/releases/download/${encodeURIComponent(latestTag)}/${encodedName}`);
|
||||
candidates.push(`${UPDATE_WEB_BASE}/${safeRepo}/releases/download/${encodeURIComponent(latestTag)}/${encodedName}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1527,7 +1527,7 @@ export function App(): ReactElement {
|
||||
<option value="ask">nachfragen</option>
|
||||
</select></div>
|
||||
</div>
|
||||
<label>GitHub Repo</label>
|
||||
<label>Codeberg Repo</label>
|
||||
<input value={settingsDraft.updateRepo} onChange={(e) => setText("updateRepo", e.target.value)} />
|
||||
<label className="toggle-line"><input type="checkbox" checked={settingsDraft.autoUpdateCheck} onChange={(e) => setBool("autoUpdateCheck", e.target.checked)} /> Beim Start auf Updates prüfen</label>
|
||||
</article>
|
||||
|
||||
@ -20,21 +20,21 @@ describe("update", () => {
|
||||
it("normalizes update repo input", () => {
|
||||
expect(normalizeUpdateRepo("")).toBe("Sucukdeluxe/real-debrid-downloader");
|
||||
expect(normalizeUpdateRepo("owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://github.com/owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://www.github.com/owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://github.com/owner/repo/releases/tag/v1.2.3")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("github.com/owner/repo.git")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("git@github.com:owner/repo.git")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://codeberg.org/owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://www.codeberg.org/owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://codeberg.org/owner/repo/releases/tag/v1.2.3")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("codeberg.org/owner/repo.git")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("git@codeberg.org:owner/repo.git")).toBe("owner/repo");
|
||||
});
|
||||
|
||||
it("uses normalized repo slug for GitHub API requests", async () => {
|
||||
it("uses normalized repo slug for Codeberg API requests", async () => {
|
||||
let requestedUrl = "";
|
||||
globalThis.fetch = (async (input: RequestInfo | URL): Promise<Response> => {
|
||||
requestedUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
tag_name: `v${APP_VERSION}`,
|
||||
html_url: "https://github.com/owner/repo/releases/tag/v1.0.0",
|
||||
html_url: "https://codeberg.org/owner/repo/releases/tag/v1.0.0",
|
||||
assets: []
|
||||
}),
|
||||
{
|
||||
@ -44,8 +44,8 @@ describe("update", () => {
|
||||
);
|
||||
}) as typeof fetch;
|
||||
|
||||
const result = await checkGitHubUpdate("https://github.com/owner/repo/releases");
|
||||
expect(requestedUrl).toBe("https://api.github.com/repos/owner/repo/releases/latest");
|
||||
const result = await checkGitHubUpdate("https://codeberg.org/owner/repo/releases");
|
||||
expect(requestedUrl).toBe("https://codeberg.org/api/v1/repos/owner/repo/releases/latest");
|
||||
expect(result.currentVersion).toBe(APP_VERSION);
|
||||
expect(result.latestVersion).toBe(APP_VERSION);
|
||||
expect(result.updateAvailable).toBe(false);
|
||||
@ -55,7 +55,7 @@ describe("update", () => {
|
||||
globalThis.fetch = (async (): Promise<Response> => new Response(
|
||||
JSON.stringify({
|
||||
tag_name: "v9.9.9",
|
||||
html_url: "https://github.com/owner/repo/releases/tag/v9.9.9",
|
||||
html_url: "https://codeberg.org/owner/repo/releases/tag/v9.9.9",
|
||||
assets: [
|
||||
{
|
||||
name: "Real-Debrid-Downloader 9.9.9.exe",
|
||||
@ -105,7 +105,7 @@ describe("update", () => {
|
||||
currentVersion: APP_VERSION,
|
||||
latestVersion: "9.9.9",
|
||||
latestTag: "v9.9.9",
|
||||
releaseUrl: "https://github.com/owner/repo/releases/tag/v9.9.9",
|
||||
releaseUrl: "https://codeberg.org/owner/repo/releases/tag/v9.9.9",
|
||||
setupAssetUrl: "https://example.invalid/stale-setup.exe",
|
||||
setupAssetName: "Real-Debrid-Downloader Setup 9.9.9.exe",
|
||||
setupAssetDigest: `sha256:${executableDigest}`
|
||||
@ -176,7 +176,7 @@ describe("update", () => {
|
||||
currentVersion: APP_VERSION,
|
||||
latestVersion: "9.9.9",
|
||||
latestTag: "v9.9.9",
|
||||
releaseUrl: "https://github.com/owner/repo/releases/tag/v9.9.9",
|
||||
releaseUrl: "https://codeberg.org/owner/repo/releases/tag/v9.9.9",
|
||||
setupAssetUrl: "",
|
||||
setupAssetName: ""
|
||||
};
|
||||
@ -240,7 +240,7 @@ describe("update", () => {
|
||||
currentVersion: APP_VERSION,
|
||||
latestVersion: "9.9.9",
|
||||
latestTag: "v9.9.9",
|
||||
releaseUrl: "https://github.com/owner/repo/releases/tag/v9.9.9",
|
||||
releaseUrl: "https://codeberg.org/owner/repo/releases/tag/v9.9.9",
|
||||
setupAssetUrl: "https://example.invalid/hang-setup.exe",
|
||||
setupAssetName: "",
|
||||
setupAssetDigest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||
@ -276,7 +276,7 @@ describe("update", () => {
|
||||
currentVersion: APP_VERSION,
|
||||
latestVersion: "9.9.9",
|
||||
latestTag: "v9.9.9",
|
||||
releaseUrl: "https://github.com/owner/repo/releases/tag/v9.9.9",
|
||||
releaseUrl: "https://codeberg.org/owner/repo/releases/tag/v9.9.9",
|
||||
setupAssetUrl: "https://example.invalid/mismatch-setup.exe",
|
||||
setupAssetName: "setup.exe",
|
||||
setupAssetDigest: "sha256:1111111111111111111111111111111111111111111111111111111111111111"
|
||||
@ -292,11 +292,11 @@ describe("normalizeUpdateRepo extended", () => {
|
||||
it("handles trailing slashes and extra path segments", () => {
|
||||
expect(normalizeUpdateRepo("owner/repo/")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("/owner/repo/")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://github.com/owner/repo/tree/main/src")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://codeberg.org/owner/repo/tree/main/src")).toBe("owner/repo");
|
||||
});
|
||||
|
||||
it("handles ssh-style git URLs", () => {
|
||||
expect(normalizeUpdateRepo("git@github.com:user/project.git")).toBe("user/project");
|
||||
expect(normalizeUpdateRepo("git@codeberg.org:user/project.git")).toBe("user/project");
|
||||
});
|
||||
|
||||
it("returns default for malformed inputs", () => {
|
||||
@ -307,12 +307,12 @@ describe("normalizeUpdateRepo extended", () => {
|
||||
it("rejects traversal-like owner or repo segments", () => {
|
||||
expect(normalizeUpdateRepo("../owner/repo")).toBe("Sucukdeluxe/real-debrid-downloader");
|
||||
expect(normalizeUpdateRepo("owner/../repo")).toBe("Sucukdeluxe/real-debrid-downloader");
|
||||
expect(normalizeUpdateRepo("https://github.com/owner/../../repo")).toBe("Sucukdeluxe/real-debrid-downloader");
|
||||
expect(normalizeUpdateRepo("https://codeberg.org/owner/../../repo")).toBe("Sucukdeluxe/real-debrid-downloader");
|
||||
});
|
||||
|
||||
it("handles www prefix", () => {
|
||||
expect(normalizeUpdateRepo("https://www.github.com/owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("www.github.com/owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("https://www.codeberg.org/owner/repo")).toBe("owner/repo");
|
||||
expect(normalizeUpdateRepo("www.codeberg.org/owner/repo")).toBe("owner/repo");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user