SYMBOL INDEX (917 symbols across 31 files) FILE: auth.py function _get_settings_file (line 24) | def _get_settings_file() -> pathlib.Path: function _get_secret_key (line 29) | def _get_secret_key() -> str: function _hash_password (line 41) | def _hash_password(password: str, salt: str | None = None) -> str: function _verify_hashed_password (line 49) | def _verify_hashed_password(password: str, hashed: str) -> bool: function _get_users (line 57) | def _get_users() -> dict[str, dict[str, Any]]: function get_all_usernames (line 69) | def get_all_usernames() -> list[str]: function is_setup_required (line 74) | def is_setup_required() -> bool: function create_user (line 79) | def create_user(username: str, password: str, admin: bool = False) -> None: function _ensure_one_admin (line 97) | def _ensure_one_admin(users: dict[str, dict[str, Any]]) -> None: function delete_user (line 104) | def delete_user(username: str) -> bool: function verify_password (line 120) | def verify_password(username: str, password: str) -> bool: function change_password (line 129) | def change_password(username: str, new_password: str) -> bool: function is_admin (line 144) | def is_admin(username: str) -> bool: function set_admin (line 151) | def set_admin(username: str, admin: bool) -> bool: function get_users_with_admin (line 167) | def get_users_with_admin() -> list[dict[str, Any]]: function get_user_limits (line 181) | def get_user_limits(username: str) -> dict[str, Any]: function set_user_limits (line 191) | def set_user_limits( function create_token (line 213) | def create_token(payload: dict[str, Any]) -> str: function verify_token (line 221) | def verify_token(token: str) -> dict[str, Any] | None: FILE: auth_test.py function auth_module (line 14) | def auth_module(tmp_path: Path): class TestPasswordHashing (line 29) | class TestPasswordHashing: method test_hash_password_creates_salt (line 30) | def test_hash_password_creates_salt(self, auth_module): method test_hash_password_with_salt_deterministic (line 37) | def test_hash_password_with_salt_deterministic(self, auth_module): method test_verify_hashed_password_correct (line 43) | def test_verify_hashed_password_correct(self, auth_module): method test_verify_hashed_password_wrong (line 47) | def test_verify_hashed_password_wrong(self, auth_module): class TestUserManagement (line 52) | class TestUserManagement: method test_is_setup_required_no_users (line 53) | def test_is_setup_required_no_users(self, auth_module): method test_create_user_and_verify (line 56) | def test_create_user_and_verify(self, auth_module): class TestTokens (line 64) | class TestTokens: method test_create_and_verify_token (line 65) | def test_create_and_verify_token(self, auth_module): method test_token_format (line 74) | def test_token_format(self, auth_module): method test_invalid_token_rejected (line 80) | def test_invalid_token_rejected(self, auth_module): method test_tampered_token_rejected (line 85) | def test_tampered_token_rejected(self, auth_module): method test_expired_token_rejected (line 92) | def test_expired_token_rejected(self, auth_module): class TestSecretKey (line 99) | class TestSecretKey: method test_get_secret_key_generates_and_persists (line 100) | def test_get_secret_key_generates_and_persists(self, auth_module): FILE: cache.py function _get_gpu_vendor (line 27) | def _get_gpu_vendor() -> str | None: function _detect_vaapi_device (line 54) | def _detect_vaapi_device() -> str | None: function _detect_libva_driver (line 60) | def _detect_libva_driver() -> str | None: function _detect_dri_path (line 75) | def _detect_dri_path() -> str | None: function _parse_json_file (line 124) | def _parse_json_file(path: str) -> tuple[Any, float] | None: function load_file_cache (line 134) | def load_file_cache(name: str, use_process: bool = False) -> tuple[Any, ... function save_file_cache (line 157) | def save_file_cache(name: str, data: Any) -> None: function clear_all_caches (line 163) | def clear_all_caches() -> None: function clear_all_file_caches (line 172) | def clear_all_file_caches() -> int: function get_cache (line 186) | def get_cache() -> dict[str, Any]: function get_cache_lock (line 191) | def get_cache_lock() -> threading.Lock: function _sanitize_name (line 196) | def _sanitize_name(name: str) -> str: function _url_to_filename (line 204) | def _url_to_filename(url: str) -> str: function get_cached_logo (line 222) | def get_cached_logo(source_name: str, url: str) -> pathlib.Path | None: function save_logo (line 241) | def save_logo(source_name: str, url: str, data: bytes, content_type: str... function get_cached_info (line 264) | def get_cached_info(cache_key: str, fetch_fn: Callable[[], Any], force: ... function _test_encoder (line 311) | def _test_encoder(cmd: list[str], timeout: int = 5, env: dict | None = N... function detect_encoders (line 337) | def detect_encoders() -> dict[str, bool]: function refresh_encoders (line 438) | def refresh_encoders() -> dict[str, bool]: function _default_encoder (line 445) | def _default_encoder() -> str: class Source (line 463) | class Source: function load_server_settings (line 478) | def load_server_settings() -> dict[str, Any]: function save_server_settings (line 512) | def save_server_settings(settings: dict[str, Any]) -> None: function _validate_username (line 517) | def _validate_username(username: str) -> None: function load_user_settings (line 529) | def load_user_settings(username: str) -> dict[str, Any]: function save_user_settings (line 547) | def save_user_settings(username: str, settings: dict[str, Any]) -> None: function get_watch_position (line 555) | def get_watch_position(username: str, stream_url: str) -> dict[str, Any]... function save_watch_position (line 570) | def save_watch_position(username: str, stream_url: str, position: float,... function get_sources (line 586) | def get_sources() -> list[Source]: function update_source_epg_url (line 592) | def update_source_epg_url(source_id: str, epg_url: str) -> None: FILE: cache_test.py function cache_module (line 16) | def cache_module(tmp_path: Path): class TestFileCache (line 40) | class TestFileCache: method test_save_and_load_file_cache (line 41) | def test_save_and_load_file_cache(self, cache_module): method test_load_nonexistent_cache (line 49) | def test_load_nonexistent_cache(self, cache_module): method test_load_corrupted_cache (line 52) | def test_load_corrupted_cache(self, cache_module): class TestMemoryCache (line 58) | class TestMemoryCache: method test_get_cache_returns_reference (line 59) | def test_get_cache_returns_reference(self, cache_module): method test_clear_all_caches_preserves_epg (line 64) | def test_clear_all_caches_preserves_epg(self, cache_module): class TestCachedInfo (line 73) | class TestCachedInfo: method test_get_cached_info_calls_fetch (line 74) | def test_get_cached_info_calls_fetch(self, cache_module): method test_get_cached_info_uses_memory_cache (line 80) | def test_get_cached_info_uses_memory_cache(self, cache_module): method test_get_cached_info_force_bypasses_memory (line 87) | def test_get_cached_info_force_bypasses_memory(self, cache_module): class TestSettings (line 94) | class TestSettings: method test_load_settings_defaults (line 95) | def test_load_settings_defaults(self, cache_module): method test_save_and_load_settings (line 110) | def test_save_and_load_settings(self, cache_module): class TestUserSettings (line 118) | class TestUserSettings: method test_load_user_settings_defaults (line 119) | def test_load_user_settings_defaults(self, cache_module): method test_save_and_load_user_settings (line 125) | def test_save_and_load_user_settings(self, cache_module): method test_watch_position_save_and_get (line 132) | def test_watch_position_save_and_get(self, cache_module): method test_watch_position_resets_at_95_percent (line 139) | def test_watch_position_resets_at_95_percent(self, cache_module): class TestSource (line 146) | class TestSource: method test_source_dataclass (line 147) | def test_source_dataclass(self, cache_module): method test_get_sources_empty (line 159) | def test_get_sources_empty(self, cache_module): method test_get_sources_from_settings (line 163) | def test_get_sources_from_settings(self, cache_module): class TestUpdateSourceEpgUrl (line 181) | class TestUpdateSourceEpgUrl: method test_update_source_epg_url (line 182) | def test_update_source_epg_url(self, cache_module): method test_update_source_epg_url_not_overwrite (line 189) | def test_update_source_epg_url_not_overwrite(self, cache_module): method test_update_source_epg_url_empty_noop (line 206) | def test_update_source_epg_url_empty_noop(self, cache_module): class TestEncoderDetection (line 214) | class TestEncoderDetection: method test_test_encoder_success (line 217) | def test_test_encoder_success(self): method test_test_encoder_failure (line 226) | def test_test_encoder_failure(self): method test_test_encoder_timeout (line 234) | def test_test_encoder_timeout(self): method test_test_encoder_exception (line 242) | def test_test_encoder_exception(self): method test_detect_encoders_all_available (line 250) | def test_detect_encoders_all_available(self): method test_detect_encoders_none_available (line 267) | def test_detect_encoders_none_available(self): method test_detect_encoders_partial (line 278) | def test_detect_encoders_partial(self): method test_detect_encoders_nvenc_only (line 299) | def test_detect_encoders_nvenc_only(self): method test_detect_encoders_vaapi_command_structure (line 314) | def test_detect_encoders_vaapi_command_structure(self): method test_detect_encoders_qsv_command_structure (line 343) | def test_detect_encoders_qsv_command_structure(self): method test_refresh_encoders_updates_global (line 360) | def test_refresh_encoders_updates_global(self): method test_default_encoder_prefers_nvenc_with_vaapi (line 381) | def test_default_encoder_prefers_nvenc_with_vaapi(self): method test_default_encoder_nvenc_without_vaapi (line 395) | def test_default_encoder_nvenc_without_vaapi(self): method test_default_encoder_falls_back_to_amf (line 409) | def test_default_encoder_falls_back_to_amf(self): method test_default_encoder_falls_back_to_qsv (line 423) | def test_default_encoder_falls_back_to_qsv(self): method test_default_encoder_falls_back_to_vaapi (line 437) | def test_default_encoder_falls_back_to_vaapi(self): method test_default_encoder_falls_back_to_software (line 451) | def test_default_encoder_falls_back_to_software(self): class TestLogoCache (line 466) | class TestLogoCache: method test_sanitize_name_removes_path_traversal (line 469) | def test_sanitize_name_removes_path_traversal(self): method test_sanitize_name_keeps_safe_chars (line 474) | def test_sanitize_name_keeps_safe_chars(self): method test_sanitize_name_truncates_long_names (line 478) | def test_sanitize_name_truncates_long_names(self): method test_sanitize_name_empty_returns_default (line 483) | def test_sanitize_name_empty_returns_default(self): method test_url_to_filename_extracts_name (line 487) | def test_url_to_filename_extracts_name(self): method test_url_to_filename_strips_extension (line 492) | def test_url_to_filename_strips_extension(self): method test_url_to_filename_hash_differs_by_url (line 497) | def test_url_to_filename_hash_differs_by_url(self): method test_url_to_filename_fallback_to_hash (line 505) | def test_url_to_filename_fallback_to_hash(self): method test_save_and_get_cached_logo (line 509) | def test_save_and_get_cached_logo(self, cache_module, tmp_path): method test_get_cached_logo_returns_none_when_missing (line 526) | def test_get_cached_logo_returns_none_when_missing(self, cache_module,... method test_get_cached_logo_expires (line 533) | def test_get_cached_logo_expires(self, cache_module, tmp_path): method test_save_logo_content_type_mapping (line 554) | def test_save_logo_content_type_mapping(self, cache_module, tmp_path): FILE: epg.py class Program (line 31) | class Program: function init (line 48) | def init(cache_dir: Path) -> None: function _get_conn (line 80) | def _get_conn() -> sqlite3.Connection: function clear (line 91) | def clear() -> None: function clear_source (line 98) | def clear_source(source_id: str) -> None: function insert_channel (line 106) | def insert_channel(channel_id: str, name: str, source_id: str) -> None: function insert_icon (line 115) | def insert_icon(channel_id: str, url: str) -> None: function insert_programs (line 124) | def insert_programs(programs: list[tuple[str, str, float, float, str, st... function commit (line 133) | def commit() -> None: function get_icon (line 138) | def get_icon(channel_id: str) -> str: function get_programs_in_range (line 145) | def get_programs_in_range( function _dedupe_programs (line 199) | def _dedupe_programs(programs: list[Program], preferred_source_id: str) ... function get_programs_batch (line 219) | def get_programs_batch( function get_icons_batch (line 282) | def get_icons_batch(channel_ids: list[str]) -> dict[str, str]: function has_programs (line 300) | def has_programs() -> bool: function get_program_count (line 307) | def get_program_count() -> int: function get_channel_count (line 314) | def get_channel_count() -> int: function prune_old_programs (line 321) | def prune_old_programs(before: datetime) -> int: function _parse_epg_time (line 334) | def _parse_epg_time(s: str) -> datetime: function _sanitize_epg_xml (line 350) | def _sanitize_epg_xml(xml_str: str) -> str: function fetch_epg (line 362) | def fetch_epg( FILE: epg_test.py function db (line 16) | def db(tmp_path: Path): class TestInit (line 26) | class TestInit: method test_init_creates_tables (line 29) | def test_init_creates_tables(self, db): class TestChannels (line 38) | class TestChannels: method test_insert_channel (line 41) | def test_insert_channel(self, db): method test_insert_channel_upsert (line 50) | def test_insert_channel_upsert(self, db): class TestIcons (line 61) | class TestIcons: method test_insert_icon (line 64) | def test_insert_icon(self, db): method test_get_icon_not_found (line 71) | def test_get_icon_not_found(self, db): method test_get_icons_batch (line 75) | def test_get_icons_batch(self, db): method test_get_icons_batch_empty (line 87) | def test_get_icons_batch_empty(self, db): class TestPrograms (line 92) | class TestPrograms: method test_insert_programs (line 95) | def test_insert_programs(self, db): method test_get_programs_in_range (line 121) | def test_get_programs_in_range(self, db): method test_get_programs_in_range_empty (line 162) | def test_get_programs_in_range_empty(self, db): method test_get_programs_batch (line 167) | def test_get_programs_batch(self, db): method test_get_programs_batch_empty_channels (line 187) | def test_get_programs_batch_empty_channels(self, db): method test_has_programs_false (line 191) | def test_has_programs_false(self, db): method test_has_programs_true (line 194) | def test_has_programs_true(self, db): method test_get_program_count (line 202) | def test_get_program_count(self, db): method test_get_channel_count (line 230) | def test_get_channel_count(self, db): class TestClear (line 240) | class TestClear: method test_clear_all (line 243) | def test_clear_all(self, db): method test_clear_source (line 258) | def test_clear_source(self, db): class TestPrune (line 290) | class TestPrune: method test_prune_old_programs (line 293) | def test_prune_old_programs(self, db): class TestPreferredSource (line 324) | class TestPreferredSource: method test_prefer_source_in_range (line 327) | def test_prefer_source_in_range(self, db): class TestProgram (line 367) | class TestProgram: method test_program_dataclass (line 370) | def test_program_dataclass(self): method test_program_defaults (line 385) | def test_program_defaults(self): FILE: ffmpeg_command.py function _parse_hw (line 30) | def _parse_hw(hw: HwAccel) -> tuple[str, str]: class SubtitleStream (line 124) | class SubtitleStream: class MediaInfo (line 131) | class MediaInfo: function init (line 148) | def init( function get_settings (line 161) | def get_settings() -> dict[str, Any]: function get_ffmpeg_env (line 166) | def get_ffmpeg_env() -> dict[str, str] | None: function _find_sr_engine (line 172) | def _find_sr_engine(model_name: str, source_height: int) -> tuple[str, i... function _build_sr_filter (line 233) | def _build_sr_filter(source_height: int, target_height: int) -> str: function get_hls_segment_duration (line 290) | def get_hls_segment_duration() -> float: function _get_gpu_nvdec_codecs (line 300) | def _get_gpu_nvdec_codecs() -> set[str]: function _has_libplacebo_filter (line 337) | def _has_libplacebo_filter() -> bool: function get_user_agent (line 362) | def get_user_agent() -> str | None: function get_transcode_dir (line 378) | def get_transcode_dir() -> pathlib.Path: function _load_series_probe_cache (line 396) | def _load_series_probe_cache() -> None: function _save_series_probe_cache (line 454) | def _save_series_probe_cache() -> None: function get_series_probe_cache_stats (line 496) | def get_series_probe_cache_stats() -> list[dict[str, Any]]: function clear_all_probe_cache (line 540) | def clear_all_probe_cache() -> int: function invalidate_series_probe_cache (line 552) | def invalidate_series_probe_cache(series_id: int, episode_id: int | None... function clear_series_mru (line 576) | def clear_series_mru(series_id: int) -> None: function restore_probe_cache_entry (line 587) | def restore_probe_cache_entry( function _lang_display_name (line 613) | def _lang_display_name(code: str) -> str: function resolve_hls_master_playlist (line 617) | def resolve_hls_master_playlist(url: str) -> str: function probe_media (line 685) | def probe_media( function _build_video_args (line 913) | def _build_video_args( function _build_audio_args (line 1170) | def _build_audio_args(*, copy_audio: bool, audio_sample_rate: int) -> li... function get_live_hls_list_size (line 1178) | def get_live_hls_list_size() -> int: function build_hls_ffmpeg_cmd (line 1188) | def build_hls_ffmpeg_cmd( FILE: ffmpeg_command_test.py function mock_vaapi_device (line 33) | def mock_vaapi_device(): class FakeMediaInfo (line 39) | class FakeMediaInfo: method __init__ (line 42) | def __init__( class TestBuildVideoArgs (line 74) | class TestBuildVideoArgs: method test_all_hw_combinations (line 83) | def test_all_hw_combinations(self, hw: HwAccel, deinterlace: bool, max... method test_copy_video (line 114) | def test_copy_video(self, hw: HwAccel): method test_nvenc_hw_pipeline_filters (line 127) | def test_nvenc_hw_pipeline_filters(self): method test_nvenc_sw_fallback_filters (line 142) | def test_nvenc_sw_fallback_filters(self): method test_vaapi_filters (line 159) | def test_vaapi_filters(self): method test_qsv_filters (line 173) | def test_qsv_filters(self): method test_software_filters (line 187) | def test_software_filters(self): method test_quality_presets (line 204) | def test_quality_presets(self, quality: str, expected_qp: str): method test_invalid_hw_raises (line 216) | def test_invalid_hw_raises(self): method test_nvenc_hdr_with_libplacebo (line 229) | def test_nvenc_hdr_with_libplacebo(self, mock_placebo): method test_nvenc_hdr_zscale_fallback (line 248) | def test_nvenc_hdr_zscale_fallback(self, mock_placebo): method test_nvenc_hdr_deinterlace_order (line 265) | def test_nvenc_hdr_deinterlace_order(self, mock_placebo): method test_nvenc_sw_hdr_deinterlace_order (line 283) | def test_nvenc_sw_hdr_deinterlace_order(self, mock_placebo): method test_vaapi_hdr_tonemap (line 301) | def test_vaapi_hdr_tonemap(self): class TestBuildAudioArgs (line 321) | class TestBuildAudioArgs: method test_copy_audio (line 324) | def test_copy_audio(self): method test_sample_rates (line 338) | def test_sample_rates(self, sample_rate: int, expected: str): class TestBuildHlsFfmpegCmd (line 350) | class TestBuildHlsFfmpegCmd: method test_command_structure (line 358) | def test_command_structure(self, hw: HwAccel, is_vod: bool): method test_vod_hls_flags (line 384) | def test_vod_hls_flags(self): method test_live_hls_flags (line 392) | def test_live_hls_flags(self): method test_copy_video_with_compatible_media (line 399) | def test_copy_video_with_compatible_media(self): method test_no_copy_for_10bit (line 414) | def test_no_copy_for_10bit(self): method test_no_copy_when_scaling_needed (line 427) | def test_no_copy_when_scaling_needed(self): method test_user_agent (line 440) | def test_user_agent(self): method test_probe_args_without_media_info (line 451) | def test_probe_args_without_media_info(self): method test_no_probe_args_with_media_info (line 457) | def test_no_probe_args_with_media_info(self): method test_subtitle_extraction (line 463) | def test_subtitle_extraction(self): class TestAspectRatioHandling (line 482) | class TestAspectRatioHandling: method test_scaling_decisions (line 496) | def test_scaling_decisions(self, input_height: int, max_res: str, shou... class TestGpuDetection (line 519) | class TestGpuDetection: method test_nvidia_gpu_detected (line 522) | def test_nvidia_gpu_detected(self): method test_no_nvidia_gpu (line 538) | def test_no_nvidia_gpu(self): method test_older_nvidia_gpu (line 551) | def test_older_nvidia_gpu(self): class TestUserAgent (line 573) | class TestUserAgent: method test_default_user_agent (line 576) | def test_default_user_agent(self): method test_vlc_user_agent (line 581) | def test_vlc_user_agent(self): method test_chrome_user_agent (line 588) | def test_chrome_user_agent(self): method test_custom_user_agent (line 595) | def test_custom_user_agent(self): method test_custom_empty_returns_none (line 603) | def test_custom_empty_returns_none(self): class TestTranscodeDir (line 617) | class TestTranscodeDir: method test_default_transcode_dir (line 620) | def test_default_transcode_dir(self): method test_custom_transcode_dir (line 626) | def test_custom_transcode_dir(self, tmp_path): class TestHlsListSize (line 642) | class TestHlsListSize: method test_default_list_size (line 645) | def test_default_list_size(self): method test_dvr_enabled_list_size (line 650) | def test_dvr_enabled_list_size(self): class TestProbeMedia (line 662) | class TestProbeMedia: method test_probe_success (line 665) | def test_probe_success(self): method test_probe_interlaced_detection (line 707) | def test_probe_interlaced_detection(self): method test_probe_10bit_detection (line 751) | def test_probe_10bit_detection(self, pix_fmt: str, expected: bool): method test_probe_hdr_detection (line 792) | def test_probe_hdr_detection(self, color_transfer: str, expected: bool): method test_probe_failure (line 826) | def test_probe_failure(self): method test_probe_cache_hit (line 844) | def test_probe_cache_hit(self): method test_probe_extracts_subtitles (line 868) | def test_probe_extracts_subtitles(self): class TestProbeCacheManagement (line 916) | class TestProbeCacheManagement: method test_clear_all_probe_cache (line 919) | def test_clear_all_probe_cache(self): method test_invalidate_series_probe_cache_entire_series (line 940) | def test_invalidate_series_probe_cache_entire_series(self): method test_invalidate_series_probe_cache_single_episode (line 954) | def test_invalidate_series_probe_cache_single_episode(self): method test_clear_series_mru (line 970) | def test_clear_series_mru(self): method test_restore_probe_cache_entry (line 986) | def test_restore_probe_cache_entry(self): method test_get_series_probe_cache_stats (line 1002) | def test_get_series_probe_cache_stats(self): class TestResolveHlsMasterPlaylist (line 1026) | class TestResolveHlsMasterPlaylist: method test_non_m3u8_url_returns_unchanged (line 1029) | def test_non_m3u8_url_returns_unchanged(self): method test_master_playlist_selects_highest_bandwidth (line 1036) | def test_master_playlist_selects_highest_bandwidth(self): method test_media_playlist_returns_unchanged (line 1060) | def test_media_playlist_returns_unchanged(self): method test_fetch_error_returns_original_url (line 1084) | def test_fetch_error_returns_original_url(self): method test_relative_url_resolved_correctly (line 1095) | def test_relative_url_resolved_correctly(self): FILE: ffmpeg_session.py class _DeadProcess (line 64) | class _DeadProcess: method terminate (line 69) | def terminate(self) -> None: method kill (line 72) | def kill(self) -> None: function get_vod_cache_timeout (line 81) | def get_vod_cache_timeout() -> int: function get_live_cache_timeout (line 86) | def get_live_cache_timeout() -> int: function _is_process_alive (line 96) | def _is_process_alive(proc: Any) -> bool: function is_session_valid (line 107) | def is_session_valid(session: dict[str, Any]) -> bool: function _kill_process (line 133) | def _kill_process(proc: Any) -> bool: function stop_session (line 155) | def stop_session(session_id: str, force: bool = False) -> None: function cleanup_expired_sessions (line 193) | def cleanup_expired_sessions() -> None: function shutdown (line 205) | def shutdown() -> None: function get_user_sessions (line 220) | def get_user_sessions(username: str) -> list[tuple[str, dict[str, Any]]]: function get_source_sessions (line 229) | def get_source_sessions(source_id: str) -> list[tuple[str, dict[str, Any... function enforce_stream_limits (line 238) | def enforce_stream_limits( function cleanup_and_recover_sessions (line 290) | def cleanup_and_recover_sessions() -> None: function _monitor_ffmpeg_stderr (line 419) | async def _monitor_ffmpeg_stderr( function _monitor_resume_ffmpeg (line 437) | async def _monitor_resume_ffmpeg( function _monitor_seek_ffmpeg (line 461) | async def _monitor_seek_ffmpeg( function _spawn_background_task (line 475) | def _spawn_background_task(coro: Any) -> None: function _wait_for_playlist (line 486) | async def _wait_for_playlist( function _calc_hls_duration (line 514) | def _calc_hls_duration(playlist_path: pathlib.Path, segment_count: int) ... function _build_subtitle_tracks (line 523) | def _build_subtitle_tracks( function _regenerate_playlist (line 540) | def _regenerate_playlist(output_dir: pathlib.Path, start_segment: int) -... class _SessionSnapshot (line 581) | class _SessionSnapshot: function _get_session_snapshot (line 591) | def _get_session_snapshot(session_id: str) -> _SessionSnapshot | None: function _update_session_process (line 607) | def _update_session_process(session_id: str, process: Any) -> bool: function _build_session_response (line 617) | def _build_session_response( function _get_existing_session (line 639) | def _get_existing_session(url: str) -> tuple[str | None, bool, float]: function _handle_existing_vod_session (line 655) | async def _handle_existing_vod_session( function _try_reuse_session (line 767) | async def _try_reuse_session( function _cleanup_invalid_session (line 795) | def _cleanup_invalid_session(url: str, session_id: str) -> None: function _do_start_transcode (line 807) | async def _do_start_transcode( function start_transcode (line 984) | async def start_transcode( function get_session (line 1054) | def get_session(session_id: str) -> dict[str, Any] | None: function touch_session (line 1061) | def touch_session(session_id: str) -> bool: function get_session_progress (line 1071) | def get_session_progress(session_id: str) -> dict[str, Any] | None: function clear_url_session (line 1088) | def clear_url_session(url: str) -> str | None: class _SeekSessionInfo (line 1100) | class _SeekSessionInfo: function _get_seek_session_info (line 1111) | def _get_seek_session_info(session_id: str) -> _SeekSessionInfo | None: function _update_seek_session (line 1127) | def _update_seek_session( function seek_transcode (line 1145) | async def seek_transcode(session_id: str, seek_time: float) -> dict[str,... FILE: ffmpeg_session_test.py class FakeProcess (line 38) | class FakeProcess: method __init__ (line 41) | def __init__(self, alive: bool = True, killed: bool = False): method terminate (line 45) | def terminate(self) -> None: method kill (line 50) | def kill(self) -> None: function _clear_session_state (line 56) | def _clear_session_state(): class TestIsProcessAlive (line 68) | class TestIsProcessAlive: method test_none_is_dead (line 71) | def test_none_is_dead(self): method test_dead_process_placeholder (line 74) | def test_dead_process_placeholder(self): method test_alive_process (line 77) | def test_alive_process(self): method test_dead_process (line 81) | def test_dead_process(self): class TestKillProcess (line 86) | class TestKillProcess: method test_kill_alive_process (line 89) | def test_kill_alive_process(self): method test_kill_already_dead (line 95) | def test_kill_already_dead(self): class TestIsSessionValid (line 105) | class TestIsSessionValid: method test_active_process_with_recent_heartbeat (line 108) | def test_active_process_with_recent_heartbeat(self): method test_active_process_stale_heartbeat (line 118) | def test_active_process_stale_heartbeat(self): method test_dead_process_live_session_no_cache (line 128) | def test_dead_process_live_session_no_cache(self): method test_dead_process_vod_session_within_cache (line 139) | def test_dead_process_vod_session_within_cache(self): method test_dead_process_vod_session_expired_cache (line 150) | def test_dead_process_vod_session_expired_cache(self): method test_heartbeat_timeout_boundary (line 161) | def test_heartbeat_timeout_boundary(self): method test_missing_last_access_uses_started (line 176) | def test_missing_last_access_uses_started(self): class TestCacheTimeouts (line 191) | class TestCacheTimeouts: method test_vod_cache_timeout_default (line 194) | def test_vod_cache_timeout_default(self): method test_vod_cache_timeout_custom (line 199) | def test_vod_cache_timeout_custom(self): method test_live_cache_timeout_default (line 204) | def test_live_cache_timeout_default(self): method test_live_cache_timeout_custom (line 209) | def test_live_cache_timeout_custom(self): class TestStopSession (line 220) | class TestStopSession: method setup_method (line 223) | def setup_method(self): method teardown_method (line 226) | def teardown_method(self): method test_stop_nonexistent_session (line 229) | def test_stop_nonexistent_session(self): method test_stop_session_force (line 233) | def test_stop_session_force(self): method test_stop_session_skip_recent_vod (line 251) | def test_stop_session_skip_recent_vod(self): method test_stop_session_skips_recent_live (line 268) | def test_stop_session_skips_recent_live(self): method test_stop_session_multi_user_grace_period (line 288) | def test_stop_session_multi_user_grace_period(self): method test_stop_session_caches_vod (line 313) | def test_stop_session_caches_vod(self): class TestCleanupExpiredSessions (line 334) | class TestCleanupExpiredSessions: method setup_method (line 337) | def setup_method(self): method teardown_method (line 340) | def teardown_method(self): method test_cleanup_removes_expired (line 343) | def test_cleanup_removes_expired(self): method test_cleanup_keeps_valid (line 362) | def test_cleanup_keeps_valid(self): class TestShutdown (line 380) | class TestShutdown: method setup_method (line 383) | def setup_method(self): method teardown_method (line 386) | def teardown_method(self): method test_shutdown_kills_all_processes (line 389) | def test_shutdown_kills_all_processes(self): class TestGetUserSessions (line 411) | class TestGetUserSessions: method setup_method (line 414) | def setup_method(self): method teardown_method (line 417) | def teardown_method(self): method test_get_user_sessions_filters_by_username (line 420) | def test_get_user_sessions_filters_by_username(self): method test_get_user_sessions_empty (line 432) | def test_get_user_sessions_empty(self): class TestGetSourceSessions (line 438) | class TestGetSourceSessions: method setup_method (line 441) | def setup_method(self): method teardown_method (line 444) | def teardown_method(self): method test_get_source_sessions_filters_by_source (line 447) | def test_get_source_sessions_filters_by_source(self): class TestEnforceStreamLimits (line 460) | class TestEnforceStreamLimits: method setup_method (line 463) | def setup_method(self): method teardown_method (line 466) | def teardown_method(self): method test_no_limits_returns_none (line 469) | def test_no_limits_returns_none(self): method test_user_limit_stops_oldest (line 474) | def test_user_limit_stops_oldest(self): method test_source_limit_stops_user_session (line 501) | def test_source_limit_stops_user_session(self): method test_source_limit_returns_error_for_other_user (line 520) | def test_source_limit_returns_error_for_other_user(self): class TestGetSession (line 543) | class TestGetSession: method setup_method (line 546) | def setup_method(self): method teardown_method (line 549) | def teardown_method(self): method test_get_existing_session (line 552) | def test_get_existing_session(self): method test_get_nonexistent_session (line 561) | def test_get_nonexistent_session(self): class TestTouchSession (line 566) | class TestTouchSession: method setup_method (line 569) | def setup_method(self): method teardown_method (line 572) | def teardown_method(self): method test_touch_updates_last_access (line 575) | def test_touch_updates_last_access(self): method test_touch_nonexistent_returns_false (line 586) | def test_touch_nonexistent_returns_false(self): class TestGetSessionProgress (line 591) | class TestGetSessionProgress: method setup_method (line 594) | def setup_method(self): method teardown_method (line 597) | def teardown_method(self): method test_progress_with_playlist (line 600) | def test_progress_with_playlist(self): method test_progress_no_playlist (line 615) | def test_progress_no_playlist(self): method test_progress_nonexistent_session (line 625) | def test_progress_nonexistent_session(self): class TestClearUrlSession (line 630) | class TestClearUrlSession: method setup_method (line 633) | def setup_method(self): method teardown_method (line 636) | def teardown_method(self): method test_clear_existing_url (line 639) | def test_clear_existing_url(self): method test_clear_nonexistent_url (line 649) | def test_clear_nonexistent_url(self): class TestCalcHlsDuration (line 660) | class TestCalcHlsDuration: method test_duration_from_playlist (line 663) | def test_duration_from_playlist(self): method test_duration_estimate_from_segments (line 673) | def test_duration_estimate_from_segments(self): class TestBuildSubtitleTracks (line 682) | class TestBuildSubtitleTracks: method test_builds_track_list (line 685) | def test_builds_track_list(self): method test_empty_sub_info (line 701) | def test_empty_sub_info(self): method test_non_dict_sub_info (line 706) | def test_non_dict_sub_info(self): class TestRegeneratePlaylist (line 711) | class TestRegeneratePlaylist: method test_regenerates_playlist_from_segments (line 714) | def test_regenerates_playlist_from_segments(self): method test_regenerate_skips_small_segments (line 734) | def test_regenerate_skips_small_segments(self): class TestCleanupAndRecoverSessions (line 754) | class TestCleanupAndRecoverSessions: method setup_method (line 757) | def setup_method(self): method teardown_method (line 760) | def teardown_method(self): method test_removes_orphaned_dirs (line 763) | def test_removes_orphaned_dirs(self): method test_recovers_valid_vod_session (line 779) | def test_recovers_valid_vod_session(self): method test_removes_expired_vod_session (line 806) | def test_removes_expired_vod_session(self): FILE: m3u.py function parse_m3u (line 38) | def parse_m3u(content: str, source_id: str) -> tuple[list[dict], list[di... function fetch_m3u (line 102) | def fetch_m3u(url: str, source_id: str, timeout: int = 30) -> tuple[list... function _fetch_all_live_data (line 109) | def _fetch_all_live_data() -> tuple[list[dict], list[dict], list[tuple[s... function fetch_source_live_data (line 151) | def fetch_source_live_data(source: Any) -> tuple[list[dict], list[dict],... function fetch_source_vod_data (line 185) | def fetch_source_vod_data(source: Any) -> tuple[list[dict], list[dict]]: function parse_epg_urls (line 200) | def parse_epg_urls(raw: list) -> list[tuple[str, int, str]]: function load_all_live_data (line 205) | def load_all_live_data() -> tuple[list[dict], list[dict], list[tuple[str... function _fetch_vod_data (line 252) | def _fetch_vod_data() -> tuple[list[dict], list[dict]]: function load_vod_data (line 275) | def load_vod_data() -> tuple[list[dict], list[dict]]: function _fetch_series_data (line 318) | def _fetch_series_data() -> tuple[list[dict], list[dict]]: function load_series_data (line 341) | def load_series_data() -> tuple[list[dict], list[dict]]: function get_first_xtream_client (line 384) | def get_first_xtream_client() -> XtreamClient | None: function get_xtream_client_by_source (line 392) | def get_xtream_client_by_source(source_id: str) -> XtreamClient | None: function get_first_xtream_source_and_client (line 400) | def get_first_xtream_source_and_client() -> tuple[str, XtreamClient] | t... function get_fetch_lock (line 408) | def get_fetch_lock(name: str) -> threading.Lock: function get_refresh_in_progress (line 413) | def get_refresh_in_progress() -> set[str]: FILE: m3u_test.py function m3u_module (line 11) | def m3u_module(tmp_path: Path): class TestParseM3u (line 29) | class TestParseM3u: method test_parse_basic_m3u (line 30) | def test_parse_basic_m3u(self, m3u_module): method test_parse_m3u_with_epg_url (line 50) | def test_parse_m3u_with_epg_url(self, m3u_module): method test_parse_m3u_x_tvg_url (line 58) | def test_parse_m3u_x_tvg_url(self, m3u_module): method test_parse_m3u_uncategorized (line 66) | def test_parse_m3u_uncategorized(self, m3u_module): method test_parse_m3u_category_ids_prefixed (line 76) | def test_parse_m3u_category_ids_prefixed(self, m3u_module): method test_parse_m3u_empty (line 85) | def test_parse_m3u_empty(self, m3u_module): class TestParseEpgUrls (line 92) | class TestParseEpgUrls: method test_parse_tuple_list (line 93) | def test_parse_tuple_list(self, m3u_module): method test_parse_tuple_passthrough (line 100) | def test_parse_tuple_passthrough(self, m3u_module): method test_parse_empty (line 105) | def test_parse_empty(self, m3u_module): method test_parse_skips_malformed (line 108) | def test_parse_skips_malformed(self, m3u_module): class TestFetchLocks (line 115) | class TestFetchLocks: method test_get_fetch_lock (line 116) | def test_get_fetch_lock(self, m3u_module): method test_get_refresh_in_progress (line 120) | def test_get_refresh_in_progress(self, m3u_module): FILE: main.py function get_sr_models (line 130) | def get_sr_models() -> list[str]: function is_sr_available (line 154) | def is_sr_available() -> bool: function _logo_url_filter (line 159) | def _logo_url_filter(url: str) -> str: function _safe_float (line 172) | def _safe_float(value: float | str | None, default: float = 0.0) -> float: function lifespan (line 192) | async def lifespan(app: FastAPI) -> AsyncIterator[None]: class AuthRequired (line 349) | class AuthRequired(Exception): function auth_required_handler (line 354) | async def auth_required_handler(request: Request, _exc: AuthRequired): function http_exception_handler (line 359) | async def http_exception_handler(request: Request, exc: HTTPException): function get_current_user (line 374) | def get_current_user(request: Request) -> dict | None: function require_auth (line 381) | def require_auth(request: Request) -> dict: function require_admin (line 388) | def require_admin(request: Request) -> dict: function setup_page (line 402) | async def setup_page(request: Request): function setup_create_user (line 410) | async def setup_create_user( function login_page (line 437) | async def login_page(request: Request, error: str | None = None): function _check_rate_limit (line 447) | def _check_rate_limit(ip: str) -> None: function login (line 467) | async def login( function logout (line 489) | async def logout(): function favicon (line 501) | async def favicon(): function index (line 506) | async def index(request: Request, _user: Annotated[dict, Depends(require... function _fetch_all_epg (line 510) | def _fetch_all_epg(epg_urls: list[tuple[str, int, str]]) -> int: function load_all_epg (line 543) | def load_all_epg(epg_urls: list[tuple[str, int, str]]) -> None: function _start_guide_background_load (line 565) | def _start_guide_background_load() -> None: function epg_events (line 592) | async def epg_events(_user: Annotated[dict, Depends(require_auth)]): function guide_page (line 624) | async def guide_page( function _get_guide_streams (line 753) | def _get_guide_streams(cats: str, username: str) -> tuple[list[dict], li... function _build_guide_rows (line 796) | def _build_guide_rows( function guide_rows_api (line 887) | async def guide_rows_api( function _start_vod_background_load (line 933) | def _start_vod_background_load() -> None: function vod_page (line 954) | async def vod_page( function _start_series_background_load (line 1042) | def _start_series_background_load() -> None: function series_page (line 1063) | async def series_page( function series_detail_page (line 1152) | async def series_detail_page( function movie_detail_page (line 1251) | async def movie_detail_page( class PlayerInfo (line 1318) | class PlayerInfo: function _get_episode_desc (line 1331) | def _get_episode_desc(ep: dict) -> str: function _get_live_player_info (line 1344) | def _get_live_player_info(stream_id: str) -> PlayerInfo: function _get_movie_player_info (line 1387) | def _get_movie_player_info(stream_id: str, ext: str) -> PlayerInfo: function _get_series_player_info (line 1423) | def _get_series_player_info( function _ensure_live_cache (line 1494) | def _ensure_live_cache() -> None: function player_page (line 1508) | async def player_page( function search_page (line 1612) | async def search_page( function stream_redirect (line 1757) | async def stream_redirect( function playlist_xspf (line 1771) | async def playlist_xspf( function transcode_start (line 1792) | async def transcode_start( function transcode_seek (line 1835) | async def transcode_seek( function transcode_progress (line 1845) | async def transcode_progress( function transcode_file (line 1857) | async def transcode_file( function subtitle_file (line 1898) | async def subtitle_file(session_id: str, filename: str): function transcode_stop (line 1928) | async def transcode_stop( function transcode_stop_post (line 1938) | async def transcode_stop_post( function transcode_clear (line 1948) | async def transcode_clear( function _build_all_groups (line 1960) | def _build_all_groups() -> list[dict[str, str]]: function _get_content_access (line 2005) | def _get_content_access(username: str) -> dict[str, bool]: function _get_content_access_from_request (line 2037) | def _get_content_access_from_request(request: Request) -> dict[str, bool]: function settings_page (line 2055) | async def settings_page(request: Request, user: Annotated[dict, Depends(... function settings_guide_filter (line 2150) | async def settings_guide_filter( function settings_vod_filter (line 2166) | async def settings_vod_filter( function settings_series_filter (line 2182) | async def settings_series_filter( function settings_add_source (line 2198) | async def settings_add_source( function settings_edit_source (line 2254) | async def settings_edit_source( function settings_delete_source (line 2308) | async def settings_delete_source( function guide_refresh (line 2322) | async def guide_refresh(_user: Annotated[dict, Depends(require_auth)]): function guide_refresh_status (line 2370) | async def guide_refresh_status(_user: Annotated[dict, Depends(require_au... function settings_refresh_source (line 2379) | async def settings_refresh_source( function settings_refresh_status (line 2514) | async def settings_refresh_status(_user: Annotated[dict, Depends(require... function settings_captions (line 2531) | async def settings_captions( function cast_log_endpoint (line 2543) | async def cast_log_endpoint(request: Request): function get_user_prefs (line 2555) | async def get_user_prefs(user: Annotated[dict, Depends(require_auth)]): function save_user_prefs (line 2569) | async def save_user_prefs( function _fetch_logo (line 2594) | def _fetch_logo(url: str, timeout: int = 10) -> tuple[bytes, str]: function get_logo (line 2609) | async def get_logo( function settings_transcode (line 2641) | async def settings_transcode( function settings_refresh_encoders (line 2679) | async def settings_refresh_encoders( function settings_user_agent (line 2688) | async def settings_user_agent( function _enrich_probe_cache_stats (line 2703) | def _enrich_probe_cache_stats(stats: list[dict], xtream: Any) -> list[di... function get_probe_cache (line 2737) | async def get_probe_cache( function clear_probe_cache (line 2752) | async def clear_probe_cache(_user: Annotated[dict, Depends(require_admin... function clear_series_probe_cache (line 2759) | async def clear_series_probe_cache( function clear_series_mru (line 2770) | async def clear_series_mru( function clear_data_cache (line 2780) | async def clear_data_cache(_user: Annotated[dict, Depends(require_admin)]): function get_settings_api (line 2787) | async def get_settings_api(_user: Annotated[dict, Depends(require_auth)]): function update_settings_api (line 2792) | async def update_settings_api( function save_watch_position_api (line 2817) | async def save_watch_position_api( function get_watch_position_api (line 2833) | async def get_watch_position_api( function settings_delete_user (line 2847) | async def settings_delete_user( function settings_add_user (line 2870) | async def settings_add_user( function settings_change_own_password (line 2902) | async def settings_change_own_password( function settings_change_password (line 2919) | async def settings_change_password( function settings_set_admin (line 2936) | async def settings_set_admin( function settings_set_user_limits (line 2948) | async def settings_set_user_limits( FILE: main_test.py function mock_deps (line 17) | def mock_deps(): function client (line 31) | def client(tmp_path: Path, mock_deps): function auth_client (line 56) | def auth_client(tmp_path: Path, mock_deps): class TestSetup (line 86) | class TestSetup: method test_setup_page_shown_when_no_users (line 89) | def test_setup_page_shown_when_no_users(self, client): method test_setup_redirects_when_users_exist (line 94) | def test_setup_redirects_when_users_exist(self, client, tmp_path): method test_setup_creates_user (line 103) | def test_setup_creates_user(self, client): method test_setup_validates_username_length (line 116) | def test_setup_validates_username_length(self, client): method test_setup_validates_password_length (line 124) | def test_setup_validates_password_length(self, client): method test_setup_validates_password_match (line 132) | def test_setup_validates_password_match(self, client): class TestLogin (line 141) | class TestLogin: method test_login_page_redirects_to_setup_when_no_users (line 144) | def test_login_page_redirects_to_setup_when_no_users(self, client): method test_login_page_shown_when_users_exist (line 149) | def test_login_page_shown_when_users_exist(self, client, tmp_path): method test_login_success_sets_cookie (line 157) | def test_login_success_sets_cookie(self, client, tmp_path): method test_login_failure_returns_401 (line 170) | def test_login_failure_returns_401(self, client, tmp_path): class TestLogout (line 184) | class TestLogout: method test_logout_clears_cookie (line 187) | def test_logout_clears_cookie(self, auth_client): class TestAuthRequired (line 193) | class TestAuthRequired: method test_index_redirects_to_login (line 196) | def test_index_redirects_to_login(self, client, tmp_path): method test_guide_redirects_to_login (line 205) | def test_guide_redirects_to_login(self, client, tmp_path): method test_vod_redirects_to_login (line 214) | def test_vod_redirects_to_login(self, client, tmp_path): method test_series_redirects_to_login (line 223) | def test_series_redirects_to_login(self, client, tmp_path): class TestIndex (line 233) | class TestIndex: method test_index_redirects_to_guide (line 236) | def test_index_redirects_to_guide(self, auth_client): class TestFavicon (line 242) | class TestFavicon: method test_favicon_returns_204 (line 245) | def test_favicon_returns_204(self, client): class TestGuide (line 250) | class TestGuide: method test_guide_shows_loading_when_no_cache (line 253) | def test_guide_shows_loading_when_no_cache(self, auth_client): method test_guide_shows_channels_from_cache (line 260) | def test_guide_shows_channels_from_cache(self, auth_client): method test_guide_uses_saved_filter (line 272) | def test_guide_uses_saved_filter(self, auth_client, tmp_path): class TestVod (line 286) | class TestVod: method test_vod_shows_loading_when_no_cache (line 289) | def test_vod_shows_loading_when_no_cache(self, auth_client): method test_vod_shows_movies_from_cache (line 294) | def test_vod_shows_movies_from_cache(self, auth_client): method test_vod_filters_by_category (line 305) | def test_vod_filters_by_category(self, auth_client): method test_vod_sorts_by_alpha (line 318) | def test_vod_sorts_by_alpha(self, auth_client): class TestSeries (line 329) | class TestSeries: method test_series_shows_loading_when_no_cache (line 332) | def test_series_shows_loading_when_no_cache(self, auth_client): method test_series_shows_list_from_cache (line 337) | def test_series_shows_list_from_cache(self, auth_client): class TestSearch (line 349) | class TestSearch: method test_search_page_renders (line 352) | def test_search_page_renders(self, auth_client): method test_search_finds_live_streams (line 360) | def test_search_finds_live_streams(self, auth_client): method test_search_regex_mode (line 373) | def test_search_regex_mode(self, auth_client): method test_search_rejects_long_regex (line 386) | def test_search_rejects_long_regex(self, auth_client): class TestSettings (line 393) | class TestSettings: method test_settings_page_renders (line 396) | def test_settings_page_renders(self, auth_client): method test_settings_guide_filter (line 403) | def test_settings_guide_filter(self, auth_client): method test_settings_captions (line 411) | def test_settings_captions(self, auth_client): method test_settings_transcode (line 419) | def test_settings_transcode(self, auth_client): class TestAddSource (line 432) | class TestAddSource: method test_add_xtream_source (line 435) | def test_add_xtream_source(self, auth_client): method test_add_m3u_source (line 451) | def test_add_m3u_source(self, auth_client): method test_add_source_validates_type (line 465) | def test_add_source_validates_type(self, auth_client): method test_add_source_validates_url_scheme (line 476) | def test_add_source_validates_url_scheme(self, auth_client): method test_add_source_validates_name_length (line 487) | def test_add_source_validates_name_length(self, auth_client): class TestDeleteSource (line 499) | class TestDeleteSource: method test_delete_source (line 502) | def test_delete_source(self, auth_client, tmp_path): class TestUserPrefs (line 524) | class TestUserPrefs: method test_get_user_prefs (line 527) | def test_get_user_prefs(self, auth_client): method test_save_user_prefs (line 534) | def test_save_user_prefs(self, auth_client): class TestWatchPosition (line 543) | class TestWatchPosition: method test_save_watch_position (line 546) | def test_save_watch_position(self, auth_client): method test_get_watch_position (line 553) | def test_get_watch_position(self, auth_client): method test_get_watch_position_not_found (line 566) | def test_get_watch_position_not_found(self, auth_client): class TestUserManagement (line 573) | class TestUserManagement: method test_delete_user (line 576) | def test_delete_user(self, auth_client, tmp_path): method test_cannot_delete_self (line 584) | def test_cannot_delete_self(self, auth_client): method test_change_password (line 588) | def test_change_password(self, auth_client): method test_change_password_wrong_current (line 595) | def test_change_password_wrong_current(self, auth_client): class TestPlaylistXspf (line 603) | class TestPlaylistXspf: method test_playlist_xspf (line 606) | def test_playlist_xspf(self, auth_client): class TestApiSettings (line 614) | class TestApiSettings: method test_get_settings (line 617) | def test_get_settings(self, auth_client): method test_update_settings (line 623) | def test_update_settings(self, auth_client): class TestTranscodeRoutes (line 631) | class TestTranscodeRoutes: method test_transcode_file_not_found (line 634) | def test_transcode_file_not_found(self, auth_client): method test_transcode_stop (line 639) | def test_transcode_stop(self, auth_client): method test_transcode_stop_post (line 645) | def test_transcode_stop_post(self, auth_client): method test_transcode_progress_not_found (line 650) | def test_transcode_progress_not_found(self, auth_client): class TestSubtitleRoutes (line 656) | class TestSubtitleRoutes: method test_subtitle_invalid_filename (line 659) | def test_subtitle_invalid_filename(self, auth_client): method test_subtitle_session_not_found (line 663) | def test_subtitle_session_not_found(self, auth_client): class TestProbeCache (line 669) | class TestProbeCache: method test_get_probe_cache (line 672) | def test_get_probe_cache(self, auth_client): method test_clear_probe_cache (line 678) | def test_clear_probe_cache(self, auth_client): method test_clear_series_probe_cache (line 684) | def test_clear_series_probe_cache(self, auth_client): class TestRefreshStatus (line 690) | class TestRefreshStatus: method test_guide_refresh_status (line 693) | def test_guide_refresh_status(self, auth_client): method test_settings_refresh_status (line 702) | def test_settings_refresh_status(self, auth_client): FILE: static/js/app.js function getFocusables (line 13) | function getFocusables(container = document) { function getGridInfo (line 19) | function getGridInfo(element) { function moveFocus (line 43) | function moveFocus(direction) { function setInitialFocus (line 90) | function setInitialFocus() { function toggleFocusedFavorite (line 112) | function toggleFocusedFavorite() { FILE: static/js/favorites-grid.js function escapeHtml (line 10) | function escapeHtml(s) { function escapeAttr (line 15) | function escapeAttr(s) { function getFavorites (line 22) | function getFavorites() { function saveFavorites (line 26) | function saveFavorites() { function getOrder (line 76) | async function getOrder() { function saveOrder (line 84) | async function saveOrder(order) { function initDragDrop (line 141) | function initDragDrop() { function saveCurrentOrder (line 217) | async function saveCurrentOrder() { FILE: static/js/player.js function formatTime (line 35) | function formatTime(seconds) { function parseTime (line 43) | function parseTime(str) { function parseVttTime (line 56) | function parseVttTime(str) { function parseVttCues (line 63) | function parseVttCues(vttText) { function hideLoading (line 91) | function hideLoading() { function showLoading (line 95) | function showLoading() { function showError (line 99) | function showError() { function updateTranscodeCheck (line 104) | function updateTranscodeCheck() { function updateCcButton (line 109) | function updateCcButton() { function updatePlayIcon (line 113) | function updatePlayIcon() { function updateMuteIcon (line 122) | function updateMuteIcon() { function updateFullscreenIcon (line 131) | function updateFullscreenIcon() { function disableCcButton (line 141) | function disableCcButton() { function enableCcButton (line 146) | function enableCcButton() { method newCue (line 158) | newCue(track, startTime, endTime, captionScreen) { function createHlsConfig (line 178) | function createHlsConfig(options = {}) { function applyCaptionStyles (line 210) | function applyCaptionStyles() { function getPreferredSubtitleTrack (line 244) | function getPreferredSubtitleTrack(tracks) { function applyCaptionsSetting (line 267) | function applyCaptionsSetting() { function startSubtitlePolling (line 292) | function startSubtitlePolling(subtitles, prefIdx) { function savePosition (line 357) | function savePosition() { function restorePosition (line 371) | function restorePosition() { function setupPositionTracking (line 383) | function setupPositionTracking() { function startProgressPolling (line 406) | function startProgressPolling() { function stopProgressPolling (line 422) | function stopProgressPolling() { function cleanupTranscode (line 433) | async function cleanupTranscode() { function cleanupTranscodeSync (line 463) | function cleanupTranscodeSync() { function handleSeekToPosition (line 481) | async function handleSeekToPosition(targetTime) { function startTranscode (line 542) | async function startTranscode(onError) { function playWithUrl (line 583) | function playWithUrl(url, onError, subtitles) { function setupKeyboardControls (line 714) | function setupKeyboardControls() { function loadSettings (line 806) | function loadSettings() { function saveSettings (line 811) | function saveSettings(updates) { function setupActivityTracking (line 816) | function setupActivityTracking() { function setupButtonHandlers (line 845) | function setupButtonHandlers() { function setupCast (line 1202) | function setupCast() { function init (line 1314) | function init() { FILE: static/js/settings.js function escapeHtml (line 11) | function escapeHtml(s) { function showFeedback (line 16) | function showFeedback(el, success) { function saveWithFeedback (line 23) | async function saveWithFeedback(url, options, feedbackEl) { function getFeedbackEl (line 35) | function getFeedbackEl(el) { function setupDragDrop (line 45) | function setupDragDrop(containerSelector, chipSelector, onDrop) { function setupSearch (line 100) | function setupSearch(inputId, clearBtnId, chipSelector) { function setupSourceTypeSelect (line 176) | function setupSourceTypeSelect() { function setupSourceEditForms (line 209) | function setupSourceEditForms() { function setupCategoryFilter (line 251) | function setupCategoryFilter() { function setupVodCategoryFilter (line 290) | function setupVodCategoryFilter() { function setupSeriesCategoryFilter (line 329) | function setupSeriesCategoryFilter() { function setupChromeCcLink (line 368) | function setupChromeCcLink() { function setupCaptionSettings (line 389) | function setupCaptionSettings() { function setupGuideSettings (line 453) | function setupGuideSettings() { function setupTranscodeSettings (line 470) | function setupTranscodeSettings() { function setupUserAgentSettings (line 554) | function setupUserAgentSettings() { function setupDataCache (line 582) | function setupDataCache() { function setupProbeCache (line 595) | function setupProbeCache() { function setupRefreshButtons (line 681) | function setupRefreshButtons() { function setupUserForms (line 739) | function setupUserForms() { function setupUserGroupDragDrop (line 855) | function setupUserGroupDragDrop() { function init (line 918) | function init() { FILE: static/js/virtual-guide.js constant VIRTUAL_GUIDE_DEFAULTS (line 7) | const VIRTUAL_GUIDE_DEFAULTS = { class VirtualGuide (line 20) | class VirtualGuide { method constructor (line 21) | constructor(options) { method currentRowHeight (line 59) | get currentRowHeight() { method visibleCount (line 63) | get visibleCount() { method init (line 68) | init() { method setupDOM (line 108) | setupDOM() { method bindEvents (line 144) | bindEvents() { method onScroll (line 176) | onScroll() { method updateVisibleRange (line 216) | async updateVisibleRange() { method findMissingRanges (line 271) | findMissingRanges(start, end) { method fetchMissingRanges (line 296) | async fetchMissingRanges(ranges) { method render (line 408) | render() { method pruneCache (line 431) | pruneCache() { method renderPlaceholder (line 456) | renderPlaceholder(index) { method renderRow (line 486) | renderRow(row, index) { method destroy (line 584) | destroy() { FILE: testing.py function run_tests (line 11) | def run_tests(test_file: str) -> None: FILE: tools/alignm3u.py function parse_callsign (line 35) | def parse_callsign(coded_callsign: str) -> tuple[str, str, int]: function parse_m3u (line 46) | def parse_m3u(path: pathlib.Path) -> list[list]: function parse_xmltv_channels (line 69) | def parse_xmltv_channels(path: pathlib.Path) -> dict[str, tuple[str, ...]]: function build_lookup (line 81) | def build_lookup(xmltv_channels: dict[str, tuple[str, ...]]) -> dict[str... function align_channels (line 90) | def align_channels( function write_m3u (line 125) | def write_m3u( function main (line 157) | def main() -> None: FILE: tools/export-tensorrt.py class SRVGGNetCompact (line 51) | class SRVGGNetCompact(nn.Module): method __init__ (line 58) | def __init__( method forward (line 77) | def forward(self, x: torch.Tensor) -> torch.Tensor: class ResidualDenseBlock (line 86) | class ResidualDenseBlock(nn.Module): method __init__ (line 96) | def __init__(self, nf: int = 64, gc: int = 32): method forward (line 105) | def forward(self, x: torch.Tensor) -> torch.Tensor: class RRDB (line 114) | class RRDB(nn.Module): method __init__ (line 121) | def __init__(self, nf: int, gc: int = 32): method forward (line 127) | def forward(self, x: torch.Tensor) -> torch.Tensor: class RRDBNet (line 134) | class RRDBNet(nn.Module): method __init__ (line 147) | def __init__( method forward (line 167) | def forward(self, x: torch.Tensor) -> torch.Tensor: class ModelInfo (line 193) | class ModelInfo(TypedDict): function resolve_model (line 236) | def resolve_model(model_name: str) -> tuple[str, ModelInfo]: function download_model (line 244) | def download_model(model_name: str, cache_dir: Path) -> Path: function list_models (line 283) | def list_models() -> None: function get_model_and_onnx (line 298) | def get_model_and_onnx( function export_onnx (line 369) | def export_onnx(model: nn.Module, opt_shape: tuple[int, int], onnx_path:... function _get_trt_dtype_map (line 402) | def _get_trt_dtype_map() -> dict[str, trt.DataType]: function _trt_dtype_str (line 413) | def _trt_dtype_str(dtype: trt.DataType) -> str: function build_engine (line 421) | def build_engine( function height_to_shape (line 525) | def height_to_shape(h: int, aspect: float = 16 / 9) -> tuple[int, int]: function main (line 540) | def main() -> None: FILE: tools/patches/dnn_backend_tensorrt.cpp type CachedEngine (line 47) | struct CachedEngine { method CachedEngine (line 52) | CachedEngine(nvinfer1::ICudaEngine *e, nvinfer1::IRuntime *r) function load_libs (line 208) | static int load_libs(void *log_ctx) { function log_gpu_memory (line 389) | static void log_gpu_memory(void *log_ctx, const char *label) { class TRTLogger (line 399) | class TRTLogger : public nvinfer1::ILogger { method TRTLogger (line 402) | TRTLogger(void *ctx = nullptr) : log_ctx(ctx) {} method log (line 404) | void log(Severity severity, const char *msg) noexcept override { type TRTDataType (line 426) | enum TRTDataType { function trt_dtype_size (line 446) | static size_t trt_dtype_size(TRTDataType dt) { function TRTDataType (line 457) | static TRTDataType nvinfer_to_trt_dtype(nvinfer1::DataType dt) { type TRTModel (line 468) | struct TRTModel { type TRTInferRequest (line 515) | struct TRTInferRequest { type TRTRequestItem (line 519) | struct TRTRequestItem { function load_cuda_kernels (line 543) | static int load_cuda_kernels(TRTModel *trt_model, void *log_ctx) { function launch_kernel (line 616) | static int launch_kernel(CUfunction func, CUstream stream, function ensure_execution_context (line 639) | static int ensure_execution_context(TRTModel *trt_model, void *log_ctx) function extract_lltask_from_task (line 706) | static int extract_lltask_from_task(TaskItem *task, Queue *lltask_queue) function trt_free_request (line 726) | static void trt_free_request(TRTInferRequest *request) function destroy_request_item (line 735) | static inline void destroy_request_item(TRTRequestItem **arg) function dnn_free_model_trt (line 748) | static void dnn_free_model_trt(DNNModel **model) function get_input_trt (line 879) | static int get_input_trt(DNNModel *model, DNNData *input, const char *in... function fill_model_input_trt (line 904) | static int fill_model_input_trt(TRTModel *trt_model, TRTRequestItem *req... function trt_capture_cuda_graph (line 1044) | static int trt_capture_cuda_graph(TRTModel *trt_model, void *log_ctx) function trt_start_inference (line 1106) | static int trt_start_inference(void *args) function infer_completion_callback (line 1165) | static void infer_completion_callback(void *args) function execute_model_trt (line 1355) | static int execute_model_trt(TRTRequestItem *request, Queue *lltask_queue) function get_output_trt (line 1419) | static int get_output_trt(DNNModel *model, const char *input_name, int i... function TRTInferRequest (line 1431) | static TRTInferRequest *trt_create_inference_request(void) function DNNModel (line 1437) | static DNNModel *dnn_load_model_trt(DnnContext *ctx, DNNFunctionType fun... function dnn_execute_model_trt (line 1748) | static int dnn_execute_model_trt(const DNNModel *model, DNNExecBaseParam... function DNNAsyncStatusType (line 1813) | static DNNAsyncStatusType dnn_get_result_trt(const DNNModel *model, AVFr... function dnn_flush_trt (line 1819) | static int dnn_flush_trt(const DNNModel *model) FILE: tools/patches/dnn_backend_torch.cpp type THModel (line 49) | struct THModel { type THInferRequest (line 63) | struct THInferRequest { type THRequestItem (line 68) | struct THRequestItem { function extract_lltask_from_task (line 82) | static int extract_lltask_from_task(TaskItem *task, Queue *lltask_queue) function th_free_request (line 102) | static void th_free_request(THInferRequest *request) function destroy_request_item (line 117) | static inline void destroy_request_item(THRequestItem **arg) function dnn_free_model_th (line 131) | static void dnn_free_model_th(DNNModel **model) function get_input_th (line 205) | static int get_input_th(DNNModel *model, DNNData *input, const char *inp... function deleter (line 217) | static void deleter(void *arg) function fill_model_input_th (line 222) | static int fill_model_input_th(THModel *th_model, THRequestItem *request) function th_start_inference (line 377) | static int th_start_inference(void *args) function infer_completion_callback (line 432) | static void infer_completion_callback(void *args) { function th_worker_thread (line 633) | static void th_worker_thread(THModel *th_model) { function execute_model_th (line 658) | static int execute_model_th(THRequestItem *request, Queue *lltask_queue) function get_output_th (line 714) | static int get_output_th(DNNModel *model, const char *input_name, int in... function THInferRequest (line 760) | static THInferRequest *th_create_inference_request(void) function DNNModel (line 771) | static DNNModel *dnn_load_model_th(DnnContext *ctx, DNNFunctionType func... function dnn_execute_model_th (line 911) | static int dnn_execute_model_th(const DNNModel *model, DNNExecBaseParams... function DNNAsyncStatusType (line 974) | static DNNAsyncStatusType dnn_get_result_th(const DNNModel *model, AVFra... function dnn_flush_th (line 980) | static int dnn_flush_th(const DNNModel *model) FILE: tools/patches/vf_dnn_processing.c type DnnProcessingContext (line 39) | typedef struct DnnProcessingContext { function av_cold (line 68) | static av_cold int init(AVFilterContext *context) type AVPixelFormat (line 74) | enum AVPixelFormat function check_modelinput_inlink (line 91) | static int check_modelinput_inlink(const DNNData *model_input, const AVF... function config_input (line 154) | static int config_input(AVFilterLink *inlink) function av_always_inline (line 176) | static av_always_inline int isPlanarYUV(enum AVPixelFormat pix_fmt) function prepare_uv_scale (line 184) | static int prepare_uv_scale(AVFilterLink *outlink) function config_output (line 228) | static int config_output(AVFilterLink *outlink) function copy_uv_planes (line 282) | static int copy_uv_planes(DnnProcessingContext *ctx, AVFrame *out, const... function flush_frame (line 321) | static int flush_frame(AVFilterLink *outlink, int64_t pts, int64_t *out_... function activate (line 359) | static int activate(AVFilterContext *filter_ctx) function av_cold (line 453) | static av_cold void uninit(AVFilterContext *ctx) FILE: tools/xtream2m3u.py class RetryableError (line 29) | class RetryableError(Exception): function _load_config (line 39) | def _load_config() -> dict: function _get_urls (line 55) | def _get_urls() -> tuple[str, str, str]: function _get_filters (line 66) | def _get_filters() -> tuple[dict[int, str], str, set[str]]: function main (line 75) | def main(cached_only: bool = False) -> None: function fetch_all_data (line 126) | def fetch_all_data(api_url: str) -> None: function fetch_text (line 182) | def fetch_text(url: str, timeout: int = 5) -> str: function fetch_series_info (line 199) | def fetch_series_info( class RateLimiter (line 274) | class RateLimiter(Protocol): method __init__ (line 275) | def __init__(self, max_calls: int, per_seconds: float = 1): ... method acquire (line 277) | def acquire(self) -> None: ... function _task (line 280) | def _task( function filter_live (line 310) | def filter_live( function process (line 351) | def process( function process_iptv_url (line 418) | def process_iptv_url(auth: dict[str, dict[str, Any]]) -> list[str]: function toint (line 440) | def toint(x: str | None) -> int | None: function tofloat (line 444) | def tofloat(x: str | None) -> float | None: function load (line 448) | def load(filename: str) -> Any: function load_dict (line 453) | def load_dict(filename: str) -> dict[str, Any]: function load_list (line 460) | def load_list(filename: str) -> list[dict[str, Any]]: class SlidingRateLimiter (line 467) | class SlidingRateLimiter: method __init__ (line 468) | def __init__(self, max_calls: int, per_seconds: float = 1): method acquire (line 474) | def acquire(self) -> None: class ChunkingRateLimiter (line 487) | class ChunkingRateLimiter: method __init__ (line 488) | def __init__(self, max_calls: int, per_seconds: float = 1): method acquire (line 495) | def acquire(self) -> None: function print_progress_bar (line 512) | def print_progress_bar( function write_m3u_live (line 544) | def write_m3u_live( function write_m3u_vod (line 568) | def write_m3u_vod( function write_m3u_series (line 590) | def write_m3u_series( function _descend (line 626) | def _descend(x: Any): FILE: tools/zap2xml.py class Namespace (line 46) | class Namespace(dict): # pyright: ignore[reportMissingTypeArgument] function main (line 55) | def main() -> None: function get_cached (line 161) | def get_cached( function remove_stale_cache (line 208) | def remove_stale_cache(cache_dir: pathlib.Path, zap_time: int) -> None: function _expired (line 228) | def _expired( function add_programme (line 240) | def add_programme( function add_programme_tvimate (line 431) | def add_programme_tvimate( function get_channel_key (line 523) | def get_channel_key(c: Mapping[str, Any]) -> str: function parse_callsign (line 529) | def parse_callsign(coded_callsign: str) -> str: function strf_time_str (line 544) | def strf_time_str(tm: str, format_str: str = "%Y%m%d%H%M%S %z") -> str: function strf_time_int (line 549) | def strf_time_int(timestamp: int, format_str: str = "%Y-%b-%d %_I:%M%P %... function parse_time_iso (line 553) | def parse_time_iso(tm: str) -> datetime.datetime: function parse_time_int (line 558) | def parse_time_int(timestamp: int) -> datetime.datetime: function add_xml_child (line 562) | def add_xml_child( function toint (line 581) | def toint(x: str | None, fail: int = 0) -> int: function parse_args (line 587) | def parse_args() -> argparse.Namespace: FILE: util.py class _SafeRedirectHandler (line 12) | class _SafeRedirectHandler(urllib.request.HTTPRedirectHandler): method redirect_request (line 15) | def redirect_request( function safe_urlopen (line 33) | def safe_urlopen(url: str, timeout: int = 30, user_agent: str | None = N... FILE: util_test.py function _fake_request (line 14) | def _fake_request(url: str) -> Any: class TestSafeRedirectHandler (line 29) | class TestSafeRedirectHandler: method test_handler_allows_http (line 30) | def test_handler_allows_http(self): method test_handler_allows_https (line 43) | def test_handler_allows_https(self): method test_handler_rejects_file_scheme (line 56) | def test_handler_rejects_file_scheme(self): method test_handler_rejects_data_scheme (line 69) | def test_handler_rejects_data_scheme(self): method test_handler_rejects_javascript_scheme (line 82) | def test_handler_rejects_javascript_scheme(self): FILE: xtream.py class XtreamClient (line 15) | class XtreamClient: method __post_init__ (line 25) | def __post_init__(self) -> None: method _base_params (line 30) | def _base_params(self) -> dict[str, str]: method api_url (line 34) | def api_url(self) -> str: method _fetch (line 38) | def _fetch(self, url: str, timeout: int = 30) -> str: method _api (line 42) | def _api(self, action: str | None = None, timeout: int = 30, **params:... method get_server_info (line 50) | def get_server_info(self, timeout: int = 15) -> dict[str, Any]: method get_live_categories (line 54) | def get_live_categories(self) -> list[dict[str, Any]]: method get_live_streams (line 57) | def get_live_streams(self, category_id: int | None = None) -> list[dic... method get_vod_categories (line 62) | def get_vod_categories(self) -> list[dict[str, Any]]: method get_vod_streams (line 65) | def get_vod_streams(self, category_id: int | None = None) -> list[dict... method get_series_categories (line 70) | def get_series_categories(self) -> list[dict[str, Any]]: method get_series (line 73) | def get_series(self, category_id: int | None = None) -> list[dict[str,... method get_series_info (line 78) | def get_series_info(self, series_id: int) -> dict[str, Any]: method get_vod_info (line 81) | def get_vod_info(self, vod_id: int) -> dict[str, Any]: method get_short_epg (line 84) | def get_short_epg(self, stream_id: int, limit: int = 10) -> dict[str, ... method build_stream_url (line 88) | def build_stream_url(self, stream_type: str, stream_id: int, ext: str ... method build_timeshift_url (line 95) | def build_timeshift_url( method epg_url (line 109) | def epg_url(self) -> str: FILE: xtream_test.py class TestXtreamClient (line 14) | class TestXtreamClient: method test_api_url_property (line 17) | def test_api_url_property(self): method test_epg_url_property (line 21) | def test_epg_url_property(self): method test_url_normalization_strips_trailing_slash (line 25) | def test_url_normalization_strips_trailing_slash(self): method test_url_normalization_strips_multiple_trailing_slashes (line 31) | def test_url_normalization_strips_multiple_trailing_slashes(self): method test_special_chars_in_credentials_are_encoded (line 35) | def test_special_chars_in_credentials_are_encoded(self): method test_build_stream_url_live_no_ext (line 44) | def test_build_stream_url_live_no_ext(self): method test_build_stream_url_live_with_ext (line 49) | def test_build_stream_url_live_with_ext(self): method test_build_stream_url_movie (line 54) | def test_build_stream_url_movie(self): method test_build_stream_url_series (line 59) | def test_build_stream_url_series(self): method test_build_timeshift_url (line 64) | def test_build_timeshift_url(self): method test_build_timeshift_url_custom_ext (line 69) | def test_build_timeshift_url_custom_ext(self): class TestXtreamClientApi (line 75) | class TestXtreamClientApi: method client (line 79) | def client(self): method mock_urlopen (line 83) | def mock_urlopen(self): method _setup_response (line 87) | def _setup_response(self, mock_urlopen, data): method test_get_live_categories (line 95) | def test_get_live_categories(self, client, mock_urlopen): method test_get_live_streams (line 106) | def test_get_live_streams(self, client, mock_urlopen): method test_get_live_streams_with_category (line 116) | def test_get_live_streams_with_category(self, client, mock_urlopen): method test_get_vod_categories (line 127) | def test_get_vod_categories(self, client, mock_urlopen): method test_get_vod_streams (line 137) | def test_get_vod_streams(self, client, mock_urlopen): method test_get_vod_streams_with_category (line 147) | def test_get_vod_streams_with_category(self, client, mock_urlopen): method test_get_series_categories (line 157) | def test_get_series_categories(self, client, mock_urlopen): method test_get_series (line 167) | def test_get_series(self, client, mock_urlopen): method test_get_series_with_category (line 177) | def test_get_series_with_category(self, client, mock_urlopen): method test_get_series_info (line 187) | def test_get_series_info(self, client, mock_urlopen): method test_get_vod_info (line 198) | def test_get_vod_info(self, client, mock_urlopen): method test_get_server_info (line 209) | def test_get_server_info(self, client, mock_urlopen): method test_get_server_info_auth_failed (line 235) | def test_get_server_info_auth_failed(self, client, mock_urlopen): method test_get_server_info_uses_shorter_timeout (line 243) | def test_get_server_info_uses_shorter_timeout(self, client, mock_urlop... method test_custom_timeout_passed_through (line 252) | def test_custom_timeout_passed_through(self, client, mock_urlopen): method test_api_encodes_special_chars_in_params (line 261) | def test_api_encodes_special_chars_in_params(self, client, mock_urlopen): method test_get_short_epg (line 270) | def test_get_short_epg(self, client, mock_urlopen): method test_get_short_epg_custom_limit (line 287) | def test_get_short_epg_custom_limit(self, client, mock_urlopen):