1import type { Database } from "bun:sqlite";2import type { ReleaseFile } from "../bucket/repo.ts";3import { releaseRecords } from "../mirror/queries.ts";456export type Release = {7 version: string;8 save: string;9 publishedAt: number;10 notes: string;11 files: ReleaseFile[];12};1314type ReleaseSetting = { version: string; hidden: number; notes: string | null };151617181920export function visibleReleases(kepr: Database, mirror: Database, repo: string): Release[] {21 const settings = new Map(22 kepr23 .query<ReleaseSetting, [string]>(24 "SELECT version, hidden, notes FROM release_settings WHERE repo = ?",25 )26 .all(repo)27 .map((row) => [row.version, row]),28 );29 return releaseRecords(mirror)30 .filter((record) => settings.get(record.version)?.hidden !== 1)31 .map((record) => ({32 version: record.version,33 save: record.save,34 publishedAt: record.published_at,35 notes: settings.get(record.version)?.notes ?? record.notes,36 files: record.files.toSorted((a, b) => (a.platform < b.platform ? -1 : 1)),37 }))38 .sort((a, b) => compareVersions(b.version, a.version));39}4041export function compareVersions(a: string, b: string): number {42 const left = a.split(".").map((part) => Number.parseInt(part, 10) || 0);43 const right = b.split(".").map((part) => Number.parseInt(part, 10) || 0);44 for (let i = 0; i < Math.max(left.length, right.length); i++) {45 const diff = (left[i] ?? 0) - (right[i] ?? 0);46 if (diff !== 0) return diff;47 }48 49 return a < b ? -1 : a > b ? 1 : 0;50}515253export function releaseContentType(name: string): string {54 const lower = name.toLowerCase();55 if (lower.endsWith(".apk")) return "application/vnd.android.package-archive";56 if (lower.endsWith(".zip")) return "application/zip";57 return "application/octet-stream";58}5960export function countDownload(61 kepr: Database,62 repo: string,63 version: string,64 platform: string,65): void {66 kepr67 .query(68 `INSERT INTO downloads (repo, version, platform, count) VALUES (?, ?, ?, 1)69 ON CONFLICT DO UPDATE SET count = count + 1`,70 )71 .run(repo, version, platform);72}737475export function countInstall(kepr: Database, repo: string): void {76 kepr77 .query(78 "INSERT INTO installs (repo, count) VALUES (?, 1) ON CONFLICT DO UPDATE SET count = count + 1",79 )80 .run(repo);81}828384export function downloadCounts(kepr: Database, repo: string): Map<string, number> {85 const rows = kepr86 .query<{ version: string; platform: string; count: number }, [string]>(87 "SELECT version, platform, count FROM downloads WHERE repo = ?",88 )89 .all(repo);90 return new Map(rows.map((row) => [`${row.version}/${row.platform}`, row.count]));91}