Self-hosted video downloader for YouTube and other sites (web UI for yt-dlp)
This report presents the forensic synthetic code analysis of alexta69/metube, a Python project with 14,100 GitHub stars. SynthScan v2.0 examined 21,835 lines of code across 82 source files, recording 299 pattern matches distributed across 7 syntactic categories. The overall adjusted score of 14.4 places this repository in the Low AI signal band.
The scanner applied 160+ deterministic lexical heuristics, multi-line block detectors, abstract syntax tree depth profilers, and a cross-file Jaccard similarity matrix to construct a statistically normalised synthetic code estimate. All matches are individually weighted by severity coefficient and contextual multiplier before summation, and the resulting headline score is temporally discounted to account for the repository's development history relative to the commercial emergence of large language model coding tooling (November 2022 onward).
This chart maps the temporal evolution of the adjusted synthetic code score across successive scan runs. An upward trajectory indicates ongoing incorporation of AI-generated code or expanding LLM-assisted scaffolding; a stable or declining trajectory may reflect active human refactoring, code removal, or the adoption of stricter authorship policies. The dashed secondary line (right axis) independently tracks total raw pattern hit count, which can diverge from the normalised score when codebase size changes significantly between scans.
Classifies detected patterns by their diagnostic confidence and structural impact. CRITICAL patterns (coefficient 10) represent definitive synthetic signatures — hallucinated imports, explicit LLM attribution metadata — virtually never produced by human authors. HIGH (5) indicates strong structural tells such as cross-file repetition or cross-linguistic idioms. MEDIUM (2) covers recognisable conversational padding and AI-specific vocabulary. LOW (1) captures subtle indicators like tautological comments and generic boilerplate that require density to carry independent signal.
This horizontal bar chart decomposes the repository's raw synthetic code score by top-level directory, allowing you to pinpoint precisely which modules or components carry the highest AI authorship density. Directories with disproportionately high scores relative to their size warrant targeted manual review: concentrated AI signatures often trace back to mass-generated configuration layers, auto-ported test suites, LLM-scaffolded boilerplate classes, or entire subsystems authored under heavy copilot assistance. Use this view to prioritise your human code-review effort.
The scanner identified 299 distinct pattern matches across 7 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a statistically significant AI authorship indicator. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the diagnostic confidence level (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — comment-context matches receive a ×1.5 weight because LLMs systematically over-annotate. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier as dense clusters constitute far stronger evidence of synthetic authorship than isolated hits.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/state_store.py | 192 | def _warn_direct_write_fallback(self, exc: OSError) -> None: | CODE |
| LOW | app/ytdl.py | 147 | def _sanitize_entry_for_pickle(obj, _depth=0): | CODE |
| LOW | app/ytdl.py | 460 | def _download_info_from_record(record: dict[str, Any]) -> DownloadInfo: | CODE |
| LOW | app/ytdl.py | 983 | def _seconds_until_next_probe(self) -> Optional[float]: | CODE |
| LOW | app/ytdl.py | 1021 | async def _probe_scheduled_download(self, download: Download) -> None: | CODE |
| LOW | app/ytdl.py | 1090 | def _schedule_upcoming_download(self, download: Download) -> None: | CODE |
| LOW | app/subscriptions.py | 144 | def _is_subscriber_only_entry(entry: dict) -> bool: | CODE |
| LOW | app/subscriptions.py | 239 | def _normalize_subscription_record(rec: dict[str, Any]) -> dict[str, Any]: | CODE |
| LOW | app/subscriptions.py | 257 | def _subscription_from_record(record: Any) -> Optional[SubscriptionInfo]: | CODE |
| LOW | app/subscriptions.py | 270 | def _normalize_title_regex_value(value: Any) -> str: | CODE |
| LOW | app/subscriptions.py | 404 | async def _queue_subscription_entries( | CODE |
| LOW | app/dl_formats.py | 34 | def _normalize_subtitle_language(language: str) -> str: | CODE |
| LOW | app/main.py | 37 | def seconds_until_next_daily_time(time_hhmm: str, now: datetime | None = None) -> float: | CODE |
| LOW | app/main.py | 334 | def _parse_ytdl_options_overrides(value, *, enabled: bool) -> dict: | CODE |
| LOW | app/main.py | 398 | def _parse_clip_timestamp_value(value) -> float: | CODE |
| LOW⚡ | app/main.py | 428 | def _clip_field_provided_in_post(raw) -> bool: | CODE |
| LOW⚡ | app/main.py | 436 | def _extract_t_query_from_url(url: str) -> tuple[str, float | None]: | CODE |
| LOW | app/main.py | 470 | def _parse_ytdl_options_presets(post: dict) -> list[str]: | CODE |
| LOW | app/main.py | 571 | async def _shutdown_download_manager(app): | CODE |
| LOW | app/main.py | 606 | async def _subscription_loop_startup(app): | CODE |
| LOW | app/main.py | 627 | async def _start_nightly_update_schedule(app): | CODE |
| LOW⚡ | app/tests/test_nightly_update.py | 12 | def test_seconds_until_later_today(self): | CODE |
| LOW⚡ | app/tests/test_nightly_update.py | 17 | def test_seconds_until_wraps_to_next_day(self): | CODE |
| LOW⚡ | app/tests/test_nightly_update.py | 22 | def test_seconds_until_same_minute_is_next_day(self): | CODE |
| LOW | app/tests/test_state_store.py | 13 | def test_save_and_load_roundtrip(self): | CODE |
| LOW | app/tests/test_state_store.py | 25 | def test_save_falls_back_to_direct_write_when_mkstemp_fails(self): | CODE |
| LOW | app/tests/test_state_store.py | 44 | def test_fallback_tightens_permissions_on_existing_file(self): | CODE |
| LOW | app/tests/test_state_store.py | 61 | def test_save_falls_back_to_direct_write_when_replace_fails(self): | CODE |
| LOW | app/tests/test_state_store.py | 77 | def test_save_reraises_when_atomic_and_direct_write_fail(self): | CODE |
| LOW | app/tests/test_state_store.py | 96 | def test_unsupported_fsync_keeps_atomic_path(self): | CODE |
| LOW | app/tests/test_state_store.py | 115 | def test_save_reraises_and_preserves_state_on_non_atomic_errno(self): | CODE |
| LOW | app/tests/test_state_store.py | 137 | def test_serialization_failure_preserves_existing_state(self): | CODE |
| LOW | app/tests/test_state_store.py | 154 | def test_invalid_file_is_quarantined(self): | CODE |
| LOW | app/tests/test_state_store.py | 168 | def test_json_compat_helpers_roundtrip_bytes_and_datetime(self): | CODE |
| LOW⚡ | app/tests/test_subscriptions.py | 88 | def test_is_subscriber_only_detects_availability(self): | CODE |
| LOW⚡ | app/tests/test_subscriptions.py | 93 | def test_coerce_optional_bool_defaults_and_fields(self): | CODE |
| LOW⚡ | app/tests/test_subscriptions.py | 102 | def test_load_imports_legacy_subscription_shelf(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 125 | def test_invalid_json_is_quarantined_and_legacy_is_imported(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 148 | def test_load_rewrites_old_json_and_trims_seen_ids(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 197 | async def test_add_subscription_rolls_back_when_state_write_fails(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 237 | async def test_add_subscription_marks_existing_videos_seen_without_queueing(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 276 | async def test_add_subscription_skips_collection_tab_entries(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 326 | async def test_check_now_keeps_failed_queue_items_unseen_and_sets_error(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 367 | async def test_check_now_queues_new_video_and_updates_seen_ids(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 412 | async def test_check_now_queues_subscriber_only_when_skip_disabled(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 463 | async def test_check_now_skips_subscriber_only_when_skip_enabled(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 514 | async def test_update_subscription_parses_string_false_enabled(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 548 | async def test_update_subscription_rejects_invalid_enabled_value(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 589 | async def test_add_subscription_rejects_invalid_title_regex(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 620 | async def test_add_subscription_stores_and_exposes_title_regex(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 652 | async def test_check_now_title_regex_queues_only_matches_and_marks_unmatched_seen(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 707 | async def test_check_now_title_regex_queue_failure_keeps_matched_id_unseen(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 759 | async def test_update_subscription_rejects_invalid_title_regex(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 791 | async def test_update_subscription_persists_valid_title_regex(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 824 | async def test_update_subscription_skip_subscriber_only(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 858 | async def test_update_subscription_rejects_invalid_skip_subscriber_only(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 890 | def test_persistence_includes_title_regex(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 932 | def test_persistence_includes_skip_subscriber_only(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 976 | def test_descends_one_level_when_root_entries_are_nested_collections(self): | CODE |
| LOW | app/tests/test_subscriptions.py | 1027 | def test_extra_opts_applied_on_top_of_config_options(self): | CODE |
| 178 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/state_store.py | 75 | except Exception as exc: | CODE |
| LOW | app/state_store.py | 113 | except Exception as exc: | CODE |
| LOW | app/state_store.py | 144 | except Exception: | CODE |
| MEDIUM | app/ytdl.py | 685 | def running(self): | CODE |
| MEDIUM | app/ytdl.py | 967 | def _wake_live_monitor(self) -> None: | CODE |
| LOW | app/ytdl.py | 171 | except Exception: | CODE |
| LOW | app/ytdl.py | 176 | except Exception: | CODE |
| LOW | app/ytdl.py | 674 | except Exception as e: | CODE |
| LOW | app/ytdl.py | 879 | except Exception: | CODE |
| LOW | app/ytdl.py | 892 | except Exception: | CODE |
| LOW | app/ytdl.py | 1013 | except Exception as exc: | CODE |
| LOW | app/ytdl.py | 1038 | except Exception as exc: | CODE |
| LOW | app/subscriptions.py | 478 | except Exception as e: | CODE |
| LOW | app/subscriptions.py | 632 | except Exception: | CODE |
| LOW | app/subscriptions.py | 657 | except Exception: | CODE |
| LOW | app/subscriptions.py | 723 | except Exception: | CODE |
| LOW | app/subscriptions.py | 788 | except Exception: | CODE |
| LOW | app/subscriptions.py | 807 | except Exception: | CODE |
| LOW | app/subscriptions.py | 823 | except Exception: | CODE |
| LOW | app/subscriptions.py | 947 | except Exception: | CODE |
| LOW | app/main.py | 289 | except Exception: | CODE |
| LOW⚡ | app/main.py | 446 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/ytdl.py | 180 | CODE | |
| LOW | app/ytdl.py | 321 | CODE | |
| LOW | app/ytdl.py | 548 | CODE | |
| LOW | app/ytdl.py | 694 | CODE | |
| LOW | app/ytdl.py | 989 | CODE | |
| LOW | app/ytdl.py | 1242 | CODE | |
| LOW | app/ytdl.py | 1563 | CODE | |
| LOW | app/ytdl.py | 562 | CODE | |
| LOW | app/subscriptions.py | 90 | CODE | |
| LOW | app/subscriptions.py | 239 | CODE | |
| LOW | app/subscriptions.py | 766 | CODE | |
| LOW | app/dl_formats.py | 96 | CODE | |
| LOW | app/main.py | 487 | CODE | |
| LOW | app/main.py | 697 | CODE | |
| LOW | app/tests/test_state_store.py | 77 | CODE | |
| LOW | app/tests/test_subscriptions.py | 197 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/state_store.py | 1 | CODE | |
| LOW | app/ytdl.py | 2 | CODE | |
| LOW | app/subscriptions.py | 3 | CODE | |
| LOW | app/tests/conftest.py | 3 | CODE | |
| LOW | app/tests/test_nightly_update.py | 3 | CODE | |
| LOW | app/tests/test_state_store.py | 1 | CODE | |
| LOW | app/tests/test_subscriptions.py | 1 | CODE | |
| LOW | app/tests/test_dl_formats.py | 3 | CODE | |
| LOW | app/tests/test_config.py | 3 | CODE | |
| LOW | app/tests/test_main_helpers.py | 3 | CODE | |
| LOW | app/tests/test_api.py | 3 | CODE | |
| LOW | app/tests/test_download_queue.py | 3 | CODE | |
| LOW | app/tests/test_ytdl_utils.py | 3 | CODE | |
| LOW | app/tests/test_bg_tasks.py | 3 | CODE | |
| LOW | app/tests/test_persistent_queue.py | 3 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/main.py | 635 | # Check if this path matches our YTDL_OPTIONS_FILE | COMMENT |
| LOW | .github/workflows/update-yt-dlp.yml | 28 | # Check if yt-dlp has updates available | COMMENT |
| LOW | .github/workflows/main.yml | 198 | # Check if release exists and delete it | COMMENT |
| LOW | .github/workflows/main.yml | 207 | # Check if tag exists (locally or remotely) and delete it | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | app/dl_formats.py | 40 | Returns yt-dlp format selector. Args: download_type (str): selected content type (video, audio, captions | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | app/ytdl.py | 253 | CODE | |
| LOW | app/ytdl.py | 1409 | CODE | |
| LOW | app/ytdl.py | 1476 | CODE |