Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d76009a
feat: add option to rename, disable, reorder catalogs
TimilsinaBimal Nov 23, 2025
8158969
feat: new recommendation system based on weights
TimilsinaBimal Nov 29, 2025
821d6ef
feat: dynamic row generator
TimilsinaBimal Nov 29, 2025
2f2bcd9
feat: add dynamic row generator with country flag
TimilsinaBimal Nov 29, 2025
5258390
feat: add watched.loved row
TimilsinaBimal Nov 29, 2025
7163101
feat: new ui with stremio auth button
TimilsinaBimal Nov 29, 2025
15f688d
feat: add languages selection button in ui for tmdb meta
TimilsinaBimal Nov 29, 2025
3d816b1
feat: add option to enable rpdb api key for posters
TimilsinaBimal Nov 29, 2025
82fb4d9
feat: ui improvements
TimilsinaBimal Nov 29, 2025
cf277a0
chore: add vercel app env
TimilsinaBimal Nov 30, 2025
6571add
chore: improve recommendation weights and refactor
TimilsinaBimal Nov 30, 2025
675fd86
chore: remove unnecessary country flags
TimilsinaBimal Nov 30, 2025
5438b75
add workflows to bump version
TimilsinaBimal Nov 30, 2025
1a8675b
chore: bump version to 1.0.0-rc.1
TimilsinaBimal Nov 30, 2025
b6e723c
chore: bump version to 1.0.0-rc.2
TimilsinaBimal Nov 30, 2025
25f7a22
chore: use redis token from config
TimilsinaBimal Dec 1, 2025
cd7ee27
fix: priotrize keywords for row generation than genre
TimilsinaBimal Dec 1, 2025
fa61711
chore: bump version to v1.0.0-rc.3
TimilsinaBimal Dec 1, 2025
a43ded9
feat: add option to delete account
TimilsinaBimal Dec 2, 2025
25da74e
refactor: update token deletion API to use DELETE / and implement dee…
TimilsinaBimal Dec 2, 2025
6eb8479
Merge branch 'main' of github.com:TimilsinaBimal/Watchly into dev
TimilsinaBimal Dec 4, 2025
db1a62d
opt: improve recommendations using larger candidate pool and better s…
TimilsinaBimal Dec 5, 2025
c7edd89
feat: Add genre exclusion UI, store excluded genres in user settings,…
TimilsinaBimal Dec 6, 2025
d51287e
feat: Rework UI into a multi-step setup wizard with account managemen…
TimilsinaBimal Dec 6, 2025
4b3a26b
feat: add translation service to translate catalog names to user lang…
TimilsinaBimal Dec 6, 2025
77c4fa2
feat: add option to rename, enable disable catalogs (#24)
TimilsinaBimal Dec 6, 2025
82b2346
feat: Implement user ID-based token management and Stremio user info…
TimilsinaBimal Dec 6, 2025
8342c9a
refactor: code refactoring and remove legacy code and components (#26)
TimilsinaBimal Dec 6, 2025
5f8526c
fernet client management
TimilsinaBimal Dec 6, 2025
4924c38
feat: add migration script to migrate old tokens to new system
TimilsinaBimal Dec 8, 2025
d2b5df8
feat: check and only update tokens that are installed from the same s…
TimilsinaBimal Dec 8, 2025
3633b5a
opt: give more weight to items watched recently
TimilsinaBimal Dec 8, 2025
a01c255
docs: add contributing guidelines and acknowledgements
TimilsinaBimal Dec 8, 2025
adcc6e0
opt: optimize translation service
TimilsinaBimal Dec 9, 2025
5b4bc0f
chore: bump version to v1.0.0-rc.6
TimilsinaBimal Dec 9, 2025
5e7bf53
feat: add gemini service to generate catalog names (#29)
TimilsinaBimal Dec 10, 2025
0e44a18
Refactor services for improved async handling and error resilience (#30)
TimilsinaBimal Dec 12, 2025
61f340f
chore: bump version to v1.0.0
TimilsinaBimal Dec 12, 2025
200960f
feat: better bare row name generation (#32)
TimilsinaBimal Dec 12, 2025
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
8 changes: 5 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ PORT=8000
ADDON_ID=com.bimal.watchly
ADDON_NAME=Watchly
REDIS_URL=redis://redis:6379/0
TOKEN_SALT=replace-with-a-long-random-string
TOKEN_TTL_SECONDS=0
ANNOUNCEMENT_HTML=
HOST_NAME=<your_addon_url>
RECOMMENDATION_SOURCE_ITEMS_LIMIT=10 # fetches recent watched/loved 10 movies and series to recommend based on those

TOKEN_SALT=change-me
# generate some very long random string preferrably using cryptography libraries
# UPDATER
CATALOG_UPDATE_MODE=cron
CATALOG_UPDATE_MODE=cron # Available options: cron, interval
# cron updates catalogs at specified times
# interval updates in specific intervals
CATALOG_UPDATE_CRON_SCHEDULES=[{"hour": 12, "minute": 0, "id": "catalog_refresh_noon"},{"hour": 0, "minute": 0, "id": "catalog_refresh_midnight"}]
CATALOG_REFRESH_INTERVAL_SECONDS=6*60*60
3 changes: 2 additions & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
custom: ["https://buymemomo.com/timilsinabimal"]
ko_fi: TimilsinaBimal
custom: ["https://www.paypal.com/donate/?hosted_button_id=KRQMVS34FC5KC"]
github: ["TimilsinaBimal"]
47 changes: 43 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ on:
push:
branches:
- main
paths:
- 'app/core/version.py'
- 'pyproject.toml'

concurrency:
group: ${{ github.head_ref || github.run_id }}
Expand All @@ -18,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
contents: write

steps:
- name: Checkout code
Expand All @@ -30,14 +33,50 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.CR_TOKEN }}

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'

- name: Read version from version.py
id: get-version
run: |
# Try Python import first
VERSION=$(python -c "import sys; sys.path.insert(0, '.'); from app.core.version import __version__; print(__version__)" 2>/dev/null || echo "")
# Fallback to regex if import fails
if [ -z "${VERSION}" ]; then
VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]*' app/core/version.py || echo "0.0.0")
fi
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
echo "Read version: ${VERSION}"

- name: Set Docker image tag
id: set-tag
run: |
echo "IMAGE_TAG=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
VERSION="${{ steps.get-version.outputs.VERSION }}"
echo "IMAGE_TAG=${VERSION}" >> $GITHUB_OUTPUT
echo "Building Docker image with version: ${VERSION}"

- name: Build and Push Docker image
working-directory: "./"
run: |
REPO_NAME="${GITHUB_REPOSITORY,,}"
docker build -t ghcr.io/${REPO_NAME}:${{ steps.set-tag.outputs.IMAGE_TAG }} .
docker push ghcr.io/${REPO_NAME}:${{ steps.set-tag.outputs.IMAGE_TAG }}
IMAGE_TAG="${{ steps.set-tag.outputs.IMAGE_TAG }}"
# Build and tag with version
docker build -t ghcr.io/${REPO_NAME}:${IMAGE_TAG} .
docker push ghcr.io/${REPO_NAME}:${IMAGE_TAG}
# Also tag as latest
docker tag ghcr.io/${REPO_NAME}:${IMAGE_TAG} ghcr.io/${REPO_NAME}:latest
docker push ghcr.io/${REPO_NAME}:latest

- name: Create and Push Git Tag
run: |
VERSION="${{ steps.get-version.outputs.VERSION }}"
# Check if tag already exists
if git rev-parse "$VERSION" >/dev/null 2>&1; then
echo "Tag $VERSION already exists, skipping"
else
echo "Creating tag: $VERSION"
git tag $VERSION
git push origin $VERSION
fi
98 changes: 98 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: Create GitHub Release

on:
workflow_run:
workflows: ["Build and Push Docker Image"]
types:
- completed
branches:
- main
push:
tags:
- '*' # Also trigger on manual tag pushes


jobs:
release:
runs-on: ubuntu-latest
# Only run if the triggering workflow succeeded
if: ${{ github.event_name == 'push' || github.event.workflow_run.conclusion == 'success' }}

permissions:
packages: write
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # Fetch all history for all tags and branches
fetch-tags: true # Fetch all tags
ref: ${{ github.event.workflow_run.head_branch || github.ref }}

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install openai pydantic

- name: Get current tag
id: get-tag
run: |
# If triggered by workflow_run, read version from version.py
if [ "${{ github.event_name }}" = "workflow_run" ]; then
# Read version from version.py (same as CI workflow did)
VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]*' app/core/version.py || echo "")
if [ -z "${VERSION}" ]; then
# Fallback: try Python import
VERSION=$(python -c "import sys; sys.path.insert(0, '.'); from app.core.version import __version__; print(__version__)" 2>/dev/null || echo "")
fi
if [ -z "${VERSION}" ]; then
echo "Error: Could not read version from version.py"
exit 1
fi
echo "TAG_NAME=${VERSION}" >> $GITHUB_OUTPUT
echo "Tag from version.py: ${VERSION}"
else
# If triggered by tag push, get from GITHUB_REF
TAG_NAME=${GITHUB_REF#refs/tags/}
echo "TAG_NAME=${TAG_NAME}" >> $GITHUB_OUTPUT
echo "Current tag from push: ${TAG_NAME}"
fi

- name: Checkout tag commit
run: |
TAG_NAME="${{ steps.get-tag.outputs.TAG_NAME }}"
git checkout ${TAG_NAME} || git checkout -b temp-${TAG_NAME} ${TAG_NAME}
echo "Checked out tag: ${TAG_NAME}"

- name: Run Python script to generate release notes
id: generate_release_notes
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CURRENT_TAG: ${{ steps.get-tag.outputs.TAG_NAME }}
run: |
echo "Running generate_release_notes.py"
python scripts/generate_release_notes.py
echo "Script completed"

- name: Debug Outputs
run: |
echo "Version: ${{ steps.generate_release_notes.outputs.version }}"
echo "Release Notes: ${{ steps.generate_release_notes.outputs.release_notes }}"

- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.get-tag.outputs.TAG_NAME }}
release_name: Release ${{ steps.get-tag.outputs.TAG_NAME }} - ${{ steps.generate_release_notes.outputs.version_name }}
body: ${{ steps.generate_release_notes.outputs.release_notes }}
draft: false
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') }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ Thumbs.db
# Logs
logs/
*.log

# python notebooks
*/ipynb_checkpoints/
*.ipynb
28 changes: 12 additions & 16 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
# Use Python 3.11 slim image as base
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1

# Install system dependencies
RUN apt-get update && apt-get install -y \
gcc \
gcc curl ca-certificates\
&& rm -rf /var/lib/apt/lists/*

# Copy requirements first for better caching
COPY requirements.txt .
# Download the latest installer
ADD https://astral.sh/uv/install.sh /uv-installer.sh

# Run the installer then remove it
RUN sh /uv-installer.sh && rm /uv-installer.sh

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

# Copy application code (including static files)
COPY app/ ./app/
COPY static/ ./static/
COPY main.py .
COPY pyproject.toml .
COPY uv.lock .

RUN uv sync --locked

ENTRYPOINT ["python", "main.py"]
ENTRYPOINT ["uv", "run", "main.py"]
Loading