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
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
### Desktop app (Electron)
|
||||
### Desktop app (Electron) — from source
|
||||
|
||||
Prerequisites: Node.js 20+, npm, `ffmpeg`/`ffprobe` on PATH.
|
||||
|
||||
@ -98,6 +124,15 @@ cp .env.example .env # add your TVDB_API_KEY
|
||||
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
|
||||
|
||||
```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",
|
||||
"version": "1.0.0",
|
||||
"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",
|
||||
"scripts": {
|
||||
"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": {
|
||||
"axios": "^1.13.5",
|
||||
"dotenv": "^17.3.1",
|
||||
"electron": "^40.4.1",
|
||||
"fluent-ffmpeg": "^2.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitest/coverage-v8": "^3.2.6",
|
||||
"electron": "^40.4.1",
|
||||
"electron-builder": "^26.0.12",
|
||||
"jsdom": "^25.0.1",
|
||||
"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