Публічний реєстр
Звіт про здоров'я програмного забезпеченнясхема 0.27.0 · метрики 1.13.0 · 2026-07-27 17:38 UTC

freedy237 / freeflix-cli

Watch movies, series & anime from your terminal — multi-source, multi-language, no browser, no ads.

PythonGPL-3.0★ 6 зірок⑂ 0 форківз трав. 2026 р.Переглянути на GitHub ↗

freedy237/freeflix-cli має індекс здоров’я 52 зі 100, що відповідає смузі «Помірний». Найвищий показник — Vitality (72/100), найнижчий — Security (30/100). Останнє оновлення — сьогодні. Більшість нещодавньої роботи виконує один учасник.

52
загалом / 100
Помірний

Індекс здоров'я програмного забезпечення

Метрики згруповано у зважені категорії на шкалі 1–100. Загальна оцінка починається як їхнє середнє; коли публічні дані активують Політику юрисдикцій високого ризику, рейтинг коригується й отримує верхню межу 49 («Під ризиком»). Готовність до ШІ не входить до індексу.

52
Відмінний85-100Зразковий; відповідає практично всім перевіреним критеріям
Добрий70-84Здоровий; незначні прогалини
Помірний50-69Прийнятний, але з помітними прогалинами; рекомендовано перевірку
У зоні ризику30-49Суттєві слабкі місця; впровадження потребує обережності
Критичний1-29Серйозні проблеми (покинутий, єдиний мейнтейнер, без базової гігієни)
ЖиттєздатністьСпільнота тавпровадженняСталість таврядуванняІнженернаякістьБезпекаГотовність доШІ

Профіль оцінок

Кожна вісь — окрема категорія. Форма важить більше, ніж середнє: здоровий об'єкт заповнює всю фігуру, тоді як профіль із піками та провалами означає, що сила в одному вимірі маскує ризик в іншому.

Власність

freedy237Особистий обліковий запис
0 підписників3 публічні репозиторіїз бер. 2025 р.

Цей репозиторій належить особистому обліковому запису. Проєкт з єдиним власником несе більший ризик безперервності, ніж підтримуваний організацією.

Пакетні екосистеми

РеєстрПакетВерсіяЗавантажень / місВерсіїОстання публікаціяТеги
PyPIfreeflix-cli1.9.32 922610 днів томуvfvostfranimeanime-samaharunamoviesmpvseriesstreaming

Метрики за категоріями

Життєздатність

Чи живий проєкт — чи пишеться код і чи виходять релізи?

72Добрий · 22% загального індексу
Як обчислюється оцінка
36/36Свіжість push — останній push 0 дн. тому
6.2/36Ритм комітів — 9/52 тижнів із комітами
18/18Обсяг комітів — 113 комітів за останній рік
0/10OpenSSF Scorecard: Maintained — project was created within the last 90 days. Please review its contents carefully
Використані вхідні дані
commits_last_year113
human_commit_share1
days_since_last_push0
active_weeks_last_year9
Як обчислюється оцінка
27/27Випускає релізи — опубліковано 61 релізів
36/36Свіжість релізів — останній реліз 0 дн. тому
27/27Ритм релізів — реліз кожні ~2,6 дн.
0/10OpenSSF Scorecard: Signed-Releases — Project has not signed or included provenance with any releases.
Використані вхідні дані
releases_count61
latest_release_tagv1.9.3
releases_from_tagsні
days_since_latest_release0
mean_days_between_releases2,6

Спільнота та впровадження

Чи має проєкт користувачів, завантаження, увагу та влаштовані умови для контриб’юторів?

36У зоні ризику · 18% загального індексу
Як обчислюється оцінка
11.3/60Зірки — 6 зірок
0/25Форки — 0 форків
0/15Спостерігачі — 0 спостерігачів
Використані вхідні дані
forks0
stars6
watchers0
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (GPL-3.0)
0/18Настанови CONTRIBUTING
0/13.5Кодекс поведінки
0/7.2Шаблон issue
0/6.3Шаблон PR
Використані вхідні дані
has_readmeтак
has_licenseтак
has_contributingні
has_issue_templateні
has_code_of_conductні
has_pull_request_templateні
Як обчислюється оцінка
46.2/80Щомісячні завантаження — 2 922 завантажень/місяць у pypi
0/20Залежні пакети в реєстрі — ця екосистема цього не повідомляє
Використані вхідні дані
packagesfreeflix-cli
dependents
ecosystemspypi
total_downloads
monthly_downloads2 922
Виключено з оцінювання (немає даних або не застосовно): Залежні пакети в реєстрі. Залишкові ваги перенормовано.

Сталість та врядування

Чи переживе проєкт своїх людей — бас-фактор, реактивність, хто за ним стоїть і як супроводжуються пакети?

47У зоні ризику · 24% загального індексу
Як обчислюється оцінка
9/54Бас-фактор — на 1 контриб’ютор(ів) припадає половина всіх комітів
0/22.5Розподіл комітів — головний контриб’ютор — автор 100% комітів
1.4/13.5Широта контриб’юторів — 1 контриб’юторів
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Використані вхідні дані
bus_factor1
contributors_sampled1
top_contributor_share1
Як обчислюється оцінка
46.8/46.8Вирішення issue — закрито 100% issue
0/38.3Прийняття PR — немає вирішених pull request-ів або даних
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Використані вхідні дані
merged_prs0
open_issues0
closed_issues1
issue_closed_ratio1
closed_unmerged_prs0
Виключено з оцінювання (немає даних або не застосовно): Прийняття PR. Залишкові ваги перенормовано.
Як обчислюється оцінка
10/30Підтримка власника — особистий (користувацький) обліковий запис
0/20Верифікований домен — не застосовно до користувацьких облікових записів
0/25Охоплення власника — 0 підписників у freedy237
7.1/25Послужний список — 3 публічних репозиторіїв, вік облікового запису ~1 р.
Використані вхідні дані
followers0
owner_typeUser
is_verified
owner_loginfreedy237
public_repos3
account_age_days487
Виключено з оцінювання (немає даних або не застосовно): Верифікований домен. Залишкові ваги перенормовано.

Супровід пакетів

100Відмінний
Як обчислюється оцінка
25/25Опубліковано й доступно — 1 пакет(ів) у pypi
35/35Свіжість публікацій — остання публікація 0 дн. тому
20/20Історія версій — 61 опублікованих версій
20/20Не застарілий — активний, не deprecated і не yanked
Використані вхідні дані
packagesfreeflix-cli
ecosystemspypi
any_deprecatedні
min_days_since_publish0

Інженерна якість

Чи наявні базові інженерні практики та документація?

66Помірний · 20% загального індексу
Як обчислюється оцінка
24/24Процеси CI — 2 процес(ів) CI
24/24Наявні тести
0/16Конфігурація лінтера
0/9.6Pre-commit-хуки
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — немає даних
Використані вхідні дані
has_ciтак
has_testsтак
has_editorconfigні
has_linter_configні
has_precommit_configні
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: CI-Tests. Залишкові ваги перенормовано.
Як обчислюється оцінка
30/30README
0/25Каталог документації
15/15Сайт документації / домашня сторінка — https://github.com/freedy237/freeflix-cli
10/10Опис репозиторію
10/10Теми — 20 тем
10/10Wiki
Використані вхідні дані
topicsanilist, anime, anime-sama, aria2, cli, french, hls, mpv, nyaa, python, streaming, terminal, vf, vostfr, yt-dlp, anime4k, downloader, movies, series, tui
has_wikiтак
homepagehttps://github.com/freedy237/freeflix-cli
has_readmeтак
has_docs_dirні
has_descriptionтак

Безпека

Чи міцні видимі практики безпеки й ланцюга постачання, без непослабленої пов’язаності з юрисдикціями високого ризику?

30У зоні ризику · 16% загального індексу

Стан безпеки

30У зоні ризику
Як обчислюється оцінка
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — немає даних
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Ліцензія — license file detected
0/7.5Maintained — project was created within the last 90 days. Please review its contents carefully
5/5Packaging — packaging workflow detected
0/5Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — Project has not signed or included provenance with any releases.
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
6/7.5Vulnerabilities — 2 existing vulnerabilities detected
Використані вхідні дані
sourceopenssf_scorecard
checks_evaluated17
scorecard_versionv5.5.0
checks_inconclusive1
scorecard_aggregate3
Виключено з оцінювання (немає даних або не застосовно): ci_tests. Залишкові ваги перенормовано.

Готовність до ШІ

Наскільки репозиторій оснащений для розробки та супроводу за участі ШІ-агентів? Незалежний, експериментальний бейдж — вага 0.0, тож він подається окремо і не впливає на загальний індекс здоров'я.

39У зоні ризику · 0% загального індексу
Як обчислюється оцінка
0/45Інструкції для агентів — немає CLAUDE.md / AGENTS.md / правил редактора
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 77 з 100 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share0,77
agent_instruction_files
agent_instruction_max_bytes
Як обчислюється оцінка
0/18Розгортання однією командою
22/22Автоматизовані тести
0/11Конфігурація лінтера / форматера
0/11Статична перевірка типів
10/10Відтворюване середовище — lockfile
0/10Підтверджена практика роботи з агентами — серед останніх 100 комітів немає створених агентом
0/8Автоматизоване супроводження — автоматичних оновлень залежностей не виявлено
0/10OpenSSF Scorecard: Pinned-Dependencies — dependency not pinned by hash detected -- score normalized to 0
Використані вхідні дані
has_nixні
has_testsтак
lockfilesuv.lock
has_dockerfileні
typed_languageні
bootstrap_files
has_devcontainerні
has_linter_configні
typecheck_configs
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
Як обчислюється оцінка
0/45Типізований код — Python без конфігурації перевірки типів
53.5/55Керовані розміри файлів — 2/73 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languagePython
largest_source_bytes77 028
source_files_sampled73
oversized_source_files2

Ключові факти

6зірок GitHub
1контриб'юторів
113комітів за останні 12 місяців
0днів від останнього пушу
61релізів
1бас-фактор
0відкритих issue
PyPIпакетних екосистем

Попередження щодо збору даних

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token
  • GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository
  • deps.dev does not index pypi:freeflix-cli@1.9.3; advisories assessed against the repository dependency graph instead

Докладніше

OpenSSF Scorecard 3.0 / 10
3.0сукупно

Незалежна, не прив'язана до інструментів оцінка безпеки від відкритого проєкту OpenSSF Scorecard. Кожна перевірка винагороджує практику безпеки, а не інструмент конкретного постачальника. Перевірки, які Scorecard не зміг визначити, позначено н/д і виключено з оцінки безпеки (вони ніколи не зараховуються як нуль).Scorecard v5.5.0 · 2026-07-27 17:38 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
н/дCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
0Maintainedproject was created within the last 90 days. Please review its contents carefully
10Packagingpackaging workflow detected
0Pinned-Dependenciesdependency not pinned by hash detected -- score normalized to 0
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
0Signed-ReleasesProject has not signed or included provenance with any releases.
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
8Vulnerabilities2 existing vulnerabilities detected
Прямі залежності 10
РеєстрПакетОбмеження версіїМаніфест
PyPIbeautifulsoup4>=4.14.3pyproject.toml
PyPIcurl-cffi>=0.13.0pyproject.toml
PyPIflask>=3.1.2pyproject.toml
PyPIhtml5lib>=1.1pyproject.toml
PyPIjsbeautifier>=1.15.4pyproject.toml
PyPIm3u8>=6.0.0pyproject.toml
PyPIplatformdirs>=4.0.0pyproject.toml
PyPIpycryptodome>=3.23.0pyproject.toml
PyPIreadchar>=4.2.1pyproject.toml
PyPIrich>=14.2.0pyproject.toml
Усі залежності не зібрано

Не вдалося зібрати розв'язаний набір залежностей для цього звіту: GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository

Звіт у форматі JSON машиночитний
{
  "data": {
    "repo": {
      "topics": [
        "anilist",
        "anime",
        "anime-sama",
        "aria2",
        "cli",
        "french",
        "hls",
        "mpv",
        "nyaa",
        "python",
        "streaming",
        "terminal",
        "vf",
        "vostfr",
        "yt-dlp",
        "anime4k",
        "downloader",
        "movies",
        "series",
        "tui"
      ],
      "is_fork": false,
      "size_kb": 1765,
      "has_wiki": true,
      "homepage": "https://github.com/freedy237/freeflix-cli",
      "languages": {
        "Lua": 2019,
        "Shell": 16580,
        "Python": 744819,
        "PowerShell": 4697
      },
      "pushed_at": "2026-07-27T17:22:03Z",
      "created_at": "2026-05-28T05:05:04Z",
      "owner_type": "User",
      "updated_at": "2026-07-27T17:23:45Z",
      "description": "Watch movies, series & anime from your terminal — multi-source, multi-language, no browser, no ads.",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "GPL-3.0",
      "default_branch": "main",
      "license_spdx_raw": "GPL-3.0",
      "primary_language": "Python",
      "significant_languages": [
        "Python"
      ]
    },
    "owner": {
      "blog": null,
      "name": null,
      "type": "User",
      "login": "freedy237",
      "company": null,
      "location": null,
      "followers": 0,
      "avatar_url": "https://avatars.githubusercontent.com/u/205066866?v=4",
      "created_at": "2025-03-26T17:50:43Z",
      "is_verified": null,
      "public_repos": 3,
      "account_age_days": 487
    },
    "license": {
      "state": "standard",
      "spdx_id": "GPL-3.0",
      "raw_spdx": "GPL-3.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v1.9.3",
          "kind": "patch",
          "published_at": "2026-07-27T17:22:39Z"
        },
        {
          "tag": "v1.9.2",
          "kind": "patch",
          "published_at": "2026-07-23T06:06:47Z"
        },
        {
          "tag": "v1.9.0",
          "kind": "minor",
          "published_at": "2026-07-18T06:10:06Z"
        },
        {
          "tag": "v1.8.5",
          "kind": "patch",
          "published_at": "2026-07-07T15:10:10Z"
        },
        {
          "tag": "v1.8.4",
          "kind": "patch",
          "published_at": "2026-07-07T14:58:38Z"
        },
        {
          "tag": "v1.8.3",
          "kind": "patch",
          "published_at": "2026-07-06T20:56:17Z"
        },
        {
          "tag": "v1.8.2",
          "kind": "patch",
          "published_at": "2026-07-06T07:03:40Z"
        },
        {
          "tag": "v1.8.1.post1",
          "kind": "other",
          "published_at": "2026-07-05T19:59:36Z"
        },
        {
          "tag": "v1.8.1",
          "kind": "patch",
          "published_at": "2026-07-05T19:21:49Z"
        },
        {
          "tag": "v1.8.0",
          "kind": "minor",
          "published_at": "2026-07-03T23:42:02Z"
        },
        {
          "tag": "v1.7.9",
          "kind": "patch",
          "published_at": "2026-07-01T08:16:53Z"
        },
        {
          "tag": "v1.7.8",
          "kind": "patch",
          "published_at": "2026-06-30T22:21:23Z"
        },
        {
          "tag": "v1.7.7",
          "kind": "patch",
          "published_at": "2026-06-29T20:20:40Z"
        },
        {
          "tag": "v1.7.6",
          "kind": "patch",
          "published_at": "2026-06-28T22:22:21Z"
        },
        {
          "tag": "v1.7.5",
          "kind": "patch",
          "published_at": "2026-06-27T15:57:11Z"
        },
        {
          "tag": "v1.7.4",
          "kind": "patch",
          "published_at": "2026-06-27T09:04:25Z"
        },
        {
          "tag": "v1.7.3",
          "kind": "patch",
          "published_at": "2026-06-26T10:20:30Z"
        },
        {
          "tag": "v1.7.2",
          "kind": "patch",
          "published_at": "2026-06-22T16:50:26Z"
        },
        {
          "tag": "v1.7.1",
          "kind": "patch",
          "published_at": "2026-06-20T16:40:12Z"
        },
        {
          "tag": "v1.7.0",
          "kind": "minor",
          "published_at": "2026-06-20T12:34:18Z"
        },
        {
          "tag": "v1.6.12",
          "kind": "patch",
          "published_at": "2026-06-20T03:12:15Z"
        },
        {
          "tag": "v1.6.11",
          "kind": "patch",
          "published_at": "2026-06-18T07:57:04Z"
        },
        {
          "tag": "v1.6.10",
          "kind": "patch",
          "published_at": "2026-06-17T19:59:48Z"
        },
        {
          "tag": "v1.6.8",
          "kind": "patch",
          "published_at": "2026-06-12T14:00:15Z"
        },
        {
          "tag": "v1.6.7",
          "kind": "patch",
          "published_at": "2026-06-10T19:16:40Z"
        },
        {
          "tag": "v1.6.6",
          "kind": "patch",
          "published_at": "2026-06-09T17:34:46Z"
        },
        {
          "tag": "v1.6.5",
          "kind": "patch",
          "published_at": "2026-06-08T16:41:00Z"
        },
        {
          "tag": "v1.6.4",
          "kind": "patch",
          "published_at": "2026-06-06T06:31:00Z"
        },
        {
          "tag": "v1.6.3",
          "kind": "patch",
          "published_at": "2026-06-06T05:46:39Z"
        },
        {
          "tag": "v1.6.2",
          "kind": "patch",
          "published_at": "2026-06-06T05:32:48Z"
        },
        {
          "tag": "v1.6.1",
          "kind": "patch",
          "published_at": "2026-06-06T05:20:47Z"
        },
        {
          "tag": "v1.6.0",
          "kind": "minor",
          "published_at": "2026-06-05T21:47:08Z"
        },
        {
          "tag": "v1.5.9",
          "kind": "patch",
          "published_at": "2026-06-04T20:21:20Z"
        },
        {
          "tag": "v1.5.8",
          "kind": "patch",
          "published_at": "2026-06-04T17:54:44Z"
        },
        {
          "tag": "v1.5.7",
          "kind": "patch",
          "published_at": "2026-06-04T15:59:07Z"
        },
        {
          "tag": "v1.5.6",
          "kind": "patch",
          "published_at": "2026-06-04T11:35:28Z"
        },
        {
          "tag": "v1.5.4",
          "kind": "patch",
          "published_at": "2026-06-04T10:21:47Z"
        },
        {
          "tag": "v1.5.3",
          "kind": "patch",
          "published_at": "2026-06-04T09:23:57Z"
        },
        {
          "tag": "v1.5.2",
          "kind": "patch",
          "published_at": "2026-06-04T08:10:58Z"
        },
        {
          "tag": "v1.5.1",
          "kind": "patch",
          "published_at": "2026-06-03T20:18:18Z"
        },
        {
          "tag": "v1.5.0",
          "kind": "minor",
          "published_at": "2026-06-03T19:16:17Z"
        },
        {
          "tag": "v1.4.5",
          "kind": "patch",
          "published_at": "2026-05-31T20:59:23Z"
        },
        {
          "tag": "v1.4.4",
          "kind": "patch",
          "published_at": "2026-05-31T16:46:04Z"
        },
        {
          "tag": "v1.4.3",
          "kind": "patch",
          "published_at": "2026-05-31T16:20:13Z"
        },
        {
          "tag": "v1.4.2",
          "kind": "patch",
          "published_at": "2026-05-31T15:56:59Z"
        },
        {
          "tag": "v1.4.1",
          "kind": "patch",
          "published_at": "2026-05-31T15:35:11Z"
        },
        {
          "tag": "v1.4.0",
          "kind": "minor",
          "published_at": "2026-05-31T15:23:24Z"
        },
        {
          "tag": "v1.3.3",
          "kind": "patch",
          "published_at": "2026-05-30T17:28:16Z"
        },
        {
          "tag": "v1.3.2",
          "kind": "patch",
          "published_at": "2026-05-30T17:13:54Z"
        },
        {
          "tag": "v1.3.1",
          "kind": "patch",
          "published_at": "2026-05-28T10:38:45Z"
        },
        {
          "tag": "v1.3.0",
          "kind": "minor",
          "published_at": "2026-05-28T10:34:53Z"
        },
        {
          "tag": "v1.2.0",
          "kind": "minor",
          "published_at": "2026-05-28T10:15:32Z"
        },
        {
          "tag": "v1.1.7",
          "kind": "patch",
          "published_at": "2026-05-28T08:01:56Z"
        },
        {
          "tag": "v1.1.6",
          "kind": "patch",
          "published_at": "2026-05-28T07:50:32Z"
        },
        {
          "tag": "v1.1.5",
          "kind": "patch",
          "published_at": "2026-05-28T07:36:58Z"
        },
        {
          "tag": "v1.1.4",
          "kind": "patch",
          "published_at": "2026-05-28T07:31:22Z"
        },
        {
          "tag": "v1.1.3",
          "kind": "patch",
          "published_at": "2026-05-28T07:24:45Z"
        },
        {
          "tag": "v1.1.2",
          "kind": "patch",
          "published_at": "2026-05-28T07:20:16Z"
        },
        {
          "tag": "v1.1.1",
          "kind": "patch",
          "published_at": "2026-05-28T07:17:04Z"
        },
        {
          "tag": "v1.1.0",
          "kind": "minor",
          "published_at": "2026-05-28T07:01:30Z"
        },
        {
          "tag": "v1.0.0",
          "kind": "major",
          "published_at": "2026-05-28T05:06:37Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "785a9fb2e5b68ff8b6aae756ee152443ba7d9a0e",
          "body": "Source network errors no longer crash the app (clean panel + resilient\nget_website_url via cf_get). New Android/Termux mode: playback delegated\nto mpv-android via intent + dedicated first-run setup. See CHANGELOG.md.",
          "is_bot": false,
          "headline": "release: 1.9.3 — crash-proof sources + Android (Termux) mode",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-27T17:21:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d32a8241ef70aa22fd5d21bc63b216accdf332b5",
          "body": "New platform_android.py : detect Termux/proot Android + hand playback to\nan external Android player (mpv-android, then VLC) via an 'am start' intent\nthat reads FreeFlix's local proxy over the shared loopback (headers +\nm3u8 rewriting preserved). No display needed.\n\n- New 'android' player, auto-offer\n[…]\nre_runtime_deps no longer\n  downloads x86_64 static builds on Android. The 'player' tool counts as\n  present via mpv-android.\nUnit-tested (detection, intent fallback, pkg/apt install, wizard routing).",
          "is_bot": false,
          "headline": "feat: Android (Termux/proot) mode — playback + first-run setup",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-27T16:29:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "889175d66b27b598811ad9d22069265bc102b8b3",
          "body": "A 'Connection reset by peer' (curl 56) in Anime-Sama's get_website_url\npropagated uncaught and killed the whole app. Now:\n- the source-handler dispatch is wrapped in a guard that shows a clean\n  'source unreachable' panel and returns to the source list (any source,\n  any network/DNS/TLS error);\n- get_website_url routes through cloudflare.cf_get (retries transient\n  resets, then plain, then DoH) so a flaky first hit doesn't fail outright.",
          "is_bot": false,
          "headline": "fix: a source network failure no longer crashes the app (R4)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-27T16:28:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "96b460d96f99eb4133757bb116f49cdd4677ae5f",
          "body": "…resilience, mpv IPC binge\n\nSee CHANGELOG.md. A3 cache, B2 posters (Windows+Linux bugs) + kitty/iterm,\n#5 hot-patchable selectors, mpv JSON-IPC live resume + auto-next episode.",
          "is_bot": false,
          "headline": "release: 1.9.2 — HTTP cache, reliable posters+kitty/iterm, extractor …",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-23T06:05:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a759e23e252809d34d7a6cb2f86a6a25923dd8a8",
          "body": "New mpv_ipc.py : cross-platform client (AF_UNIX socket / Windows named\npipe) for mpv's --input-ipc-server. A background PlaybackMonitor saves\ntime-pos LIVE (survives a crash — the old lua hook only wrote on clean\nexit) and learns the end reason (eof vs quit).\n\nplay_video launches mpv with --input-ip\n[…]\n EOF, the next one auto-plays\nafter a cancelable countdown (confirm_or_timeout); if the user quit early,\nit still just asks. Unit-tested against a fake mpv IPC server (pos/dur\ntracking + eof-vs-quit).",
          "is_bot": false,
          "headline": "feat: mpv JSON-IPC — live resume + auto-play-next / binge",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-23T06:01:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5e7cbf25e41ff6af34753c6453c52718a582eb1e",
          "body": "New scraping/resilient.py : fragile CSS selectors live in a table that a\nremote data/selectors.jsonc can override (background-fetched like portals),\nso a broken source can be fixed for everyone WITHOUT a release. first_text/\nfirst_attr try a list of selectors in order (a renamed class still resolves\nvia the next fallback). Anime-Sama search + get_series now ride on it, with\ntoday's selectors as defaults (zero behavior change until a patch is pushed).",
          "is_bot": false,
          "headline": "feat: hot-patchable extractor selectors + multi-strategy fallback (#5)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-23T05:32:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f14d799a7f5151ee34606e0646ef9d83611f36b6",
          "body": "Windows: force encoding='utf-8' when capturing chafa's symbol output —\ntext=True decoded as cp1252 and raised UnicodeDecodeError, so posters\nsilently never rendered during search on Windows (only the direct\nfull-screen render after selecting worked).\n\nReliability (both OSes): stop caching FAILED ren\n[…]\nect_image_protocol() hands chafa a real graphics format\n(kitty on Kitty/Ghostty/WezTerm, iterm on iTerm2) when the env AND chafa\nversion confirm support; otherwise defers to chafa's own autodetection.",
          "is_bot": false,
          "headline": "feat: reliable posters + kitty/iTerm2 image protocol (B2)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-23T05:24:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f7c14954e107c9e3b0354347f33632650d22e566",
          "body": "New httpcache module (per-URL JSON on disk, TTL freshness, CachedResponse\nshim). Wired into Anime-Sama search/series/season (cache-buster-safe key)\nand the Cinemeta films/series metadata reads. Repeat browsing is instant\n(1.8s -> ~30ms). Settings gains a 'Clear HTTP cache' action with size.\nBest-effort: any I/O error behaves as a miss, never breaks a fetch.",
          "is_bot": false,
          "headline": "feat: persistent HTTP cache for catalogue reads (A3)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-23T05:17:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cb4cb0b1f479cf4b5d8c144121e240f4d395ce04",
          "body": "…13 Windows)\n\n_find_in_tar passed filter='data' unconditionally; the PEP 706 backport is\nabsent on older 3.9 (e.g. the 3.9.13 Windows runner), raising TypeError and\nsilently failing the managed ffmpeg install. Fall back to a plain extract.",
          "is_bot": false,
          "headline": "fix: tar extract falls back when 'data' filter is unavailable (py3.9.…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-18T06:15:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "05182ee76ca8d0b3bd04095c4984bfb3f62509f2",
          "body": "_have_managed appends .exe on Windows, so the fixture files must too.\nWas a pre-existing Linux-only assumption; the new Windows CI leg caught it.",
          "is_bot": false,
          "headline": "test: make managed-binary tests Windows-aware (.exe suffix)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-18T06:12:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "551a131728af8ae4744119fd67f77aee6984c339",
          "body": "Perf\n- Proxy Flask démarré paresseusement à la 1re lecture (plus de Flask ni de\n  port ouvert au lancement) ; options DNS déplacées dans net_config léger.\n- Badges d'épisodes : listing de dossier mis en cache (fin des ~6 stat/ligne).\n\nSécurité\n- Garde anti-SSRF sur le proxy local (refus des IP loopb\n[…]\nns (Ubuntu + Windows, py3.9/3.12) : ruff + pytest.\n- Tests clavier multi-plateformes, SSRF, démarrage proxy, santé des sources.\n\nNettoyage\n- Code mort retiré (get_language_flag, cloudflare.available).",
          "is_bot": false,
          "headline": "1.9.0 — optimisation & robustesse (Linux + Windows)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-18T06:09:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "011b02f9c9a40dcec48f9fc3ab5028176bb00d4c",
          "body": "_read_menu_key Windows path: read the \\x00/\\xe0 special-key scan code\nunconditionally (the kbhit() guard made arrows do nothing in classic console),\nand drain the \\x1b[… VT sequence with a short bounded wait so VT arrows aren't\nmistaken for a lone Esc. Focus events still ignored; isolated Esc still = back.",
          "is_bot": false,
          "headline": "1.8.5 — Windows: fix arrow keys (1.8.4 regression)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-07T15:07:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "03e215b655c4b621c91272ce13924aee11ab66a0",
          "body": "- Phantom Esc / self-close on Windows: add a msvcrt path to _read_menu_key that\n  drains the full escape sequence and ignores focus (\\x1b[I/\\x1b[O) / mouse\n  events (only an isolated \\x1b is Esc); handle \\x00/\\xe0 arrow prefixes. Use\n  _read_menu_key in select_with_preview's non-raw path too (the se\n[…]\nder download no longer re-triggers \"install the\n  players\"). _have() also resolves mpv.net/VLC via get_mpv_path/get_vlc_path on\n  Windows so an installed-but-not-on-PATH player isn't reported missing.",
          "is_bot": false,
          "headline": "1.8.4 — Windows: robust key reader (phantom Esc) + stop player re-prompt",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-07T14:56:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "42e32a393ee1ff0033fa231d1987ce0948fd0e1c",
          "body": "… themes, downloads manager\n\n- Search history: tracker.add/get_search_query; get_user_input `history=` shows a\n  recent-searches helper with ↑/↓ recall; wired into anime_sama/french_stream/\n  papystreaming.\n- New releases: recent.py daemon fetches newer seasons for history shows (non-\n  blocking); \"\n[…]\ne_settings\n  with a live preview panel.\n- Downloads manager: _downloads_summary (disk free + total size) as select_from_list\n  top=; play/delete finished files; loop UX. select_from_list gains `top=`.",
          "is_bot": false,
          "headline": "1.8.3 — search history, background new-releases, settings categories,…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-06T20:55:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3fcf54a5792ab23384f452bf6c6a26920a04babe",
          "body": "…+ startup bar\n\n- Home dashboard (_home_dashboard): greeting + stats line (this week / streak /\n  in-progress) + Continue-watching carousel with resume/watched/downloaded\n  badges, from local data. select_from_list gains a `top=` renderable rendered\n  above the menu (home passes the dashboard).\n- Mo\n[…]\n startup splash + remaining Anime-Sama\n  in-flow messages.\n- Fix the startup loading bar: proportional catch-up easing (x0.5, 0.06 floor)\n  so it fills to 100% within a few frames instead of crawling.",
          "is_bot": false,
          "headline": "1.8.2 — enriched home dashboard + source order/badges + translations …",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-06T07:02:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "73690d7ad03318c98021a10354a8c8b040dcaf38",
          "body": "Post-release of 1.8.1 (PyPI is immutable, so these ship as .post1).\n\n- anime_sama.get_series: replace the split('panneauAnime(\"')[2:]+break parser\n  (stopped early → dropped Dr Stone S3 P2 / S4 + parts) with a regex over the\n  whole page. AniList continue flow benefits too.\n- Phantom Esc: _read_menu\n[…]\nrains the full escape sequence and ignores focus\n  (\\x1b[I/\\x1b[O) / mouse / paste events; only an isolated \\x1b is Esc. Add\n  disable_terminal_reports() called at startup and after every player exit.",
          "is_bot": false,
          "headline": "1.8.1.post1 — Anime-Sama missing seasons + phantom-Esc / self-close fix",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-05T19:57:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d8d289de83f0f1f82e78d598753591e0cc84e847",
          "body": null,
          "is_bot": false,
          "headline": "docs: add 'Why FreeFlix' value-prop showcase to README",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-05T19:23:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "67ece522662d717470f29e1b7540a2f8a764a689",
          "body": "…loaded)\n\n- select_from_list: '/' enters a type-to-filter mode (view of original indices,\n  returns the original index; Enter picks, Esc clears). Status bar + i18n keys.\n- Episode badges via player_manager.episode_badges(series, season, ep) using the\n  same md5(window_title) key as resume: ✓ watched (tracker.watched_episodes,\n  marked on successful play in play_episode_flow), ▸NNm resume (saved position),\n  ⬇ downloaded (file on disk). Wired into anime_sama / coflix / french_stream.",
          "is_bot": false,
          "headline": "1.8.1 — '/' filter in lists + episode badges (watched / resume / down…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-05T19:17:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "54f09b96866eee96c3dc47b21c74e3a38753341c",
          "body": "…pass\n\nNavigation\n- Breadcrumb trail rendered above every menu (crumb_reset/crumb_push + scoped\n  `crumb` CM in cli_utils; wired in home/sources/settings and the anime_sama,\n  coflix, french_stream, papystreaming flows). Left-truncates on long trails.\n- '?' opens a help overlay listing all shortcuts\n[…]\n get_hls_link; B904 raise-from in cloudflare; B007\n  unused loop vars; E401 split imports; E741 renames; W29x whitespace; noqa-\n  document the deliberate late imports (E402). Renumber run_setup steps.",
          "is_bot": false,
          "headline": "1.8.0 — navigation UI (breadcrumbs, ? help, status bar) + full audit …",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-03T23:41:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "acce237f43c9c6014c7ace4e7d5c340b62cac041",
          "body": "VLC\n- Hide VLC's libav/libva/codec console flood (run stdout/stderr to DEVNULL,\n  pass --quiet) in both proxy and direct modes.\n- Cap the HLS adaptive ladder to the chosen resolution via --adaptive-maxheight\n  so VLC stops ramping to the highest variant and ignoring the picked quality.\n\nCleanup\n- Re\n[…]\ning/player, subtitles) so Ctrl-C / real errors propagate.\n- Add missing network timeouts: anime_sama/coflix `_get` wrappers + portal\n  get/head calls, cloudflare.get wrapper, goldenanime requests.get.",
          "is_bot": false,
          "headline": "1.7.9 — VLC quiet + quality cap, internal cleanup (excepts, timeouts)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-07-01T08:15:52Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "eb9b24637d43f50ccfc5ebc08abfb15e55736a3b",
          "body": "Linux install\n- mpv & aria2 static-build repos 404'd → install both via the distro package\n  manager (apt/dnf/pacman/zypper/apk) with a prompt; add VLC for parity. ffmpeg\n  stays self-managed. The deps cache is version-aware so updaters re-check.\n\nNerd Font\n- run_setup installs the Nerd Font on ever\n[…]\nguage/quality badges in the player menu via _player_label.\n- toast() helper; settings confirmations use it instead of print+pause.\n\nOther\n- Update notice shows only `uv tool upgrade` (we ship via uv).",
          "is_bot": false,
          "headline": "1.7.8 — Linux install fix, Nerd Font dep, AniList flow upgrade, comfort",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-30T22:20:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "da9bf08bc4ba129ade46f2f578fa23d63087ca05",
          "body": "…s set)",
          "is_bot": false,
          "headline": "Restore 'Continue from AniList' home-menu entry (shown when a token i…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-29T20:56:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "382f2e5a84d23238e8c1ab60bf715fae7260c501",
          "body": null,
          "is_bot": false,
          "headline": "docs: remove Project layout and French summary sections from README",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-29T20:29:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7c626ad156303cd63e4b2fe3032ee7080ed59487",
          "body": null,
          "is_bot": false,
          "headline": "docs: drop stale v1.7.2 callout from README",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-29T20:24:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a82b0d60c254e59290caf3f341336039b49e9dea",
          "body": "Add assets/logo.png and a centered header (logo + title + badges + tagline)\nusing an absolute raw URL so it renders on both GitHub and PyPI.",
          "is_bot": false,
          "headline": "docs: add FreeFlix-CLI logo + centered README header",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-29T20:23:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4ab4264db7d401de31b208790e9a1dc76d84a098",
          "body": "- All backends download into the hidden .temp/ dir; the final file is placed in\n  Downloads (or the season subfolder) only on success. aria2c used to write the\n  .mp4 directly into Downloads, leaving a partial there on a dropped connection.\n  Interrupted downloads now stay in .temp/ (resumable) and \n[…]\n Downloads\" lists interrupted downloads (list_interrupted_downloads) with % (HLS\n  via .ytdl) or MB, and offers Resume (resume_download) / Delete. .temp is now\n  excluded from the playable-files walk.",
          "is_bot": false,
          "headline": "1.7.7 — no partial files in Downloads + resume interrupted downloads",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-29T20:19:34Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9e8380e547b3a605057dc9177dd24833050b313e",
          "body": "…older\n\ntest_download_fixes.py created a stable temp dir under the REAL DOWNLOAD_DIR\n(~/Downloads/FreeFlix/.temp/<title>) then \"cleaned up\" with\nrmtree(dirname(dirname(d1))) == rmtree(~/Downloads/FreeFlix), wiping the user's\nactual downloads on every pytest run. Clean up only the dirs the test created.",
          "is_bot": false,
          "headline": "test: stop test cleanup from deleting the real ~/Downloads/FreeFlix f…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-28T22:37:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4c2c6c56ecf375294e08cc8a29b317a37372367a",
          "body": "… Font\n\n- Esc on Linux: arrow menus now read keys with a raw reader that detects a lone\n  Esc via a 50 ms peek (readchar blocks on Esc waiting for a 2nd byte on POSIX,\n  so Esc did nothing on Linux). Esc reliably steps back one level on every OS.\n- Anime4K on Windows: the real cause was mpv.conf's s\n[…]\nrd_font early-returned before); plus a one-time launch\n  check (ensure_nerd_terminal_font) applies it when icon style is already nerd.\n- Hint \"Space: select\" at the bottom of the episode multi-select.",
          "is_bot": false,
          "headline": "1.7.6 — Esc works on Linux, Anime4K fixed on Windows (mpv.conf), Nerd…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-28T22:21:27Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9f02beb8933923d566557f9700c9add75cf21ae3",
          "body": "Season downloads\n- Episode list offers a plain \"Download\" → choose quality → multi-select which\n  episodes to grab (Space toggles, `a` all). Episodes already on disk are\n  detected, shown locked and skipped. Each season goes into its own folder\n  (Downloads/FreeFlix/<Series - Season>/) with clean pe\n[…]\npystreaming moved to EN sources and renamed (no \"VF\").\n- Subtitle download OFF by default.\n- Translate default-player names (download/manual/browser).\n- Remove \"Continue from AniList\" home-menu entry.",
          "is_bot": false,
          "headline": "1.7.5 — episode-select downloads, Esc=back everywhere, faster posters",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-27T15:56:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "62f8490fd5c5ac0c8f775c17ca8f7e1691f603fc",
          "body": "…fixes\n\nNew source\n- Papystreaming (FR films & series): TMDB-based French search; series get a\n  selectable seasons/episodes menu (via Cinemeta) instead of typing numbers;\n  streams resolved through the shared GoldenMS resolvers.\n\nWindows fixes\n- Anime4K shaders failed to load on Windows: input.conf\n[…]\nr now eases/climbs smoothly toward the next\n  milestone while each tool installs, instead of jumping 20/40/80.\n\nHome menu\n- Browse sources moved to right after Resume (before History/Downloads/Stats).",
          "is_bot": false,
          "headline": "1.7.4 — new source Papystreaming (FR), Windows Anime4K + install-bar …",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-27T09:03:35Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "85f01661cc7ca47a7ab43bff41f87d119d33cf44",
          "body": "…ash/approx glyphs",
          "is_bot": false,
          "headline": "install.ps1: keep it pure ASCII (PS 5.1 encoding trap) - replace em-d…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-26T10:21:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "30ba45663cc102f0d52895d77fae53a974a3083a",
          "body": "…+ installer hardening\n\nDownloads\n- Esc Esc cancels a download (single + season batch); hint shown in the box.\n- aria2c progress bar fixed: reader keeps only progress lines, so aria2c's\n  \"[#… (X%) …]\" line isn't overwritten by the summary block's FILE:/---- junk\n  before the UI reads it -> the bar \n[…]\nss --force, so\n  the one-liner always upgrades existing installs to the latest fixes.\n\nCleanup\n- Fixed latent NameErrors (print_warning / re not imported), removed duplicate\n  i18n keys and dead code.",
          "is_bot": false,
          "headline": "1.7.3 — Esc-Esc cancel download, Esc→source list, Coflix search, 3.9 …",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-26T10:19:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "292bb58605fe7d68300169f2c0c3633c68412fb9",
          "body": "…ice; ETA regex\n\n- play_episode_flow: ⬇ Download now shows a quality picker instead of\n  silently using players[0]; also passes title=window_title so the file\n  is named properly\n- player_manager: revert --console-log-level to notice (progress lines\n  come from --summary-interval=1 regardless of log level)\n- progress.py: ETA regex handles aria2c format (1m30s, 1h30m)",
          "is_bot": false,
          "headline": "fix: ⬇ Download picks quality + passes title; revert log-level to not…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-22T17:37:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c25090779a78c841fa4e319d6adf2448b1fb9ee8",
          "body": "…back\n\n- _pick_player_for_batch(): analyse le 1er épisode, probe les qualités,\n  laisse l'utilisateur choisir le serveur/qualité pour tout le batch\n- _download_one_episode(): preferred_player en priorité, fallback ensuite\n- download_episodes_batch(): relaye preferred_player aux workers\n- mis à jour les 4 handlers (Anime-Sama, Coflix, French-Stream, French-Manga)",
          "is_bot": false,
          "headline": "feat: quality selection before batch download + preferred player fall…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-22T17:15:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "086ecf3e937a4bc2c296fd5b213c2c0c9338b2ac",
          "body": "- player_manager: --console-log-level=info instead of notice so\n  aria2c outputs progress lines (they are at info level)\n- progress.py: widen ETA regex to handle aria2c format (1m30s, 1h30m)",
          "is_bot": false,
          "headline": "fix: aria2c progress bar not updating (log-level info + ETA regex)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-22T17:04:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef0d33077da3110b16920dc704d0a76b4d9a2d51",
          "body": null,
          "is_bot": false,
          "headline": "fix: update README release notes to v1.7.2",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-22T16:52:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "85fe6f1d7f0aed3b87a1786be22cf4a2ccb8352f",
          "body": "- player_manager: aria2c log-level warn→notice (progress bar fix)\n- play_episode_flow: add ⬇ Download option before player selection\n- Anime-Sama / Coflix / French-Stream / French-Manga: add 📥 Download ALL episodes in each season\n- Coflix: fetch .players before batch download\n- bump version to 1.7.2",
          "is_bot": false,
          "headline": "v1.7.2 — add download option + batch download per season",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-22T16:49:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0355635e50ce0ba81e1e1b86d12e49631ddaa322",
          "body": null,
          "is_bot": false,
          "headline": "gitignore: add .opencode/; remove tracked plan file",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T20:13:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a2cf83162e6f6a3cf587758dcdd44ed69a2398cc",
          "body": null,
          "is_bot": false,
          "headline": "v1.7.1 — bump version",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T16:39:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3bf5e707c8d9e878f4a33083b4c8fb6a0cae487b",
          "body": "…handlers/*, player_manager, scraping/*, languages, tracker, notifications), remove AutoFlix references (proxy, notifications), remove player remote config fetches",
          "is_bot": false,
          "headline": "v1.7.1 — massive cleanup: remove unused imports (anilist, cli_utils, …",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T16:39:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5deb909b1afdc8c145a841381c7c775f6fbe7448",
          "body": "…independent)",
          "is_bot": false,
          "headline": "player.py: remove AutoFlix upstream remote config fetch (FreeFlix is …",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T16:22:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dbc4dff95bbc700bda9fbec2ca26e5b74d4c3f8f",
          "body": "…d Python download stall",
          "is_bot": false,
          "headline": "install.ps1: install Python via winget before uv tool install to avoi…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T16:15:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ae0d7d85a387c3447cd8279cc75fbb19ba581ee4",
          "body": "…sage",
          "is_bot": false,
          "headline": "install.ps1: detect uv on disk even if not on PATH; show download mes…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T16:08:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3fb0696b9b20476a06eac82101d11920d2de8466",
          "body": null,
          "is_bot": false,
          "headline": "install.ps1: remove Out-Null so uv progress is visible",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T13:35:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5d4e2057682d31cd9442782f29c0fc9bfc114828",
          "body": "… block)",
          "is_bot": false,
          "headline": "install.ps1: download uv binary directly (no iex, no execution-policy…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:54:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "85ed8cf892a9e2f68f6a440617fe734629e2f501",
          "body": null,
          "is_bot": false,
          "headline": "install.ps1: fix execution policy — add Bypass at process level",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:52:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "dc617edae09a10eaa1bdd338490157626d2729e5",
          "body": null,
          "is_bot": false,
          "headline": "README: add Windows one-liner in install section",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:42:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bdd18868a759ac9f42762f61d2b620ab4a4d3507",
          "body": null,
          "is_bot": false,
          "headline": "README: keep one-liner Linux/macOS only — Windows uses install.ps1",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:41:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8334f7e252c30bb56bbfba46195cd18a039076fe",
          "body": null,
          "is_bot": false,
          "headline": "README: add Windows one-liner via WebClient",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:40:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "209008ca9e498a142028d7a8eb21af676a2a49f1",
          "body": "…p/--version, fix docstring URL; setup_assistant.py: add aria2c+mpv managed sources for Linux",
          "is_bot": false,
          "headline": "README: installation section clearer, fix curl URL; install.py: --hel…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:38:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b8e786a15ec87fb9ea28e6e11543815a375b90a0",
          "body": null,
          "is_bot": false,
          "headline": "1.7.0 — update README: new one-liner installer, doctor, cleanup",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:29:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3a093dce43e6a3f37794f8c74412930850883f71",
          "body": null,
          "is_bot": false,
          "headline": "1.7.0 — remove ArkAnime source (CDN dead), clean up",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T12:23:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "32c0d108880cdc5f13bfac57f699c0b18999e94d",
          "body": "- French-Stream: add fsschal challenge detection in _get() (was only in _post())\n- French-Stream: defensive og:title fallback (title tag / URL slug)\n- French-Stream: guard #s-list parsing against missing element\n- Coflix/Anime-Sama/Player: guards against missing h1/iframe/span/a/img/h2/source\n- clou\n[…]\n DoH)\n- french_stream._get()/_post(): DoH fallback on connection/timeout errors\n- french_stream.search(): catch network timeouts instead of crashing\n- tests: 19 regression tests for scraper resilience",
          "is_bot": false,
          "headline": "1.6.12 — fix: scraper resilience + DoH DNS fallback",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-20T03:11:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ff14fde447b463901bd12d722fcb977f43bee29e",
          "body": null,
          "is_bot": false,
          "headline": "1.6.11 — fix: DNS timeout on all sources (remove DoH from scrapers)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-18T07:56:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "72b1d6ce6ed19b7eb752befdd222005086e914a0",
          "body": null,
          "is_bot": false,
          "headline": "1.6.10 — feat: Nerd Font auto-detection + auto-install",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-17T19:58:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5011432d6be8e3affcbf59cbb89c31e0b20e1102",
          "body": null,
          "is_bot": false,
          "headline": "1.6.9 — fix: French-Stream search (fsschal cookie)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-17T19:45:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d4a8809d112a7ab4363118c516a01dbc4be9e414",
          "body": null,
          "is_bot": false,
          "headline": "1.6.9 — fix: French-Stream search blocked by JS challenge",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-17T19:38:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f4615db2bf470e569536e775cb9b2069dddda81a",
          "body": null,
          "is_bot": false,
          "headline": "1.6.8 — feat: quality selection for downloads",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-12T13:59:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "735b381938539d479380bc40f8d42382b2d8de99",
          "body": null,
          "is_bot": false,
          "headline": "1.6.7 — fix: episode title duplicate in downloads (Coflix full path)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-10T19:15:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5b982ae6021048541dba2d10bbe1f103daf2deff",
          "body": "…ions)",
          "is_bot": false,
          "headline": "1.6.6 — fix: Python 3.9 compatibility (from __future__ import annotat…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-09T17:33:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "165f919cff9109c6b4b180ca0be99354efaa9a4c",
          "body": null,
          "is_bot": false,
          "headline": "1.6.5 — bump version to 1.6.5 for PyPI release",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-08T16:39:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f702119485ffa6ad308e9b1cd376652478a4f249",
          "body": null,
          "is_bot": false,
          "headline": "1.6.5 — fix: duplicate filename in downloads + resume after interruption",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-08T16:32:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c3711bac0a8eb24652a3c4b013a8d48e3fc184cb",
          "body": "…ort path)\n\nLaunching `freeflix` had ~2.5 s of dead air before anything rendered. Cause:\nscraping/player.py and scraping/config.py each fetched remote JSONC overrides\n(players_info, new_url, kakaflix_players, source_portal) SYNCHRONOUSLY at import\ntime — four blocking network calls before main() eve\n[…]\nre ready long before any extraction. The vidmoly domain\ncorrection is re-asserted after the remote merge so it always wins.\n\nimport freeflix_cli.main: ~3.8 s -> ~0.6 s. Also trimmed the splash timing.",
          "is_bot": false,
          "headline": "1.6.4 — fix: instant startup (defer remote config fetches off the imp…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-06T06:30:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c037945492e716f330ca44fdea24fd8ff7496b0b",
          "body": "…ria2c)\n\nWith --downloader aria2c, yt-dlp only emits its overall \"(frag a/b)\" progress at\nthe end of an HLS download, so the bar stayed on \"starting…\" the whole time then\nsnapped to 100%. Switch HLS back to yt-dlp's native --concurrent-fragments 16,\nwhich reports progress continuously -> the bar climbs live. It's just as fast for\nHLS (parallel fragments) and still keeps the folder clean (fragments in a temp\ndir, deleted after). aria2c stays for direct .mp4.",
          "is_bot": false,
          "headline": "1.6.3 — fix: real-time HLS download progress (native fragments, not a…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-06T05:45:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0c1ae2ccd80e135053c9594772c9a988fad172e1",
          "body": "Downloads\n- HLS uses yt-dlp + aria2c (x16) again for speed, but routes every fragment and\n  the .part file to a temp dir (-P temp:) that is deleted afterwards, so the\n  Downloads folder only ever holds the final .mp4 (no .part-FragN / .aria2).\n- Progress fraction is driven solely by yt-dlp's overall\n[…]\ny -> the bar\n  no longer jumps around.\n\nDownload box\n- Renders full-screen (screen=True), centered: resize reflows cleanly with no\n  offset/leftover and it erases on exit. Width-clamped to a tidy box.",
          "is_bot": false,
          "headline": "1.6.2 — downloads: aria2c speed kept, folder clean, rock-stable bar",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-06T05:32:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1a8b311112dcbdc7f6852efae987219883af529d",
          "body": "Downloads\n- HLS uses yt-dlp native --concurrent-fragments instead of aria2c-per-fragment,\n  which spammed the folder with *.part-FragN / *.aria2 files and made the\n  progress bar jump per fragment. One .part -> one .mp4, stable overall bar.\n- Sweep leftover fragment/temp clutter before and after eac\n[…]\nne\n  level) across Anime-Sama, Coflix, French-Stream, French-Manga, GoldenMS,\n  GoldenAnime — back out without completing the flow.\n\nLaunch\n- Smooth 0->100% splash sequence instead of an abrupt flash.",
          "is_bot": false,
          "headline": "1.6.1 — clean downloads (no fragment clutter), back buttons everywhere",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-06T05:19:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "be96b4a01c84fa475da0babc2bd841623587e11f",
          "body": null,
          "is_bot": false,
          "headline": "docs: add CHANGELOG.md with full 1.6.0 notes",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-06T04:54:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7b392c86a70e13311ca19aaee34f4d12062aaa09",
          "body": "Search / browse\n- Live preview pane (poster + title + genres/metadata) on every source:\n  Anime-Sama, Coflix, French-Stream, French-Manga (TMDB thumbs), GoldenMS\n  (Cinemeta), GoldenAnime (AniList covers). Shared make_preview() shape.\n- Preview pane perfected: per-URL image cache (no re-download on \n[…]\nll.sh / install-mac.sh.\n\nRobustness\n- Removed Wiflix entirely (handler, scraper, objects).\n- cf_get: 3 retries + system-DNS (no-DoH) fallback; graceful handling for\n  network failures in source flows.",
          "is_bot": false,
          "headline": "Release 1.6.0 — preview pane on all sources, grouped menu, progress bars",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-05T21:46:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "88f5e8067844dd07a9c83c319851d6f2a4ca5fb7",
          "body": "… spinners\n\nAdd icons.py with two glyph sets (emoji default, Nerd Font opt-in) and a\ncentral iconify() applied in cli_utils (headers, menus, messages, stats,\nabout, update banner) so a single \"Icon Style\" setting flips the whole UI\n— no per-string edits. Menus get a full-width themed selection bar with\ndisplay-column-accurate padding (handles wide emoji, never wraps). Slow\nscraping/loading calls are wrapped in a rich spinner.",
          "is_bot": false,
          "headline": "feat: emoji/Nerd Font icon system, full-width selection bar, scraping…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T20:19:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e790ca372f980cc6a83124f40757726cbc1b07c4",
          "body": "The proxy now counts the bytes streamed to the player (HLS segments +\nMP4). player_manager shows a live \"Data used: X MB\" counter that grows\nas the cache fills, then the total at the end. The player menu labels\nmpv as \"(recommended)\".",
          "is_bot": false,
          "headline": "feat: live data-usage meter during playback + mpv marked recommended",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T20:19:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6426ab1a2e62a263bb85c489f3922685fe67c36b",
          "body": "The cover was read from <img id=\"coverOeuvre\">, which is missing on many\ncatalogue pages (One Piece, Frieren…), leaving the poster blank \"when it\nfelt like it\". Read the always-present og:image meta first, fall back to\ncoverOeuvre/data-src, and make it absolute. Also retry the image download\na few times since Anime-Sama covers are on raw.githubusercontent.com,\nwhich rate-limits intermittently.",
          "is_bot": false,
          "headline": "fix: Anime-Sama poster always shows (og:image + download retry)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T20:19:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9a4e7629840b21f1d00671331ed9221ecf24f08c",
          "body": "Show the cover + summary at selection for the movie/series sources, so\nposters now appear on every source. GoldenMS uses the Cinemeta/TMDB\nposter; French-Stream uses the page thumbnail or the search-result\nimage. Fix a French-Stream scraper bug that double-prefixed the site\norigin onto already-absolute TMDB image URLs.",
          "is_bot": false,
          "headline": "feat: anime/movie posters for GoldenMS and French-Stream too",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T17:53:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "241a4d95ed56a3bd59c446404ff8de8d3f7ec070",
          "body": "When the chosen player can't be resolved at play time, FreeFlix now\noffers to install it (mpv / VLC) via the OS package manager and retries,\ninstead of only showing \"not installed\". setup_assistant.install_media_player\nis OS-aware (dnf/apt/pacman/zypper/apk, brew, winget mpv.net/VideoLAN.VLC)\nand player_manager._resolve_or_install checks presence first so nothing\nalready installed is touched.",
          "is_bot": false,
          "headline": "feat: install mpv/VLC on demand at playback if missing",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T17:53:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a9a26d5d434b666129a4192fb0fd1295300761f0",
          "body": "setup_assistant now offers to install chafa via the OS package manager\n(dnf/apt/pacman/zypper/apk/brew/winget) on first launch, and the three\ninstall scripts include chafa. On Windows, first-launch installs mpv.net\nand VLC via winget, and player_manager.get_mpv_path() resolves mpv.net's\nmpvnet.exe (and winget shims) so FreeFlix can actually launch mpv there.",
          "is_bot": false,
          "headline": "feat: install chafa in setup + scripts; Windows mpv/vlc bootstrap",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T15:58:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d677574b801dd91b7078d2b8bbcf9f37b0ed34c1",
          "body": "Add terminal_image.py: draws anime cover art inside the terminal via\nchafa (sixel when available, coloured Unicode blocks otherwise), with a\ngraceful no-op fallback when chafa is missing. Posters + a short summary\nare shown when an anime is selected, for French-Manga (TMDB/og:image\ncover), Anime-Sam\n[…]\n: menu option labels are truncated to the terminal width so\nthey never wrap and break the live render; poster size scales with the\nterminal; the splash logo degrades (full / compact / hidden) by size.",
          "is_bot": false,
          "headline": "feat: anime posters in the terminal (chafa) + responsive UI",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T15:58:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3d0eb34f049a49d0697ce82422a125c4369df841",
          "body": "Previously --setup only re-ran the dependency assistant, never the\nlanguage choices. check_language_setup/_prompt_anime_language now accept\nforce=True so --setup redoes both the anime content language and the\ninterface language. The choices remain changeable individually from\nSettings.",
          "is_bot": false,
          "headline": "feat: freeflix --setup re-runs the language wizard (anime + interface)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T15:21:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "92b0c54d3b7bf4174b968c4abbd9af5b91e589a8",
          "body": "Resuming a French-Manga entry did nothing because handle_resume had no\nbranch for the provider. Add resume_french_manga (Continue / Watch again\n/ Cancel) and wire the dispatch. Also normalise relative series URLs\nstored in older history entries (get_episodes now makes them absolute),\nwhich is what made resume report \"no episodes found\". Factor the play\nloop into a shared _play_episodes helper.",
          "is_bot": false,
          "headline": "fix: French-Manga resume from history (dispatch + relative URLs)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T15:21:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "68577bced4a1702753f5baeb48c244e830bd09fa",
          "body": "Add the v1.5.6 changelog, list French-Manga among the sources (drop\nCoflix), fix the position-resume script filename, refresh the French\nsummary, and add an educational-purposes / no-hosting / DMCA disclaimer.",
          "is_bot": false,
          "headline": "docs: README — French-Manga source, v1.5.6 features, disclaimer",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T11:34:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "37beed21e3e9d7e5fd476cf3e482397feda8e247",
          "body": "…tering & subtitles\n\nOn the very first launch FreeFlix now asks the anime content language\n(English VO/sub vs French VF/VOSTFR) BEFORE the interface language.\nThat choice drives which sources are listed — English shows Anime-Sama,\nGoldenAnime, GoldenMS and Nyaa; French shows Anime-Sama, GoldenAnime,\n[…]\nnAnime/GoldenMS subtitle search now\nfollow the same content language. Adds an \"Update Anime Language\" entry\nin Settings and reorders the source menu (anime top, movies/series\nmiddle, torrents bottom).",
          "is_bot": false,
          "headline": "feat: anime-language first-launch wizard, content-language source fil…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T11:34:24Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d69aee80ae0e6dcd20212789dc8d12f53268ae37",
          "body": "New scraper + handler for w16.french-manga.net: DLE ajax search,\nnewsId lookup, and manga_episodes_api.php for per-episode VF/VOSTFR\nplayers. Registers vidzy and luluvid (vidhsareup.io) players, which\nthe upstream players_info.jsonc doesn't list, by re-injecting the\nFreeFlix DEFAULT_PLAYERS extras after the remote list loads.",
          "is_bot": false,
          "headline": "feat: add French-Manga source (anime VF/VOSTFR, vidzy + luluvid)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T10:20:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2326eca590ff436d549feb5d0605a2835fd9fc75",
          "body": "Quality selection previously swapped the master playlist URL for a\nsingle video-only variant, which dropped the separate EXT-X-MEDIA\naudio renditions (GoldenAnime/anizone \"video but no sound\"). Revert\nto applying the choice via mpv --hls-bitrate on the untouched master,\nso audio renditions are preserved.",
          "is_bot": false,
          "headline": "fix: keep audio when selecting quality on anizone/HLS streams",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T10:20:22Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "33866d0d6e8beac37c52fca439ef758708b1e9c0",
          "body": "…ceful filemoon\n\nCoflix : removed from selectable sources — its player aggregator\n(lecteurvideo.com) is Cloudflare-protected, nothing is playable. Handler\n+ scraper kept (season parsing repaired, Cloudflare message) but not\nregistered.\n\nFrench-Stream / shared extractors (player.py) :\n- uqload : 'lis\n[…]\nruto all return a source again.\n\nplayer_manager : endpoint choice is content-aware — an HLS stream\n(.m3u8/.txt) always uses /stream even under an ext:mp4 config (uqload now\nreturns m3u8 with ext:mp4).",
          "is_bot": false,
          "headline": "fix: revive providers — drop Coflix, repair uqload/fsvid/anizone, gra…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T09:23:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "cabcb5c832b4e2e5bc2f524b7cb1e239184453e9",
          "body": "… all players\n\nBuilds on the 1.4.5 quality menu so it triggers for EVERY multi-quality\nsource, not just vidmoly. Four fixes, all in play_video's single probe :\n\n1. Per-host probe headers : the probe fetched the master with the\n   generic anime-sama referer, so hosts that check referer (embed4me,\n   \n[…]\nd') with a clear 'pick another source' message\n   instead of a cryptic mpv failure.\n\nNote: reverted a stream=True peek (curl_cffi early-break could hang) to\na plain GET — HLS playlists are small text.",
          "is_bot": false,
          "headline": "feat(v1.5.2): universal quality selection — all providers, all hosts,…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-04T08:10:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "efef48c41d05f2c8a0ba9ce7af1e72d7e3d34eee",
          "body": "anime-sama.to updated its layout : the series title moved from\n<h4 id='titreOeuvre'> to a plain <h1>, and the genres anchor is gone\non some pages. The copied autoflix get_series did\nsoup.find('h4', {'id':'titreOeuvre'}).text and crashed with\nAttributeError: 'NoneType' on every series now.\n\nMade get_\n[…]\n title falls back h4#titreOeuvre → h1 → URL\nslug ; cover and genres are guarded (empty if missing). Seasons\n(panneauAnime parsing) are unchanged. Verified on Asobi Asobase (was\ncrashing) and Dr Stone.",
          "is_bot": false,
          "headline": "fix(anime-sama): robust get_series (h4#titreOeuvre dropped for h1)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-03T20:17:08Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "2fff2a3d450578e63a5bbc41b4f00a1bf5cfba9f",
          "body": "Sprint 1 of the v2 roadmap, shipped as 1.5.0 :\n\n- Splash screen : FreeFlix ASCII wordmark at launch, themed + tagline +\n  version (new splash.py ; skipped on tiny terminals).\n\n- Colour themes (new themes.py) : Default, Catppuccin Mocha, Dracula,\n  Nord. Each maps semantic roles (accent/header/border\n[…]\ns so the genre breakdown populates.\n\n- i18n : all new strings translated FR.\n\nVerified : 4 themes switch colours correctly, splash renders, stats\ndashboard aggregates (incl. genres) and renders in FR.",
          "is_bot": false,
          "headline": "feat(v1.5): splash screen, colour themes, stats dashboard",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-06-03T19:15:11Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "83e1b2d2a68f6a050c7398fdbac762d5a128de19",
          "body": "1. Quality selection : when a resolved stream is a multi-variant HLS\n   master (e.g. vidmoly's 1080p+480p '_,n,l,.urlset'), FreeFlix now\n   fetches the master, parses the variants, and prompts the user to\n   pick a quality before playback. The choice is applied to mpv via\n   --hls-bitrate=<bandwidth\n[…]\n value on quit. Also switched script-opts reading to\n   get_property_native (cleaner). Verified : pos=12.75 now written on\n   quit, and --start=<pos> applied on the next launch of the same\n   episode.",
          "is_bot": false,
          "headline": "feat: HLS quality selection + fix position-resume (lua time-pos bug)",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-31T20:58:36Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d9580fb3f4ec4acfc8ce897b09280a186bac8cda",
          "body": "Two user-reported issues :\n\n1. Anime-Sama VF showed fewer sources on FreeFlix than autoflix (notably\n   missing embed4me). Root cause : FreeFlix read the animes-sama.fr\n   mirror, autoflix reads anime-sama.to (via the anime-sama.pw portal).\n   Different mirrors expose different players per episode.\n\n[…]\nct_delay_max=10\n   (a single network hiccup could pause up to 10 s). Reverted to a\n   light, vanilla-like cache (256 MiB / 30 s readahead, no reconnect\n   delay) — matching the fast autoflix behavior.",
          "is_bot": false,
          "headline": "fix(anime-sama): copy autoflix's scraper wholesale + revert mpv cache",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-31T16:45:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fad52055dea614d02a13619e0fb20e8a4f4fdf60",
          "body": "…robe\n\nTwo findings from a full autoflix-vs-freeflix repo scan :\n\n1. The tuned mpv.conf was GLOBAL (~/.config/mpv/), so it applied to the\n   user's normal 'mpv file.mkv' too — Anime4K shader compile + huge cache\n   on every video, not just FreeFlix. autoflix used vanilla mpv, which is\n   why it 'fel\n[…]\nplayer.py (HLS extraction) was confirmed byte-identical to autoflix, so\nstream resolution speed was never the difference — the real wins were the\nproxy session reuse (1.4.2) and this config isolation.",
          "is_bot": false,
          "headline": "perf: isolate mpv config to FreeFlix + parallel anime-sama language p…",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-31T16:19:28Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "991bd4668453d6f57cdc77afe90f57b4f38944c7",
          "body": "Root cause of 'the buffer never gets ahead even at 320p' : the proxy\ncreated a brand-new curl_cffi session for EVERY segment. Each one re-did\nthe DoH DNS resolution (an HTTPS round-trip to 1.1.1.1) plus a fresh\nTLS handshake to the CDN — ~200-600 ms of pure setup overhead per\nsegment, with zero conn\n[…]\nfreeze, which felt like 'always catching up'. 2s gives short,\ndiscreet micro-pauses instead.\n\nOn a transport error the thread session is reset before retrying so a\ndead keep-alive handle isn't reused.",
          "is_bot": false,
          "headline": "perf(proxy): reuse session per thread — 2.5× faster segment fetch",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-31T15:56:10Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "97ce3b376d2cf8008c3cdb24ef420795a14e3b18",
          "body": "v1.4.0's cache-on-disk=yes made the cache fill noticeably slower :\nmpv's on-disk cache has extra bookkeeping overhead vs RAM, even on a\nfast SSD, and the 2h/8GB readahead made the cache bar crawl.\n\nWith 8+ GB RAM there's no reason to use disk. Reverted to RAM cache,\nsized generously :\n  cache-on-dis\n[…]\nnd has zero I/O overhead,\nso the buffer fills at full network speed again. Still buffers far\nenough ahead to survive a long connection drop.\n\nLow-RAM users (<8 GB) can lower demuxer-max-bytes to 1GiB.",
          "is_bot": false,
          "headline": "fix(mpv): switch back to fast RAM cache (4 GiB) instead of disk",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-31T15:34:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0da6f81d5ccb289fb0ce9b7eb65d500adb8aa3f7",
          "body": "Per user request : instead of a 250 MB RAM cache, mpv now pre-buffers\nas much of the video as the network allows — up to the end of the\nepisode/film — into an on-DISK cache.\n\n- cache-on-disk=yes          → cache goes to disk, not RAM\n- cache-dir=~/.cache/mpv\n- demuxer-max-bytes=8GiB      → up to a f\n[…]\nin ~/.cache/mpv.\n\nResult : once a video has had a moment to buffer, it plays to the end\neven if the connection dies completely. Combined with cache-pause +\nkeep-open, network drops become a non-issue.",
          "is_bot": false,
          "headline": "feat(mpv): buffer the whole episode/film to disk cache",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-31T15:22:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c103ad9d45a47d7c7af0612f02c382813a99d054",
          "body": "The systemd timer used OnBootSec=15min + OnUnitActiveSec=24h, which on\nan already-running machine produced 'Trigger: n/a' / 'NEXT: -' — i.e.\nit fired once and then never scheduled a next run.\n\nSwitched to the robust daily idiom :\n  OnCalendar=daily\n  Persistent=true        (catches up if the machine\n[…]\nescription\nstrings to 'FreeFlix'.\n\nNote for existing users : re-toggle the notification setting (Settings →\nDaily New-Episode Notifications, off then on) to regenerate the timer\nwith the new schedule.",
          "is_bot": false,
          "headline": "fix(notifications): use OnCalendar=daily so the timer actually re-fires",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-30T17:27:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "87d09108c1fe50600fcbdec91b18884ab10be874",
          "body": "Two bugs surfaced on 'L'Atelier des Sorciers' :\n\n1. parse_episodes_from_js crashed with 'max() iterable argument is\n   empty' when a season page had no (or only empty) 'var epsN' player\n   arrays. Now skips empty players and returns [] cleanly, so the\n   handler shows 'no episodes' instead of a trac\n[…]\nned portal cache (users with a cached .to will\n  re-resolve on next launch since the cache is keyed and TTL'd).\n\nVerified : L'Atelier des Sorciers → saison1 → vostfr/vf/va, 27 ep-lang\npairs, no crash.",
          "is_bot": false,
          "headline": "fix: empty-season crash + point remote config at our own repo",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-30T17:13:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a34d6e95f9f44800661b0069f692b99fd6054ce",
          "body": "Each freeflix launch tries to fetch 4 remote JSONC files (portals,\nplayers_info, new_url, kakaflix_players) from PaulExplorer's upstream\nrepo. When GitHub raw is slow or unreachable, the 5 s timeout × 4 was\ndelaying startup by ~20 s and dumping a 4-line curl error per file.\n\nSince the local override\n[…]\nead of 20 s\n- single one-line warning per file (was 4-line curl traceback)\n- format: '  · offline-mode : remote <file> unavailable, ...'\n\nFunctionality unchanged — local defaults remain authoritative.",
          "is_bot": false,
          "headline": "fix(config-loader): quieter & faster remote fetch failure",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-28T10:37:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9056fb67c7b2aa4fe8e2f87abedcf1dff8ea05ce",
          "body": "Haruna is removed because :\n- Video track switching never reliably worked through its Qt wrappers\n- input.conf bindings (Anime4K toggle, track cycle) were inconsistently\n  picked up between Haruna versions\n- mpv + the freeflix proxy already covers all the same use cases with\n  better behavior\n- Main\n[…]\ninstall.sh / install-mac.sh\n- All Haruna mentions in README.md\n\nmpv remains the recommended player and gains the full benefit of the\nNvidia/AMD PRIME offload that was previously split between the two.",
          "is_bot": false,
          "headline": "refactor: remove Haruna player support",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-28T10:34:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f6988cbb67378bc896668830d7b9ff6182f1e781",
          "body": "Big quality-of-life release. When freeflix is installed via uv/pip/pipx,\nrunning it for the first time now offers to install everything else :\n\n- Tuned mpv.conf + input.conf + position-resume lua hook\n- Anime4K shaders (Mode A_S + A_VL, downloaded from bloc97/Anime4K)\n- Haruna config mirror (on Linu\n[…]\n wizard at any time\n- freeflix --version  print installed version\n- freeflix --help     usage\n\nThe wizard remembers if the user declined (setup_declined in tracker)\nso it won't pester on every launch.",
          "is_bot": false,
          "headline": "feat: first-launch setup wizard + cross-platform + AMD GPU support",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-28T10:14:40Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "10684dbfc247bda3190d72c9bfe86187e32e68a0",
          "body": "Tuned for the 'leave mpv open, come back later' use case where the\nconnection may drop or thrash in the meantime.\n\nCache : 250 MB / 3 min readahead :\n  - cache-secs=180, demuxer-readahead-secs=180\n  - demuxer-max-bytes=250M, demuxer-max-back-bytes=80M\n\nGraceful behavior when network dies :\n  - cache\n[…]\nose if stream ends\n  - network-timeout=120    → tolerate slow segments (was 60s)\n  - reconnect_delay_max=10 → softer reconnect cadence\n\nLose Wi-Fi for ~3 minutes mid-episode without losing your place.",
          "is_bot": false,
          "headline": "feat(mpv): 250 MB cache + survive-connection-drops mode",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-28T08:00:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d1dec3630534d5524b68c7c4c09a0d5423dba90e",
          "body": "Silences info-level mpv chatter from congested CDNs :\n- 'Audio device underrun detected'\n- 'Error decoding audio' (×100s)\n- 'Invalid audio PTS'\n- 'Audio/Video desynchronisation detected'\n\nvia quiet=yes + msg-level for ad/vd/ao/af modules.\n\nAlso makes the audio pipeline more forgiving :\n- audio-buffer=0.5\n- audio-stream-silence=yes\n- audio-fallback-to-null=yes",
          "is_bot": false,
          "headline": "fix(mpv): silence terminal spam + harden audio against bad PTS",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-28T07:49:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d64ee5030f5c85149b7839f64ce4f7a1b4ffeaa6",
          "body": "- Home header now displays 'FreeFlix CLI — Accueil  •  v1.1.5'\n  (or 'v<dev>' when running from a checkout)\n- Settings → 'ℹ About' opens a rich panel with :\n    version, GitHub repo, PyPI page, issue tracker\n    license (GPL-3.0-or-later)\n    author (freedy237)\n    credits to PaulExplorer (autoflix-cli) and bloc97 (Anime4K)\n- French labels added to i18n.py",
          "is_bot": false,
          "headline": "feat: show version in home header + add About panel in Settings",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-28T07:35:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "39a3ff775987cdf023d0fc343f9b415a82107216",
          "body": "Two bugs surfaced after the FreeFlix rebrand :\n\n1. config/freeflix_position.lua still referenced 'autoflix-key' /\n   'autoflix-out' while player_manager.py sends 'freeflix-key' /\n   'freeflix-out'. The position resume has been silently broken\n   since v1.0.0. Lua script regenerated with the correct \n[…]\ng/demuxer=fatal'\n   but mpv doesn't expose those sub-prefixes — only the bare\n   'ffmpeg' module. The reconnect spam was still going through.\n   Now uses 'msg-level=ffmpeg=fatal' which actually works.",
          "is_bot": false,
          "headline": "fix: silence ffmpeg log spam + repair broken position-resume",
          "author_name": "freedy237",
          "author_login": "freedy237",
          "committed_at": "2026-05-28T07:30:16Z",
          "body_truncated": true,
          "is_coding_agent": false
        }
      ],
      "releases_count": 61,
      "commits_last_year": 113,
      "latest_release_at": "2026-07-27T17:22:39Z",
      "latest_release_tag": "v1.9.3",
      "releases_from_tags": false,
      "days_since_last_push": 0,
      "active_weeks_last_year": 9,
      "days_since_latest_release": 0,
      "mean_days_between_releases": 2.6
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "freeflix-cli",
          "exists": true,
          "license": "GPL-3.0-or-later",
          "keywords": [
            "VF",
            "VOSTFR",
            "anime",
            "anime-sama",
            "haruna",
            "movies",
            "mpv",
            "series",
            "streaming",
            "Development Status :: 5 - Production/Stable",
            "Environment :: Console",
            "Intended Audience :: End Users/Desktop",
            "Operating System :: OS Independent",
            "Programming Language :: Python :: 3",
            "Topic :: Multimedia :: Video"
          ],
          "ecosystem": "pypi",
          "matches_repo": true,
          "registry_url": "https://pypi.org/project/freeflix-cli/",
          "is_deprecated": false,
          "latest_version": "1.9.3",
          "repository_url": "https://github.com/freedy237/freeflix-cli.git",
          "versions_count": 61,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 2922,
          "first_published_at": "2026-05-28T05:26:07.389302Z",
          "latest_published_at": "2026-07-27T17:22:32.525926Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 0
        }
      ]
    },
    "popularity": {
      "forks": 0,
      "stars": 6,
      "watchers": 0,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 77028,
      "source_files_sampled": 73,
      "oversized_source_files": 2,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "pyproject.toml"
      ],
      "advisories": {
        "error": null,
        "scope": null,
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "pypi"
      ],
      "dependencies": [
        {
          "name": "beautifulsoup4",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=4.14.3"
        },
        {
          "name": "curl-cffi",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=0.13.0"
        },
        {
          "name": "flask",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=3.1.2"
        },
        {
          "name": "html5lib",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.1"
        },
        {
          "name": "jsbeautifier",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=1.15.4"
        },
        {
          "name": "m3u8",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=6.0.0"
        },
        {
          "name": "platformdirs",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=4.0.0"
        },
        {
          "name": "pycryptodome",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=3.23.0"
        },
        {
          "name": "readchar",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=4.2.1"
        },
        {
          "name": "rich",
          "manifest": "pyproject.toml",
          "ecosystem": "pypi",
          "version_constraint": ">=14.2.0"
        }
      ],
      "all_dependencies": {
        "error": "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
        "source": null,
        "packages": [],
        "collected": false,
        "truncated": false,
        "total_count": null,
        "direct_count": null,
        "indirect_count": null
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 0,
        "closed_ratio": 1,
        "closed_issues": 1,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "freedy237",
          "commits": 116,
          "avatar_url": "https://avatars.githubusercontent.com/u/205066866?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "ci.yml",
        "release.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [
        "uv.lock"
      ],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 0,
            "reason": "project was created within the last 90 days. Please review its contents carefully",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": 10,
            "reason": "packaging workflow detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": 0,
            "reason": "dependency not pinned by hash detected -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": 0,
            "reason": "Project has not signed or included provenance with any releases.",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 8,
            "reason": "2 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "785a9fb2e5b68ff8b6aae756ee152443ba7d9a0e",
        "ran_at": "2026-07-27T17:38:35Z",
        "aggregate_score": 3,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-27T17:22:43Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/freedy237/freeflix-cli",
    "host": "github.com",
    "name": "freeflix-cli",
    "owner": "freedy237"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 52,
      "inputs": {
        "security": 30,
        "vitality": 72,
        "community": 36,
        "governance": 47,
        "engineering": 66
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 72,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 60,
            "inputs": {
              "commits_last_year": 113,
              "human_commit_share": 1,
              "days_since_last_push": 0,
              "active_weeks_last_year": 9
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "9/52 weeks with commits",
                "points": 6.2,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 9
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "113 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 113
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "name": "Release discipline",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "releases_count": 61,
              "latest_release_tag": "v1.9.3",
              "releases_from_tags": false,
              "days_since_latest_release": 0,
              "mean_days_between_releases": 2.6
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "61 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 61
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 0 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~2.6 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 2.6
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "unverified",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": "repository_too_young",
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": null,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "maintenance record not established from the collected data",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_unverified",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 36,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 11,
            "inputs": {
              "forks": 0,
              "stars": 6,
              "watchers": 0,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "6 stars",
                "points": 11.3,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 6
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "0 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (GPL-3.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "GPL-3.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "moderate",
            "name": "Ecosystem adoption (downloads)",
            "note": "Excluded from scoring (no data or not applicable): Registry dependents. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "registry_dependents"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 58,
            "inputs": {
              "packages": [
                "freeflix-cli"
              ],
              "dependents": null,
              "ecosystems": "pypi",
              "total_downloads": null,
              "monthly_downloads": 2922
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "2,922 downloads/month across pypi",
                "points": 46.2,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 2922,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "not reported by this ecosystem",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_reported_by_this_ecosystem",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 47,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "good",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): PR acceptance. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "pr_acceptance"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 76,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 1,
              "issue_closed_ratio": 1,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "100% of issues closed",
                "points": 46.8,
                "status": "met",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "no decided pull requests or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_decided_prs_or_data",
                    "params": {}
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "critical",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 21,
            "inputs": {
              "followers": 0,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "freedy237",
              "public_repos": 3,
              "account_age_days": 487
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "0 followers of freedy237",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 0,
                      "login": "freedy237"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "3 public repos, account ~1 yr old",
                "points": 7.1,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 3
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 1
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "freeflix-cli"
              ],
              "ecosystems": "pypi",
              "any_deprecated": false,
              "min_days_since_publish": 0
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on pypi",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "pypi"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 0 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 0
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "61 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 61
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 66,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "moderate",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 60,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "2 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "good",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "topics": [
                "anilist",
                "anime",
                "anime-sama",
                "aria2",
                "cli",
                "french",
                "hls",
                "mpv",
                "nyaa",
                "python",
                "streaming",
                "terminal",
                "vf",
                "vostfr",
                "yt-dlp",
                "anime4k",
                "downloader",
                "movies",
                "series",
                "tui"
              ],
              "has_wiki": true,
              "homepage": "https://github.com/freedy237/freeflix-cli",
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://github.com/freedy237/freeflix-cli",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": "20 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 20
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 30,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 30,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 17,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 1,
              "scorecard_aggregate": 3
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "project was created within the last 90 days. Please review its contents carefully",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow detected",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "Project has not signed or included provenance with any releases.",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "2 existing vulnerabilities detected",
                "points": 6,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "at_risk",
        "name": "AI Readiness",
        "value": 39,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.77,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "77 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 77,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "at_risk",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 32,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [
                "uv.lock"
              ],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": "lockfile",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": "lockfile"
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "dependency not pinned by hash detected -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 54,
            "inputs": {
              "primary_language": "Python",
              "largest_source_bytes": 77028,
              "source_files_sampled": 73,
              "oversized_source_files": 2
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Python without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "Python"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "2/73 source files over 60KB",
                "points": 53.5,
                "status": "partial",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 73,
                      "oversized": 2
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token",
    "GitHub dependency-graph SBOM unavailable (404); the dependency graph may be disabled for this repository",
    "deps.dev does not index pypi:freeflix-cli@1.9.3; advisories assessed against the repository dependency graph instead"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-27T17:38:41.363179Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/f/freedy237/freeflix-cli.svg",
  "full_name": "freedy237/freeflix-cli",
  "license_state": "standard",
  "license_spdx": "GPL-3.0"
}

Оцінки — це сигнали, а не гарантії. Вони відображають публічно видимі практики на GitHub — це не аудит коду й не гарантія безпеки.

Відсутні дані виключаються, а ваги перенормовуються — нуль за відсутність ніколи не ставиться. Методологія версіонована й відкрита: метрики v1.13.0, схема v0.27.0 — повна методологія · вікі метрик.

Як окремий результат виглядає на тлі всього реєстру: сукупна статистикаPyPI.