feat: release packaging — electron-builder installers + release pipeline
- electron-builder config: AppImage/deb (linux), dmg (mac), nsis (win) - app icon, desktopName sync, deb maintainer metadata - move electron to devDependencies; add author/license/repo metadata - pin @noble/hashes 1.8.0 (electron-builder 26 ESM conflict) - .github/workflows/release.yml: tag-triggered multi-OS build + release - scripts/publish-release.sh: upload dist/ assets to a Gitea release - README: installation + installer build instructions - add missing .env.example - verified locally: AppImage + deb build, deb structure checks out, 118 JS tests still green
This commit is contained in:
parent
e674e1f96d
commit
43114cfe3c
2
.env.example
Normal file
2
.env.example
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# TheTVDB v4 API token — https://www.thetvdb.com/docs
|
||||||
|
TVDB_API_KEY=
|
||||||
56
.github/workflows/release.yml
vendored
Normal file
56
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v*"]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
args: --linux
|
||||||
|
upload: "dist/*.AppImage dist/*.deb"
|
||||||
|
- os: macos-latest
|
||||||
|
args: --mac
|
||||||
|
upload: "dist/*.dmg"
|
||||||
|
- os: windows-latest
|
||||||
|
args: --win
|
||||||
|
upload: "dist/*.exe"
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
cache: npm
|
||||||
|
- run: npm ci
|
||||||
|
- run: npx electron-builder ${{ matrix.args }}
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: release-${{ matrix.os }}
|
||||||
|
path: |
|
||||||
|
${{ matrix.upload }}
|
||||||
|
|
||||||
|
publish:
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: dist
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Publish release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
TAG="${GITHUB_REF#refs/tags/}"
|
||||||
|
gh release create "$TAG" --title "$TAG" \
|
||||||
|
--notes "MovieMapper $TAG release." \
|
||||||
|
dist/*
|
||||||
37
README.md
37
README.md
@ -86,9 +86,35 @@ directory scan ──▶ ffprobe metadata ──▶ tag (extra/commentary)
|
|||||||
└── docs/ # Design docs, phase summaries, plans
|
└── docs/ # Design docs, phase summaries, plans
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Installers are published on the [releases page](https://git.home.ms/jarianc/MovieMapper/releases)
|
||||||
|
(AppImage + .deb for Linux, .dmg for macOS, .exe for Windows).
|
||||||
|
|
||||||
|
### Linux — AppImage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x MovieMapper-*.AppImage
|
||||||
|
./MovieMapper-*.AppImage
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux — Debian/Ubuntu
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dpkg -i MovieMapper_*_amd64.deb
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rust CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo install --path Rust
|
||||||
|
```
|
||||||
|
|
||||||
|
Requires Rust and `ffmpeg`/`ffprobe` on PATH (used for metadata extraction).
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
### Desktop app (Electron)
|
### Desktop app (Electron) — from source
|
||||||
|
|
||||||
Prerequisites: Node.js 20+, npm, `ffmpeg`/`ffprobe` on PATH.
|
Prerequisites: Node.js 20+, npm, `ffmpeg`/`ffprobe` on PATH.
|
||||||
|
|
||||||
@ -98,6 +124,15 @@ cp .env.example .env # add your TVDB_API_KEY
|
|||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Building installers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dist # current platform
|
||||||
|
npm run dist:linux # AppImage + deb
|
||||||
|
npm run dist:mac # dmg (macOS only)
|
||||||
|
npm run dist:win # nsis exe
|
||||||
|
```
|
||||||
|
|
||||||
### Rust core
|
### Rust core
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
BIN
buildResources/icon.png
Normal file
BIN
buildResources/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
57
electron-builder.yml
Normal file
57
electron-builder.yml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
appId: ms.jarian.moviemapper
|
||||||
|
productName: MovieMapper
|
||||||
|
copyright: Copyright © 2026 Jarian Cottingham
|
||||||
|
|
||||||
|
directories:
|
||||||
|
output: dist
|
||||||
|
buildResources: buildResources
|
||||||
|
|
||||||
|
files:
|
||||||
|
- main.js
|
||||||
|
- preload.js
|
||||||
|
- renderer.js
|
||||||
|
- index.html
|
||||||
|
- utils/**/*
|
||||||
|
- package.json
|
||||||
|
|
||||||
|
asar: true
|
||||||
|
|
||||||
|
# The app shells out to ffprobe/ffmpeg for metadata extraction. It expects
|
||||||
|
# them on PATH (documented in the README) rather than bundling them.
|
||||||
|
|
||||||
|
linux:
|
||||||
|
syncDesktopName: true
|
||||||
|
target:
|
||||||
|
- target: AppImage
|
||||||
|
arch: [x64]
|
||||||
|
- target: deb
|
||||||
|
arch: [x64]
|
||||||
|
category: Utility
|
||||||
|
synopsis: Organize movie and TV collections
|
||||||
|
description: Desktop app for organizing movie and TV show collections with Jellyfin-compatible naming, TheTVDB metadata, and audit logging.
|
||||||
|
maintainer: jarianc@proton.me
|
||||||
|
icon: buildResources/icon.png
|
||||||
|
|
||||||
|
mac:
|
||||||
|
target:
|
||||||
|
- target: dmg
|
||||||
|
arch: [x64, arm64]
|
||||||
|
category: public.app-category.video
|
||||||
|
icon: buildResources/icon.png
|
||||||
|
# Notarization requires an Apple ID + team; configured via env in CI.
|
||||||
|
|
||||||
|
win:
|
||||||
|
target:
|
||||||
|
- target: nsis
|
||||||
|
arch: [x64]
|
||||||
|
icon: buildResources/icon.png
|
||||||
|
|
||||||
|
nsis:
|
||||||
|
oneClick: false
|
||||||
|
perMachine: false
|
||||||
|
allowToChangeInstallationDirectory: true
|
||||||
|
createDesktopShortcut: true
|
||||||
|
|
||||||
|
# Publishing is driven by the release workflow, which uploads the built
|
||||||
|
# artifacts to a Gitea/GitHub release. Keep the default off for local builds.
|
||||||
|
publish: null
|
||||||
2675
package-lock.json
generated
2675
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@ -2,20 +2,36 @@
|
|||||||
"name": "MovieMapper",
|
"name": "MovieMapper",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "A desktop application for organizing and managing movie and TV show collections",
|
"description": "A desktop application for organizing and managing movie and TV show collections",
|
||||||
|
"author": "Jarian Cottingham <jarianc@proton.me>",
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://git.home.ms/jarianc/MovieMapper",
|
||||||
|
"desktopName": "MovieMapper",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.home.ms/jarianc/MovieMapper.git"
|
||||||
|
},
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron .",
|
"start": "electron .",
|
||||||
"test": "vitest run --coverage"
|
"test": "vitest run --coverage",
|
||||||
|
"dist": "electron-builder",
|
||||||
|
"dist:linux": "electron-builder --linux",
|
||||||
|
"dist:mac": "electron-builder --mac",
|
||||||
|
"dist:win": "electron-builder --win"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.13.5",
|
"axios": "^1.13.5",
|
||||||
"dotenv": "^17.3.1",
|
"dotenv": "^17.3.1",
|
||||||
"electron": "^40.4.1",
|
|
||||||
"fluent-ffmpeg": "^2.1.3"
|
"fluent-ffmpeg": "^2.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitest/coverage-v8": "^3.2.6",
|
"@vitest/coverage-v8": "^3.2.6",
|
||||||
|
"electron": "^40.4.1",
|
||||||
|
"electron-builder": "^26.0.12",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^25.0.1",
|
||||||
"vitest": "^3.2.6"
|
"vitest": "^3.2.6"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"@noble/hashes": "1.8.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
scripts/publish-release.sh
Executable file
53
scripts/publish-release.sh
Executable file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Publish built artifacts (dist/) as a Gitea release with attached assets.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# GITEA_PASS=... ./scripts/publish-release.sh v1.0.0
|
||||||
|
#
|
||||||
|
# Environment:
|
||||||
|
# GITEA_URL (default: https://git.home.ms)
|
||||||
|
# GITEA_USER (default: jarianc)
|
||||||
|
# GITEA_PASS (required)
|
||||||
|
# GITEA_REPO (default: jarianc/MovieMapper)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TAG="${1:?usage: publish-release.sh <tag> (e.g. v1.0.0)}"
|
||||||
|
GITEA_URL="${GITEA_URL:-https://git.home.ms}"
|
||||||
|
GITEA_USER="${GITEA_USER:-jarianc}"
|
||||||
|
GITEA_PASS="${GITEA_PASS:?GITEA_PASS is required}"
|
||||||
|
GITEA_REPO="${GITEA_REPO:-jarianc/MovieMapper}"
|
||||||
|
AUTH=("${GITEA_USER}:${GITEA_PASS}")
|
||||||
|
API="$GITEA_URL/api/v1/repos/$GITEA_REPO"
|
||||||
|
|
||||||
|
# Create the release if it does not exist yet.
|
||||||
|
existing="$(curl -sf -u "${AUTH[@]}" "$API/releases/tags/$TAG" 2>/dev/null \
|
||||||
|
| python3 -c 'import json,sys; print(json.load(sys.stdin).get("id",""))' || true)"
|
||||||
|
if [ -z "${existing}" ]; then
|
||||||
|
curl -sf -u "${AUTH[@]}" -X POST "$API/releases" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\",\"body\":\"MovieMapper $TAG release. Linux: AppImage + deb. See README for install instructions.\"}" \
|
||||||
|
> /dev/null
|
||||||
|
echo "created release $TAG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
uploaded=0
|
||||||
|
for f in dist/*.AppImage dist/*.deb dist/*.dmg dist/*.exe dist/*.zip; do
|
||||||
|
[ -e "$f" ] || continue
|
||||||
|
if curl -sf -u "${AUTH[@]}" -X POST "$API/releases/$TAG/assets" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"$f" > /dev/null; then
|
||||||
|
echo "uploaded $(basename "$f")"
|
||||||
|
uploaded=$((uploaded + 1))
|
||||||
|
else
|
||||||
|
echo "FAILED to upload $f" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$uploaded" -eq 0 ]; then
|
||||||
|
echo "no artifacts found in dist/ — run npm run dist first" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "done: $uploaded assets on release $TAG"
|
||||||
Loading…
x
Reference in New Issue
Block a user