Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .github/workflows/app.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: app

on:
push:
branches: [main, tauri]
tags: ["v*"]
paths:
- app/**
- parser-harness.js
- .github/workflows/app.yml
pull_request:
paths:
- app/**
- parser-harness.js
workflow_dispatch:

jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: windows-latest
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
permissions:
contents: write
defaults:
run:
shell: bash

steps:
- uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- name: Install Linux system deps
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
libssl-dev \
pkg-config

- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
app/src-tauri/target
key: ${{ matrix.os }}-cargo-${{ hashFiles('app/src-tauri/Cargo.lock', 'app/src-tauri/Cargo.toml') }}

- name: Stage Node sidecar + parser-harness
run: bash app/scripts/prepare-sidecar.sh ${{ matrix.target }}

- name: Install tauri-cli
uses: taiki-e/install-action@v2
with:
tool: tauri-cli

- name: Generate icons from source PNG
working-directory: app
run: cargo tauri icon src-tauri/icons/icon.png

- name: Build Tauri app
working-directory: app
run: cargo tauri build --target ${{ matrix.target }}

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: combatlog-${{ matrix.target }}
path: |
app/src-tauri/target/${{ matrix.target }}/release/bundle/**/*
if-no-files-found: error

- name: Attach bundles to GitHub Release
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v2
with:
draft: true
fail_on_unmatched_files: false
files: |
app/src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
app/src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage
app/src-tauri/target/${{ matrix.target }}/release/bundle/rpm/*.rpm
app/src-tauri/target/${{ matrix.target }}/release/bundle/msi/*.msi
app/src-tauri/target/${{ matrix.target }}/release/bundle/nsis/*-setup.exe
24 changes: 24 additions & 0 deletions .github/workflows/web.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: web

on:
push:
branches: [main]
paths:
- web/**
- parser-harness.js
- docker-compose*.yml
- .github/workflows/web.yml
pull_request:
paths:
- web/**
- parser-harness.js

jobs:
docker-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build production image
run: docker build -f web/Dockerfile -t combatlog-web:ci .
- name: Build local image
run: docker build -f web/Dockerfile.local -t combatlog-web-local:ci .
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
.vscode
__pycache__/
.claude/

# Rust build output
app/src-tauri/target/
app/src-tauri/Cargo.lock

# Node sidecar and staged parser harness are fetched at build time
app/src-tauri/binaries/
app/src-tauri/resources/parser-harness.js

# Icons generated by `cargo tauri icon`. Keep only the source icon.png.
app/src-tauri/icons/*
!app/src-tauri/icons/icon.png
!app/src-tauri/icons/.gitkeep

# Tauri generated schemas and ACL manifests
app/src-tauri/gen/
41 changes: 29 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,60 @@
# combatlog.dev

A privacy-conscious combat log uploader for [WarcraftLogs](https://www.warcraftlogs.com). No telemetry, no analytics, no ads.
A privacy-conscious combat log uploader for [WarcraftLogs](https://www.warcraftlogs.com). No telemetry, no analytics, no ads.

## Web UI (Self-Hosted)
## Desktop app

### Requirements
The easiest option if you just want to upload logs from your own machine. Grab the installer for your OS from the [Releases](../../releases) page:

- Docker & Docker Compose
- **Windows** — `.msi` installer
- **Linux** — `.deb`, `.rpm`, or `.AppImage`

### Local
Credentials stay in local storage on your machine.

## Web UI (self-hosted)

**Requirements:** Docker + Docker Compose.

```bash
docker compose -f docker-compose.local.yml up --build
```

Open [http://localhost:5050](http://localhost:5050) in your browser.

## CLI Script
Then open [http://localhost:5050](http://localhost:5050).

### Requirements
## CLI

**Requirements:**
- Python 3.10+
- Node.js 18+
- `curl_cffi` (`pip install curl_cffi`)

### Usage
**Usage:**

```bash
python3 wcl-upload.py WoWCombatLog-041225_203000.txt \
--email you@example.com \
--password yourpass
```

### Options
**Options:**

| Flag | Default | Description |
|---|---|---|
| `--email` | *(required)* | WarcraftLogs email |
| `--password` | *(required)* | WarcraftLogs password |
| `--region` | `2` | 1=US, 2=EU, 3=KR, 4=TW, 5=CN |
| `--visibility` | `2` | 0=Public, 1=Private, 2=Unlisted |
| `--guild-id` | *none* | Guild ID to associate the report with |
| `--guild-id` | *none* | Guild ID to associate the report with |

## Building the desktop app from source

If you want to build yourself instead of downloading a release:

```bash
cd app
bash scripts/prepare-sidecar.sh # downloads the Node sidecar for your host
cargo tauri icon src-tauri/icons/icon.png # first time only
cargo tauri build
```

Needs Rust (stable) and, on Linux, the usual webkit2gtk dev packages.
65 changes: 65 additions & 0 deletions app/scripts/prepare-sidecar.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# This downloads the Node.js binary for the current host target and copies
# it into app/src-tauri/binaries/ with the target-triple suffix Tauri expects.
# Also copies the root parser-harness.js into src-tauri/resources/.

# This is necessary because the whole thing ig silly and we're running
# an obfuscated js, and the rust node runtimes can't JIT compile it properly
# so this is the only way to avoid 10 min uploads at the cost of 800MB of sidecar.

set -euo pipefail

cd "$(dirname "$0")/.."
ROOT="$(cd .. && pwd)"
BINARIES_DIR="src-tauri/binaries"
RESOURCES_DIR="src-tauri/resources"
NODE_VERSION="${NODE_VERSION:-v20.18.1}"

TARGET="${1:-}"
if [[ -z "$TARGET" ]]; then
TARGET="$(rustc -vV | awk -F': ' '/^host/ {print $2}')"
fi

case "$TARGET" in
x86_64-unknown-linux-gnu)
NODE_ARCHIVE="node-${NODE_VERSION}-linux-x64.tar.xz"
NODE_BIN_PATH="node-${NODE_VERSION}-linux-x64/bin/node"
EXT=""
;;
x86_64-pc-windows-msvc|x86_64-pc-windows-gnu)
NODE_ARCHIVE="node-${NODE_VERSION}-win-x64.zip"
NODE_BIN_PATH="node-${NODE_VERSION}-win-x64/node.exe"
EXT=".exe"
;;
aarch64-unknown-linux-gnu)
NODE_ARCHIVE="node-${NODE_VERSION}-linux-arm64.tar.xz"
NODE_BIN_PATH="node-${NODE_VERSION}-linux-arm64/bin/node"
EXT=""
;;
*)
echo "unsupported target: $TARGET" >&2
exit 2
;;
esac

mkdir -p "$BINARIES_DIR" "$RESOURCES_DIR"
cp "$ROOT/parser-harness.js" "$RESOURCES_DIR/parser-harness.js"

DEST="$BINARIES_DIR/node-${TARGET}${EXT}"
if [[ -f "$DEST" ]]; then
echo "sidecar already present: $DEST"
exit 0
fi

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
url="https://nodejs.org/dist/${NODE_VERSION}/${NODE_ARCHIVE}"
echo "downloading $url"
curl -fsSL -o "$tmp/$NODE_ARCHIVE" "$url"
if [[ "$NODE_ARCHIVE" == *.zip ]]; then
unzip -q "$tmp/$NODE_ARCHIVE" -d "$tmp"
else
tar -xJf "$tmp/$NODE_ARCHIVE" -C "$tmp"
fi
install -m 0755 "$tmp/$NODE_BIN_PATH" "$DEST"
echo "staged sidecar: $DEST"
32 changes: 32 additions & 0 deletions app/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "combatlog"
version = "0.1.0"
edition = "2021"
description = "combatlog.dev — local WarcraftLogs uploader"
default-run = "combatlog"

[build-dependencies]
tauri-build = { version = "2", features = [] }

[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-shell = "2"
tauri-plugin-dialog = "2"
tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-util", "process", "sync", "fs", "time"] }
rquest = { version = "2", features = ["json", "cookies"] }
regex = "1"
anyhow = "1"
rand = "0.8"
zip = { version = "2", default-features = false, features = ["deflate"] }

[features]
default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]

[profile.release]
opt-level = 3
lto = "thin"
strip = true
3 changes: 3 additions & 0 deletions app/src-tauri/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
tauri_build::build();
}
9 changes: 9 additions & 0 deletions app/src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Default capabilities granted to the main window",
"windows": ["main"],
"permissions": [
"core:default"
]
}
2 changes: 2 additions & 0 deletions app/src-tauri/icons/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Icons are generated from a source PNG via `cargo tauri icon <source.png>`.
Run that command before `cargo tauri build` or let the CI workflow do it.
Binary file added app/src-tauri/icons/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading