media-archive-sync 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- media_archive_sync-0.1.0/.coderabbit.yaml +58 -0
- media_archive_sync-0.1.0/.gitconfig +4 -0
- media_archive_sync-0.1.0/.githooks/pre-commit +78 -0
- media_archive_sync-0.1.0/.githooks/pre-push +51 -0
- media_archive_sync-0.1.0/.github/workflows/ci.yml +45 -0
- media_archive_sync-0.1.0/.github/workflows/docker-build.yml +65 -0
- media_archive_sync-0.1.0/.github/workflows/lint.yml +75 -0
- media_archive_sync-0.1.0/.github/workflows/publish.yml +55 -0
- media_archive_sync-0.1.0/.gitignore +44 -0
- media_archive_sync-0.1.0/CONTRIBUTING.md +97 -0
- media_archive_sync-0.1.0/Dockerfile +64 -0
- media_archive_sync-0.1.0/LICENSE +21 -0
- media_archive_sync-0.1.0/Makefile +36 -0
- media_archive_sync-0.1.0/PKG-INFO +151 -0
- media_archive_sync-0.1.0/README.md +112 -0
- media_archive_sync-0.1.0/examples/basic_download.py +20 -0
- media_archive_sync-0.1.0/examples/custom_organizer.py +31 -0
- media_archive_sync-0.1.0/pyproject.toml +131 -0
- media_archive_sync-0.1.0/src/media_archive_sync/__init__.py +64 -0
- media_archive_sync-0.1.0/src/media_archive_sync/cache.py +460 -0
- media_archive_sync-0.1.0/src/media_archive_sync/cli.py +108 -0
- media_archive_sync-0.1.0/src/media_archive_sync/config.py +50 -0
- media_archive_sync-0.1.0/src/media_archive_sync/crawler.py +438 -0
- media_archive_sync-0.1.0/src/media_archive_sync/display.py +368 -0
- media_archive_sync-0.1.0/src/media_archive_sync/downloader.py +599 -0
- media_archive_sync-0.1.0/src/media_archive_sync/logging.py +25 -0
- media_archive_sync-0.1.0/src/media_archive_sync/merge.py +315 -0
- media_archive_sync-0.1.0/src/media_archive_sync/nfo.py +289 -0
- media_archive_sync-0.1.0/src/media_archive_sync/organizer.py +353 -0
- media_archive_sync-0.1.0/src/media_archive_sync/strings.py +197 -0
- media_archive_sync-0.1.0/tests/conftest.py +8 -0
- media_archive_sync-0.1.0/tests/test_cache.py +309 -0
- media_archive_sync-0.1.0/tests/test_cli.py +419 -0
- media_archive_sync-0.1.0/tests/test_config.py +77 -0
- media_archive_sync-0.1.0/tests/test_crawler.py +576 -0
- media_archive_sync-0.1.0/tests/test_display.py +195 -0
- media_archive_sync-0.1.0/tests/test_display_extended.py +195 -0
- media_archive_sync-0.1.0/tests/test_downloader.py +148 -0
- media_archive_sync-0.1.0/tests/test_downloader_extended.py +566 -0
- media_archive_sync-0.1.0/tests/test_init.py +84 -0
- media_archive_sync-0.1.0/tests/test_logging.py +41 -0
- media_archive_sync-0.1.0/tests/test_merge.py +335 -0
- media_archive_sync-0.1.0/tests/test_nfo.py +264 -0
- media_archive_sync-0.1.0/tests/test_organizer.py +222 -0
- media_archive_sync-0.1.0/tests/test_strings.py +178 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# CodeRabbit configuration for media-archive-sync
|
|
2
|
+
# https://docs.coderabbit.ai/guides/configure-coderabbit
|
|
3
|
+
|
|
4
|
+
language: en-US
|
|
5
|
+
|
|
6
|
+
reviews:
|
|
7
|
+
# Review settings
|
|
8
|
+
profile: "chill" # Options: "chill", "balanced", "assertive"
|
|
9
|
+
|
|
10
|
+
# Auto-review settings
|
|
11
|
+
auto_review:
|
|
12
|
+
enabled: true
|
|
13
|
+
auto_incremental_reviews: true
|
|
14
|
+
drafts: false
|
|
15
|
+
|
|
16
|
+
# Base branches to review
|
|
17
|
+
base_branches:
|
|
18
|
+
- "main"
|
|
19
|
+
- "dev"
|
|
20
|
+
- "release/*"
|
|
21
|
+
|
|
22
|
+
# Tools configuration
|
|
23
|
+
tools:
|
|
24
|
+
# Static analysis
|
|
25
|
+
ruff:
|
|
26
|
+
enabled: true
|
|
27
|
+
|
|
28
|
+
# Type checking
|
|
29
|
+
mypy:
|
|
30
|
+
enabled: true
|
|
31
|
+
|
|
32
|
+
# Security scanning
|
|
33
|
+
bandit:
|
|
34
|
+
enabled: true
|
|
35
|
+
|
|
36
|
+
# Spell checking
|
|
37
|
+
languagetool:
|
|
38
|
+
enabled: true
|
|
39
|
+
level: "default"
|
|
40
|
+
|
|
41
|
+
# Path filters (what to review)
|
|
42
|
+
path_filters:
|
|
43
|
+
- "!**/*.md"
|
|
44
|
+
- "!**/tests/**"
|
|
45
|
+
- "!examples/**"
|
|
46
|
+
|
|
47
|
+
# Comment settings
|
|
48
|
+
review_comment:
|
|
49
|
+
enabled: true
|
|
50
|
+
collapse_walkthrough: true
|
|
51
|
+
|
|
52
|
+
# Chat settings
|
|
53
|
+
chat:
|
|
54
|
+
auto_reply: true
|
|
55
|
+
|
|
56
|
+
# Knowledge base (optional)
|
|
57
|
+
knowledge_base:
|
|
58
|
+
opt_out: true
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Native git pre-commit hook for media-archive-sync
|
|
3
|
+
# Runs linting and quick tests before allowing commits
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "Running pre-commit checks..."
|
|
8
|
+
|
|
9
|
+
# Colors for output
|
|
10
|
+
RED='\033[0;31m'
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
YELLOW='\033[1;33m'
|
|
13
|
+
NC='\033[0m' # No Color
|
|
14
|
+
|
|
15
|
+
# Check if we're in a virtual environment
|
|
16
|
+
if [ -z "$VIRTUAL_ENV" ] && [ -z "$CONDA_DEFAULT_ENV" ]; then
|
|
17
|
+
echo "${YELLOW}Warning: Not in a virtual environment${NC}"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Get list of staged Python files (null-terminated)
|
|
21
|
+
# Save to temp file to avoid shell variable issues with null bytes
|
|
22
|
+
STAGED_PY_FILE=$(mktemp)
|
|
23
|
+
git diff --cached --name-only -z --diff-filter=ACM | grep -z '\.py$' > "$STAGED_PY_FILE" || true
|
|
24
|
+
|
|
25
|
+
# Check if we have any Python files staged
|
|
26
|
+
if [ ! -s "$STAGED_PY_FILE" ]; then
|
|
27
|
+
rm -f "$STAGED_PY_FILE"
|
|
28
|
+
echo "${GREEN}No Python files staged for commit.${NC}"
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# Count files for display
|
|
33
|
+
echo "Staged Python files:"
|
|
34
|
+
cat "$STAGED_PY_FILE" | tr '\0' '\n'
|
|
35
|
+
echo ""
|
|
36
|
+
|
|
37
|
+
# Run Ruff linter
|
|
38
|
+
echo "Running Ruff linter..."
|
|
39
|
+
if command -v ruff >/dev/null 2>&1; then
|
|
40
|
+
cat "$STAGED_PY_FILE" | xargs -0 ruff check --fix
|
|
41
|
+
# Re-stage any files that were auto-fixed
|
|
42
|
+
cat "$STAGED_PY_FILE" | xargs -0 git add
|
|
43
|
+
echo "${GREEN}Ruff checks passed${NC}"
|
|
44
|
+
else
|
|
45
|
+
echo "${YELLOW}ruff not found, skipping...${NC}"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Run Black formatter check
|
|
49
|
+
echo "Running Black formatter..."
|
|
50
|
+
if command -v black >/dev/null 2>&1; then
|
|
51
|
+
cat "$STAGED_PY_FILE" | xargs -0 black --check --diff 2>/dev/null || {
|
|
52
|
+
echo "${YELLOW}Running black to fix formatting...${NC}"
|
|
53
|
+
cat "$STAGED_PY_FILE" | xargs -0 black
|
|
54
|
+
cat "$STAGED_PY_FILE" | xargs -0 git add
|
|
55
|
+
echo "${GREEN}Formatting fixed and staged${NC}"
|
|
56
|
+
}
|
|
57
|
+
echo "${GREEN}Black checks passed${NC}"
|
|
58
|
+
else
|
|
59
|
+
echo "${YELLOW}black not found, skipping...${NC}"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
# Cleanup temp file
|
|
63
|
+
rm -f "$STAGED_PY_FILE"
|
|
64
|
+
|
|
65
|
+
# Run quick tests
|
|
66
|
+
echo "Running quick tests..."
|
|
67
|
+
if command -v pytest >/dev/null 2>&1; then
|
|
68
|
+
pytest -x -q --tb=short --disable-warnings 2>/dev/null || {
|
|
69
|
+
echo "${RED}Tests failed!${NC}"
|
|
70
|
+
exit 1
|
|
71
|
+
}
|
|
72
|
+
echo "${GREEN}Tests passed${NC}"
|
|
73
|
+
else
|
|
74
|
+
echo "${YELLOW}pytest not found, skipping tests...${NC}"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
echo "${GREEN}All pre-commit checks passed!${NC}"
|
|
78
|
+
exit 0
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Native git pre-push hook for media-archive-sync
|
|
3
|
+
# Runs full test suite with coverage before allowing push
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
echo "Running pre-push checks..."
|
|
8
|
+
|
|
9
|
+
# Colors for output
|
|
10
|
+
RED='\033[0;31m'
|
|
11
|
+
GREEN='\033[0;32m'
|
|
12
|
+
YELLOW='\033[1;33m'
|
|
13
|
+
NC='\033[0m' # No Color
|
|
14
|
+
|
|
15
|
+
# Check if we're in a virtual environment
|
|
16
|
+
if [ -z "$VIRTUAL_ENV" ] && [ -z "$CONDA_DEFAULT_ENV" ]; then
|
|
17
|
+
echo "${YELLOW}Warning: Not in a virtual environment${NC}"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# Run full test suite with coverage
|
|
21
|
+
echo "Running full test suite with coverage..."
|
|
22
|
+
if command -v pytest >/dev/null 2>&1; then
|
|
23
|
+
pytest \
|
|
24
|
+
--cov=src/media_archive_sync \
|
|
25
|
+
--cov-report=term-missing \
|
|
26
|
+
--cov-fail-under=80 \
|
|
27
|
+
--tb=short \
|
|
28
|
+
-q \
|
|
29
|
+
--disable-warnings 2>/dev/null || {
|
|
30
|
+
echo "${RED}Tests or coverage check failed!${NC}"
|
|
31
|
+
echo "${YELLOW}Coverage must be >= 80%${NC}"
|
|
32
|
+
exit 1
|
|
33
|
+
}
|
|
34
|
+
echo "${GREEN}All tests passed with adequate coverage!${NC}"
|
|
35
|
+
else
|
|
36
|
+
echo "${YELLOW}pytest not found, skipping...${NC}"
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Run MyPy type checking
|
|
40
|
+
echo "Running MyPy type checking..."
|
|
41
|
+
if command -v mypy >/dev/null 2>&1; then
|
|
42
|
+
mypy src/media_archive_sync --ignore-missing-imports || {
|
|
43
|
+
echo "${YELLOW}MyPy found type issues (warnings only, not blocking)${NC}"
|
|
44
|
+
}
|
|
45
|
+
echo "${GREEN}MyPy checks completed${NC}"
|
|
46
|
+
else
|
|
47
|
+
echo "${YELLOW}mypy not found, skipping...${NC}"
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "${GREEN}All pre-push checks passed!${NC}"
|
|
51
|
+
exit 0
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout repository
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Setup Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Cache pip
|
|
25
|
+
uses: actions/cache@v4
|
|
26
|
+
with:
|
|
27
|
+
path: ~/.cache/pip
|
|
28
|
+
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
|
|
29
|
+
restore-keys: |
|
|
30
|
+
${{ runner.os }}-pip-
|
|
31
|
+
|
|
32
|
+
- name: Install dependencies
|
|
33
|
+
run: |
|
|
34
|
+
python -m pip install --upgrade pip
|
|
35
|
+
pip install -e ".[dev]"
|
|
36
|
+
|
|
37
|
+
- name: Run tests
|
|
38
|
+
run: |
|
|
39
|
+
pytest -v --tb=short
|
|
40
|
+
|
|
41
|
+
- name: Upload coverage
|
|
42
|
+
uses: codecov/codecov-action@v4
|
|
43
|
+
with:
|
|
44
|
+
files: ./coverage.xml
|
|
45
|
+
fail_ci_if_error: false
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Build and Push Docker Image
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
tags:
|
|
8
|
+
- 'v*'
|
|
9
|
+
pull_request:
|
|
10
|
+
branches:
|
|
11
|
+
- main
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
env:
|
|
15
|
+
REGISTRY: ghcr.io
|
|
16
|
+
IMAGE_NAME: ${{ github.repository }}
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build-and-push:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
packages: write
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout repository
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Set up QEMU
|
|
30
|
+
uses: docker/setup-qemu-action@v3
|
|
31
|
+
|
|
32
|
+
- name: Set up Docker Buildx
|
|
33
|
+
uses: docker/setup-buildx-action@v3
|
|
34
|
+
|
|
35
|
+
- name: Log in to Container Registry
|
|
36
|
+
if: github.event_name != 'pull_request'
|
|
37
|
+
uses: docker/login-action@v3
|
|
38
|
+
with:
|
|
39
|
+
registry: ${{ env.REGISTRY }}
|
|
40
|
+
username: ${{ github.actor }}
|
|
41
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
42
|
+
|
|
43
|
+
- name: Extract metadata (tags, labels) for Docker
|
|
44
|
+
id: meta
|
|
45
|
+
uses: docker/metadata-action@v5
|
|
46
|
+
with:
|
|
47
|
+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
48
|
+
tags: |
|
|
49
|
+
type=ref,event=branch
|
|
50
|
+
type=ref,event=pr
|
|
51
|
+
type=semver,pattern={{version}}
|
|
52
|
+
type=semver,pattern={{major}}.{{minor}}
|
|
53
|
+
type=semver,pattern={{major}}
|
|
54
|
+
type=sha
|
|
55
|
+
|
|
56
|
+
- name: Build and push Docker image
|
|
57
|
+
uses: docker/build-push-action@v5
|
|
58
|
+
with:
|
|
59
|
+
context: .
|
|
60
|
+
platforms: linux/amd64,linux/arm64
|
|
61
|
+
push: ${{ github.event_name != 'pull_request' }}
|
|
62
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
63
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
64
|
+
cache-from: type=gha
|
|
65
|
+
cache-to: type=gha,mode=max
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: Lint & Format
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches: [ main ]
|
|
6
|
+
push:
|
|
7
|
+
branches: [ main ]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
lint:
|
|
12
|
+
name: Ruff + Black
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: '3.11'
|
|
24
|
+
|
|
25
|
+
- name: Install tools
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install ruff black
|
|
29
|
+
|
|
30
|
+
- name: Run ruff
|
|
31
|
+
run: ruff check .
|
|
32
|
+
|
|
33
|
+
- name: Run black (check)
|
|
34
|
+
run: black --check .
|
|
35
|
+
|
|
36
|
+
autofix:
|
|
37
|
+
name: Autofix (manual)
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs: lint
|
|
40
|
+
permissions:
|
|
41
|
+
contents: write
|
|
42
|
+
pull-requests: write
|
|
43
|
+
if: github.event_name == 'workflow_dispatch' || contains(github.event.pull_request.labels.*.name, 'autofix')
|
|
44
|
+
steps:
|
|
45
|
+
- name: Checkout
|
|
46
|
+
uses: actions/checkout@v4
|
|
47
|
+
with:
|
|
48
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
49
|
+
ref: ${{ github.event.pull_request.head.ref || github.ref }}
|
|
50
|
+
|
|
51
|
+
- name: Set up Python
|
|
52
|
+
uses: actions/setup-python@v5
|
|
53
|
+
with:
|
|
54
|
+
python-version: '3.11'
|
|
55
|
+
|
|
56
|
+
- name: Install tools
|
|
57
|
+
run: |
|
|
58
|
+
python -m pip install --upgrade pip
|
|
59
|
+
pip install ruff black
|
|
60
|
+
|
|
61
|
+
- name: Run ruff --fix
|
|
62
|
+
run: ruff check --fix .
|
|
63
|
+
|
|
64
|
+
- name: Run black
|
|
65
|
+
run: black .
|
|
66
|
+
|
|
67
|
+
- name: Commit & push fixes
|
|
68
|
+
run: |
|
|
69
|
+
git config user.name "github-actions[bot]"
|
|
70
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
71
|
+
git add -A
|
|
72
|
+
git commit -m "chore: apply ruff/black fixes" || echo "no changes to commit"
|
|
73
|
+
git push
|
|
74
|
+
env:
|
|
75
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Build and Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- name: Checkout
|
|
14
|
+
uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: '3.11'
|
|
20
|
+
|
|
21
|
+
- name: Install build dependencies
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip
|
|
24
|
+
pip install build twine
|
|
25
|
+
|
|
26
|
+
- name: Build package
|
|
27
|
+
run: python -m build
|
|
28
|
+
|
|
29
|
+
- name: Check package
|
|
30
|
+
run: twine check dist/*
|
|
31
|
+
|
|
32
|
+
- name: Upload artifacts
|
|
33
|
+
uses: actions/upload-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
|
|
38
|
+
publish:
|
|
39
|
+
needs: build
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
42
|
+
environment: pypi
|
|
43
|
+
permissions:
|
|
44
|
+
id-token: write
|
|
45
|
+
steps:
|
|
46
|
+
- name: Download artifacts
|
|
47
|
+
uses: actions/download-artifact@v4
|
|
48
|
+
with:
|
|
49
|
+
name: dist
|
|
50
|
+
path: dist/
|
|
51
|
+
|
|
52
|
+
- name: Publish to PyPI
|
|
53
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
54
|
+
with:
|
|
55
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
.cache
|
|
3
|
+
*.pyc
|
|
4
|
+
__pycache__/
|
|
5
|
+
.venv/
|
|
6
|
+
venv/
|
|
7
|
+
env/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
dist/
|
|
10
|
+
build/
|
|
11
|
+
*.egg
|
|
12
|
+
|
|
13
|
+
# Testing
|
|
14
|
+
htmlcov/
|
|
15
|
+
.coverage
|
|
16
|
+
coverage.xml
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.mypy_cache/
|
|
19
|
+
|
|
20
|
+
# IDE
|
|
21
|
+
.vscode/
|
|
22
|
+
.idea/
|
|
23
|
+
*.swp
|
|
24
|
+
*.swo
|
|
25
|
+
*~
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
30
|
+
|
|
31
|
+
# Project specific
|
|
32
|
+
media/
|
|
33
|
+
*.partial
|
|
34
|
+
*.partial.*
|
|
35
|
+
downloads/
|
|
36
|
+
temp/
|
|
37
|
+
|
|
38
|
+
# Logs
|
|
39
|
+
*.log
|
|
40
|
+
log.txt
|
|
41
|
+
|
|
42
|
+
# Oh-My-OpenCode
|
|
43
|
+
oh-my-opencode.json
|
|
44
|
+
.sisyphus/coverage.xml
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Contributing to Media Archive Sync
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing! This document outlines the development workflow.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
### 1. Clone the repository
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/djdembeck/media-archive-sync.git
|
|
11
|
+
cd media-archive-sync
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### 2. Enable Git Hooks (Required)
|
|
15
|
+
|
|
16
|
+
This repository uses git hooks for code quality. Enable them with:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Option 1: Use make
|
|
20
|
+
make install-hooks
|
|
21
|
+
|
|
22
|
+
# Option 2: Manual git config
|
|
23
|
+
git config --local core.hooksPath .githooks
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Note:** The hooks will now run automatically on every commit and push.
|
|
27
|
+
|
|
28
|
+
### 3. Install Development Dependencies
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install -e ".[dev]"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or use the Makefile:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
make dev-install # Installs deps + enables hooks
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Git Hooks
|
|
41
|
+
|
|
42
|
+
The following hooks run automatically:
|
|
43
|
+
|
|
44
|
+
### pre-commit
|
|
45
|
+
- Runs `ruff` linter with auto-fix
|
|
46
|
+
- Runs `black` formatter
|
|
47
|
+
- Runs quick tests with pytest
|
|
48
|
+
|
|
49
|
+
### pre-push
|
|
50
|
+
- Runs full test suite with coverage (requires 80%)
|
|
51
|
+
- Runs `mypy` type checking
|
|
52
|
+
|
|
53
|
+
### Bypassing Hooks
|
|
54
|
+
|
|
55
|
+
If you need to bypass hooks temporarily:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git commit --no-verify # or -n
|
|
59
|
+
git push --no-verify
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Development Commands
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Run tests
|
|
66
|
+
make test
|
|
67
|
+
|
|
68
|
+
# Run tests with coverage
|
|
69
|
+
make test-cov
|
|
70
|
+
|
|
71
|
+
# Run linter
|
|
72
|
+
make lint
|
|
73
|
+
|
|
74
|
+
# Run formatter
|
|
75
|
+
make format
|
|
76
|
+
|
|
77
|
+
# Clean build artifacts
|
|
78
|
+
make clean
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Code Quality Standards
|
|
82
|
+
|
|
83
|
+
- **Linting:** Ruff (configured in `pyproject.toml`)
|
|
84
|
+
- **Formatting:** Black (88 char line length)
|
|
85
|
+
- **Type Checking:** MyPy
|
|
86
|
+
- **Testing:** pytest with coverage (80% minimum)
|
|
87
|
+
|
|
88
|
+
## Submitting Changes
|
|
89
|
+
|
|
90
|
+
1. Create a feature branch
|
|
91
|
+
2. Make your changes
|
|
92
|
+
3. Ensure hooks pass (they run automatically)
|
|
93
|
+
4. Push and create a Pull Request
|
|
94
|
+
|
|
95
|
+
## Questions?
|
|
96
|
+
|
|
97
|
+
Open an issue or discussion on GitHub.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Build stage
|
|
2
|
+
FROM python:3.13-slim AS builder
|
|
3
|
+
|
|
4
|
+
# Install build dependencies
|
|
5
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
6
|
+
ca-certificates \
|
|
7
|
+
curl \
|
|
8
|
+
gcc \
|
|
9
|
+
libxml2-dev \
|
|
10
|
+
libxslt-dev \
|
|
11
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
12
|
+
|
|
13
|
+
# Create non-root user
|
|
14
|
+
ARG UID=1000
|
|
15
|
+
ARG GID=1000
|
|
16
|
+
RUN groupadd -g ${GID} appgroup && \
|
|
17
|
+
useradd -m -u ${UID} -g ${GID} appuser
|
|
18
|
+
|
|
19
|
+
# Install Python dependencies
|
|
20
|
+
WORKDIR /app
|
|
21
|
+
COPY pyproject.toml README.md ./
|
|
22
|
+
COPY src/ ./src/
|
|
23
|
+
|
|
24
|
+
RUN pip install --upgrade pip && \
|
|
25
|
+
pip install build && \
|
|
26
|
+
python -m build
|
|
27
|
+
|
|
28
|
+
# Runtime stage
|
|
29
|
+
FROM python:3.13-slim
|
|
30
|
+
|
|
31
|
+
# Install runtime dependencies
|
|
32
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
33
|
+
ffmpeg \
|
|
34
|
+
mkvtoolnix \
|
|
35
|
+
mediainfo \
|
|
36
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
37
|
+
|
|
38
|
+
# Create non-root user
|
|
39
|
+
ARG UID=1000
|
|
40
|
+
ARG GID=1000
|
|
41
|
+
RUN groupadd -g ${GID} appgroup && \
|
|
42
|
+
useradd -m -u ${UID} -g ${GID} appuser
|
|
43
|
+
|
|
44
|
+
# Install the built package
|
|
45
|
+
COPY --from=builder /app/dist/*.whl /tmp/
|
|
46
|
+
RUN pip install /tmp/*.whl && rm /tmp/*.whl
|
|
47
|
+
|
|
48
|
+
# Set up directories
|
|
49
|
+
ARG MEDIA_ROOT=/media
|
|
50
|
+
ARG CACHE_DIR=/app/.cache
|
|
51
|
+
ENV MEDIA_ROOT=${MEDIA_ROOT}
|
|
52
|
+
ENV CACHE_DIR=${CACHE_DIR}
|
|
53
|
+
|
|
54
|
+
RUN mkdir -p ${MEDIA_ROOT} ${CACHE_DIR} && \
|
|
55
|
+
chown -R ${UID}:${GID} ${MEDIA_ROOT} ${CACHE_DIR}
|
|
56
|
+
|
|
57
|
+
USER appuser
|
|
58
|
+
|
|
59
|
+
# Expose volumes
|
|
60
|
+
VOLUME ["/media", "/app/.cache"]
|
|
61
|
+
|
|
62
|
+
# Default command
|
|
63
|
+
ENTRYPOINT ["media-archive-sync"]
|
|
64
|
+
CMD ["--help"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 djdembeck
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.PHONY: help install-hooks dev-install test test-cov lint format clean
|
|
2
|
+
|
|
3
|
+
help:
|
|
4
|
+
@echo "Available targets:"
|
|
5
|
+
@echo " install-hooks - Configure git to use hooks from .githooks/"
|
|
6
|
+
@echo " dev-install - Install package with dev dependencies"
|
|
7
|
+
@echo " test - Run tests"
|
|
8
|
+
@echo " test-cov - Run tests with coverage"
|
|
9
|
+
@echo " lint - Run ruff linter"
|
|
10
|
+
@echo " format - Run black formatter"
|
|
11
|
+
@echo " clean - Clean build artifacts"
|
|
12
|
+
|
|
13
|
+
install-hooks:
|
|
14
|
+
git config --local include.path ../.gitconfig
|
|
15
|
+
@echo "Git hooks configured! They will run on commit/push."
|
|
16
|
+
|
|
17
|
+
dev-install:
|
|
18
|
+
pip install -e ".[dev]"
|
|
19
|
+
$(MAKE) install-hooks
|
|
20
|
+
|
|
21
|
+
test:
|
|
22
|
+
pytest -v --tb=short
|
|
23
|
+
|
|
24
|
+
test-cov:
|
|
25
|
+
pytest --cov=src/media_archive_sync --cov-report=term-missing --cov-fail-under=80
|
|
26
|
+
|
|
27
|
+
lint:
|
|
28
|
+
ruff check --fix src/ tests/
|
|
29
|
+
|
|
30
|
+
format:
|
|
31
|
+
black src/ tests/
|
|
32
|
+
|
|
33
|
+
clean:
|
|
34
|
+
rm -rf build/ dist/ *.egg-info .pytest_cache .coverage htmlcov
|
|
35
|
+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
36
|
+
find . -type f -name "*.pyc" -delete
|