Compare commits
47 Commits
b1484641d9
...
2edb00b047
| Author | SHA1 | Date | |
|---|---|---|---|
| 2edb00b047 | |||
| 3a31ba8866 | |||
| 814156035e | |||
| c24625274e | |||
| c2dc0b2beb | |||
| 3e017a3d17 | |||
| 91e749ccdc | |||
| 4d1dc3b06f | |||
| 41ece0af86 | |||
| 1848ed61bf | |||
| c04fe8d083 | |||
| 3e5c80279f | |||
| de3896b8c3 | |||
| 07b3110c72 | |||
| 96de17e0c5 | |||
| 7de99ef945 | |||
| 95273be0b0 | |||
| a74feeb67e | |||
| e7749620f6 | |||
| f563c67405 | |||
| 93cee77ce0 | |||
| 927d7cdeff | |||
| a4b1042b65 | |||
| 09b28abcdc | |||
| fa3f41e6fd | |||
| 49d63a9136 | |||
| fcc21d8eb7 | |||
| cd22cd3340 | |||
| d5937b13be | |||
| 3abef7057c | |||
| 31d2c6404a | |||
| 5dce72841b | |||
| 605e78c093 | |||
| 32d614f2f8 | |||
| 82310b5f43 | |||
| b1c5c825f8 | |||
| cbfd21c4ee | |||
| 86235142a0 | |||
| 44fdc1cdf0 | |||
| f272baf2a4 | |||
| aae36ac145 | |||
| faa320d299 | |||
| fab3da938f | |||
| 0e9b117ff4 | |||
| cd31caf313 | |||
| b7d695ab62 | |||
| 2c13fd778a |
@@ -0,0 +1,28 @@
|
||||
# NFOGuard Environment Variables
|
||||
|
||||
# User and Group IDs
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
|
||||
# Timezone
|
||||
TZ=UTC
|
||||
|
||||
# Media path (for read-only access to scan NFO files)
|
||||
MEDIA_PATH=/path/to/your/media
|
||||
|
||||
# Database settings (if using PostgreSQL)
|
||||
# DB_USER=nfoguard
|
||||
# DB_PASSWORD=your_secure_password
|
||||
|
||||
# Emby Plugin Deployment - Bind Mount Method (Recommended)
|
||||
# Set this to the path where Emby plugins are installed on your host
|
||||
# Common paths:
|
||||
# - /var/lib/emby/plugins (native Emby install)
|
||||
# - /path/to/emby/config/plugins (Docker Emby)
|
||||
# - /config/plugins (linuxserver.io Emby)
|
||||
EMBY_PLUGINS_PATH=/path/to/emby/plugins
|
||||
|
||||
# NFOGuard specific settings
|
||||
DEBUG=false
|
||||
PATH_DEBUG=false
|
||||
SUPPRESS_TVDB_WARNINGS=true
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help fixing issues
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots & Logs**
|
||||
If applicable, add screenshots/logs to help explain your problem.
|
||||
|
||||
**Please complete the following information:**
|
||||
- OS: [e.g. Fedora Linux 42 x86_64]
|
||||
- Architecture [e.g. amd64, arm64]
|
||||
- Docker Version
|
||||
- Remediarr Version [e.g. 0.1.9]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here. Such as logs from Remediarr , Sonarr, Radarr. .env file(with API removed) docker compose file as well.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"template": "# Changelog for {{currentTag}}\n\n{{#conventionalCommits}}\n- {{#scope}}**{{scope}}:** {{/scope}}{{subject}}\n{{/conventionalCommits}}\n",
|
||||
"categories": [
|
||||
{ "title": "### 🚀 Features", "labels": ["feat", "feature"], "collapseAfter": 0 },
|
||||
{ "title": "### 🐛 Fixes", "labels": ["fix", "bug"], "collapseAfter": 0 },
|
||||
{ "title": "### 🧹 Chore", "labels": ["chore"], "collapseAfter": 0 },
|
||||
{ "title": "### 📝 Docs", "labels": ["docs"], "collapseAfter": 0 },
|
||||
{ "title": "### 🔧 Refactor", "labels": ["refactor"], "collapseAfter": 0 }
|
||||
],
|
||||
"replacers": [],
|
||||
"sort": {
|
||||
"order": "ASC",
|
||||
"onProperty": "scope"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
name-template: 'v$NEXT_PATCH_VERSION'
|
||||
tag-template: 'v$NEXT_PATCH_VERSION'
|
||||
categories:
|
||||
- title: '🚀 Features'
|
||||
labels: ['feature', 'enhancement']
|
||||
- title: '🐛 Fixes'
|
||||
labels: ['fix', 'bug']
|
||||
- title: '🧰 Maintenance'
|
||||
labels: ['chore', 'maintenance', 'deps']
|
||||
change-template: '- $TITLE (#$NUMBER) by @$AUTHOR'
|
||||
no-changes-template: 'Minor internal improvements.'
|
||||
template: |
|
||||
|
||||
## Container Images
|
||||
- `sbcrumb/nfoguard:latest`
|
||||
- `sbcrumb/nfoguard:$NEXT_PATCH_VERSION`
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Generate Changelog on Tag
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout (full history)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build changelog from commits
|
||||
id: build
|
||||
uses: mikepenz/release-changelog-builder-action@v4
|
||||
with:
|
||||
configuration: .github/changelog-config.json
|
||||
ignorePreReleases: false
|
||||
toTag: ${{ github.ref_name }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create / Update GitHub Release notes
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
body: ${{ steps.build.outputs.changelog }}
|
||||
@@ -0,0 +1,67 @@
|
||||
name: Build & Push DEV to DockerHub
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ dev ]
|
||||
push:
|
||||
branches: [ dev ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
# PRs: single-arch build (faster). Push to dev: multi-arch.
|
||||
PLATFORMS: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Read VERSION and compute DEV tags
|
||||
run: |
|
||||
if [[ ! -f VERSION ]]; then echo "VERSION file missing"; exit 1; fi
|
||||
RAW=$(tr -d ' \n' < VERSION)
|
||||
if [[ -z "$RAW" ]]; then echo "VERSION empty"; exit 1; fi
|
||||
# Remove 'v' prefix if present for version number
|
||||
if [[ "$RAW" =~ ^v ]]; then NUM="${RAW#v}"; else NUM="$RAW"; fi
|
||||
|
||||
# Get repository name (assumes format: owner/repo)
|
||||
REPO_NAME=$(echo "${GITHUB_REPOSITORY}" | cut -d'/' -f2)
|
||||
|
||||
echo "VERSION_NUM=$NUM" >> $GITHUB_ENV
|
||||
echo "DEV_VERSION=${NUM}-dev" >> $GITHUB_ENV
|
||||
echo "DOCKER_REPO=${{ secrets.DOCKER_HUB_USERNAME }}/${REPO_NAME}" >> $GITHUB_ENV
|
||||
echo "DEV_TAGS=${{ secrets.DOCKER_HUB_USERNAME }}/${REPO_NAME}:${NUM}-dev,${{ secrets.DOCKER_HUB_USERNAME }}/${REPO_NAME}:dev" >> $GITHUB_ENV
|
||||
echo "Computed DEV_VERSION=${NUM}-dev"
|
||||
|
||||
- name: Set up QEMU
|
||||
if: ${{ env.PLATFORMS == 'linux/amd64,linux/arm64' }}
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to DockerHub
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Build & (maybe) push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ env.DEV_TAGS }}
|
||||
build-args: |
|
||||
APP_VERSION=${{ env.DEV_VERSION }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
provenance: false
|
||||
@@ -0,0 +1,107 @@
|
||||
name: Build & Publish to DockerHub (from VERSION + Release)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
permissions:
|
||||
contents: write # create tag + release
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
PLATFORMS: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Read VERSION
|
||||
id: ver
|
||||
run: |
|
||||
if [[ ! -f VERSION ]]; then echo "VERSION missing"; exit 1; fi
|
||||
RAW=$(tr -d ' \n' < VERSION)
|
||||
if [[ -z "$RAW" ]]; then echo "VERSION empty"; exit 1; fi
|
||||
if [[ "$RAW" =~ ^v ]]; then TAG="$RAW"; NUM="${RAW#v}"; else TAG="v${RAW}"; NUM="$RAW"; fi
|
||||
|
||||
# Get repository name for DockerHub
|
||||
REPO_NAME=$(echo "${GITHUB_REPOSITORY}" | cut -d'/' -f2)
|
||||
|
||||
echo "TAG=$TAG" >> $GITHUB_ENV
|
||||
echo "NUM=$NUM" >> $GITHUB_ENV
|
||||
echo "DOCKER_REPO=${{ secrets.DOCKER_HUB_USERNAME }}/${REPO_NAME}" >> $GITHUB_ENV
|
||||
echo "DOCKER_TAGS=${{ secrets.DOCKER_HUB_USERNAME }}/${REPO_NAME}:${NUM},${{ secrets.DOCKER_HUB_USERNAME }}/${REPO_NAME}:latest" >> $GITHUB_ENV
|
||||
echo "Resolved TAG=$TAG NUM=$NUM"
|
||||
|
||||
- name: Create tag (if missing)
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const tag = process.env.TAG;
|
||||
const sha = context.sha;
|
||||
const { owner, repo } = context.repo;
|
||||
try {
|
||||
await github.rest.git.getRef({ owner, repo, ref: `tags/${tag}` });
|
||||
core.info(`Tag ${tag} exists`);
|
||||
} catch (e) {
|
||||
if (e.status === 404) {
|
||||
core.info(`Creating tag ${tag} -> ${sha}`);
|
||||
await github.rest.git.createRef({ owner, repo, ref: `refs/tags/${tag}`, sha });
|
||||
} else { throw e; }
|
||||
}
|
||||
|
||||
- name: Update draft release notes
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
id: drafter
|
||||
uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
config-name: release-drafter.yml
|
||||
publish: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Publish GitHub Release
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ env.TAG }}
|
||||
name: NFOGuard ${{ env.TAG }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
body: ${{ steps.drafter.outputs.body }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set up QEMU
|
||||
if: ${{ env.PLATFORMS == 'linux/amd64,linux/arm64' }}
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Set up Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to DockerHub
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Build & Push (main)
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
platforms: ${{ env.PLATFORMS }}
|
||||
tags: ${{ env.DOCKER_TAGS }}
|
||||
build-args: |
|
||||
APP_VERSION=${{ env.NUM }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
provenance: false
|
||||
@@ -0,0 +1,66 @@
|
||||
name: Notify on new issues
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
workflow_dispatch: {}
|
||||
|
||||
jobs:
|
||||
notify:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Validate required secrets
|
||||
run: |
|
||||
if [[ -z "${{ secrets.GOTIFY_URL }}" ]]; then
|
||||
echo "Error: GOTIFY_URL secret is not set"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "${{ secrets.GOTIFY_TOKEN }}" ]]; then
|
||||
echo "Error: GOTIFY_TOKEN secret is not set"
|
||||
exit 1
|
||||
fi
|
||||
echo "Secrets validation passed"
|
||||
|
||||
- name: Build and send Gotify notification
|
||||
env:
|
||||
GOTIFY_URL: ${{ secrets.GOTIFY_URL }}
|
||||
GOTIFY_TOKEN: ${{ secrets.GOTIFY_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Remove trailing slash from URL if present
|
||||
GOTIFY_URL="${GOTIFY_URL%/}"
|
||||
|
||||
# Validate URL format
|
||||
if [[ ! "$GOTIFY_URL" =~ ^https?:// ]]; then
|
||||
echo "Error: GOTIFY_URL must start with http:// or https://"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Build the notification payload
|
||||
TITLE="New issue in ${{ github.repository }}"
|
||||
MESSAGE="Issue #${{ github.event.issue.number }}: ${{ github.event.issue.title }}
|
||||
By: ${{ github.actor }}
|
||||
${{ github.event.issue.html_url }}"
|
||||
|
||||
# Create JSON payload
|
||||
PAYLOAD=$(jq -n \
|
||||
--arg title "$TITLE" \
|
||||
--arg message "$MESSAGE" \
|
||||
--argjson priority 5 \
|
||||
'{title: $title, message: $message, priority: $priority}')
|
||||
|
||||
echo "Sending notification to Gotify..."
|
||||
echo "URL: ${GOTIFY_URL}/message"
|
||||
echo "Payload: $PAYLOAD"
|
||||
|
||||
# Send the notification using header authentication
|
||||
curl -X POST "${GOTIFY_URL}/message" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Gotify-Key: ${GOTIFY_TOKEN}" \
|
||||
-d "$PAYLOAD" \
|
||||
--fail \
|
||||
--show-error \
|
||||
--silent
|
||||
|
||||
echo "Notification sent successfully!"
|
||||
@@ -0,0 +1,21 @@
|
||||
name: Release Drafter
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, closed]
|
||||
branches: [ main ]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
update_release_draft:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@v6
|
||||
with:
|
||||
config-name: release-drafter.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -70,6 +70,9 @@ sync-to-github.sh
|
||||
# Ignore Gitea workflows when pushing to GitHub
|
||||
.gitea/
|
||||
|
||||
# Local development documentation (Gitea only, not for GitHub)
|
||||
.local/
|
||||
|
||||
# Temporary troubleshooting files - to be removed
|
||||
Dockerfile.optimized
|
||||
fix-gitea-packages.md
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# NFOGuard Environment Variables
|
||||
|
||||
# User and Group IDs
|
||||
PUID=1000
|
||||
PGID=1000
|
||||
|
||||
# Timezone
|
||||
TZ=UTC
|
||||
|
||||
# Media path (for read-only access to scan NFO files)
|
||||
MEDIA_PATH=/path/to/your/media
|
||||
|
||||
# Database settings (if using PostgreSQL)
|
||||
# DB_USER=nfoguard
|
||||
# DB_PASSWORD=your_secure_password
|
||||
|
||||
# Emby Plugin Deployment - Bind Mount Method (Recommended)
|
||||
# Set this to the path where Emby plugins are installed on your host
|
||||
# Common paths:
|
||||
# - /var/lib/emby/plugins (native Emby install)
|
||||
# - /path/to/emby/config/plugins (Docker Emby)
|
||||
# - /config/plugins (linuxserver.io Emby)
|
||||
EMBY_PLUGINS_PATH=/path/to/emby/plugins
|
||||
|
||||
# NFOGuard specific settings
|
||||
DEBUG=false
|
||||
PATH_DEBUG=false
|
||||
SUPPRESS_TVDB_WARNINGS=true
|
||||
@@ -0,0 +1,141 @@
|
||||
# NFOGuard Environment Configuration Template
|
||||
# Copy this to .env and customize for your setup
|
||||
|
||||
# ===========================================
|
||||
# MEDIA PATHS (REQUIRED)
|
||||
# ===========================================
|
||||
# Paths where your movies and TV shows are stored inside the container
|
||||
# Adjust these to match YOUR directory structure
|
||||
TV_PATHS=/media/TV/tv,/media/TV/tv6
|
||||
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
|
||||
|
||||
# ===========================================
|
||||
# DATABASE CONFIGURATION
|
||||
# ===========================================
|
||||
# NFOGuard SQLite database location
|
||||
DB_PATH=/app/data/media_dates.db
|
||||
|
||||
# ===========================================
|
||||
# RADARR DATABASE CONNECTION (REQUIRED)
|
||||
# ===========================================
|
||||
# Connection to Radarr's PostgreSQL database
|
||||
# NOTE: Database password should be set in .env.secrets file
|
||||
RADARR_DB_HOST=radarr-postgres
|
||||
RADARR_DB_PORT=5432
|
||||
RADARR_DB_NAME=radarr
|
||||
RADARR_DB_USER=radarr
|
||||
|
||||
# ===========================================
|
||||
# RADARR API (OPTIONAL - for fallback)
|
||||
# ===========================================
|
||||
# Only needed if you want API fallback (not recommended for performance)
|
||||
# NOTE: API key should be set in .env.secrets file
|
||||
RADARR_URL=http://radarr:7878
|
||||
|
||||
# ===========================================
|
||||
# SONARR API (REQUIRED for Enhanced TV NFOs - v0.6.0+)
|
||||
# ===========================================
|
||||
# Required for TV processing and enhanced NFO generation with metadata
|
||||
# NOTE: API key should be set in .env.secrets file
|
||||
SONARR_URL=http://sonarr:8989
|
||||
|
||||
# ===========================================
|
||||
# EXTERNAL APIs FOR DIGITAL RELEASE DATES
|
||||
# ===========================================
|
||||
# NOTE: All API keys should be set in .env.secrets file
|
||||
# See .env.secrets.template for required keys:
|
||||
# - TMDB_API_KEY (recommended for digital release dates)
|
||||
# - OMDB_API_KEY (optional for DVD/digital release dates)
|
||||
# - JELLYSEERR_API_KEY (optional for additional digital release data)
|
||||
|
||||
# Jellyseerr URL (optional)
|
||||
JELLYSEERR_URL=http://jellyseerr:5055
|
||||
|
||||
# ===========================================
|
||||
# NFO MANAGEMENT
|
||||
# ===========================================
|
||||
# Whether to create/update .nfo files
|
||||
MANAGE_NFO=true
|
||||
|
||||
# Whether to fix file modification times to match import dates
|
||||
FIX_DIR_MTIMES=true
|
||||
|
||||
# Whether to add <lockdata> tags to prevent metadata drift
|
||||
LOCK_METADATA=true
|
||||
|
||||
# Brand name to add to NFO files
|
||||
MANAGER_BRAND=NFOGuard
|
||||
|
||||
# ===========================================
|
||||
# PROCESSING SETTINGS
|
||||
# ===========================================
|
||||
# Delay before processing batched webhook events (seconds)
|
||||
BATCH_DELAY=5.0
|
||||
|
||||
# Maximum concurrent series processing
|
||||
MAX_CONCURRENT_SERIES=3
|
||||
|
||||
# Movie date strategy: import_then_digital or digital_then_import
|
||||
MOVIE_PRIORITY=import_then_digital
|
||||
|
||||
# Smart fallback: prefer release dates over file dates for manual imports (true/false)
|
||||
PREFER_RELEASE_DATES_OVER_FILE_DATES=true
|
||||
|
||||
# Allow file dates as absolute last resort (true/false)
|
||||
# If false, movies with no valid import AND no release dates will be skipped entirely
|
||||
ALLOW_FILE_DATE_FALLBACK=false
|
||||
|
||||
# Fallback priority order when no valid Radarr import exists (comma-separated)
|
||||
# Options: digital, physical, theatrical
|
||||
# digital = VOD/streaming release, physical = DVD/Blu-ray, theatrical = cinema release
|
||||
RELEASE_DATE_PRIORITY=digital,physical,theatrical
|
||||
|
||||
# Smart date validation: automatically prefer theatrical over unreasonably late digital/physical dates
|
||||
# Example: "The Craft (1996)" theatrical vs "The Craft (2022)" physical → chooses 1996 theatrical
|
||||
ENABLE_SMART_DATE_VALIDATION=true
|
||||
|
||||
# Maximum reasonable gap between theatrical and digital/physical release (in years)
|
||||
# If digital/physical is more than this many years after theatrical, prefer theatrical instead
|
||||
MAX_RELEASE_DATE_GAP_YEARS=10
|
||||
|
||||
# TMDB country for regional release date preferences
|
||||
TMDB_COUNTRY=US
|
||||
|
||||
# TMDB release type priority (comma-separated numbers)
|
||||
# 1=Premiere, 2=Limited Theatrical, 3=Theatrical, 4=Digital, 5=Physical, 6=TV Premiere
|
||||
# Default: 4,5,3,2,6,1 (Digital → Physical → Theatrical → Limited → TV → Premiere)
|
||||
TMDB_TYPE_PRIORITY=4,5,3,2,6,1
|
||||
|
||||
# When to query APIs: always, if_missing, never
|
||||
MOVIE_POLL_MODE=always
|
||||
|
||||
# Update mode: backfill_only or overwrite
|
||||
MOVIE_DATE_UPDATE_MODE=backfill_only
|
||||
|
||||
# ===========================================
|
||||
# TV SERIES PROCESSING
|
||||
# ===========================================
|
||||
# Season directory naming format (supports {season} placeholder)
|
||||
# Examples: "Season {season:02d}" -> "Season 01", "S{season:02d}" -> "S01"
|
||||
TV_SEASON_DIR_FORMAT=Season {season:02d}
|
||||
|
||||
# Season directory detection pattern (lowercase, what to look for at start of dir name)
|
||||
# Examples: "season " -> matches "Season 01", "s" -> matches "S01", "season" -> matches "Season01"
|
||||
TV_SEASON_DIR_PATTERN=season
|
||||
|
||||
# TV webhook processing mode (v0.6.0+)
|
||||
# targeted = Only process episodes mentioned in webhook (efficient, recommended)
|
||||
# series = Process entire series directory (comprehensive, current default)
|
||||
TV_WEBHOOK_PROCESSING_MODE=targeted
|
||||
|
||||
# ===========================================
|
||||
# LOGGING
|
||||
# ===========================================
|
||||
# Enable debug logging
|
||||
DEBUG=false
|
||||
|
||||
# ===========================================
|
||||
# SERVER
|
||||
# ===========================================
|
||||
# Port to run the webhook server on
|
||||
PORT=8080
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
# NFOGuard Setup Guide
|
||||
|
||||
## 🔐 Secure Configuration Setup
|
||||
|
||||
NFOGuard now uses a **two-file configuration system** for better security and easier troubleshooting:
|
||||
|
||||
- **`.env`** - Main configuration (safe to share for debugging)
|
||||
- **`.env.secrets`** - Sensitive API keys and passwords (never commit to git)
|
||||
|
||||
### Step 1: Copy Configuration Templates
|
||||
|
||||
```bash
|
||||
# Copy main configuration
|
||||
cp .env.template .env
|
||||
|
||||
# Copy secrets configuration
|
||||
cp .env.secrets.template .env.secrets
|
||||
```
|
||||
|
||||
### Step 2: Configure Main Settings
|
||||
|
||||
Edit your `.env` file with your specific paths and preferences:
|
||||
|
||||
```bash
|
||||
# Media paths (adjust to your directory structure)
|
||||
TV_PATHS=/media/TV/tv,/media/TV/tv6
|
||||
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
|
||||
|
||||
# Database connection details
|
||||
RADARR_DB_HOST=radarr-postgres
|
||||
RADARR_DB_PORT=5432
|
||||
RADARR_DB_NAME=radarr
|
||||
RADARR_DB_USER=radarr
|
||||
|
||||
# Processing preferences
|
||||
PREFER_RELEASE_DATES_OVER_FILE_DATES=true
|
||||
ALLOW_FILE_DATE_FALLBACK=false
|
||||
RELEASE_DATE_PRIORITY=digital,physical,theatrical
|
||||
|
||||
# TV webhook processing mode (v0.6.0+)
|
||||
TV_WEBHOOK_PROCESSING_MODE=targeted
|
||||
```
|
||||
|
||||
### Step 3: Configure Secrets
|
||||
|
||||
Edit your `.env.secrets` file with your actual API keys and passwords:
|
||||
|
||||
```bash
|
||||
# Database password
|
||||
RADARR_DB_PASSWORD=your_actual_radarr_password
|
||||
|
||||
# TMDB API key (required for release date detection)
|
||||
TMDB_API_KEY=your_actual_tmdb_api_key
|
||||
|
||||
# Sonarr API key (REQUIRED for v0.6.0+ Enhanced TV NFO Generation)
|
||||
SONARR_API_KEY=your_actual_sonarr_api_key
|
||||
|
||||
# Optional API keys
|
||||
RADARR_API_KEY=your_radarr_api_key
|
||||
OMDB_API_KEY=your_omdb_api_key
|
||||
```
|
||||
|
||||
### Step 4: Verify Configuration
|
||||
|
||||
Test your setup:
|
||||
|
||||
```bash
|
||||
# Test database connections
|
||||
curl -X POST "http://localhost:8080/test/bulk-update"
|
||||
|
||||
# Test movie scanning
|
||||
curl -X POST "http://localhost:8080/test/movie-scan"
|
||||
|
||||
# Check system health
|
||||
curl "http://localhost:8080/health"
|
||||
```
|
||||
|
||||
## 🔒 Security Features
|
||||
|
||||
### API Key Masking
|
||||
All API keys and passwords are automatically masked in logs:
|
||||
```
|
||||
[2025-09-09T12:34:56] INFO: TMDB API call with key=***masked***
|
||||
[2025-09-09T12:34:56] INFO: Database connection password=***masked***
|
||||
```
|
||||
|
||||
### Sensitive Data Separation
|
||||
- **Main `.env`**: Paths, preferences, URLs (safe to share)
|
||||
- **`.env.secrets`**: API keys, passwords (never commit to version control)
|
||||
- **Automatic loading**: Both files loaded automatically at startup
|
||||
|
||||
### Git Protection
|
||||
The `.gitignore` file prevents accidental commits:
|
||||
```
|
||||
.env
|
||||
.env.secrets
|
||||
.env.local
|
||||
```
|
||||
|
||||
## 🛠 Troubleshooting
|
||||
|
||||
### "Environment files not loaded" Warning
|
||||
Install python-dotenv:
|
||||
```bash
|
||||
pip install python-dotenv==1.0.0
|
||||
# or
|
||||
docker-compose build # rebuilds with updated requirements.txt
|
||||
```
|
||||
|
||||
### Sharing Configuration for Help
|
||||
You can safely share your `.env` file for debugging since it contains no sensitive data. The `.env.secrets` file should never be shared.
|
||||
|
||||
### Migration from Old Setup
|
||||
If you have an existing `.env` with API keys:
|
||||
1. Move all `*_API_KEY` and `*_PASSWORD` variables to `.env.secrets`
|
||||
2. Remove sensitive data from `.env`
|
||||
3. Restart NFOGuard
|
||||
|
||||
## 🎯 Docker Compose Example
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
nfoguard:
|
||||
image: sbcrumb/nfoguard:latest
|
||||
container_name: nfoguard
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /path/to/your/media:/media:rw
|
||||
- ./data:/app/data
|
||||
- ./.env:/app/.env:ro # Main configuration
|
||||
- ./.env.secrets:/app/.env.secrets:ro # Secrets
|
||||
environment:
|
||||
- PORT=8080
|
||||
depends_on:
|
||||
- radarr-postgres
|
||||
```
|
||||
|
||||
## 📋 Configuration Reference
|
||||
|
||||
### Main Configuration (.env)
|
||||
- **Paths**: `TV_PATHS`, `MOVIE_PATHS`, `DB_PATH`
|
||||
- **Processing**: `MOVIE_PRIORITY`, `RELEASE_DATE_PRIORITY`
|
||||
- **Features**: `MANAGE_NFO`, `FIX_DIR_MTIMES`, `LOCK_METADATA`
|
||||
- **URLs**: `RADARR_URL`, `SONARR_URL`, `JELLYSEERR_URL`
|
||||
|
||||
### Secrets Configuration (.env.secrets)
|
||||
- **Database**: `RADARR_DB_PASSWORD`
|
||||
- **APIs**: `TMDB_API_KEY`, `OMDB_API_KEY`, `RADARR_API_KEY`, `SONARR_API_KEY`
|
||||
- **Optional**: `JELLYSEERR_API_KEY`
|
||||
|
||||
This setup makes NFOGuard more secure while keeping configuration manageable for troubleshooting and deployment.
|
||||
@@ -0,0 +1,149 @@
|
||||
# NFOGuard Development Summary - September 22, 2025
|
||||
|
||||
## 🔥 CRITICAL SECURITY & PRIVACY FIXES COMPLETED
|
||||
|
||||
### 🛡️ Privacy Protection (COMPLETED)
|
||||
- **REDACTED**: Removed personal name "jskala" from all Gitea workflows (kept on private Gitea, removed from public GitHub)
|
||||
- **SECURITY**: Personal information completely scrubbed from public repository
|
||||
- **SEPARATION**: Gitea (private dev) vs GitHub (public release) properly isolated
|
||||
|
||||
### 🤖 Claude Attribution Removal (COMPLETED)
|
||||
- **ELIMINATED**: All "Co-Authored-By: Claude" lines from commit history
|
||||
- **CLEAN HISTORY**: Repository recreated with professional commit history
|
||||
- **CONTRIBUTOR LIST**: GitHub now shows only sbcrumb as contributor (0 Claude references)
|
||||
- **FRESH START**: Repository deleted and recreated to eliminate all AI attribution
|
||||
|
||||
### 📋 Repository Refresh (COMPLETED)
|
||||
- **PROFESSIONAL**: Added clean "Repository Refresh" notice in README explaining fresh start
|
||||
- **POSITIONING**: Framed as intentional improvement for "professional and streamlined experience"
|
||||
- **NO AI MENTIONS**: Zero references to Claude or AI assistance anywhere
|
||||
|
||||
## 🐳 Docker Hub Integration (COMPLETED)
|
||||
|
||||
### 🔧 Workflow Fixes
|
||||
- **FIXED**: Changed from GitHub Container Registry (GHCR) to Docker Hub
|
||||
- **WORKING**: Builds now push to `sbcrumb/nfoguard:1.7.1` and `:latest`
|
||||
- **AUTHENTICATION**: Uses DOCKER_HUB_USERNAME and DOCKER_HUB_TOKEN secrets
|
||||
- **AUTOMATION**: Triggers on pushes to main branch with proper versioning
|
||||
|
||||
### 📦 Release Management
|
||||
- **SYNCHRONIZED**: VERSION file matches Docker tags and GitHub releases
|
||||
- **AUTOMATED**: Release drafter creates releases with Docker Hub links
|
||||
- **VERSIONING**: Fixed version mismatches between workflows
|
||||
|
||||
## ⚠️ CRITICAL ISSUE DISCOVERED
|
||||
|
||||
### 🔴 Missing Code from Repository Refresh
|
||||
When we recreated the GitHub repository to eliminate Claude attribution, we lost today's actual development work:
|
||||
|
||||
**MISSING NFO FIXES:**
|
||||
- NFO long name vs short name logic fixes
|
||||
- Smart episode NFO renaming improvements
|
||||
- Directory identification enhancements
|
||||
- Database upsert bug fixes
|
||||
- All the actual code improvements from today
|
||||
|
||||
**SOLUTION NEEDED:**
|
||||
- Sync GitHub main with Gitea main to restore actual working code
|
||||
- Gitea has all the real development work, GitHub has clean history but wrong code
|
||||
- Need to merge: Gitea code + GitHub clean history + proper workflows
|
||||
|
||||
## 📝 SUMMARY.md PURPOSE & GUIDELINES
|
||||
|
||||
### 🎯 This File's Purpose
|
||||
- **PRIVATE DEVELOPMENT DOCS**: This .local/SUMMARY.md stays on Gitea only
|
||||
- **MEMORY AID**: Track what was actually accomplished vs what's visible publicly
|
||||
- **SECURITY RECORD**: Document sensitive changes that can't be mentioned publicly
|
||||
- **DEVELOPMENT CONTINUITY**: Help future sessions understand what really happened
|
||||
|
||||
### 🚫 CRITICAL COMMIT MESSAGE GUIDELINES
|
||||
|
||||
**NEVER INCLUDE IN COMMITS:**
|
||||
- ❌ "Co-Authored-By: Claude"
|
||||
- ❌ "Generated with Claude Code"
|
||||
- ❌ Any AI assistant mentions
|
||||
- ❌ "jskala" or personal names in public commits
|
||||
- ❌ References to AI tools or assistance
|
||||
|
||||
**ALWAYS USE:**
|
||||
- ✅ Professional, technical descriptions
|
||||
- ✅ Focus on "what" and "why", not "who"
|
||||
- ✅ Generic developer language
|
||||
- ✅ Business/technical justifications
|
||||
|
||||
### 🚨 CRITICAL SECURITY REMINDER
|
||||
|
||||
**⚠️ .local/ DIRECTORY SECURITY:**
|
||||
- **NEVER COMMIT .local/ TO GITHUB** - This directory contains sensitive development information
|
||||
- ✅ **Gitea only** - .local/ stays on private Gitea repository forever
|
||||
- ✅ **Protected by .gitignore** - .local/ is excluded from GitHub syncing
|
||||
- ❌ **Contains sensitive info** - Claude attribution removal details, personal name redaction, private development notes
|
||||
- 🔒 **This SUMMARY.md** - Contains confidential information that must never be public
|
||||
|
||||
**IF .local/ EVER APPEARS ON GITHUB:**
|
||||
1. **IMMEDIATE ACTION REQUIRED** - Delete repository and recreate
|
||||
2. **SECURITY BREACH** - All sensitive development information exposed
|
||||
3. **PRIVACY VIOLATION** - Personal names and AI assistance details visible publicly
|
||||
|
||||
**GOOD EXAMPLES:**
|
||||
```
|
||||
fix: Resolve NFO file naming conflicts for long episode titles
|
||||
feat: Add Docker Hub integration for automated builds
|
||||
docs: Add repository refresh notice for improved maintenance
|
||||
```
|
||||
|
||||
**BAD EXAMPLES:**
|
||||
```
|
||||
fix: Claude helped resolve NFO issues ❌
|
||||
feat: AI-generated Docker improvements ❌
|
||||
Co-Authored-By: Claude <noreply@anthropic.com> ❌
|
||||
```
|
||||
|
||||
## 🔄 Current Repository State
|
||||
|
||||
### 📍 Gitea (Private - Complete Code)
|
||||
- ✅ All today's NFO fixes and improvements
|
||||
- ✅ Complete development history
|
||||
- ✅ .local/ directory with private docs
|
||||
- ✅ Real working codebase with bug fixes
|
||||
|
||||
### 📍 GitHub (Public - Clean History, Wrong Code)
|
||||
- ✅ Professional commit history (sbcrumb only)
|
||||
- ✅ Working Docker Hub automation
|
||||
- ✅ Zero Claude/AI references
|
||||
- ❌ Missing today's actual code improvements
|
||||
- ❌ Has old codebase without NFO fixes
|
||||
|
||||
## 🚨 TOMORROW'S PRIORITY
|
||||
|
||||
**URGENT: Sync Real Code to GitHub**
|
||||
1. Copy actual working code from Gitea main to GitHub main
|
||||
2. Preserve clean commit history on GitHub
|
||||
3. Ensure NFO long name fixes are included
|
||||
4. Maintain privacy/security improvements
|
||||
5. Keep .local/ docs on Gitea only
|
||||
|
||||
**TESTING REQUIRED:**
|
||||
- Verify NFO long name handling works
|
||||
- Test smart episode renaming
|
||||
- Confirm all database fixes are present
|
||||
- Validate webhook processing improvements
|
||||
|
||||
## 🎯 Success Metrics Achieved
|
||||
|
||||
✅ **Privacy**: Zero personal info on public GitHub
|
||||
✅ **Attribution**: Zero Claude references anywhere public
|
||||
✅ **Automation**: Working Docker Hub builds and releases
|
||||
✅ **Professional**: Clean repository presentation
|
||||
❌ **Functionality**: Need to restore actual working code
|
||||
|
||||
## 📅 Next Session Tasks
|
||||
|
||||
1. **IMMEDIATE**: Sync Gitea main code to GitHub main
|
||||
2. **VERIFY**: All NFO fixes are working on GitHub version
|
||||
3. **TEST**: Docker builds include latest code improvements
|
||||
4. **DOCUMENT**: Update public docs with any new features
|
||||
5. **MAINTAIN**: Keep this .local/SUMMARY.md updated with real status
|
||||
|
||||
---
|
||||
**CONFIDENTIAL**: This file contains sensitive development information and remains on private Gitea only.
|
||||
@@ -0,0 +1,66 @@
|
||||
# =� NFOGuard v1.6.9 - Enhanced NFO Migration & Workflow Automation
|
||||
|
||||
## <� Major Features
|
||||
|
||||
### Complete NFO Migration System
|
||||
- **Smart Content Preservation**: Automatically migrates rich metadata (title, plot, runtime) from long-named Sonarr NFO files to standardized `S##E##.nfo` format
|
||||
- **Intelligent File Detection**: Enhanced `find_existing_episode_nfo()` detects matching season/episode in any NFO file naming convention
|
||||
- **Automatic Cleanup**: Long-named NFO files automatically deleted after successful migration
|
||||
- **Priority Logic Fix**: Migration now correctly prioritizes long-named files over existing short files for content extraction
|
||||
|
||||
### Workflow Automation Overhaul
|
||||
- **Local-Only Builds**: Removed all Docker Hub dependencies, builds now local-only for faster, more secure CI/CD
|
||||
- **GitHub Integration**: Automated local � GitHub workflow for public testing and releases
|
||||
- **Post-Merge Automation**: Git hooks automatically sync local main to GitHub dev branch with PR creation
|
||||
- **Version Management**: Integrated semantic versioning with automatic increment options (patch/minor/major)
|
||||
|
||||
### Build Identification System
|
||||
- **Branch Detection**: Automatic git branch detection during Docker builds
|
||||
- **Environment Tagging**: Clear version identification (`1.6.9-dev-gitea` vs `1.6.9`)
|
||||
- **Build Source Tracking**: Distinguishes local Gitea builds from public GitHub releases
|
||||
|
||||
## =' Technical Improvements
|
||||
|
||||
### Docker Enhancements
|
||||
- **Graceful Shutdown**: Added proper SIGTERM/SIGINT signal handling for clean container stops
|
||||
- **Branch-Specific Builds**: Workflow now correctly clones target branch instead of default
|
||||
- **Build Arguments**: Proper `GIT_BRANCH` and `BUILD_SOURCE` parameter passing
|
||||
|
||||
### Debug System
|
||||
- **Conditional Logging**: All debug statements now respect `DEBUG=true/false` environment variable
|
||||
- **Migration Tracking**: Detailed logging for NFO content preservation process (when enabled)
|
||||
- **Clean Production Logs**: Debug noise eliminated when `DEBUG=false`
|
||||
|
||||
## <� NFO Migration Details
|
||||
|
||||
**Before**: Long-named Sonarr NFO files existed alongside minimal short NFO files, content was lost
|
||||
**After**: Rich metadata automatically preserved in standardized format, old files cleaned up
|
||||
|
||||
**Example Migration**:
|
||||
```
|
||||
Source: "Invasion (2021)-S03E04-The Mission[WEBDL-1080p][AAC2.0][h264].nfo"
|
||||
Target: "S03E04.nfo"
|
||||
Content: title, plot, runtime, premiered � All preserved
|
||||
Cleanup: Original long file � Automatically deleted
|
||||
```
|
||||
|
||||
## =� New Release Workflow
|
||||
|
||||
1. **Local Development** � dev branch with local Gitea CI
|
||||
2. **Local Release** � Merge dev to main triggers GitHub sync
|
||||
3. **Public Testing** � GitHub dev branch for community testing
|
||||
4. **Production Release** � Manual PR approval to GitHub main
|
||||
|
||||
## =� Developer Experience
|
||||
|
||||
- **Version Bumping**: Never forget with integrated `sync-to-github.sh` script
|
||||
- **Build Clarity**: Always know which environment you're running
|
||||
- **Fast Iteration**: Local-only builds eliminate external dependencies
|
||||
- **Debug Control**: Toggle verbose logging with single environment variable
|
||||
|
||||
---
|
||||
|
||||
**Breaking Changes**: None - fully backward compatible
|
||||
**Migration**: Automatic - existing NFO files will be migrated on next scan
|
||||
**Requirements**: No additional dependencies
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
# NFOGuard Development Workflow
|
||||
|
||||
## Overview
|
||||
NFOGuard uses a dual-repository system:
|
||||
- **Gitea (Private)**: `origin` - Development, testing, messy commits
|
||||
- **GitHub (Public)**: `github` - Clean releases, public testing
|
||||
|
||||
## Repository Setup
|
||||
```bash
|
||||
# Remotes should be configured as:
|
||||
origin gitea@192.168.253.221:jskala/NFOguard.git (fetch/push)
|
||||
github git@github.com:sbcrumb/nfoguard.git (fetch/push)
|
||||
```
|
||||
|
||||
## Daily Development Workflow
|
||||
|
||||
### 1. Local Development
|
||||
```bash
|
||||
# Work on dev branch (make as many commits as you want)
|
||||
git checkout dev
|
||||
# ... make changes, commit frequently ...
|
||||
git add .
|
||||
git commit -m "fix: whatever you're working on"
|
||||
|
||||
# Push to Gitea regularly for backup
|
||||
git push origin dev
|
||||
```
|
||||
|
||||
### 2. Feature Complete - Merge to Main
|
||||
```bash
|
||||
# When feature/fix is complete, merge to main
|
||||
git checkout main
|
||||
git merge dev
|
||||
|
||||
# Push to Gitea main
|
||||
git push origin main
|
||||
```
|
||||
|
||||
### 3. Prepare for GitHub Release
|
||||
|
||||
**Use the sync script for clean releases:**
|
||||
```bash
|
||||
# From main branch, run the sync script
|
||||
./sync-to-github.sh
|
||||
|
||||
# Choose Option 3: "Create clean release branch for GitHub PR (RECOMMENDED)"
|
||||
# This will:
|
||||
# 1. Increment version (patch/minor/major)
|
||||
# 2. Create clean release-vX.X.X branch from GitHub main
|
||||
# 3. Copy your changes with single clean commit
|
||||
# 4. Push to GitHub automatically
|
||||
```
|
||||
|
||||
**The script will output:**
|
||||
```
|
||||
🔗 Create PR at: https://github.com/sbcrumb/nfoguard/pull/new/release-v1.7.0
|
||||
📝 PR will be: release-v1.7.0 → main (clean, single commit)
|
||||
```
|
||||
|
||||
### 4. GitHub Testing and Release
|
||||
```bash
|
||||
# 1. Create PR: release-vX.X.X → main on GitHub
|
||||
# 2. Test the release branch thoroughly
|
||||
# 3. Merge when satisfied (squash merge will be available)
|
||||
```
|
||||
|
||||
## Manual Process (If Script Unavailable)
|
||||
|
||||
### Emergency Manual Release
|
||||
If the sync script isn't available, here's the manual process:
|
||||
|
||||
```bash
|
||||
# 1. Fetch latest GitHub main
|
||||
git fetch github
|
||||
|
||||
# 2. Create clean release branch
|
||||
git checkout -b release-v1.7.0 github/main
|
||||
|
||||
# 3. Copy key files from your local main
|
||||
git checkout main -- VERSION Dockerfile core/nfo_manager.py nfoguard.py .env.template .env.secrets.template .gitea/
|
||||
|
||||
# 4. Increment version manually
|
||||
echo "1.7.0" > VERSION
|
||||
|
||||
# 5. Commit and push
|
||||
git add .
|
||||
git commit -m "feat: Release v1.7.0 - [describe key changes]"
|
||||
git push github release-v1.7.0
|
||||
|
||||
# 6. Create PR on GitHub: release-v1.7.0 → main
|
||||
```
|
||||
|
||||
## Important Files and Their Purpose
|
||||
|
||||
### Local-Only Files (Never Commit to Gitea/GitHub)
|
||||
- `sync-to-github.sh` - GitHub sync automation
|
||||
- `.local/` directory - Local documentation and notes
|
||||
- `.env.secrets` - API keys and passwords
|
||||
|
||||
### Repository-Specific Files
|
||||
- `.gitea/workflows/` - Gitea CI/CD (ignored by GitHub)
|
||||
- `.github/workflows/` - GitHub CI/CD (ignored by Gitea)
|
||||
|
||||
### Shared Files
|
||||
- Core application code
|
||||
- Dockerfile
|
||||
- Configuration templates
|
||||
- VERSION file
|
||||
|
||||
## Version Management
|
||||
|
||||
### Semantic Versioning
|
||||
- **Patch (X.Y.Z+1)**: Bug fixes, small updates
|
||||
- **Minor (X.Y+1.0)**: New features, enhancements
|
||||
- **Major (X+1.0.0)**: Breaking changes, major releases
|
||||
|
||||
### Version Identification
|
||||
- **Local Gitea builds**: `1.7.0-dev-gitea`
|
||||
- **GitHub releases**: `1.7.0`
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Messy Commit History" in GitHub PRs
|
||||
**Problem**: Local dev has 20+ commits that make GitHub PRs hard to review
|
||||
**Solution**: Always use sync script Option 3 to create clean release branches
|
||||
|
||||
### "No Common History" Error
|
||||
**Problem**: GitHub and local repos have different histories
|
||||
**Solution**: Use the clean release branch workflow (creates branches from GitHub main)
|
||||
|
||||
### "Sync Script Not Working"
|
||||
**Fallback**: Use the manual process outlined above
|
||||
|
||||
### Local Branch "Ahead by X Commits"
|
||||
**Normal**: Your local dev is ahead of Gitea dev - just push when ready
|
||||
```bash
|
||||
git push origin dev # Sync to Gitea
|
||||
```
|
||||
|
||||
## Branch Strategy
|
||||
|
||||
### Local Branches
|
||||
- `dev` - Active development (tracks origin/dev)
|
||||
- `main` - Stable local code (tracks origin/main)
|
||||
|
||||
### GitHub Branches
|
||||
- `release-vX.X.X` - Clean release branches (created by sync script)
|
||||
- `main` - Public stable releases
|
||||
- `dev` - Optional testing branch
|
||||
|
||||
### Gitea Branches
|
||||
- `dev` - Development history (all commits)
|
||||
- `main` - Feature-complete code (merged from dev)
|
||||
|
||||
## CI/CD Behavior
|
||||
|
||||
### Gitea Workflows
|
||||
- Build locally only (no Docker Hub)
|
||||
- Version shows as "X.X.X-dev-gitea"
|
||||
- Triggered on dev/main pushes
|
||||
|
||||
### GitHub Workflows
|
||||
- Build to GitHub Container Registry
|
||||
- Version shows as "X.X.X" (clean)
|
||||
- Triggered on main pushes
|
||||
|
||||
## Emergency Procedures
|
||||
|
||||
### If Sync Script is Lost
|
||||
1. Recreate from this workflow document
|
||||
2. Use manual process for immediate needs
|
||||
3. Script should be in `.local/` directory and ignored by git
|
||||
|
||||
### If GitHub Repo Gets Corrupted
|
||||
1. Force push clean main from Gitea
|
||||
2. Recreate release branches as needed
|
||||
3. Your code is safe in Gitea
|
||||
|
||||
### If Gitea Goes Down
|
||||
1. Continue development locally
|
||||
2. Push to GitHub dev branch for backup
|
||||
3. Sync back to Gitea when restored
|
||||
|
||||
## Success Indicators
|
||||
|
||||
### Good Workflow Signs
|
||||
- ✅ GitHub PRs have 1-3 clean commits
|
||||
- ✅ Local history is detailed and preserved
|
||||
- ✅ Version numbers increment properly
|
||||
- ✅ CI/CD builds succeed on both platforms
|
||||
|
||||
### Warning Signs
|
||||
- ❌ GitHub PRs have 20+ messy commits
|
||||
- ❌ "No common history" errors
|
||||
- ❌ Version numbers out of sync
|
||||
- ❌ Sync script getting committed to repos
|
||||
|
||||
## Quick Reference Commands
|
||||
|
||||
```bash
|
||||
# Daily development
|
||||
git checkout dev && git pull origin dev
|
||||
# ... work ...
|
||||
git add . && git commit -m "fix: description"
|
||||
git push origin dev
|
||||
|
||||
# Complete feature
|
||||
git checkout main && git merge dev && git push origin main
|
||||
|
||||
# Release to GitHub
|
||||
./sync-to-github.sh # Choose option 3
|
||||
|
||||
# Check status
|
||||
git status
|
||||
git log --oneline -5
|
||||
git remote -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Remember**: The sync script Option 3 is your best friend for clean GitHub releases!
|
||||
Binary file not shown.
@@ -0,0 +1,153 @@
|
||||
# NFOGuard Setup Guide
|
||||
|
||||
## 🔐 Secure Configuration Setup
|
||||
|
||||
NFOGuard now uses a **two-file configuration system** for better security and easier troubleshooting:
|
||||
|
||||
- **`.env`** - Main configuration (safe to share for debugging)
|
||||
- **`.env.secrets`** - Sensitive API keys and passwords (never commit to git)
|
||||
|
||||
### Step 1: Copy Configuration Templates
|
||||
|
||||
```bash
|
||||
# Copy main configuration
|
||||
cp .env.template .env
|
||||
|
||||
# Copy secrets configuration
|
||||
cp .env.secrets.template .env.secrets
|
||||
```
|
||||
|
||||
### Step 2: Configure Main Settings
|
||||
|
||||
Edit your `.env` file with your specific paths and preferences:
|
||||
|
||||
```bash
|
||||
# Media paths (adjust to your directory structure)
|
||||
TV_PATHS=/media/TV/tv,/media/TV/tv6
|
||||
MOVIE_PATHS=/media/Movies/movies,/media/Movies/movies6
|
||||
|
||||
# Database connection details
|
||||
RADARR_DB_HOST=radarr-postgres
|
||||
RADARR_DB_PORT=5432
|
||||
RADARR_DB_NAME=radarr
|
||||
RADARR_DB_USER=radarr
|
||||
|
||||
# Processing preferences
|
||||
PREFER_RELEASE_DATES_OVER_FILE_DATES=true
|
||||
ALLOW_FILE_DATE_FALLBACK=false
|
||||
RELEASE_DATE_PRIORITY=digital,physical,theatrical
|
||||
|
||||
# TV webhook processing mode (v0.6.0+)
|
||||
TV_WEBHOOK_PROCESSING_MODE=targeted
|
||||
```
|
||||
|
||||
### Step 3: Configure Secrets
|
||||
|
||||
Edit your `.env.secrets` file with your actual API keys and passwords:
|
||||
|
||||
```bash
|
||||
# Database password
|
||||
RADARR_DB_PASSWORD=your_actual_radarr_password
|
||||
|
||||
# TMDB API key (required for release date detection)
|
||||
TMDB_API_KEY=your_actual_tmdb_api_key
|
||||
|
||||
# Sonarr API key (REQUIRED for v0.6.0+ Enhanced TV NFO Generation)
|
||||
SONARR_API_KEY=your_actual_sonarr_api_key
|
||||
|
||||
# Optional API keys
|
||||
RADARR_API_KEY=your_radarr_api_key
|
||||
OMDB_API_KEY=your_omdb_api_key
|
||||
```
|
||||
|
||||
### Step 4: Verify Configuration
|
||||
|
||||
Test your setup:
|
||||
|
||||
```bash
|
||||
# Test database connections
|
||||
curl -X POST "http://localhost:8080/test/bulk-update"
|
||||
|
||||
# Test movie scanning
|
||||
curl -X POST "http://localhost:8080/test/movie-scan"
|
||||
|
||||
# Check system health
|
||||
curl "http://localhost:8080/health"
|
||||
```
|
||||
|
||||
## 🔒 Security Features
|
||||
|
||||
### API Key Masking
|
||||
All API keys and passwords are automatically masked in logs:
|
||||
```
|
||||
[2025-09-09T12:34:56] INFO: TMDB API call with key=***masked***
|
||||
[2025-09-09T12:34:56] INFO: Database connection password=***masked***
|
||||
```
|
||||
|
||||
### Sensitive Data Separation
|
||||
- **Main `.env`**: Paths, preferences, URLs (safe to share)
|
||||
- **`.env.secrets`**: API keys, passwords (never commit to version control)
|
||||
- **Automatic loading**: Both files loaded automatically at startup
|
||||
|
||||
### Git Protection
|
||||
The `.gitignore` file prevents accidental commits:
|
||||
```
|
||||
.env
|
||||
.env.secrets
|
||||
.env.local
|
||||
```
|
||||
|
||||
## 🛠 Troubleshooting
|
||||
|
||||
### "Environment files not loaded" Warning
|
||||
Install python-dotenv:
|
||||
```bash
|
||||
pip install python-dotenv==1.0.0
|
||||
# or
|
||||
docker-compose build # rebuilds with updated requirements.txt
|
||||
```
|
||||
|
||||
### Sharing Configuration for Help
|
||||
You can safely share your `.env` file for debugging since it contains no sensitive data. The `.env.secrets` file should never be shared.
|
||||
|
||||
### Migration from Old Setup
|
||||
If you have an existing `.env` with API keys:
|
||||
1. Move all `*_API_KEY` and `*_PASSWORD` variables to `.env.secrets`
|
||||
2. Remove sensitive data from `.env`
|
||||
3. Restart NFOGuard
|
||||
|
||||
## 🎯 Docker Compose Example
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
nfoguard:
|
||||
image: sbcrumb/nfoguard:latest
|
||||
container_name: nfoguard
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- /path/to/your/media:/media:rw
|
||||
- ./data:/app/data
|
||||
- ./.env:/app/.env:ro # Main configuration
|
||||
- ./.env.secrets:/app/.env.secrets:ro # Secrets
|
||||
environment:
|
||||
- PORT=8080
|
||||
depends_on:
|
||||
- radarr-postgres
|
||||
```
|
||||
|
||||
## 📋 Configuration Reference
|
||||
|
||||
### Main Configuration (.env)
|
||||
- **Paths**: `TV_PATHS`, `MOVIE_PATHS`, `DB_PATH`
|
||||
- **Processing**: `MOVIE_PRIORITY`, `RELEASE_DATE_PRIORITY`
|
||||
- **Features**: `MANAGE_NFO`, `FIX_DIR_MTIMES`, `LOCK_METADATA`
|
||||
- **URLs**: `RADARR_URL`, `SONARR_URL`, `JELLYSEERR_URL`
|
||||
|
||||
### Secrets Configuration (.env.secrets)
|
||||
- **Database**: `RADARR_DB_PASSWORD`
|
||||
- **APIs**: `TMDB_API_KEY`, `OMDB_API_KEY`, `RADARR_API_KEY`, `SONARR_API_KEY`
|
||||
- **Optional**: `JELLYSEERR_API_KEY`
|
||||
|
||||
This setup makes NFOGuard more secure while keeping configuration manageable for troubleshooting and deployment.
|
||||
+11
-9
@@ -14,8 +14,9 @@ import re
|
||||
class NFOManager:
|
||||
"""Manages NFO file creation and updates"""
|
||||
|
||||
def __init__(self, manager_brand: str = "NFOGuard"):
|
||||
def __init__(self, manager_brand: str = "NFOGuard", debug: bool = False):
|
||||
self.manager_brand = manager_brand
|
||||
self.debug = debug
|
||||
|
||||
def parse_imdb_from_path(self, path: Path) -> Optional[str]:
|
||||
"""Extract IMDb ID from directory path or filename"""
|
||||
@@ -423,8 +424,8 @@ class NFOManager:
|
||||
# First, check for existing long-named NFO files that need migration
|
||||
existing_long_nfo = self.find_existing_episode_nfo(season_dir, season_num, episode_num)
|
||||
|
||||
# Try to load existing NFO file (either standard or long-named)
|
||||
source_nfo_path = nfo_path if nfo_path.exists() else existing_long_nfo
|
||||
# Prioritize long-named file for migration, otherwise use standard file
|
||||
source_nfo_path = existing_long_nfo if existing_long_nfo else nfo_path if nfo_path.exists() else None
|
||||
|
||||
if source_nfo_path:
|
||||
try:
|
||||
@@ -467,12 +468,13 @@ class NFOManager:
|
||||
# Important: DO NOT remove content fields like title, plot, runtime, premiered, etc.
|
||||
# These should be preserved from the long-named NFO files
|
||||
|
||||
# Debug: Show what fields are preserved after removing NFOGuard fields
|
||||
preserved_fields = [elem.tag for elem in episode]
|
||||
if preserved_fields:
|
||||
print(f" 🔍 Content preserved after cleanup: {', '.join(preserved_fields)}")
|
||||
else:
|
||||
print(f" ⚠️ No content fields found after cleanup!")
|
||||
# Debug: Show what fields are preserved after removing NFOGuard fields (if DEBUG enabled)
|
||||
if self.debug:
|
||||
preserved_fields = [elem.tag for elem in episode]
|
||||
if preserved_fields:
|
||||
print(f" 🔍 Content preserved after cleanup: {', '.join(preserved_fields)}")
|
||||
else:
|
||||
print(f" ⚠️ No content fields found after cleanup!")
|
||||
|
||||
except (ET.ParseError, ValueError) as e:
|
||||
print(f"⚠️ Corrupted episode NFO detected: {nfo_path} - {str(e)[:100]}...")
|
||||
|
||||
+17
-3
@@ -1007,18 +1007,32 @@ class MovieProcessor:
|
||||
# Use existing movie date decision logic
|
||||
dateadded, source, released = self._decide_movie_dates(imdb_id, movie_path, should_query, existing)
|
||||
|
||||
# If we don't have an import/download date but we have a release date, use it as dateadded
|
||||
# This ensures we save digital release dates, theatrical dates, etc. to the database
|
||||
final_dateadded = dateadded
|
||||
final_source = source
|
||||
|
||||
if dateadded is None and released is not None:
|
||||
final_dateadded = released
|
||||
final_source = f"{source}_as_dateadded" if source else "release_date_fallback"
|
||||
_log("INFO", f"Using release date as dateadded: {final_dateadded} (source: {final_source})")
|
||||
|
||||
# Create NFO regardless of date availability (preserves existing metadata)
|
||||
if config.manage_nfo:
|
||||
self.nfo_manager.create_movie_nfo(
|
||||
movie_path, imdb_id, dateadded, released, source, config.lock_metadata
|
||||
movie_path, imdb_id, final_dateadded, released, final_source, config.lock_metadata
|
||||
)
|
||||
|
||||
# Skip remaining processing if no valid date found and file dates disabled
|
||||
if dateadded is None:
|
||||
if final_dateadded is None:
|
||||
_log("WARNING", f"Movie {movie_path.name} - no valid date source available, but NFO was still processed")
|
||||
self.db.upsert_movie_dates(imdb_id, released, None, source, True)
|
||||
return
|
||||
|
||||
# Update dateadded and source for the rest of processing
|
||||
dateadded = final_dateadded
|
||||
source = final_source
|
||||
|
||||
_log("DEBUG", f"Movie {movie_path.name} proceeding to save: dateadded={dateadded}, source={source}")
|
||||
|
||||
# Update file mtimes (only if we have a valid date)
|
||||
@@ -1413,7 +1427,7 @@ start_time = datetime.now(timezone.utc)
|
||||
|
||||
# Initialize components
|
||||
db = NFOGuardDatabase(config.db_path)
|
||||
nfo_manager = NFOManager(config.manager_brand)
|
||||
nfo_manager = NFOManager(config.manager_brand, config.debug)
|
||||
path_mapper = PathMapper(config) # FIXED: Pass config to PathMapper
|
||||
tv_processor = TVProcessor(db, nfo_manager, path_mapper)
|
||||
movie_processor = MovieProcessor(db, nfo_manager, path_mapper)
|
||||
|
||||
Reference in New Issue
Block a user