В Lampa: Настройки → Расширения → «+», вставить URL (на каждом устройстве отдельно; PWA на iPhone — отдельно от вкладки Safari):
| Плагин | URL |
|---|---|
| Top | https://0x3654.github.io/lampa-plugins/top.js |
| Torrent Send | https://0x3654.github.io/lampa-plugins/transmission-send.js |
| Plex Sync | https://0x3654.github.io/lampa-plugins/plex-sync.js |
| всё сразу | https://0x3654.github.io/t.js (бутстрап, см. ниже) |
Три пункта в главном меню — основной плагин.
Популярное и лучшее по TMDB — по три смысла на фильмы и сериалы: тренды недели, лучшее по рейтингу, новинки 2025+. Переключение варианта — кнопка вправо. Карточки и пагинация нативные, запросы идут через API Lampa (учитывается прокси TMDB из настроек).
Топ раздач NNMClub/RUTOR (только видео-категории) с постерами и
метаданными TMDB. Клик — обычная страница фильма в Lampa; раздачи одного
фильма схлопываются в одну позицию — качество и озвучку выбираешь дальше
в парсере. Сортировка (вправо): по сидам сейчас или «классика» —
завершённость за всё время (NNM o=6). Несматчившееся с TMDB (софт, игры,
сборники) не показывается.
Лист фильтров (вправо) повторяет штатный фильтр торрентов: качество, озвучки, тумблеры.
Зеркало seasonvar.ru + статусы просмотра аккаунта.
Четыре варианта (кнопка вправо): Топ, Новинки, Обновления — блоки
главной сайта — и Отслеживаемые — закладки аккаунта («на чём остановились»)
с плашками прогресса 2/8 и ✓ за целиком просмотренные сезоны. Карточки
нативные: айтем seasonvar матчится с TMDB, клик открывает обычную страницу
сериала — поиск раздач дальше штатный парсер Lampa.
Статусы пишутся в обе стороны:
Учётка — в Настройки → Seasonvar (e-mail + пароль): сервер единожды логинится
и возвращает устройству куку сессии svid1 (живёт ~30 дней, обновляется
кнопкой «Сессия»). Креды на сервере не хранятся; у сайта нет CORS, поэтому
всё ходит через tracker-top /seasonvar/* тем же origin.
Настройки → Топ:
| Параметр | Что делает |
|---|---|
| Адрес сервера топа | URL tracker-top (рабочий — https://top.0x3654.com) |
| «Топ» вместо главной | при запуске открывается последний вариант «Топа» вместо ленты |
| Мин. качество (трекеры) | Любое / 720p+ / 1080p+ / 2160p+ |
| Озвучка 1 / Озвучка 2 (трекеры) | какие плашки озвучки показывать (напр. Дубляж + Многоголосый) |
| Скрывать просмотренные | исключать просмотренное по истории Lampa, на сервере |
| Только с раздачами | в «Топе · TMDB» показывать только фильмы, у которых на трекерах есть раздача под наши фильтры |
| Скрыть сериалы | «Топ · трекеры»: только фильмы |
| Только на русском | скрывать раздачи/карточки совсем без русских букв в названии |
| Скрыть аниме | «Топ · трекеры»: японские аниме прочь, мультики остаются (вкл по умолчанию) |
| Скрывать CAM/TS | камрипы и «звук с TS» вычищаются ДО дедупа: фильм только с такими раздачами исчезает целиком, с нормальной — остаётся с ней (вкл по умолчанию) |
Настройки → Seasonvar: Логин/Пароль (e-mail аккаунта seasonvar.ru), Сессия · войти/обновить (статус и перелогин), Скроббл в Seasonvar (тумблер, вкл по умолчанию).
Два способа отправить раздачу из меню долгого нажатия (работает с любым трекером — магнет парсера уходит как есть):
| Пункт | Когда показывается | Что делает |
|---|---|---|
| Скопировать магнет | есть магнет | магнет в буфер обмена |
| Открыть магнет | есть магнет | window.location = magnet: → системный обработчик схемы |
| Добавить в Plex (всегда последним) | есть магнет | раздача → личная лента «авто» nnm-rss → transmission-rss качает в библиотеку Plex; повторное добавление — «Уже в ленте» |
Бывший плагин nnm-auto.js влит в Torrent Send и удалён; если он остался в расширениях со старых установок — удалите его.
[!NOTE] Transmission 4.1.3 убрал CORS-заголовки из RPC, поэтому браузер/PWA не могут обращаться к нему напрямую — Torrent Send идёт через системные обработчики
magnet:и нативные клиенты, а не черезfetch.
[!TIP] Системного UI для схем на macOS нет — обработчик переключается записью в LaunchServices (TRG для примера, bundle id
com.transgui):
defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandlers \
-array-add '<dict><key>LSHandlerURLScheme</key><string>magnet</string>\
<key>LSHandlerRoleAll</key><string>com.transgui</string></dict>'
killall lsd
Проверить: open 'magnet:?xt=urn:btih:0000000000000000000000000000000000000000'.
Bundle id любого приложения: osascript -e 'id of app "Имя"'.
Настройки → NNM RSS (nnm.0x3654.com):
| Параметр | Что делает |
|---|---|
| Адрес сервера | URL сервиса nnm-rss (предзаполнен https://nnm.0x3654.com) |
| Логин / Пароль | аккаунт на сервисе (регистрация на его главной); пароль лежит в localStorage устройства и в настройках скрыт точками |
| Проверить вход | кнопка: логинится текущим логином/паролем, статус прямо в строке (✓ зелёным / ✗ красным) |
Авторизация: JSON-логин → токен (кэшируется на пару сервер+логин), далее
Authorization: Bearer; при 401 (смена пароля ротирует токен) — перелогин и
один повтор.
Двусторонний статус просмотра с аккаунтом Plex (Настройки → Plex). Привязка — кодом plex.tv/link (или ручным X-Plex-Token); сервер аккаунта определяется сам, ручной LAN-адрес — опционально. До привязки аккаунта ничего не отправляется.
| Направление | Что происходит |
|---|---|
| Lampa → Plex | досмотрели (≥ 90%) — scrobble на сервере; частичный просмотр — позиция; сняли отметку — unscrobble |
| Plex → Lampa | «Синхронизировать» переносит просмотренное и позиции в таймлайн Lampa (прогресс на карточках), «Историю просмотров» и отметки «Просмотрено» (скрытие лент читает отметки и не зависит от истории; заодно плагин поднимает сам лимит истории лампы со 100 до 5000) |
Матчинг точный, по TMDB-гуидам (tmdb://id — их несут агенты Plex
Movie/Series). Локальная отметка новее входящей не затирается (LWW). С
включённым «Sync Watch State» у аккаунта отметка на одном сервере сама
разъедется по остальным. Адрес сервера по умолчанию — тоннель на ru2 по
https (https://ru2.0x3654.com/plex; чистый http с https-страницы браузер
режет как mixed content); очистите поле — плагин возьмёт адрес
из списка серверов аккаунта.
Импорт пишет отметки и локально (обходя «облачную» ветку бандла, где при аккаунт-синке списки не растут вовсе), и событием в облако — иначе сверка затирает их своей копией. При включённом аккаунт-синке CUB отметки из Plex долгое время жили только в таймлайне — теперь и «История», и «Просмотрено» на месте, а открытый экран топов пересобирается по завершению импорта.
Одно стабильное хранилище всех отметок: ручные статусы карточки («Смотрю / Просмотрено / Запланировано / Продолжение / Брошено»), «История», закладки. Локальный кеш расходник, облако CUB оказалось ненадёжным («Просмотрено» не хранит вообще, историю капит 500, сверка затирает локальные списки) — поэтому отметки живут в нашем маленьком сервисе, а устройства только зеркалят его.
| Механика | Что происходит |
|---|---|
| pull | при старте + вотчдог каждые 5 минут: недостающие отметки вливаются, снятые (tombstone) убираются, съеденное сверкой восстанавливается |
| push | каждая отметка — ручная, из Plex-импорта, от плеера — уезжает дебаунс-пачкой с карточкой и временем |
| sync-up | при старте локальные отметки, которых нет в базе, доталкиваются сами — база наполняется с первого запуска любого устройства, серверного засева нет |
| LWW | запись с бóльшим временем побеждает; снятие отметки — tombstone, разъезжается тоже |
Хранилище — JSON-файл с атомарной заменой (SQL на личные объёмы не
окупается), доступ по секретному пути, CORS для браузерного клиента.
Сборка и тесты в CI → ghcr.io/0x3654/marks; публичный инстанс —
https://marks.0x3654.com.
[!NOTE] Чистое устройство или снесённый кеш — всё возвращается первым стартом: boot-pull вольёт базу, sync-up дотолкает остаток.
Один короткий URL для чистой установки Lampa: ставит плагины выше (плюс etor — разблокировщик торрентов — и tmdb-proxy), один раз применяет кураторский блок настроек (version-gated), выбирает ссылку TorrServer пробой, мигрирует старые URL плагинов после переименования репозитория и самолечит глюк детекции платформы Apple TV. Источник правды — репо user-site; копия здесь — зеркало.
Go-сервис экранов «Топ · трекеры» и серверной сборки TMDB-топов: один
статический бинарник в scratch-образе (~11 МБ). Источники: NNMClub
(tracker.php?o=10, видео-поддерево категорий парсится со страницы) и rutor
(топы по разделам). Философия: фильмы для просмотра, а не лента раздач —
раздачи одного фильма схлопываются в одну позицию.
GET /top?src=both|nnm|rut&cat=video|all&pages=1..3&minq=720|1080|2160&audio=all|dub|no_ts
GET /feed?... серверная сборка TMDB-топов с фильтрами и exclude просмотренного
GET /seasonvar/... прокси seasonvar.ru: login/home/tracking/serial/search/mark
GET /healthz
Кэш в памяти (TTL 600 с), CORS *, зеркала — env NNM_BASE / RUTOR_BASE.
CI собирает multi-arch образ ghcr.io/0x3654/tracker-top (deps → test →
build → scratch; сломанный парсер валит сборку; non-root, healthcheck).
Публичный инстанс: https://top.0x3654.com.
seasonvar)o=5)
рядом с топами по сидам/датеСделано из крупного:
Разработка и тестирование — локально, против локальной лампы; main — прод
(Pages отдаёт плагины устройствам, CI собирает образы tracker-top и marks).
Тесты — в контейнерах (хост не пачкаем):
docker run --rm -v "$PWD":/src -w /src node:24-alpine node smoke-top.js
docker run --rm -v "$PWD":/src -w /src node:24-alpine node smoke-test.js
docker run --rm -v "$PWD"/tracker-top:/src -w /src golang:1.27-alpine go test ./...
Два контейнера на маке; остальные устройства в LAN видят его по Bonjour-имени
мака (scutil --get LocalHostName → <имя-мака>.local). Конфиг nginx с
same-origin-прокси /topapi — в репо: dev/nginx.conf.
# tracker-top под тестом (:8355)
docker build -t tracker-top:dev tracker-top
docker run -d --name trackertop-dev -p 8355:8355 \
-v trackertop-dev-cache:/data tracker-top:dev
# локальная лампа (:8098): официальный вебрут + конфиг nginx, один раз:
git clone --depth 1 https://github.com/yumata/lampa ~/code/lampa
rm -rf ~/code/lampa/.git # вебрут расходный
docker run -d --name lampa-dev -p 8098:80 \
-v "$HOME/code/lampa":/usr/share/nginx/html:ro \
-v "$PWD/dev/nginx.conf":/etc/nginx/conf.d/default.conf:ro \
nginx:1.27-alpine
# синхронизация правок плагинов в вебрут (после каждой правки; одиночные
# bind-mount файлов цепляют старый inode и отдавали бы устаревший код):
cp top.js transmission-send.js t.js plex-sync.js ~/code/lampa/
Опционально: вывод исходящего трафика tracker-top (Jackett-прокси, трекеры, TMDB) через свой VPS — IP мака при интенсивной отладке быстро набирает рейт-лимиты. Достаточно чистого SSH-SOCKS-туннеля — HTTP-стек Go понимает socks5-прокси из окружения. Туннель эпемерный: поднял на сессию отладки — опусти после; без него дев-контейнер теряет внешние запросы (пулы живут на дисковом кэше):
ssh -fN -D 127.0.0.1:1080 <vps> # любой VPS с ssh-доступом
docker run -d --name trackertop-dev -p 8355:8355 -v trackertop-dev-cache:/data \
-e HTTP_PROXY=socks5://host.docker.internal:1080 \
-e HTTPS_PROXY=socks5://host.docker.internal:1080 \
-e NO_PROXY=localhost,127.0.0.1 \
tracker-top:dev
Однократно после клона вшить в ~/code/lampa/index.html дев-хук (перед
скриптом с var lampa_url) — он помечает бутстрап дев-режимом и грузит
локальный /t.js:
<script>
window.TJS_DEV = true
;(function waitLampa(n){
if(window.appready || window.Lampa || n > 400){
var s = document.createElement('script')
// бустер: даже кэшированная страница возьмёт свежий t.js
s.src = '/t.js?v=' + Math.floor((new Date()).getTime() / 6e4)
document.head.appendChild(s)
} else setTimeout(function(){ waitLampa(n + 1) }, 50)
})(0)
</script>
Дальше открываешь страницу — бутстрап делает всё сам:
http://localhost:8098 — t.js ставит плагины с того же
origin, адрес сервера Топа — same-origin прокси /topapi (в dev
прописывается на каждом старте), одна перезагрузка. Руками настраивать
ничего не надо.http://<имя-мака>.local:8098 — оба адреса выводятся из адреса страницы,
так что с любого устройства одно и то же (localhost на TV — это сам TV).protocol() дефолтит в https (storage protocol пуст) и шлёт
TLS-хендшейки в http-nginx — дев-бутстрап форсит protocol=http на
каждом старте.Заметки:
mcr.microsoft.com/playwright:v1.49.0-jammy (тег именно
с .0), модуль playwright ставить в /work контейнера, скрипты монтировать
в /work; контейнер ходит на мак как host.docker.internal:8098./forum/:
nnmclub.to/forum/tracker.php?o=10 (200; без /forum/ — 404).Деплой: пуш в main → Pages публикует плагины, CI собирает образ; публичный
инстанс обновляется из registry.
Точки расширения (сверены по исходникам Lampa 3.3.3): хуки
Lampa.Listener('torrent'/'torrent_file', onlong) добавляют пункты в
e.menu; экраны — Lampa.InteractionCategory (приём плагина collections) +
Lampa.Api.sources.tmdb.get; меню Lampa.Menu.addButton, настройки
Lampa.SettingsApi.
[!IMPORTANT] Неофициальный хобби-проект, никакого отношения к Lampa, NNM Club и rutor не имеет. Парсинг трекеров опирается на гостевые страницы и может ломаться при редизайнах.
MIT © 0x3654
</div>
In Lampa: Settings → Extensions → «+», paste a URL (per device; on iPhone the PWA is separate from the Safari tab):
| Plugin | URL |
|---|---|
| Top | https://0x3654.github.io/lampa-plugins/top.js |
| Torrent Send | https://0x3654.github.io/lampa-plugins/transmission-send.js |
| Plex Sync | https://0x3654.github.io/lampa-plugins/plex-sync.js |
| everything at once | https://0x3654.github.io/t.js (bootstrap, see below) |
Two menu items instead of the default feed — this is the main plugin.
TMDB popularity screens for movies and series — three flavours each: weekly trending (what’s hot now), best rated (all-time classics) and new releases of 2025+ (six variants; the day/window tops were dropped — they overlapped the weekly trending by 78–100% and the premiere windows held 8–15 films). Switch the variant with the right button on the screen. Cards and pagination are native, requests go through the Lampa API (your TMDB proxy setting applies), so screens open instantly.
Release tops of NNM Club + rutor (video categories only), enriched with TMDB
posters and metadata. A click opens the native film page — quality and voice
are picked later in the Lampa parser, so releases of the same film collapse
into a single position. Sorting (right button): by seeders now or
all-time classics (NNM o=6, rutor doesn’t take part in that mode).
Releases that don’t match TMDB (software, games, packs) are not shown.
The filter sheet (right button) mirrors the native torrent-filter UI: quality, up to two voices, toggles, «Show».
A mirror of seasonvar.ru plus the account’s watching
statuses. Four variants (right button): Top, New, Updates — the
site’s main-page blocks — and Tracked — the account’s bookmarks
(«where you left off») with 2/8 progress plates and a ✓ for fully watched
seasons. Cards are native: a seasonvar item is matched to TMDB, a click opens
the regular series page — release search continues in the stock Lampa parser.
Statuses flow both ways:
Credentials live in Settings → Seasonvar (e-mail + password): the server logs
in once and hands the device the svid1 session cookie (~30 days, refreshed
by the «Session» button). Credentials are not stored server-side; the site
has no CORS, so everything goes through tracker-top /seasonvar/*,
same origin.
Settings → Top:
| Setting | What it does |
|---|---|
| Top server address | tracker-top URL (a working one: https://top.0x3654.com) |
| Top as home screen | open the last used Top variant on start instead of the feed |
| Min quality (trackers) | Any / 720p+ / 1080p+ / 2160p+ |
| Voice 1 / Voice 2 (trackers) | voice plates to show (e.g. Dub + Multi) |
| Hide watched | exclude watched by Lampa history, server-side |
| With releases only | in Top · TMDB show only films that have a tracker release under our filters |
| Hide series | Top · trackers: movies only |
| Russian titles only | hide releases/cards with no cyrillic in the title |
| Hide anime | Top · trackers: no Japanese anime, cartoons stay (on by default) |
| Hide CAM/TS | camrips and TS sound are cut before dedup: a film with only such releases disappears entirely, one with a proper release stays (on by default) |
Settings → Seasonvar: Login/Password (seasonvar.ru account e-mail), Session · sign in / refresh (status and re-login), Scrobble to Seasonvar (toggle, on by default).
Two ways to send a release from the long-press menu (any tracker — the parser magnet goes as-is):
| Menu item | When shown | What it does |
|---|---|---|
| Copy magnet | magnet present | magnet to clipboard |
| Open magnet | magnet present | window.location = magnet: → the system handler (a torrent client or a helper app) |
| Add to Plex (always last) | magnet present | pushes the release into the personal «auto» feed of nnm-rss, from which transmission-rss downloads it into the Plex library; duplicate releases answer «already in the feed» |
The former nnm-auto.js plugin is merged into Torrent Send and gone; remove it from the extension list if it was ever installed.
[!NOTE] Transmission 4.1.3 removed CORS headers from its RPC, so browser/PWA clients cannot talk to it directly. That is why Torrent Send routes through system
magnet:handlers and native clients instead offetch.
macOS has no UI for URL schemes; the handler is switched via LaunchServices
(TRG here as an example, bundle id com.transgui):
defaults write com.apple.LaunchServices/com.apple.launchservices.secure LSHandlers \
-array-add '<dict><key>LSHandlerURLScheme</key><string>magnet</string>\
<key>LSHandlerRoleAll</key><string>com.transgui</string></dict>'
killall lsd
Check: open 'magnet:?xt=urn:btih:0000000000000000000000000000000000000000'.
Bundle id of any app: osascript -e 'id of app "Name"'.
Settings → NNM RSS (nnm.0x3654.com):
| Setting | What it does |
|---|---|
| Server address | nnm-rss URL (prefilled https://nnm.0x3654.com) |
| Login / Password | an account on the service (register on its front page); the password stays in device localStorage and is masked with dots |
| Check login | button: logs in with the current credentials, status right in the row (✓ green / ✗ red) |
Authorization: JSON login → token (cached per server+login), then
Authorization: Bearer; on 401 (a password change rotates the token) it
re-logins and retries once.
Two-way watch status with a Plex account (Settings → Plex). Linking is a plex.tv/link code (or a manual X-Plex-Token); the account’s server is detected automatically, a manual LAN address is optional. Nothing is sent until an account is linked.
| Direction | What happens |
|---|---|
| Lampa → Plex | finished (≥ 90%) — scrobble on the server; partial — playback position; unmarked — unscrobble |
| Plex → Lampa | «Sync now» pulls watched items and positions into the Lampa timeline (progress on cards), «Viewing history» and the «Viewed» marks (hiding feeds reads the marks and doesn’t depend on history; the plugin also lifts lampa’s own history cap of 100 to 5000) |
Matching is exact, by TMDB guids (tmdb://id — the Plex Movie/Series
agents carry them). A local mark newer than the incoming one is never
overwritten (LWW). With «Sync Watch State» enabled on the account, a mark
on one server propagates to the others by itself. The server address
defaults to the ru2 tunnel over https (https://ru2.0x3654.com/plex;
plain http would be blocked as mixed content from an https page) — clear
the field to let the account’s own server list pick the address.
The import writes marks both locally (working around the bundle’s account-sync branch where the lists never grow) and as the cloud event — otherwise the reconcile wipes them with its own copy. With the CUB account sync on, imported marks used to survive only in the timeline; now «History» and «Viewed» land too, and an open Top screen rebuilds once the import finishes.
The single stable store for every watch mark — manual card statuses (watching / viewed / planned / continuing / dropped), history, bookmarks. The local cache is expendable and the CUB cloud proved unreliable (it does not store «Viewed» at all, caps history at 500 and its reconcile wipes local lists), so the marks live in our own tiny service and every device just mirrors it.
| Mechanics | What happens |
|---|---|
| pull | on boot + a 5-minute watchdog: missing marks merge in, unmarked (tombstones) drop out, whatever a reconcile ate comes back |
| push | every mark — manual toggles, Plex imports, the player — leaves in a debounced batch with the card and a timestamp |
| sync-up | on boot, local marks missing from the base backfill it — the base fills itself from the first start of any device, no server-side seeding |
| LWW | the newer timestamp wins; unmarking is a tombstone and travels too |
The store is a JSON file with atomic renames (SQL does not pay off at
personal scale), reached over a secret URL path, CORS-open for the
browser client. Build and tests in CI → ghcr.io/0x3654/marks; the
public instance serves https://marks.0x3654.com. A fresh device or a
wiped cache recovers everything on first start.
One short URL for a fresh Lampa install: adds the plugins above (plus the tmdb-proxy), applies a curated settings block once (version-gated), picks the TorrServer link by probing (embedded on Apple TV, the Mac’s own TorrServer on desktops, the public ru2 server elsewhere), unlocks the torrent features natively (no etor cub plugin), migrates old plugin URLs after the repository rename and self-heals the Apple TV platform detection glitch. Source of truth lives in the user-site repo; the copy here mirrors it.
On the clone itself the settings UI carries no foreign sync: the «Синхронизация» (CUB account) section and the head profile button are removed, and the card statuses are unlocked from the CUB premium gate — every status flows into the marks base instead.
The Go service behind «Top · trackers» and the server-side TMDB screens: one
static binary in a scratch image (~11 MB). Sources: NNM Club
(tracker.php?o=10, the video category subtree parsed from the page) and
rutor (per-category tops). Philosophy: films for browsing, not a release
feed — releases of the same film collapse into one position.
GET /top?src=both|nnm|rut&cat=video|all&pages=1..3&minq=720|1080|2160&audio=all|dub|no_ts
GET /feed?... server-side TMDB-top assembly with filters and watched-exclude
GET /healthz
In-memory cache (TTL 600 s), CORS *, mirror override via NNM_BASE /
RUTOR_BASE. CI builds a multi-arch image: ghcr.io/0x3654/tracker-top
(deps → test → build → scratch; a broken parser fails the build; non-root,
healthcheck). A public instance serves https://top.0x3654.com.
o=5) next to the
seeds/date topsDone highlights: the seasonvar.ru sync (a Seasonvar top with read/write
watching marks and auto-scrobble, branch seasonvar), the marks single store,
the Apple TV embedded TorrServer
over http, the cub cuts on the clone (ads/analytics/censorship/Shots),
unlocked card statuses, the Plex↔Lampa sync.
Everything is developed and tested locally against a local Lampa; main
is production (Pages serves the plugins, CI builds the tracker-top and
marks images).
Tests run in containers (host stays clean):
docker run --rm -v "$PWD":/src -w /src node:24-alpine node smoke-top.js
docker run --rm -v "$PWD":/src -w /src node:24-alpine node smoke-test.js
docker run --rm -v "$PWD"/tracker-top:/src -w /src golang:1.27-alpine go test ./...
Two containers on the Mac; other devices on the LAN reach it by the Mac’s
Bonjour name (scutil --get LocalHostName → <mac-name>.local). The nginx
config with the same-origin /topapi proxy is in the repo —
dev/nginx.conf.
# tracker-top under test (:8355)
docker build -t tracker-top:dev tracker-top
docker run -d --name trackertop-dev -p 8355:8355 \
-v trackertop-dev-cache:/data tracker-top:dev
# local Lampa (:8098): official webroot + nginx conf, once:
git clone --depth 1 https://github.com/yumata/lampa ~/code/lampa
rm -rf ~/code/lampa/.git # disposable static webroot
docker run -d --name lampa-dev -p 8098:80 \
-v "$HOME/code/lampa":/usr/share/nginx/html:ro \
-v "$PWD/dev/nginx.conf":/etc/nginx/conf.d/default.conf:ro \
nginx:1.27-alpine
# sync plugin edits into the webroot (after every edit; single-file bind
# mounts would pin the old inode and serve stale code):
cp top.js transmission-send.js t.js plex-sync.js ~/code/lampa/
Optional: route the tracker-top container’s outbound traffic (Jackett proxy, trackers, TMDB) through a VPS — the Mac’s IP collects rate limits fast during heavy debugging. A plain SSH SOCKS tunnel is enough; Go’s HTTP stack honours a socks5 proxy from the environment. The tunnel is ephemeral: raise it for a debugging session and drop it after — with it down the dev container loses external fetches (pools hold on the disk cache):
ssh -fN -D 127.0.0.1:1080 <vps> # any VPS you can ssh to
docker run -d --name trackertop-dev -p 8355:8355 -v trackertop-dev-cache:/data \
-e HTTP_PROXY=socks5://host.docker.internal:1080 \
-e HTTPS_PROXY=socks5://host.docker.internal:1080 \
-e NO_PROXY=localhost,127.0.0.1 \
tracker-top:dev
One-time, after cloning the webroot, inject the dev hook into
~/code/lampa/index.html (before the var lampa_url script) — it flags
the bootstrap for dev and loads the local /t.js:
<script>
window.TJS_DEV = true
;(function waitLampa(n){
if(window.appready || window.Lampa || n > 400){
var s = document.createElement('script')
// bust: even a cached page always fetches a fresh t.js
s.src = '/t.js?v=' + Math.floor((new Date()).getTime() / 6e4)
document.head.appendChild(s)
} else setTimeout(function(){ waitLampa(n + 1) }, 50)
})(0)
</script>
Open the page and the bootstrap does the rest:
http://localhost:8098 — t.js installs the plugins
from the same origin and points the Top server at the same-origin
/topapi proxy automatically (dev sets it on every boot), then reloads
once. Nothing to configure by hand.http://<mac-name>.local:8098 — both addresses are derived from the page
address, so the same setup works from any device (localhost on the TV
is the TV itself).protocol() helper defaults
to https (empty protocol storage) and fires TLS handshakes into the
http nginx — the dev bootstrap forces protocol=http on every boot.Notes:
mcr.microsoft.com/playwright:v1.49.0-jammy (the tag with
.0), the playwright module installed into /work of the container,
scripts mounted at /work; the container reaches the Mac as
host.docker.internal:8098./forum/ prefix:
nnmclub.to/forum/tracker.php?o=10 (200; without /forum/ — 404).Deploy: push to main → Pages publishes the plugins, CI builds the image;
the public instance updates from the registry.
Extension points (verified against the Lampa 3.3.3 sources): hooks
Lampa.Listener('torrent'/'torrent_file', onlong) push menu items into
e.menu; screens use Lampa.InteractionCategory (the collections-plugin
reception) + Lampa.Api.sources.tmdb.get; menus Lampa.Menu.addButton,
settings Lampa.SettingsApi.
[!IMPORTANT] Unofficial hobby project, no affiliation with Lampa, NNM Club or rutor. Tracker parsing follows guest-accessible pages and may break on redesigns.