Skip to content

Commit 94ddecc

Browse files
Merge branch 'main' of github.com:TimilsinaBimal/Watchly into dev
2 parents 834ba18 + e1dfb74 commit 94ddecc

File tree

13 files changed

+68
-39
lines changed

13 files changed

+68
-39
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ jobs:
3838
- name: Build and Push Docker image
3939
working-directory: "./"
4040
run: |
41-
docker build -t ghcr.io/${{ github.repository }}:${{ steps.set-tag.outputs.IMAGE_TAG }} .
42-
docker push ghcr.io/${{ github.repository }}:${{ steps.set-tag.outputs.IMAGE_TAG }}
41+
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 }}

app/api/endpoints/catalogs.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from app.services.catalog_updater import refresh_catalogs_for_credentials
55
from app.services.recommendation_service import RecommendationService
66
from app.services.stremio_service import StremioService
7-
from app.utils import resolve_user_credentials
7+
from app.utils import redact_token, resolve_user_credentials
88

99
router = APIRouter()
1010

@@ -32,7 +32,7 @@ async def get_catalog(
3232
detail="Missing credentials token. Please open Watchly from a configured manifest URL.",
3333
)
3434

35-
logger.info(f"Fetching catalog for {type} with id {id}")
35+
logger.info(f"[{redact_token(token)}] Fetching catalog for {type} with id {id}")
3636

3737
credentials = await resolve_user_credentials(token)
3838

@@ -84,7 +84,7 @@ async def get_catalog(
8484
except HTTPException:
8585
raise
8686
except Exception as e:
87-
logger.error(f"Error fetching catalog for {type}/{id}: {e}", exc_info=True)
87+
logger.error(f"[{redact_token(token)}] Error fetching catalog for {type}/{id}: {e}", exc_info=True)
8888
raise HTTPException(status_code=500, detail=str(e))
8989

9090

@@ -96,7 +96,7 @@ async def update_catalogs(token: str):
9696
# Decode credentials from path
9797
credentials = await resolve_user_credentials(token)
9898

99-
logger.info("Updating catalogs in response to manual request")
99+
logger.info(f"[{redact_token(token)}] Updating catalogs in response to manual request")
100100
updated = await refresh_catalogs_for_credentials(credentials)
101101
logger.info(f"Manual catalog update completed: {updated}")
102102
return {"success": updated}

app/api/endpoints/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
def get_base_manifest():
1414
return {
1515
"id": settings.ADDON_ID,
16-
"version": "0.1.1",
16+
"version": settings.APP_VERSION,
1717
"name": settings.ADDON_NAME,
1818
"description": "Movie and series recommendations based on your Stremio library",
1919
"logo": "https://raw.githubusercontent.com/TimilsinaBimal/Watchly/refs/heads/main/static/logo.png",

app/api/endpoints/tokens.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from app.services.catalog_updater import refresh_catalogs_for_credentials
99
from app.services.stremio_service import StremioService
1010
from app.services.token_store import token_store
11+
from app.utils import redact_token
1112

1213
router = APIRouter(prefix="/tokens", tags=["tokens"])
1314

@@ -106,6 +107,7 @@ async def create_token(payload: TokenRequest, request: Request) -> TokenResponse
106107

107108
try:
108109
token, created = await token_store.store_payload(payload_to_store)
110+
logger.info(f"[{redact_token(token)}] Token {'created' if created else 'updated'}")
109111
except RuntimeError as exc:
110112
logger.error("Token storage failed: {}", exc)
111113
raise HTTPException(
@@ -123,7 +125,7 @@ async def create_token(payload: TokenRequest, request: Request) -> TokenResponse
123125
try:
124126
await refresh_catalogs_for_credentials(payload_to_store, auth_key=verified_auth_key)
125127
except Exception as exc: # pragma: no cover - remote dependency
126-
logger.error("Initial catalog refresh failed: {}", exc, exc_info=True)
128+
logger.error(f"[{redact_token(token)}] Initial catalog refresh failed: {{}}", exc, exc_info=True)
127129
await token_store.delete_token(token)
128130
raise HTTPException(
129131
status_code=502,

app/core/app.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ async def lifespan(app: FastAPI):
6161
app = FastAPI(
6262
title="Watchly",
6363
description="Stremio catalog addon for movie and series recommendations",
64-
version="0.1.0",
64+
version=settings.APP_VERSION,
6565
lifespan=lifespan,
6666
)
6767

@@ -99,6 +99,8 @@ async def configure_page(token: str | None = None):
9999
if announcement_html:
100100
snippet = '\n <div class="announcement">' f"{announcement_html}" "</div>"
101101
html_content = html_content.replace("<!-- ANNOUNCEMENT_HTML -->", snippet, 1)
102+
# Inject version
103+
html_content = html_content.replace("<!-- APP_VERSION -->", settings.APP_VERSION, 1)
102104
return HTMLResponse(content=html_content, media_type="text/html")
103105
return HTMLResponse(
104106
content="Watchly API is running. Static files not found.",

app/core/config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ class Settings(BaseSettings):
1717
PORT: int = 8000
1818
ADDON_ID: str = "com.bimal.watchly"
1919
ADDON_NAME: str = "Watchly"
20-
REDIS_URL: str = "redis://localhost:6379/0"
20+
APP_VERSION: str = "0.1.3"
21+
REDIS_URL: str = "redis://redis:6379/0"
2122
TOKEN_SALT: str = "change-me"
2223
TOKEN_TTL_SECONDS: int = 0 # 0 = never expire
2324
ANNOUNCEMENT_HTML: str = ""
2425
AUTO_UPDATE_CATALOGS: bool = True
25-
CATALOG_REFRESH_INTERVAL_SECONDS: int = 60 # 6 hours
26+
CATALOG_REFRESH_INTERVAL_SECONDS: int = 6 * 60 * 60 # 6 hours
2627
APP_ENV: Literal["development", "production"] = "development"
2728
HOST_NAME: str = "https://1ccea4301587-watchly.baby-beamup.club"
2829

app/services/catalog_updater.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from app.services.catalog import DynamicCatalogService
99
from app.services.stremio_service import StremioService
1010
from app.services.token_store import token_store
11+
from app.utils import redact_token
1112

1213
# Max number of concurrent updates to prevent overwhelming external APIs
1314
MAX_CONCURRENT_UPDATES = 5
@@ -26,9 +27,9 @@ async def refresh_catalogs_for_credentials(credentials: dict[str, Any], auth_key
2627

2728
catalogs = await dynamic_catalog_service.get_watched_loved_catalogs(library_items=library_items)
2829
catalogs += await dynamic_catalog_service.get_genre_based_catalogs(library_items=library_items)
29-
logger.info(
30-
f"Prepared {len(catalogs)} catalogs for {credentials.get('authKey') or credentials.get('username')}"
31-
)
30+
auth_key_or_username = credentials.get("authKey") or credentials.get("username")
31+
redacted = redact_token(auth_key_or_username) if auth_key_or_username else "unknown"
32+
logger.info(f"[{redacted}] Prepared {len(catalogs)} catalogs")
3233
auth_key = await stremio_service.get_auth_key()
3334
return await stremio_service.update_catalogs(catalogs, auth_key)
3435
finally:

app/services/recommendation_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ async def _fetch_details(tmdb_id: int):
106106

107107
meta_data = {
108108
"id": stremio_id,
109-
"type": media_type,
109+
"type": "series" if media_type in ["tv", "series"] else "movie",
110110
"name": title,
111111
"poster": f"https://image.tmdb.org/t/p/w500{poster_path}" if poster_path else None,
112112
"background": f"https://image.tmdb.org/t/p/original{backdrop_path}" if backdrop_path else None,

app/utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@
55
from app.services.token_store import token_store
66

77

8+
def redact_token(token: str | None, visible_chars: int = 8) -> str:
9+
"""
10+
Redact a token for logging purposes.
11+
Shows first few characters followed by *** for debugging.
12+
13+
Args:
14+
token: The token to redact
15+
visible_chars: Number of characters to show before redaction (default: 8)
16+
17+
Returns:
18+
Redacted token string (e.g., "ksfjads***" or "None" if token is None)
19+
"""
20+
if not token:
21+
return "None"
22+
if len(token) <= visible_chars:
23+
return "***"
24+
return f"{token[:visible_chars]}***"
25+
26+
827
async def resolve_user_credentials(token: str) -> dict[str, Any]:
928
"""Resolve credentials from Redis token."""
1029
if not token:

docker-compose.yml

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,23 @@
11
services:
2+
redis:
3+
image: redis:7-alpine
4+
container_name: watchly-redis
5+
restart: unless-stopped
26
watchly:
37
build:
48
context: .
59
dockerfile: Dockerfile
610
container_name: watchly
711
restart: unless-stopped
812
ports:
9-
- "${PORT:-8000}:8000"
10-
environment:
11-
- TMDB_API_KEY=${TMDB_API_KEY}
12-
- PORT=${PORT:-8000}
13-
- ADDON_ID=${ADDON_ID:-com.bimal.watchly}
14-
- ADDON_NAME=${ADDON_NAME:-Watchly}
15-
- REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
16-
- TOKEN_SALT=${TOKEN_SALT:-change-me}
17-
- TOKEN_TTL_SECONDS=${TOKEN_TTL_SECONDS:-0}
18-
- ANNOUNCEMENT_HTML=${ANNOUNCEMENT_HTML:-}
13+
- "127.0.0.1:8000:8000"
14+
# some macos users need to use 127.0.0.1:8000:8000 to access the app on localhost due to IPV6 issues
1915
env_file:
2016
- .env
17+
environment:
18+
# Override REDIS_URL to use Docker service name instead of localhost
19+
- REDIS_URL=redis://redis:6379/0
2120
volumes:
22-
- ./static:/app/static:ro
23-
networks:
24-
- watchly-network
21+
- ./:/app
2522
depends_on:
2623
- redis
27-
28-
redis:
29-
image: redis:7-alpine
30-
container_name: watchly-redis
31-
restart: unless-stopped
32-
networks:
33-
- watchly-network
34-
35-
networks:
36-
watchly-network:
37-
driver: bridge

0 commit comments

Comments
 (0)