From 70cc5e38065d1af58311cf48997463015b905a1f Mon Sep 17 00:00:00 2001 From: Artur Flis Date: Thu, 1 Oct 2026 20:28:55 +0200 Subject: [PATCH 1/2] Fixed workflows --- .github/workflows/ci.yml | 3 +-- .github/workflows/release.yml | 13 +++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8556edf..f887067 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,6 @@ name: CI -# Only Go sources feed the build/vet/test steps, so doc- and asset-only -# changes skip CI. schema.sql is go:embed'ed, hence included. +# Only Go sources feed the build/vet/test steps, so doc- and asset-only changes skip CI. schema.sql is go:embed'ed, hence included. on: push: branches: [main] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2d92d5a..c7e0b0f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -5,21 +5,20 @@ on: workflow_dispatch: permissions: + actions: write contents: write packages: write jobs: binaries: name: Build and attach binaries - # Only a real release has somewhere to upload to; a manual dispatch run - # builds the image but skips this job. + # Only a real release has somewhere to upload to; a manual dispatch run builds the image but skips this job. if: github.event_name == 'release' runs-on: ubuntu-latest strategy: matrix: # Mirrors the platforms the Docker image is built for; there is no - # bundled yt-dlp/ffmpeg/imagemagick here, so this is the bare Go - # binary only, for people who already have those tools on PATH. + # bundled yt-dlp/ffmpeg/imagemagick here, so this is the bare Go binary only, for people who already have those tools on PATH. goarch: [amd64, arm64] steps: - uses: actions/checkout@v7 @@ -91,5 +90,7 @@ jobs: APP_VERSION=${{ github.ref_name }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha - cache-to: type=gha,mode=max + # Use the v2 cache service explicitly. The legacy v1 service can + # return `not_found` while exporting a layer after the image push has already succeeded. + cache-from: type=gha,scope=aiofiles,version=2 + cache-to: type=gha,scope=aiofiles,mode=max,version=2,ignore-error=true From 50987873d1de3506664db3d711be5a7eb63ee6f8 Mon Sep 17 00:00:00 2001 From: Artur Flis Date: Thu, 15 Oct 2026 18:17:11 +0200 Subject: [PATCH 2/2] Fixed some stuff --- frontend/app.js | 28 +++++++++++++++++++++++----- frontend/index.html | 22 +++++++++++++++++++--- internal/api/handlers_jobs.go | 33 ++++++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/frontend/app.js b/frontend/app.js index 0e40d36..3f005f8 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -240,6 +240,23 @@ function isIOS() { return /Macintosh/.test(ua) && (window.navigator.maxTouchPoints || 0) > 1; } +var SAVE_TYPES = { + mp4: "video/mp4", m4v: "video/mp4", mov: "video/quicktime", webm: "video/webm", + mkv: "video/x-matroska", mp3: "audio/mpeg", m4a: "audio/mp4", aac: "audio/aac", + ogg: "audio/ogg", opus: "audio/ogg", wav: "audio/wav", flac: "audio/flac", + jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", gif: "image/gif", + webp: "image/webp", avif: "image/avif", heic: "image/heic", heif: "image/heif", + tif: "image/tiff", tiff: "image/tiff", bmp: "image/bmp", +}; + +/* The share sheet only offers Save to Photos for a recognised image or video + type, so a generic or missing one is replaced by the extension's. */ +function saveType(blob, name) { + var type = String(blob.type || "").toLowerCase(); + if (/^(image|video|audio)\//.test(type)) return type; + return SAVE_TYPES[extOf(name)] || type || "application/octet-stream"; +} + /* Mirrors the .job phone breakpoint in app.css. */ function isMobileViewport() { return !!(window.matchMedia && window.matchMedia("(max-width: 680px)").matches); @@ -1272,7 +1289,9 @@ function mediaApp() { onPick(event, tab) { var files = event.target.files; if (files && files.length) this.addFiles(files, tab); - event.target.value = ""; + /* Not cleared here: iOS drops the picked files' temp copies when the + input is reset, before they have been read. The input resets on its + next click instead. */ }, /* One batch, one kind: the options on screen belong to either a video or @@ -2382,9 +2401,7 @@ function mediaApp() { if (tick !== saveTick) return; saveRequest = null; - savePending = new File([blob], name, { - type: blob.type || "application/octet-stream", - }); + savePending = new File([blob], name, { type: saveType(blob, name) }); this.save.phase = "ready"; /* The share sheet wants a fresh user gesture and the fetch has probably outlived the tap that started it. Try anyway - a short fetch usually @@ -2398,7 +2415,8 @@ function mediaApp() { var file = savePending; if (!file) return; - var payload = { files: [file], title: file.name }; + /* No title or text: iOS saves those as an extra .txt next to the file. */ + var payload = { files: [file] }; var sharable = navigator.canShare && navigator.share && navigator.canShare(payload); /* No file sharing on old iOS, or on plain HTTP where it is undefined. */ diff --git a/frontend/index.html b/frontend/index.html index 2812aab..0bd1eb2 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -538,6 +538,8 @@

New job

@@ -582,7 +584,13 @@

New job

Add more - +