- Detect shorts by duration (SHORTS_MAX_DURATION_SECONDS, default 180)
and expose is_short in feed, video and channel-activity DTOs.
- Feed gains type=all|long|short and anchor; lists show a two-mode
'Обычные | Shorts' filter (no 'Все') persisted in the URL.
- Clicking a short opens /shorts/🆔 a vertical scroll-snap feed with
autoplay for the active slide, context-aware endpoints and infinite
loading.
- Keep the sound choice across swipes, syncing with the player's own
mute control and guarding against the widget's stale isMuted() reads.
55 lines
2.2 KiB
Python
55 lines
2.2 KiB
Python
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
|
|
|
|
app_env: str = "production"
|
|
app_base_url: str = "http://localhost:8080"
|
|
app_port: int = 8080
|
|
app_secret_key: str
|
|
token_encryption_key: str
|
|
|
|
database_url: str
|
|
|
|
google_client_id: str = ""
|
|
google_client_secret: str = ""
|
|
google_redirect_uri: str = ""
|
|
allowed_google_email: str = ""
|
|
|
|
# Google/YouTube endpoints (AGENTS.md rule 12): configurable via env,
|
|
# defaults keep the current behaviour without touching .env.
|
|
google_auth_uri: str = "https://accounts.google.com/o/oauth2/auth"
|
|
google_token_uri: str = "https://oauth2.googleapis.com/token"
|
|
google_userinfo_uri: str = "https://www.googleapis.com/oauth2/v3/userinfo"
|
|
google_revoke_uri: str = "https://oauth2.googleapis.com/revoke"
|
|
youtube_api_base_url: str = "https://www.googleapis.com/youtube/v3"
|
|
youtube_watch_url_template: str = "https://www.youtube.com/watch?v={video_id}"
|
|
|
|
metube_api_base_url: str = "http://127.0.0.1:8081"
|
|
metube_public_base_url: str = "http://127.0.0.1:8081"
|
|
metube_container_download_dir: str = "/downloads"
|
|
metube_request_timeout_seconds: int = 30
|
|
|
|
subscriptions_sync_interval_hours: int = 6
|
|
# Videos sync is no longer scheduled: it is triggered by user activity
|
|
# (any authenticated request) after this much idle time since the last
|
|
# completed sync.
|
|
videos_sync_idle_hours: int = 2
|
|
# Hard history-depth limit per channel per videos sync: at most the
|
|
# newest N playlist items are considered; anything older is never
|
|
# backfilled by design (full channel history is out of scope).
|
|
videos_backfill_cap: int = 200
|
|
# Stop playlistItems pagination for a channel once this many already
|
|
# known video ids are seen in a row (the rest of the playlist is history
|
|
# we have already synced).
|
|
videos_known_stop_threshold: int = 50
|
|
new_videos_window_days: int = 2
|
|
# Videos with a known duration at or below this threshold (seconds) are
|
|
# treated as Shorts; unknown duration (NULL) counts as a regular video.
|
|
shorts_max_duration_seconds: int = 180
|
|
|
|
log_level: str = "INFO"
|
|
|
|
|
|
settings = Settings()
|