From d7864e99a6fd74a07884c046d51c1cc84e458938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A4=D0=BE=D1=84=D0=B0=D0=BD=D0=BE=D0=B2=20=D0=94=D0=BC?= =?UTF-8?q?=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=92=D0=B8=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 1 Sep 2026 11:39:23 +0300 Subject: [PATCH] Document public release and trim Emby export scope --- LICENSE | 21 +++++++ README.md | 98 ++++++++++++++++++++++++++---- src/emby_strm_exporter/exporter.py | 10 ++- 3 files changed, 111 insertions(+), 18 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..254ce26 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Dmitry Fofanov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 978a8aa..48a760a 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,92 @@ # Emby STRM Exporter -Восстановленный и безопасно переоформленный вариант `GenerateEmbyContent.py`. -Экспортёр читает строки медиатеки из PostgreSQL и создаёт дерево `.strm`/`.nfo` -для Emby. Настройки и учётные данные передаются только через окружение. +Утилита экспорта одной категории медиатеки PostgreSQL в дерево `.strm`-файлов +для Emby. Она переработана из `GenerateEmbyContent.py`: устаревшие жёстко +заданные IP-адреса, пароль, загрузка постеров и генерация NFO исключены. Осталась +только главная задача — безопасно подготовить ссылки на поток для локальной +медиатеки. -## Подготовка +## Возможности и границы -```bash -python -m pip install -e . -cp .env.example .env # заполните значения и экспортируйте их в окружение -export DATABASE_URL='postgresql://...' -export ACE_STREAM_URL='http://localhost:6878/ace/getstream?infohash={infohash}&.mp4' -emby-strm-export output/ 1 +- получает категорию по `site_code` из таблицы `categorys`; +- для каждой комбинации названия и качества выбирает строку с максимумом `seeds`; +- строит каталог `<категория>/<год>/<название (год)>`; +- создаёт UTF-8 `.strm`, содержащий URL, сформированный из `infohash`; +- получает параметры подключения исключительно из переменных окружения. + +Экспортёр не изменяет базу данных, не загружает изображения, не обращается к API +Emby и не содержит учётных данных. Используйте его только для своей базы данных +и разрешённых источников потоков. + +## Требования + +- Python 3.10+; +- PostgreSQL с таблицами `categorys` и `torrents`; +- доступ на чтение к этим таблицам. + +В используемой исторической схеме требуются поля: + +```text +categorys(site_code, name) +torrents(category_id, name, year, quality, seeds, infohash) ``` -Ожидается прежняя схема с таблицами `categorys` и `torrents`. Запросы оставлены -параметризованными; исходные пароли, IP-адреса и API-ключи не переносились. +## Установка + +```bash +git clone https://github.dfv24.com/fofanov.dmitry/emby-strm-exporter.git +cd emby-strm-exporter +python -m venv .venv +. .venv/bin/activate +python -m pip install --editable . +``` + +## Конфигурация + +Скопируйте шаблон, но не добавляйте заполненный `.env` в Git: + +```bash +cp .env.example .env +export DATABASE_URL='postgresql://reader:password@db.example.org:5432/media' +export ACE_STREAM_URL='http://stream.example.org/ace/getstream?infohash={infohash}&.mp4' +``` + +`ACE_STREAM_URL` обязан содержать литерал `{infohash}`. Он будет заменён на +значение строки БД. Переменная `.env` не загружается программой автоматически: +экспортируйте значения в оболочку либо используйте ваш менеджер секретов. + +## Экспорт + +```bash +emby-strm-export ./library 1 +``` + +Где `./library` — корневой каталог медиатеки, а `1` — `site_code` категории. +Пример результата: + +```text +library/ + Фильмы/ + 2024/ + Пример (2024)/ + Пример (2024)-WEB-DL.strm +``` + +Повторный запуск может перезаписать `.strm` того же качества. Перед массовым +экспортом удобно сначала выполнить его в тестовый каталог. + +## Структура и проверка + +```text +src/emby_strm_exporter/ + exporter.py # запрос к БД и запись файлов + cli.py # интерфейс командной строки +``` + +```bash +python -m compileall -q src +``` + +## Лицензия + +Код распространяется по лицензии [MIT](LICENSE). diff --git a/src/emby_strm_exporter/exporter.py b/src/emby_strm_exporter/exporter.py index f1a3377..1b343c8 100644 --- a/src/emby_strm_exporter/exporter.py +++ b/src/emby_strm_exporter/exporter.py @@ -19,7 +19,7 @@ def export_category(output_dir: Path, category_id: int, database_url: str, strea """Экспортировать наиболее раздаваемую версию каждого названия в `.strm`.""" query = ''' - SELECT s.name, s.year, s.quality, s.imdb, s.infohash + SELECT s.name, s.year, s.quality, s.infohash FROM torrents s JOIN ( SELECT category_id, name, quality, MAX(seeds) AS seeds @@ -38,18 +38,15 @@ def export_category(output_dir: Path, category_id: int, database_url: str, strea rows = cursor.fetchall() root = output_dir / safe_path_part(category[0]) - for name, year, quality, imdb, infohash in rows: + for name, year, quality, infohash in rows: title, release_year = safe_path_part(name), safe_path_part(year or "unknown") movie_dir = root / release_year / f"{title} ({release_year})" movie_dir.mkdir(parents=True, exist_ok=True) base_name = f"{title} ({release_year})" + # В STRM хранится только URL: метаданные Emby получает своим обычным способом. (movie_dir / f"{base_name}-{safe_path_part(quality)}.strm").write_text( stream_url.format(infohash=infohash) + "\n", encoding="utf-8" ) - if imdb: - (movie_dir / f"{base_name}.nfo").write_text( - f"{imdb}\n", encoding="utf-8" - ) return len(rows) @@ -58,6 +55,7 @@ def required_environment() -> tuple[str, str]: database_url = os.environ.get("DATABASE_URL") stream_url = os.environ.get("ACE_STREAM_URL") + # Конфигурация не записывается в код или в файлы проекта. if not database_url or not stream_url: raise RuntimeError("DATABASE_URL and ACE_STREAM_URL must be set") if "{infohash}" not in stream_url: