Skip to content

Commit 1a75bdf

Browse files
Chore: Stable release v1.0.0 (#31)
* feat: add option to rename, disable, reorder catalogs * feat: new recommendation system based on weights * feat: dynamic row generator * feat: add dynamic row generator with country flag * feat: add watched.loved row * feat: new ui with stremio auth button * feat: add languages selection button in ui for tmdb meta * feat: add option to enable rpdb api key for posters * feat: ui improvements * chore: add vercel app env * chore: improve recommendation weights and refactor * chore: remove unnecessary country flags * add workflows to bump version * chore: bump version to 1.0.0-rc.1 * chore: bump version to 1.0.0-rc.2 * chore: use redis token from config * fix: priotrize keywords for row generation than genre * chore: bump version to v1.0.0-rc.3 * feat: add option to delete account * refactor: update token deletion API to use DELETE / and implement deep cloning for catalog data in the frontend, removing conditional name handling. * opt: improve recommendations using larger candidate pool and better similarity methods * feat: Add genre exclusion UI, store excluded genres in user settings,and apply them during catalog generation (#21) * feat: Add genre exclusion UI, store excluded genres in user settings, and apply them during catalog generation. * refactor: simplify filtering recommendations by excluded genres using list comprehension * refactor: streamline genre exclusion logic for similarity recommendations * feat: Rework UI into a multi-step setup wizard with account management and section navigation (#22) * feat: Rework UI into a multi-step setup wizard with Watchly account management and section navigation * critical: check if user already exists * refactor: remove disabled class from source code button * feat: add translation service to translate catalog names to user language (#23) * feat: add option to rename, enable disable catalogs (#24) * feat: Implement user ID-based token management and Stremio user info fetching, replacing credential-derived tokens and direct login. (#25) * refactor: code refactoring and remove legacy code and components (#26) * feat: add option to rename, enable disable catalogs * feat: add option to rename, enable disable catalogs * feat: Implement user ID-based token management and Stremio user info fetching, replacing credential-derived tokens and direct login. * feat: Implement user ID-based token management and Stremio user info fetching, replacing credential-derived tokens and direct login. * feat: Refactor token management to use a dedicated token model, remove token salt, and streamline catalog refresh logic. * feat: Encrypt auth keys in token store and enforce 401 for invalid tokens across endpoints. * feat: Introduce token redaction utility and apply it to log messages for enhanced security. * feat: Introduce token redaction utility and apply it to log messages for enhanced security. * fernet client management * feat: add migration script to migrate old tokens to new system * feat: check and only update tokens that are installed from the same system * opt: give more weight to items watched recently * docs: add contributing guidelines and acknowledgements * opt: optimize translation service * chore: bump version to v1.0.0-rc.6 * feat: add gemini service to generate catalog names (#29) * Refactor services for improved async handling and error resilience (#30) * refactor: fetch loved and liked items at once and use that * Refactor services for improved async handling and error resilience * chore: bump version to v1.0.0 * feat: better bare row name generation (#32)
2 parents 4f0f930 + 200960f commit 1a75bdf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+5575
-1929
lines changed

.env.example

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ PORT=8000
33
ADDON_ID=com.bimal.watchly
44
ADDON_NAME=Watchly
55
REDIS_URL=redis://redis:6379/0
6-
TOKEN_SALT=replace-with-a-long-random-string
76
TOKEN_TTL_SECONDS=0
87
ANNOUNCEMENT_HTML=
98
HOST_NAME=<your_addon_url>
109
RECOMMENDATION_SOURCE_ITEMS_LIMIT=10 # fetches recent watched/loved 10 movies and series to recommend based on those
11-
10+
TOKEN_SALT=change-me
11+
# generate some very long random string preferrably using cryptography libraries
1212
# UPDATER
13-
CATALOG_UPDATE_MODE=cron
13+
CATALOG_UPDATE_MODE=cron # Available options: cron, interval
14+
# cron updates catalogs at specified times
15+
# interval updates in specific intervals
1416
CATALOG_UPDATE_CRON_SCHEDULES=[{"hour": 12, "minute": 0, "id": "catalog_refresh_noon"},{"hour": 0, "minute": 0, "id": "catalog_refresh_midnight"}]
1517
CATALOG_REFRESH_INTERVAL_SECONDS=6*60*60

.github/FUNDING.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
custom: ["https://buymemomo.com/timilsinabimal"]
12
ko_fi: TimilsinaBimal
2-
custom: ["https://www.paypal.com/donate/?hosted_button_id=KRQMVS34FC5KC"]
3+
github: ["TimilsinaBimal"]

.github/workflows/ci.yml

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88
push:
99
branches:
1010
- main
11+
paths:
12+
- 'app/core/version.py'
13+
- 'pyproject.toml'
1114

1215
concurrency:
1316
group: ${{ github.head_ref || github.run_id }}
@@ -18,7 +21,7 @@ jobs:
1821
runs-on: ubuntu-latest
1922
permissions:
2023
id-token: write
21-
contents: read
24+
contents: write
2225

2326
steps:
2427
- name: Checkout code
@@ -30,14 +33,50 @@ jobs:
3033
username: ${{ github.actor }}
3134
password: ${{ secrets.CR_TOKEN }}
3235

36+
- name: Set up Python
37+
uses: actions/setup-python@v6
38+
with:
39+
python-version: '3.11'
40+
41+
- name: Read version from version.py
42+
id: get-version
43+
run: |
44+
# Try Python import first
45+
VERSION=$(python -c "import sys; sys.path.insert(0, '.'); from app.core.version import __version__; print(__version__)" 2>/dev/null || echo "")
46+
# Fallback to regex if import fails
47+
if [ -z "${VERSION}" ]; then
48+
VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]*' app/core/version.py || echo "0.0.0")
49+
fi
50+
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
51+
echo "Read version: ${VERSION}"
52+
3353
- name: Set Docker image tag
3454
id: set-tag
3555
run: |
36-
echo "IMAGE_TAG=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
56+
VERSION="${{ steps.get-version.outputs.VERSION }}"
57+
echo "IMAGE_TAG=${VERSION}" >> $GITHUB_OUTPUT
58+
echo "Building Docker image with version: ${VERSION}"
3759
3860
- name: Build and Push Docker image
3961
working-directory: "./"
4062
run: |
4163
REPO_NAME="${GITHUB_REPOSITORY,,}"
42-
docker build -t ghcr.io/${REPO_NAME}:${{ steps.set-tag.outputs.IMAGE_TAG }} .
43-
docker push ghcr.io/${REPO_NAME}:${{ steps.set-tag.outputs.IMAGE_TAG }}
64+
IMAGE_TAG="${{ steps.set-tag.outputs.IMAGE_TAG }}"
65+
# Build and tag with version
66+
docker build -t ghcr.io/${REPO_NAME}:${IMAGE_TAG} .
67+
docker push ghcr.io/${REPO_NAME}:${IMAGE_TAG}
68+
# Also tag as latest
69+
docker tag ghcr.io/${REPO_NAME}:${IMAGE_TAG} ghcr.io/${REPO_NAME}:latest
70+
docker push ghcr.io/${REPO_NAME}:latest
71+
72+
- name: Create and Push Git Tag
73+
run: |
74+
VERSION="${{ steps.get-version.outputs.VERSION }}"
75+
# Check if tag already exists
76+
if git rev-parse "$VERSION" >/dev/null 2>&1; then
77+
echo "Tag $VERSION already exists, skipping"
78+
else
79+
echo "Creating tag: $VERSION"
80+
git tag $VERSION
81+
git push origin $VERSION
82+
fi

.github/workflows/release.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: Create GitHub Release
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Build and Push Docker Image"]
6+
types:
7+
- completed
8+
branches:
9+
- main
10+
push:
11+
tags:
12+
- '*' # Also trigger on manual tag pushes
13+
14+
15+
jobs:
16+
release:
17+
runs-on: ubuntu-latest
18+
# Only run if the triggering workflow succeeded
19+
if: ${{ github.event_name == 'push' || github.event.workflow_run.conclusion == 'success' }}
20+
21+
permissions:
22+
packages: write
23+
contents: write
24+
25+
steps:
26+
- name: Checkout repository
27+
uses: actions/checkout@v5
28+
with:
29+
fetch-depth: 0 # Fetch all history for all tags and branches
30+
fetch-tags: true # Fetch all tags
31+
ref: ${{ github.event.workflow_run.head_branch || github.ref }}
32+
33+
- name: Set up Python
34+
uses: actions/setup-python@v6
35+
with:
36+
python-version: '3.11'
37+
38+
- name: Install dependencies
39+
run: |
40+
python -m pip install --upgrade pip
41+
pip install openai pydantic
42+
43+
- name: Get current tag
44+
id: get-tag
45+
run: |
46+
# If triggered by workflow_run, read version from version.py
47+
if [ "${{ github.event_name }}" = "workflow_run" ]; then
48+
# Read version from version.py (same as CI workflow did)
49+
VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]*' app/core/version.py || echo "")
50+
if [ -z "${VERSION}" ]; then
51+
# Fallback: try Python import
52+
VERSION=$(python -c "import sys; sys.path.insert(0, '.'); from app.core.version import __version__; print(__version__)" 2>/dev/null || echo "")
53+
fi
54+
if [ -z "${VERSION}" ]; then
55+
echo "Error: Could not read version from version.py"
56+
exit 1
57+
fi
58+
echo "TAG_NAME=${VERSION}" >> $GITHUB_OUTPUT
59+
echo "Tag from version.py: ${VERSION}"
60+
else
61+
# If triggered by tag push, get from GITHUB_REF
62+
TAG_NAME=${GITHUB_REF#refs/tags/}
63+
echo "TAG_NAME=${TAG_NAME}" >> $GITHUB_OUTPUT
64+
echo "Current tag from push: ${TAG_NAME}"
65+
fi
66+
67+
- name: Checkout tag commit
68+
run: |
69+
TAG_NAME="${{ steps.get-tag.outputs.TAG_NAME }}"
70+
git checkout ${TAG_NAME} || git checkout -b temp-${TAG_NAME} ${TAG_NAME}
71+
echo "Checked out tag: ${TAG_NAME}"
72+
73+
- name: Run Python script to generate release notes
74+
id: generate_release_notes
75+
env:
76+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
77+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
78+
CURRENT_TAG: ${{ steps.get-tag.outputs.TAG_NAME }}
79+
run: |
80+
echo "Running generate_release_notes.py"
81+
python scripts/generate_release_notes.py
82+
echo "Script completed"
83+
84+
- name: Debug Outputs
85+
run: |
86+
echo "Version: ${{ steps.generate_release_notes.outputs.version }}"
87+
echo "Release Notes: ${{ steps.generate_release_notes.outputs.release_notes }}"
88+
89+
- name: Create GitHub Release
90+
uses: actions/create-release@v1
91+
env:
92+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
93+
with:
94+
tag_name: ${{ steps.get-tag.outputs.TAG_NAME }}
95+
release_name: Release ${{ steps.get-tag.outputs.TAG_NAME }} - ${{ steps.generate_release_notes.outputs.version_name }}
96+
body: ${{ steps.generate_release_notes.outputs.release_notes }}
97+
draft: false
98+
prerelease: ${{ contains(steps.get-tag.outputs.TAG_NAME, 'beta') || contains(steps.get-tag.outputs.TAG_NAME, 'alpha') || contains(steps.get-tag.outputs.TAG_NAME, 'rc') || contains(steps.get-tag.outputs.TAG_NAME, 'pre') }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,7 @@ Thumbs.db
4242
# Logs
4343
logs/
4444
*.log
45+
46+
# python notebooks
47+
*/ipynb_checkpoints/
48+
*.ipynb

Dockerfile

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,26 @@
1-
# Use Python 3.11 slim image as base
21
FROM python:3.11-slim
32

4-
# Set working directory
53
WORKDIR /app
64

7-
# Set environment variables
8-
ENV PYTHONDONTWRITEBYTECODE=1 \
9-
PYTHONUNBUFFERED=1 \
10-
PIP_NO_CACHE_DIR=1 \
11-
PIP_DISABLE_PIP_VERSION_CHECK=1
12-
135
# Install system dependencies
146
RUN apt-get update && apt-get install -y \
15-
gcc \
7+
gcc curl ca-certificates\
168
&& rm -rf /var/lib/apt/lists/*
179

18-
# Copy requirements first for better caching
19-
COPY requirements.txt .
10+
# Download the latest installer
11+
ADD https://astral.sh/uv/install.sh /uv-installer.sh
12+
13+
# Run the installer then remove it
14+
RUN sh /uv-installer.sh && rm /uv-installer.sh
2015

21-
# Install Python dependencies
22-
RUN pip install --no-cache-dir -r requirements.txt
16+
# Ensure the installed binary is on the `PATH`
17+
ENV PATH="/root/.local/bin/:$PATH"
2318

24-
# Copy application code (including static files)
2519
COPY app/ ./app/
26-
COPY static/ ./static/
2720
COPY main.py .
2821
COPY pyproject.toml .
22+
COPY uv.lock .
23+
24+
RUN uv sync --locked
2925

30-
ENTRYPOINT ["python", "main.py"]
26+
ENTRYPOINT ["uv", "run", "main.py"]

0 commit comments

Comments
 (0)