Skip to content
Open
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
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
target/
.git/
.github/
*.md
.gitignore
.dockerignore
docker-compose.yml
105 changes: 105 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: CI

on:
push:
branches: [ master, main ]
pull_request:
branches: [ master, main ]

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
rust: [stable, beta]

steps:
- uses: actions/checkout@v4

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libudev-dev pkg-config libssl-dev

- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
components: rustfmt, clippy

- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}

- name: Check formatting
run: cargo fmt -- --check

- name: Run clippy
run: cargo clippy -- -D warnings

- name: Build
run: cargo build --verbose

- name: Run tests
run: cargo test --verbose

build:
name: Build Release
runs-on: ubuntu-latest
needs: test

steps:
- uses: actions/checkout@v4

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libudev-dev pkg-config libssl-dev

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Cache cargo registry
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo index
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}

- name: Cache cargo build
uses: actions/cache@v4
with:
path: target
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }}

- name: Build release
run: cargo build --release --verbose

- name: Upload binary
uses: actions/upload-artifact@v4
with:
name: torn-binary
path: target/release/torn
66 changes: 66 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Docker Build and Deploy

on:
push:
branches: [ master, main ]
tags: [ 'v*' ]
pull_request:
branches: [ master, main ]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Generate artifact attestation
if: github.event_name != 'pull_request'
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.build.outputs.digest }}
push-to-registry: true
63 changes: 63 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Build stage
FROM rust:1.88.0-slim as builder

WORKDIR /usr/src/app

# Install required system dependencies
RUN apt-get update && apt-get install -y \
pkg-config \
libssl-dev \
libudev-dev \
&& rm -rf /var/lib/apt/lists/*

# Copy manifests
COPY Cargo.toml Cargo.lock ./

# Copy source code
COPY src ./src
COPY config ./config
COPY style ./style
COPY templates ./templates

# Build the application
RUN cargo build --release

# Runtime stage
FROM debian:bookworm-slim

# Install runtime dependencies
RUN apt-get update && apt-get install -y \
ca-certificates \
libudev1 \
libssl3 \
wget \
gnupg \
&& rm -rf /var/lib/apt/lists/*

# Install HandBrake and MakeMKV from PPAs
RUN apt-get update && apt-get install -y \
software-properties-common \
&& add-apt-repository ppa:stebbins/handbrake-releases \
&& add-apt-repository ppa:heyarje/makemkv-beta \
&& apt-get update && apt-get install -y \
handbrake-cli \
makemkv-bin \
makemkv-oss \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy the binary from builder stage
COPY --from=builder /usr/src/app/target/release/torn /app/torn
COPY --from=builder /usr/src/app/config /app/config
COPY --from=builder /usr/src/app/style /app/style
COPY --from=builder /usr/src/app/templates /app/templates

# Create directories for data
RUN mkdir -p /app/data/raw /app/data/output

# Expose the web interface port
EXPOSE 8080

# Run the application
CMD ["./torn", "rip"]
1 change: 0 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub struct Options {

#[derive(Clone, Debug, Deserialize)]
pub struct Directory {
pub logs: String,
pub raw: String,
pub output: String,
}
Expand Down
16 changes: 8 additions & 8 deletions src/disc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ impl Disc {
}

pub fn title(&self) -> String {
if let Some(val) = self.properties.get("ID_FS_LABEL") {
if val != "iso9660" {
return val.to_title_case();
}
if let Some(val) = self.properties.get("ID_FS_LABEL")
&& val != "iso9660"
{
return val.to_title_case();
}

if let Some(val) = self.properties.get("ID_FS_UUID") {
Expand Down Expand Up @@ -78,10 +78,10 @@ fn get_device_proprties(device: &str) -> HashMap<String, String> {
}

fn get_device_type(properties: &HashMap<String, String>) -> Option<DiscType> {
if let Some(val) = properties.get("ID_FS_LABEL") {
if val == "iso9660" {
return Some(DiscType::Data);
}
if let Some(val) = properties.get("ID_FS_LABEL")
&& val == "iso9660"
{
return Some(DiscType::Data);
}

if properties.get("ID_CDROM_MEDIA_BD").is_some() {
Expand Down
6 changes: 3 additions & 3 deletions src/handbrake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl HandbrakeProcess {
// Mark job as failed
let mut jobs_map = jobs_clone.write().await;
if let Some(job_status) = jobs_map.get_mut(&job.id) {
job_status.status = format!("Failed: {}", e);
job_status.status = format!("Failed: {e}");
job_status.progress = 0.0;
}
}
Expand Down Expand Up @@ -180,13 +180,13 @@ async fn handbrake(
{
let mut jobs_map = jobs.write().await;
if let Some(job_status) = jobs_map.get_mut(job_id) {
job_status.status = format!("Processing: {}", source_file);
job_status.status = format!("Processing: {source_file}");
job_status.progress = 0.5; // Rough estimate
}
}

let mut child = Command::new("HandBrakeCLI")
.args(&[
.args([
"-i",
source_file,
"-o",
Expand Down
10 changes: 5 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ async fn main() -> Result<(), Error> {
rip(settings).await?;
}
Command::Debug(_) => {
println!("Settings: {:#?}", settings);
println!("Settings: {settings:#?}");

for device in settings.options.devices {
let disc = Disc::new(&device);

println!("{:#?}", disc);
println!("{disc:#?}");
}
}
}
Expand All @@ -65,7 +65,7 @@ async fn rip(settings: Settings) -> Result<(), Error> {
let web_hb_process = hb_process.clone();
let web_handle = tokio::spawn(async move {
if let Err(e) = web::run_web_server(web_settings, web_hb_process).await {
warn!("Web interface error: {}", e);
warn!("Web interface error: {e}");
}
Ok(())
});
Expand All @@ -86,7 +86,7 @@ async fn rip(settings: Settings) -> Result<(), Error> {

for res in results {
if let Err(err) = res {
error!("Error: {}", err);
error!("Error: {err}");
}
}

Expand Down Expand Up @@ -121,7 +121,7 @@ fn spawn_rip_process(
disc::eject(&disc).await;
}
Some(t) => {
warn!("Disc type {:?} currently unsupported", t);
warn!("Disc type {t:?} currently unsupported");
disc::eject(&disc).await;
}
None => {
Expand Down
4 changes: 2 additions & 2 deletions src/makemkv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{
time::SystemTime,
};

use failure::{format_err, Error};
use failure::{Error, format_err};
use tokio::{fs, process::Command};

use crate::config::MakeMKV;
Expand All @@ -25,7 +25,7 @@ pub async fn rip(config: &MakeMKV, disc: &Disc, target_folder: &Path) -> Result<
fs::create_dir_all(&target_folder).await?;

let mut child = Command::new("makemkvcon")
.args(&[
.args([
"mkv",
"-r",
&format!("dev:{}", disc.name),
Expand Down
Loading
Loading