diff --git a/.github/workflows/build-flatpak.yml b/.github/workflows/build-flatpak.yml new file mode 100644 index 0000000..156faf2 --- /dev/null +++ b/.github/workflows/build-flatpak.yml @@ -0,0 +1,80 @@ +name: Build Flatpak + +on: + workflow_dispatch: + inputs: + version: + description: "Version to build (e.g. 0.9.0)" + required: true + +permissions: + contents: write + +jobs: + flatpak: + name: Build Flatpak bundle + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Free up disk space + run: | + sudo rm -rf /usr/local/lib/android /opt/ghc /usr/share/dotnet /opt/hostedtoolcache/CodeQL + sudo docker image prune -af || true + + - name: Install flatpak tooling + run: | + sudo apt-get update + sudo apt-get install -y flatpak flatpak-builder + flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + + - name: Cache flatpak runtimes/SDKs + uses: actions/cache@v4 + with: + path: ~/.local/share/flatpak + key: flatpak-runtimes-gnome48-rust-stable + + - name: Install runtime, SDK and rust-stable extension + run: | + flatpak --user install -y --noninteractive flathub \ + org.gnome.Platform//48 \ + org.gnome.Sdk//48 \ + org.freedesktop.Sdk.Extension.rust-stable//48 + + - name: Build flatpak + run: | + rm -rf build-dir repo + flatpak-builder \ + --user \ + --install-deps-from=flathub \ + --repo=repo \ + --force-clean \ + build-dir \ + io.github.moku_project.Moku.yml + + - name: Bundle flatpak + run: | + flatpak build-bundle \ + --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo \ + repo \ + moku.flatpak \ + io.github.moku_project.Moku + + - name: Upload Flatpak artifact to release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + for i in $(seq 1 12); do + RELEASE_ID=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ + "https://api.github.com/repos/moku-project/Moku/releases" \ + | jq -r '.[] | select(.tag_name == "v${{ github.event.inputs.version }}") | .id' | head -1) + [ -n "$RELEASE_ID" ] && break + echo "Waiting for release... attempt $i"; sleep 15 + done + [ -z "$RELEASE_ID" ] && { echo "ERROR: release not found"; exit 1; } + + curl -s -X POST \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Content-Type: application/octet-stream" \ + --data-binary @"moku.flatpak" \ + "https://uploads.github.com/repos/moku-project/Moku/releases/$RELEASE_ID/assets?name=moku.flatpak" diff --git a/.github/workflows/build-static.yml b/.github/workflows/build-static.yml new file mode 100644 index 0000000..4f58161 --- /dev/null +++ b/.github/workflows/build-static.yml @@ -0,0 +1,51 @@ +name: Build Static WebUI + +on: + workflow_dispatch: + inputs: + version: + description: "Version to build (e.g. 0.9.0)" + required: true + +permissions: + contents: write + +jobs: + build: + name: Build static frontend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: { version: latest } + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + - run: pnpm build:static + + - name: Zip static build + run: | + cd dist + zip -r "../moku-webui-${{ github.event.inputs.version }}.zip" . + + - name: Upload WebUI artifact to release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + for i in $(seq 1 12); do + RELEASE_ID=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ + "https://api.github.com/repos/moku-project/Moku/releases" \ + | jq -r '.[] | select(.tag_name == "v${{ github.event.inputs.version }}") | .id' | head -1) + [ -n "$RELEASE_ID" ] && break + echo "Waiting for release... attempt $i"; sleep 15 + done + [ -z "$RELEASE_ID" ] && { echo "ERROR: release not found"; exit 1; } + + curl -s -X POST \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "Content-Type: application/zip" \ + --data-binary @"moku-webui-${{ github.event.inputs.version }}.zip" \ + "https://uploads.github.com/repos/moku-project/Moku/releases/$RELEASE_ID/assets?name=moku-webui-${{ github.event.inputs.version }}.zip" diff --git a/src/lib/components/recent/Recent.svelte b/src/lib/components/recent/Recent.svelte index 1c08519..4666bd2 100644 --- a/src/lib/components/recent/Recent.svelte +++ b/src/lib/components/recent/Recent.svelte @@ -12,7 +12,7 @@ import RecentToolbar from './RecentToolbar.svelte' import UpdatesTab from './UpdatesTab.svelte' import HistoryTab from './HistoryTab.svelte' - import type { Manga } from '$lib/types' + import type { Manga, Chapter } from '$lib/types' import type { RecentUpdate, UpdateGroup } from './lib/recentUpdates' import type { HistoryGroup } from './lib/recentHistory' @@ -122,9 +122,9 @@ if (force) cache.clear(key) const [updatesRes, statusRes] = await Promise.all([ - cache.get( + cache.get( key, - () => getAdapter().getRecentlyUpdated(nextCtrl.signal), + () => getAdapter().getRecentlyUpdated(), RECENT_UPDATES_TTL_MS, CACHE_GROUPS.LIBRARY, ), @@ -210,7 +210,7 @@ async function deleteDownloaded(item: RecentUpdate) { try { - await getAdapter().deleteDownloadedChapter(String(item.id)) + await getAdapter().deleteDownloadedChapters([String(item.id)]) updates = updates.map(u => u.id === item.id ? { ...u, isDownloaded: false } : u) } catch { addToast({ kind: 'error', title: 'Delete failed', body: 'Could not delete download.' }) diff --git a/src/lib/components/settings/lib/bugReport.ts b/src/lib/components/settings/lib/bugReport.ts index b8518fd..d8ee196 100644 --- a/src/lib/components/settings/lib/bugReport.ts +++ b/src/lib/components/settings/lib/bugReport.ts @@ -129,9 +129,10 @@ export function buildIssueUrl( ): string { const base = 'https://github.com/moku-project/Moku/issues/new' + const prefix = type === 'bug' ? '[Bug] ' : '[Feature Request] ' const common = { template: type === 'bug' ? 'bug_report.yml' : 'feature_request.yml', - title, + title: title.startsWith(prefix) ? title : `${prefix}${title}`, environment: buildEnvironmentBlock(serverVersion), } diff --git a/src/lib/server-adapters/suwayomi/index.ts b/src/lib/server-adapters/suwayomi/index.ts index f031182..21fe3da 100644 --- a/src/lib/server-adapters/suwayomi/index.ts +++ b/src/lib/server-adapters/suwayomi/index.ts @@ -691,6 +691,10 @@ export class SuwayomiAdapter implements ServerAdapter { return [] } + async startLibraryUpdate(): Promise { + await this.gql(UPDATE_LIBRARY) + } + async stopLibraryUpdate(): Promise { await this.gql(UPDATE_STOP) } diff --git a/src/lib/server-adapters/types.ts b/src/lib/server-adapters/types.ts index eda1dc4..d8dd009 100644 --- a/src/lib/server-adapters/types.ts +++ b/src/lib/server-adapters/types.ts @@ -233,6 +233,7 @@ export interface ServerAdapter { clearCachedImages(opts: { cachedPages: boolean; cachedThumbnails: boolean; downloadedThumbnails: boolean }): Promise checkForUpdates(mangaIds?: string[]): Promise + startLibraryUpdate(): Promise stopLibraryUpdate(): Promise getLibraryUpdateStatus(): Promise clearPageCache(chapterId?: number): void