chore: rename remaining subfeed references to siftlode
Replace the leftover 'subfeed' name across logger names + log_config, frontend localStorage keys, Postgres user/db/volume defaults in the compose files, .env.example, config.py, backup/restore scripts and the README. Pure rename; no behavioural change. localStorage keys move from subfeed.* to siftlode.* (one-time UI-state reset is acceptable).
This commit is contained in:
parent
f13e51fdc8
commit
ebcb5144b6
31 changed files with 67 additions and 67 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
# ---- Copy this file to .env and fill in the values ----
|
# ---- Copy this file to .env and fill in the values ----
|
||||||
|
|
||||||
# Postgres (used by docker-compose for the db service and the DATABASE_URL)
|
# Postgres (used by docker-compose for the db service and the DATABASE_URL)
|
||||||
POSTGRES_USER=subfeed
|
POSTGRES_USER=siftlode
|
||||||
POSTGRES_PASSWORD=change-this-password
|
POSTGRES_PASSWORD=change-this-password
|
||||||
POSTGRES_DB=subfeed
|
POSTGRES_DB=siftlode
|
||||||
|
|
||||||
# Host port the app is exposed on (http://localhost:<APP_PORT>)
|
# Host port the app is exposed on (http://localhost:<APP_PORT>)
|
||||||
APP_PORT=8080
|
APP_PORT=8080
|
||||||
|
|
@ -51,7 +51,7 @@ SMTP_FROM=
|
||||||
# --- Deployment role ---
|
# --- Deployment role ---
|
||||||
# DATABASE_URL is set automatically by docker-compose.yml / docker-compose.server.yml to the
|
# DATABASE_URL is set automatically by docker-compose.yml / docker-compose.server.yml to the
|
||||||
# bundled `db` service. Override it only for local dev against the central server DB, e.g.:
|
# bundled `db` service. Override it only for local dev against the central server DB, e.g.:
|
||||||
# DATABASE_URL=postgresql+psycopg://subfeed:<password>@your-db-host:5432/subfeed
|
# DATABASE_URL=postgresql+psycopg://siftlode:<password>@your-db-host:5432/siftlode
|
||||||
# Exactly one instance may run the background scheduler. The central server keeps it on; every
|
# Exactly one instance may run the background scheduler. The central server keeps it on; every
|
||||||
# other instance (local dev, etc.) must set SCHEDULER_ENABLED=false. The compose files set this
|
# other instance (local dev, etc.) must set SCHEDULER_ENABLED=false. The compose files set this
|
||||||
# for you (server=true via docker-compose.server.yml, local=false via docker-compose.localdev.yml).
|
# for you (server=true via docker-compose.server.yml, local=false via docker-compose.localdev.yml).
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ sync.
|
||||||
depend on a refresh token (which expires after 7 days while the OAuth screen is in *Testing*).
|
depend on a refresh token (which expires after 7 days while the OAuth screen is in *Testing*).
|
||||||
|
|
||||||
- **Local dev** (`docker-compose.localdev.yml`): webapp only, no local DB, no scheduler. In `.env`
|
- **Local dev** (`docker-compose.localdev.yml`): webapp only, no local DB, no scheduler. In `.env`
|
||||||
set `DATABASE_URL` to the central DB (e.g. `…@your-db-host:5432/subfeed`), then
|
set `DATABASE_URL` to the central DB (e.g. `…@your-db-host:5432/siftlode`), then
|
||||||
`docker compose -f docker-compose.localdev.yml up --build` and browse http://localhost:8080.
|
`docker compose -f docker-compose.localdev.yml up --build` and browse http://localhost:8080.
|
||||||
|
|
||||||
**Exactly one instance may run the scheduler.** The server keeps `SCHEDULER_ENABLED=true`; every
|
**Exactly one instance may run the scheduler.** The server keeps `SCHEDULER_ENABLED=true`; every
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ BASE_SCOPES = "openid email profile"
|
||||||
READ_SCOPES = f"{BASE_SCOPES} {READ_SCOPE}"
|
READ_SCOPES = f"{BASE_SCOPES} {READ_SCOPE}"
|
||||||
WRITE_SCOPES = f"{BASE_SCOPES} {READ_SCOPE} {WRITE_SCOPE}"
|
WRITE_SCOPES = f"{BASE_SCOPES} {READ_SCOPE} {WRITE_SCOPE}"
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.auth")
|
log = logging.getLogger("siftlode.auth")
|
||||||
|
|
||||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class Settings(BaseSettings):
|
||||||
git_sha: str = "unknown"
|
git_sha: str = "unknown"
|
||||||
build_date: str = ""
|
build_date: str = ""
|
||||||
|
|
||||||
database_url: str = "postgresql+psycopg://subfeed:subfeed@db:5432/subfeed"
|
database_url: str = "postgresql+psycopg://siftlode:siftlode@db:5432/siftlode"
|
||||||
|
|
||||||
# Session cookie signing key.
|
# Session cookie signing key.
|
||||||
secret_key: str = _DEFAULT_SECRET_KEY
|
secret_key: str = _DEFAULT_SECRET_KEY
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ from app import sysconfig
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
from app.db import SessionLocal
|
from app.db import SessionLocal
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.email")
|
log = logging.getLogger("siftlode.email")
|
||||||
|
|
||||||
|
|
||||||
def _smtp() -> dict:
|
def _smtp() -> dict:
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,20 @@ from pathlib import Path
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
|
|
||||||
# When started via uvicorn --log-config the "subfeed" logger is already configured
|
# When started via uvicorn --log-config the "siftlode" logger is already configured
|
||||||
# (see log_config.json). This block is a timestamped fallback for other entrypoints
|
# (see log_config.json). This block is a timestamped fallback for other entrypoints
|
||||||
# (tests, scripts) so our logs are never silently dropped.
|
# (tests, scripts) so our logs are never silently dropped.
|
||||||
_subfeed_logger = logging.getLogger("subfeed")
|
_siftlode_logger = logging.getLogger("siftlode")
|
||||||
if not _subfeed_logger.handlers:
|
if not _siftlode_logger.handlers:
|
||||||
_handler = logging.StreamHandler(sys.stdout)
|
_handler = logging.StreamHandler(sys.stdout)
|
||||||
_handler.setFormatter(
|
_handler.setFormatter(
|
||||||
logging.Formatter("%(asctime)s %(levelname)-5s [%(name)s] %(message)s")
|
logging.Formatter("%(asctime)s %(levelname)-5s [%(name)s] %(message)s")
|
||||||
)
|
)
|
||||||
_subfeed_logger.addHandler(_handler)
|
_siftlode_logger.addHandler(_handler)
|
||||||
_subfeed_logger.setLevel(logging.INFO)
|
_siftlode_logger.setLevel(logging.INFO)
|
||||||
_subfeed_logger.propagate = False
|
_siftlode_logger.propagate = False
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.app")
|
log = logging.getLogger("siftlode.app")
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import FileResponse, JSONResponse
|
from fastapi.responses import FileResponse, JSONResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ from app.youtube.client import YouTubeClient, YouTubeError
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/channels", tags=["channels"])
|
router = APIRouter(prefix="/api/channels", tags=["channels"])
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.api")
|
log = logging.getLogger("siftlode.api")
|
||||||
|
|
||||||
|
|
||||||
@router.get("")
|
@router.get("")
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ from app.sync.runner import (
|
||||||
run_subscription_resync,
|
run_subscription_resync,
|
||||||
)
|
)
|
||||||
|
|
||||||
logger = logging.getLogger("subfeed.scheduler")
|
logger = logging.getLogger("siftlode.scheduler")
|
||||||
|
|
||||||
_scheduler: BackgroundScheduler | None = None
|
_scheduler: BackgroundScheduler | None = None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from sqlalchemy.orm import Session
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
from app.models import AppState
|
from app.models import AppState
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.state")
|
log = logging.getLogger("siftlode.state")
|
||||||
|
|
||||||
# Bounds for the admin-set maintenance re-validation batch (videos re-checked per run).
|
# Bounds for the admin-set maintenance re-validation batch (videos re-checked per run).
|
||||||
MAINTENANCE_BATCH_MIN = 100
|
MAINTENANCE_BATCH_MIN = 100
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import re
|
||||||
from sqlalchemy import and_, exists, func, select
|
from sqlalchemy import and_, exists, func, select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.autotag")
|
log = logging.getLogger("siftlode.autotag")
|
||||||
|
|
||||||
from app import progress, sysconfig
|
from app import progress, sysconfig
|
||||||
from app.models import Channel, ChannelTag, Tag, Video
|
from app.models import Channel, ChannelTag, Tag, Video
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ from app.sync.runner import get_service_user
|
||||||
from app.sync.videos import apply_video_details, parse_dt
|
from app.sync.videos import apply_video_details, parse_dt
|
||||||
from app.youtube.client import YouTubeClient
|
from app.youtube.client import YouTubeClient
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.maintenance")
|
log = logging.getLogger("siftlode.maintenance")
|
||||||
|
|
||||||
# Reasons recorded on Video.unavailable_reason. "removed" = absent from videos.list
|
# Reasons recorded on Video.unavailable_reason. "removed" = absent from videos.list
|
||||||
# (deleted or made private); "abandoned" = an upcoming premiere that never went live.
|
# (deleted or made private); "abandoned" = an upcoming premiere that never went live.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ from app.models import Channel, OAuthToken, Playlist, PlaylistItem, User, Video
|
||||||
from app.sync.videos import apply_video_details, parse_dt
|
from app.sync.videos import apply_video_details, parse_dt
|
||||||
from app.youtube.client import YouTubeClient, YouTubeError
|
from app.youtube.client import YouTubeClient, YouTubeError
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.sync")
|
log = logging.getLogger("siftlode.sync")
|
||||||
|
|
||||||
# Cost of a single YouTube write op (playlists/playlistItems insert/update/delete).
|
# Cost of a single YouTube write op (playlists/playlistItems insert/update/delete).
|
||||||
WRITE_UNIT_COST = 50
|
WRITE_UNIT_COST = 50
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from app import progress, quota, sysconfig
|
from app import progress, quota, sysconfig
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.sync")
|
log = logging.getLogger("siftlode.sync")
|
||||||
from app.models import Channel, OAuthToken, Subscription, User
|
from app.models import Channel, OAuthToken, Subscription, User
|
||||||
from app.sync.subscriptions import import_subscriptions
|
from app.sync.subscriptions import import_subscriptions
|
||||||
from app.sync.videos import (
|
from app.sync.videos import (
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from sqlalchemy.orm import Session
|
||||||
from app.models import Channel, Subscription, User
|
from app.models import Channel, Subscription, User
|
||||||
from app.youtube.client import YouTubeClient, best_thumbnail
|
from app.youtube.client import YouTubeClient, best_thumbnail
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.sync")
|
log = logging.getLogger("siftlode.sync")
|
||||||
|
|
||||||
|
|
||||||
def _to_int(value) -> int | None:
|
def _to_int(value) -> int | None:
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ from app.config import settings
|
||||||
from app.models import User
|
from app.models import User
|
||||||
from app.security import decrypt
|
from app.security import decrypt
|
||||||
|
|
||||||
log = logging.getLogger("subfeed.youtube")
|
log = logging.getLogger("siftlode.youtube")
|
||||||
|
|
||||||
GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token"
|
GOOGLE_TOKEN_URL = "https://oauth2.googleapis.com/token"
|
||||||
API_BASE = "https://www.googleapis.com/youtube/v3"
|
API_BASE = "https://www.googleapis.com/youtube/v3"
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,6 @@
|
||||||
"uvicorn": { "handlers": ["default"], "level": "INFO", "propagate": false },
|
"uvicorn": { "handlers": ["default"], "level": "INFO", "propagate": false },
|
||||||
"uvicorn.error": { "handlers": ["default"], "level": "INFO", "propagate": false },
|
"uvicorn.error": { "handlers": ["default"], "level": "INFO", "propagate": false },
|
||||||
"uvicorn.access": { "handlers": ["access"], "level": "INFO", "propagate": false },
|
"uvicorn.access": { "handlers": ["access"], "level": "INFO", "propagate": false },
|
||||||
"subfeed": { "handlers": ["plain"], "level": "INFO", "propagate": false }
|
"siftlode": { "handlers": ["plain"], "level": "INFO", "propagate": false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,15 @@ services:
|
||||||
db:
|
db:
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-subfeed}
|
POSTGRES_USER: ${POSTGRES_USER:-siftlode}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-subfeed}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-siftlode}
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-subfeed}
|
POSTGRES_DB: ${POSTGRES_DB:-siftlode}
|
||||||
volumes:
|
volumes:
|
||||||
- pgdata:/var/lib/postgresql/data
|
- pgdata:/var/lib/postgresql/data
|
||||||
security_opt:
|
security_opt:
|
||||||
- apparmor:unconfined
|
- apparmor:unconfined
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-subfeed} -d ${POSTGRES_DB:-subfeed}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-siftlode} -d ${POSTGRES_DB:-siftlode}"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
|
|
@ -40,7 +40,7 @@ services:
|
||||||
env_file: .env
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
# Own local database (overrides whatever DATABASE_URL is in .env).
|
# Own local database (overrides whatever DATABASE_URL is in .env).
|
||||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-subfeed}:${POSTGRES_PASSWORD:-subfeed}@db:5432/${POSTGRES_DB:-subfeed}
|
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-siftlode}:${POSTGRES_PASSWORD:-siftlode}@db:5432/${POSTGRES_DB:-siftlode}
|
||||||
# This instance owns its scheduler now (its own DB, so no double-write concern).
|
# This instance owns its scheduler now (its own DB, so no double-write concern).
|
||||||
SCHEDULER_ENABLED: "true"
|
SCHEDULER_ENABLED: "true"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
|
||||||
|
|
@ -16,18 +16,18 @@ services:
|
||||||
db:
|
db:
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-subfeed}
|
POSTGRES_USER: ${POSTGRES_USER:-siftlode}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in the env file}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set in the env file}
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-subfeed}
|
POSTGRES_DB: ${POSTGRES_DB:-siftlode}
|
||||||
volumes:
|
volumes:
|
||||||
- subfeed_pgdata:/var/lib/postgresql/data
|
- siftlode_pgdata:/var/lib/postgresql/data
|
||||||
networks: [internal]
|
networks: [internal]
|
||||||
mem_limit: 512m
|
mem_limit: 512m
|
||||||
cpus: 0.75
|
cpus: 0.75
|
||||||
security_opt:
|
security_opt:
|
||||||
- no-new-privileges:true
|
- no-new-privileges:true
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-subfeed} -d ${POSTGRES_DB:-subfeed}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-siftlode} -d ${POSTGRES_DB:-siftlode}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
|
|
@ -41,7 +41,7 @@ services:
|
||||||
env_file:
|
env_file:
|
||||||
- /srv/siftlode/.env
|
- /srv/siftlode/.env
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-subfeed}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-subfeed}
|
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-siftlode}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-siftlode}
|
||||||
# The public instance owns the background scheduler (single writer).
|
# The public instance owns the background scheduler (single writer).
|
||||||
SCHEDULER_ENABLED: "true"
|
SCHEDULER_ENABLED: "true"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
@ -70,7 +70,7 @@ services:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
subfeed_pgdata:
|
siftlode_pgdata:
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
internal:
|
internal:
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,16 @@ services:
|
||||||
db:
|
db:
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-subfeed}
|
POSTGRES_USER: ${POSTGRES_USER:-siftlode}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set (run install.sh)}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set (run install.sh)}
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-subfeed}
|
POSTGRES_DB: ${POSTGRES_DB:-siftlode}
|
||||||
volumes:
|
volumes:
|
||||||
- siftlode_pgdata:/var/lib/postgresql/data
|
- siftlode_pgdata:/var/lib/postgresql/data
|
||||||
networks: [internal]
|
networks: [internal]
|
||||||
security_opt:
|
security_opt:
|
||||||
- no-new-privileges:true
|
- no-new-privileges:true
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-subfeed} -d ${POSTGRES_DB:-subfeed}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-siftlode} -d ${POSTGRES_DB:-siftlode}"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
|
|
@ -34,7 +34,7 @@ services:
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-subfeed}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-subfeed}
|
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-siftlode}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-siftlode}
|
||||||
# This instance owns the background scheduler (single writer).
|
# This instance owns the background scheduler (single writer).
|
||||||
SCHEDULER_ENABLED: "true"
|
SCHEDULER_ENABLED: "true"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
# export COMPOSE_FILE=docker-compose.server.yml # or put it in .env
|
# export COMPOSE_FILE=docker-compose.server.yml # or put it in .env
|
||||||
# docker compose up -d --build
|
# docker compose up -d --build
|
||||||
#
|
#
|
||||||
# Postgres data lives in ./pgdata (a host-visible bind mount under /docker/subfeed)
|
# Postgres data lives in ./pgdata (a host-visible bind mount under /docker/siftlode)
|
||||||
# so it is covered by the host's /docker backups; logical pg_dump backups via
|
# so it is covered by the host's /docker backups; logical pg_dump backups via
|
||||||
# scripts/backup.sh remain the portable mechanism for moving between hosts.
|
# scripts/backup.sh remain the portable mechanism for moving between hosts.
|
||||||
|
|
||||||
|
|
@ -18,9 +18,9 @@ services:
|
||||||
db:
|
db:
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-subfeed}
|
POSTGRES_USER: ${POSTGRES_USER:-siftlode}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-subfeed}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-siftlode}
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-subfeed}
|
POSTGRES_DB: ${POSTGRES_DB:-siftlode}
|
||||||
volumes:
|
volumes:
|
||||||
- ./pgdata:/var/lib/postgresql/data
|
- ./pgdata:/var/lib/postgresql/data
|
||||||
ports:
|
ports:
|
||||||
|
|
@ -31,7 +31,7 @@ services:
|
||||||
security_opt:
|
security_opt:
|
||||||
- apparmor:unconfined
|
- apparmor:unconfined
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-subfeed} -d ${POSTGRES_DB:-subfeed}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-siftlode} -d ${POSTGRES_DB:-siftlode}"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
|
|
@ -47,7 +47,7 @@ services:
|
||||||
BUILD_DATE: ${BUILD_DATE:-}
|
BUILD_DATE: ${BUILD_DATE:-}
|
||||||
env_file: .env
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-subfeed}:${POSTGRES_PASSWORD:-subfeed}@db:5432/${POSTGRES_DB:-subfeed}
|
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-siftlode}:${POSTGRES_PASSWORD:-siftlode}@db:5432/${POSTGRES_DB:-siftlode}
|
||||||
# This instance owns the background sync. Keep it true here and false everywhere else.
|
# This instance owns the background sync. Keep it true here and false everywhere else.
|
||||||
SCHEDULER_ENABLED: "true"
|
SCHEDULER_ENABLED: "true"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ services:
|
||||||
db:
|
db:
|
||||||
image: postgres:16-alpine
|
image: postgres:16-alpine
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: ${POSTGRES_USER:-subfeed}
|
POSTGRES_USER: ${POSTGRES_USER:-siftlode}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-subfeed}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-siftlode}
|
||||||
POSTGRES_DB: ${POSTGRES_DB:-subfeed}
|
POSTGRES_DB: ${POSTGRES_DB:-siftlode}
|
||||||
volumes:
|
volumes:
|
||||||
- pgdata:/var/lib/postgresql/data
|
- pgdata:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-subfeed} -d ${POSTGRES_DB:-subfeed}"]
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-siftlode} -d ${POSTGRES_DB:-siftlode}"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 12
|
retries: 12
|
||||||
|
|
@ -24,7 +24,7 @@ services:
|
||||||
BUILD_DATE: ${BUILD_DATE:-}
|
BUILD_DATE: ${BUILD_DATE:-}
|
||||||
env_file: .env
|
env_file: .env
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-subfeed}:${POSTGRES_PASSWORD:-subfeed}@db:5432/${POSTGRES_DB:-subfeed}
|
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-siftlode}:${POSTGRES_PASSWORD:-siftlode}@db:5432/${POSTGRES_DB:-siftlode}
|
||||||
depends_on:
|
depends_on:
|
||||||
db:
|
db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,9 @@ const DEFAULT_FILTERS: FeedFilters = {
|
||||||
show: "unwatched",
|
show: "unwatched",
|
||||||
};
|
};
|
||||||
|
|
||||||
const FILTERS_KEY = "subfeed.filters";
|
const FILTERS_KEY = "siftlode.filters";
|
||||||
const PAGE_KEY = "siftlode.page";
|
const PAGE_KEY = "siftlode.page";
|
||||||
const PERF_KEY = "subfeed.perfMode";
|
const PERF_KEY = "siftlode.perfMode";
|
||||||
|
|
||||||
// The preferences edited on the Settings page. They apply locally for instant preview but
|
// The preferences edited on the Settings page. They apply locally for instant preview but
|
||||||
// persist to the server only on an explicit Save — so App holds both the live "draft" (the
|
// persist to the server only on an explicit Save — so App holds both the live "draft" (the
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// App-wide "hints" toggle: when on, Tooltip components reveal short explanatory
|
// App-wide "hints" toggle: when on, Tooltip components reveal short explanatory
|
||||||
// captions on hover so the UI is somewhat self-documenting for new users. Experienced
|
// captions on hover so the UI is somewhat self-documenting for new users. Experienced
|
||||||
// users can turn it off in Settings. Persisted to localStorage (+ server preferences).
|
// users can turn it off in Settings. Persisted to localStorage (+ server preferences).
|
||||||
const KEY = "subfeed.hints";
|
const KEY = "siftlode.hints";
|
||||||
|
|
||||||
let enabled = load();
|
let enabled = load();
|
||||||
let listeners: Array<() => void> = [];
|
let listeners: Array<() => void> = [];
|
||||||
|
|
|
||||||
|
|
@ -71,8 +71,8 @@ export interface NotifyInput {
|
||||||
transient?: boolean; // live status: sticky toast, not persisted (see Notification.transient)
|
transient?: boolean; // live status: sticky toast, not persisted (see Notification.transient)
|
||||||
}
|
}
|
||||||
|
|
||||||
const HISTORY_KEY = "subfeed.notifications";
|
const HISTORY_KEY = "siftlode.notifications";
|
||||||
const SETTINGS_KEY = "subfeed.notifSettings";
|
const SETTINGS_KEY = "siftlode.notifSettings";
|
||||||
const MAX_HISTORY = 100;
|
const MAX_HISTORY = 100;
|
||||||
const ERROR_TTL = 15000;
|
const ERROR_TTL = 15000;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@
|
||||||
// suppresses the auto-popup on future logins (they
|
// suppresses the auto-popup on future logins (they
|
||||||
// can still reopen it from Settings → Account).
|
// can still reopen it from Settings → Account).
|
||||||
|
|
||||||
export const ONBOARD_ACTIVE = "subfeed.onboarding.active";
|
export const ONBOARD_ACTIVE = "siftlode.onboarding.active";
|
||||||
export const ONBOARD_DISMISSED = "subfeed.onboarding.dismissed";
|
export const ONBOARD_DISMISSED = "siftlode.onboarding.dismissed";
|
||||||
|
|
||||||
export function shouldAutoOpenOnboarding(me: {
|
export function shouldAutoOpenOnboarding(me: {
|
||||||
can_read: boolean;
|
can_read: boolean;
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export const DEFAULT_LAYOUT: SidebarLayout = {
|
||||||
hidden: {},
|
hidden: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const KEY = "subfeed.sidebarLayout";
|
const KEY = "siftlode.sidebarLayout";
|
||||||
|
|
||||||
// Tolerate stale/partial data: keep only known widgets and append any that are missing
|
// Tolerate stale/partial data: keep only known widgets and append any that are missing
|
||||||
// (e.g. a widget added in a later version) so nothing silently disappears.
|
// (e.g. a widget added in a later version) so nothing silently disappears.
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export function applyTheme(t: ThemePrefs): void {
|
||||||
el.style.setProperty("--font-scale", String(t.fontScale));
|
el.style.setProperty("--font-scale", String(t.fontScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
const KEY = "subfeed.theme";
|
const KEY = "siftlode.theme";
|
||||||
|
|
||||||
export function loadLocalTheme(): ThemePrefs {
|
export function loadLocalTheme(): ThemePrefs {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# Dumps the Siftlode Postgres database to backupssiftlode-<timestamp>.dump (custom format).
|
# Dumps the Siftlode Postgres database to backupssiftlode-<timestamp>.dump (custom format).
|
||||||
# Run from the project root: .\scripts\backup.ps1
|
# Run from the project root: .\scripts\backup.ps1
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
$user = if ($env:POSTGRES_USER) { $env:POSTGRES_USER } else { "subfeed" }
|
$user = if ($env:POSTGRES_USER) { $env:POSTGRES_USER } else { "siftlode" }
|
||||||
$dbname = if ($env:POSTGRES_DB) { $env:POSTGRES_DB } else { "subfeed" }
|
$dbname = if ($env:POSTGRES_DB) { $env:POSTGRES_DB } else { "siftlode" }
|
||||||
New-Item -ItemType Directory -Force -Path "backups" | Out-Null
|
New-Item -ItemType Directory -Force -Path "backups" | Out-Null
|
||||||
$ts = Get-Date -Format "yyyyMMdd-HHmmss"
|
$ts = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||||
$out = "backups\siftlode-$ts.dump"
|
$out = "backups\siftlode-$ts.dump"
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
# Dumps the Siftlode Postgres database to backups/siftlode-<timestamp>.dump (custom format).
|
# Dumps the Siftlode Postgres database to backups/siftlode-<timestamp>.dump (custom format).
|
||||||
# Run from the project root: ./scripts/backup.sh
|
# Run from the project root: ./scripts/backup.sh
|
||||||
set -e
|
set -e
|
||||||
USER_NAME="${POSTGRES_USER:-subfeed}"
|
USER_NAME="${POSTGRES_USER:-siftlode}"
|
||||||
DB_NAME="${POSTGRES_DB:-subfeed}"
|
DB_NAME="${POSTGRES_DB:-siftlode}"
|
||||||
mkdir -p backups
|
mkdir -p backups
|
||||||
TS=$(date +%Y%m%d-%H%M%S)
|
TS=$(date +%Y%m%d-%H%M%S)
|
||||||
OUT="backups/siftlode-$TS.dump"
|
OUT="backups/siftlode-$TS.dump"
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
# Usage: .\scripts\restore.ps1 backupssiftlode-YYYYMMDD-HHMMSS.dump
|
# Usage: .\scripts\restore.ps1 backupssiftlode-YYYYMMDD-HHMMSS.dump
|
||||||
param([Parameter(Mandatory = $true)][string]$DumpFile)
|
param([Parameter(Mandatory = $true)][string]$DumpFile)
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
$user = if ($env:POSTGRES_USER) { $env:POSTGRES_USER } else { "subfeed" }
|
$user = if ($env:POSTGRES_USER) { $env:POSTGRES_USER } else { "siftlode" }
|
||||||
$dbname = if ($env:POSTGRES_DB) { $env:POSTGRES_DB } else { "subfeed" }
|
$dbname = if ($env:POSTGRES_DB) { $env:POSTGRES_DB } else { "siftlode" }
|
||||||
if (-not (Test-Path $DumpFile)) { throw "Dump file not found: $DumpFile" }
|
if (-not (Test-Path $DumpFile)) { throw "Dump file not found: $DumpFile" }
|
||||||
Get-Content -Encoding Byte $DumpFile | docker compose exec -T db pg_restore -U $user -d $dbname --clean --if-exists
|
Get-Content -Encoding Byte $DumpFile | docker compose exec -T db pg_restore -U $user -d $dbname --clean --if-exists
|
||||||
Write-Output "Restored $DumpFile"
|
Write-Output "Restored $DumpFile"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ set -e
|
||||||
FILE="$1"
|
FILE="$1"
|
||||||
if [ -z "$FILE" ]; then echo "Usage: restore.sh <dumpfile>"; exit 1; fi
|
if [ -z "$FILE" ]; then echo "Usage: restore.sh <dumpfile>"; exit 1; fi
|
||||||
if [ ! -f "$FILE" ]; then echo "Dump file not found: $FILE"; exit 1; fi
|
if [ ! -f "$FILE" ]; then echo "Dump file not found: $FILE"; exit 1; fi
|
||||||
USER_NAME="${POSTGRES_USER:-subfeed}"
|
USER_NAME="${POSTGRES_USER:-siftlode}"
|
||||||
DB_NAME="${POSTGRES_DB:-subfeed}"
|
DB_NAME="${POSTGRES_DB:-siftlode}"
|
||||||
docker compose exec -T db pg_restore -U "$USER_NAME" -d "$DB_NAME" --clean --if-exists < "$FILE"
|
docker compose exec -T db pg_restore -U "$USER_NAME" -d "$DB_NAME" --clean --if-exists < "$FILE"
|
||||||
echo "Restored $FILE"
|
echo "Restored $FILE"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue