myspoti
Native Android client for Spotify, built with Jetpack Compose
zipline: сообщения разработчиков Deadlock из Discord в одной ленте.
Translation pending
MediaPython · JavaScriptGitHub @trebushe1OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
zipline — трекер сообщений разработчиков Deadlock из Discord
Translation pending
Taken from the repository README
Loading the full README.
Read the full README ↗Новостной трекер по Deadlock. Первый модуль — трекер разработчиков: сообщения разработчиков из официального Discord-сервера Deadlock в одной ленте, с поиском, фильтрами и кнопкой «Текст для поста» для канала.
./run.sh
Сайт откроется на http://127.0.0.1:8000. Без настроек работает в демо-режиме (вымышленные авторы).
Бота на официальный сервер Valve не добавить, поэтому есть два пути:
backend/discord_collector.py). Нужен токен Discord-аккаунта,
который состоит на сервере Deadlock. Сборщик раз в POLL_SECONDS ищет по серверу сообщения
от авторов из backend/developers.json — это охватывает все каналы и ветки за несколько запросов.
⚠️ Автоматизация обычного аккаунта нарушает правила Discord — используйте отдельный аккаунт,
не основной.POST /api/ingest — любой мост или бот присылает сырые объекты
сообщений Discord с заголовком X-Ingest-Secret. Формат описан в backend/app.py.Настройки — в .env (образец: .env.example). После первого успешного получения
реальных сообщений демо-данные удаляются автоматически.
Страница changes.html («Изменения» в шапке) показывает, что поменялось в файлах игры от билда к билду:
модели, текстуры, материалы и эффекты по героям и зонам, новые строки локализации и значения
из игровых скриптов (было → стало).
Источник — открытый репозиторий SteamDB GameTracking-Deadlock:
по коммиту на каждый билд Steam со списком файлов (с контрольными суммами), скриптами .vdata и английской локализацией.
python -m backend.patches # скачать новые билды и записать сводки в data/patches/
python -m backend.patches --rebuild # пересобрать последние PATCH_BUILDS (30) билдов заново
На GitHub это делает .github/workflows/patches.yml каждые 20 минут: коммитит новые сводки и перезапускает деплой.
backend/media.py для последних 10 билдов достаёт из Steam изменённые модели и текстуры (только нужные
файлы из архивов игры, через SteamFileDownloader),
конвертирует их Source2Viewer-CLI в GLB и WebP
и кладёт в GitHub-релиз media-<билд>-<sha>. Билды старше 10-го теряют медиа, их релизы удаляются;
общий объём ограничен MEDIA_BUDGET_MB (400). В git попадает только список файлов.
Нужны секреты репозитория STEAM_USERNAME и STEAM_PASSWORD — отдельный аккаунт с доступом к Deadlock
и выключенным Steam Guard (иначе вход с серверов GitHub требует код). Без секретов шаг пропускается.
Страница heroes.html («Герои» в шапке) показывает всех играбельных героев карточками, как в игре. По клику
открывается окно с 3D-моделью из файлов игры: её можно крутить, выбирать анимацию, ставить на паузу и
выбирать кадр, а потом скачивать PNG на прозрачном фоне (×1/×2/×4). Кнопка «Скачать WebM» пишет
один цикл выбранной анимации (24 кадра/с) в WebM-видео с прозрачностью — размером с окно или
квадратом 500×500 / 100×100, куда герой вписывается целиком. Внутри VP9 плюс второй VP9-поток
с альфой, как это делает ffmpeg (тот же формат, что у видеостикеров Telegram). Safari прозрачность
в WebM не показывает.
Окно растягивается за угол и разворачивается на весь экран.
backend/heroes.py берёт список героев из heroes.vdata последнего билда, качает из Steam модель героя
со всем, что она использует, и конвертирует её Source2Viewer-CLI. Из анимаций остаются бег и ближний бой.
Материалы запекаются по логике шейдера игры: тинт по маске, контраст/насыщенность/яркость, цвет вершин
(в игре он в sRGB), карты нормалей; текстуры цвета — в исходном разрешении.
Модель (GLB, сжатая gltfpack) и пакет анимаций лежат в GitHub-релизе heroes; страница подгружает
каждую анимацию отдельно (HTTP range). Иконки и список — в data/heroes/.
python -m backend.heroes # сконвертировать новых и изменившихся героев
python -m backend.heroes --fetch DIR # скачать модели из релиза (так делает деплой)
На GitHub это делает .github/workflows/heroes.yml раз в 6 часов (и вручную: можно указать героев в only).
Нужны те же секреты STEAM_USERNAME / STEAM_PASSWORD.
Страница items.html («Предметы» в шапке) — магазин Deadlock как в игре: вкладки «Все / Оружие / Живучесть / Дух»,
предметы по тирам с ценой в душах (легендарные из «Уличной драки» — отдельным рядом), поиск по-русски и по-английски,
игровые фильтры («что даёт предмет», режимы «любой» и «все сразу»), сортировка по цене и названию. Наведение показывает
подсказку как в игре: характеристики, пассивка и активка с перезарядкой, рост от силы духа, из чего собирается.
По клику — карточка предмета: иконка в PNG 100×100, 300×300 или 500×500; внизу магазина — ZIP со всеми иконками
(или только с показанными) нужного размера.
Кнопка «Создать билд» превращает магазин в редактор, как в игре: клик по предмету кладёт его в выбранную категорию, предметы перетаскиваются между категориями, к каждому можно оставить заметку; категории добавляются, переименовываются, двигаются и получают описание. Есть выбор героя и порядок прокачки способностей (открытие и улучшения за 1, 2 и 5 очков). Во вкладке «Билд» категории — блоки на сетке в 12 колонок, как во вкладке «Билд» в игре: блок переставляется за ⠿, ширина и высота меняются за уголок (или стрелками), предметы во всех блоках одного размера и подгоняются под самый тесный блок. Раскладка сохраняется в ссылке и JSON и так же выглядит на полноэкранной странице и на картинках. Билды хранятся в браузере; «Ссылка» упаковывает билд в адрес страницы (deflate + base64). По ссылке билд открывается на всю страницу — герой, категории с крупными предметами и заметками, прокачка; «Сохранить себе» копирует его в свои билды и открывает редактор. Свой билд так же разворачивается кнопкой «На весь экран». Там же билд скачивается картинкой PNG 1080×1080 или 1920×1080: она рисуется на canvas заново под размер (герой, сумма, категории с предметами и заметками, прокачка), поэтому кнопок и интерфейса сайта на ней нет. Есть экспорт и импорт JSON.
backend/items.py берёт предметы из abilities.vdata последнего билда (цены тиров — generic_data.vdata, английский
текст — локализация в репозитории SteamDB). Из Steam приходят иконки магазина (без потерь, в разрешении игры,
через Source2Viewer-CLI) и русская локализация; и то и другое качается заново, только когда файл в игре изменился
(контрольные суммы есть в pak01_dir.txt и манифесте депо). Результат — data/items/index.json, data/items/icons/
и data/items/loc_ru.json (нужные русские строки, чтобы балансный патч не требовал входа в Steam).
python -m backend.items # обновить список, иконки и русский текст
python -m backend.items --offline # только список, без Steam
На GitHub это делает .github/workflows/items.yml раз в час и после изменений backend/items.py.
Нужны те же секреты STEAM_USERNAME / STEAM_PASSWORD.
Страница tierlist.html («Тир-лист» в шапке) — свой тир-лист героев: строки S, A, B, C и D, под ними все герои
из heroes/index.json (по алфавиту, с поиском). Героя перетаскивают в строку, внутри строки — чтобы поменять порядок,
и обратно вниз — чтобы убрать; при перетаскивании к краю окна страница прокручивается сама. Перетаскивание сделано на
pointer-событиях, поэтому работает и мышью, и пальцем (на телефоне героя нужно чуть подержать, иначе палец листает
страницу). Без перетаскивания: нажать на героя, потом на строку, или клавиши S/A/B/C/D, Delete — обратно в список.
Тир-лист и его название хранятся в браузере. Кнопка «Скачать 1080×1080» рисует PNG на canvas заново: название, дата,
наш логотип и пять строк с портретами — размер портретов подбирается самый крупный, при котором влезают все строки.
backend/emoji.py рисует пак кастомных эмодзи: голова каждого героя и каждая его способность — PNG 100×100 с прозрачностью
(44 + 176 = 220 штук), в data/emoji/ с понятными именами (apollo-0-head.png, apollo-2-riposte.png); список — в
data/emoji/index.json, в порядке пака: герои по алфавиту (The Doorman — на D), у каждого голова, потом способности 1–4.
Голова вырезана из портрета с карточки героя, как вырезка из журнала, без фона: сверху силуэт самой карточки, плечи срезаны
дугой, тот же тёмный контур и бумажная кайма, и второй оттиск силуэта в цвете героя со сдвигом. Где на карточке голова,
задано для каждого героя кругом в HEADS (подобран на глаз: от макушки, шляпы, рогов или ушей до подбородка, у Калико и
Мо и Крилла — оба персонажа); у нового героя без круга берётся примерное место, и его стоит подобрать.
Предметы магазина — отдельный пак (156 штук, без легендарных из «Уличной драки»), в data/emoji/items/ (weapon-1-close-quarters.png),
в порядке магазина: оружие, живучесть, дух, внутри — по тирам и названию. Предмет — иллюстрация из магазина, напечатанная
как фото и приклеенная к чату двумя уголками скотча: тот же контур и кайма, тонкая рамка цвета вкладки (оружие оранжевое,
живучесть зелёная, дух фиолетовый), картинка — сколько позволяет край, ведь узнают предмет именно по ней; тир и так виден
по фону картинки. ITEM_TIER_ON_TAPE = True вместо уголков даёт один скотч сверху с тиром маркером (I–IV).
Знаки для постов — третий пак (backend/emoji_symbols.py, 39 штук в data/emoji/symbols/): стрелки в 8 сторон и красная стрелка вниз (для нерфов), точка
по центру, кружок, ромб, звезда, искра, плей, молния, тире, дефис, кавычки «» и „“, ! ? . , : …, скобки, + − = ✓ ✗ / # % №.
Знак без плашки: сам вырезан из бумаги нашего зелёного (полоски с косыми срезами, сгибы срезаны поперёк), сверху светлый
сухой мазок, вокруг те же кайма и контур, сзади оттиск тёмно-зелёным со сдвигом. Ширина полоски у всех знаков одна, чтобы
в строке текста они стояли ровно.
Способность — наш шаблон поста в миниатюре: фотокарточка на скотче. Снаружи внутрь: тёмный контур, бумажная кайма, рамка цвета героя, почти чёрное нутро с сухим мазком, иконка способности из игры. Четыре карточки героя наклонены по-разному, у ульты второй кусок скотча на нижнем углу. Двойной край (контур + кайма) — то, что делает один дизайн годным для любой темы: на тёмном чате видна кайма, на светлом — контур, на средних стандартных обоях — оба.
Цвет героя — одна строка в PALETTE (подобран по внешности; игровой m_colorUI у многих героев одинаковый). Оттенки
рамки, мазка и нутра считаются из неё в CIELAB; "#рамка/#мазок" — для двухцветных героев (Шив: чёрный и кровь).
Новый герой без цвета рисуется серым, и скрипт об этом пишет. Шум с фиксированным зерном: те же иконки и палитра дают
те же пиксели, поэтому в git меняются только эмодзи с новой иконкой или цветом.
python -m backend.emoji # нарисовать весь пак
python -m backend.emoji --check # и проверить край каждого эмодзи на фонах Telegram
--check накладывает каждый эмодзи на 9 фонов Telegram (ночные фон и пузыри, чёрный iOS/AMOLED, дневные пузыри,
три оттенка стандартных обоев) и меряет контраст края: в каждой точке силуэта — самую контрастную линию в пределах 3 px
внутрь, по медиане вдоль контура; ниже 3:1 (порог WCAG для фигур) — ошибка.
В Telegram пак выкладывает backend/emoji_telegram.py. В наборе кастомных эмодзи не больше 200 штук, поэтому их два,
по первой букве героя (SETS), предметы и знаки — отдельными наборами «@zipline items» и «@zipline symbols»: «@zipline ability A–L» (https://t.me/addemoji/zipline_ability_al_by_zipline_emoji_bot)
и «@zipline ability M–Z» (https://t.me/addemoji/zipline_ability_mz_by_zipline_emoji_bot). Наборы делает отдельный бот
(TELEGRAM_EMOJI_BOT_TOKEN): Telegram дописывает имя бота в название набора, а название — это публичная ссылка, поэтому
бот уведомлений их не делает и его имя нигде не видно. Владелец наборов — пользователь из TELEGRAM_CHAT_ID (личный чат
с ботом уведомлений); в боте эмодзи ему нужно один раз нажать Start. Недостающий набор создаётся, в остальных меняется
только изменившееся: перерисованный эмодзи заменяется на своём месте, новый добавляется, ушедший удаляется, порядок
и название — как в SETS и паке. Что уже лежит в Telegram, записано в data/emoji/telegram.json.
У каждого эмодзи есть обычный эмодзи-синоним (ALT, по ключу способности или hero_<герой> для головы: его видно там, где
кастомные не рисуются, и по нему Telegram подсказывает наш) и ключевые слова для поиска — герой по-английски и по-русски
и способность.
python -m backend.emoji_telegram --dry-run # что изменится; из Telegram только читает
python -m backend.emoji_telegram # создать или обновить наборы
Страница reddit.html («Reddit» в шапке) — «Пульс» r/DeadlockTheGame: свежие посты, которые набирают голоса
и комментарии быстрее своих ровесников, — наверху. Вкладки «Пульс», «Взлетают», «Новые», «Топ 24 ч»,
темы (новости, клипы, арт, обсуждения) и кнопка «Текст для поста».
Алгоритм (backend/reddit.py). Пост сравнивается только с ровесниками — постами возраста от 0,6 до 1,6 его
собственного, — поэтому 20-минутный пост с 30 голосами может обойти 10-часовой с тремя сотнями.
Сила — место среди ровесников по голосам и комментариям; разгон — рост силы за полчаса; новостям (патчи,
утечки, ссылки на сайты Valve) — надбавка; вес поста падает вдвое каждые 8 часов.
Откуда данные. Без ключа Reddit отвечает на JSON-запросы ошибкой 403, а ключи API с ноября 2025 года выдаёт
только после ручного одобрения. Поэтому по умолчанию используются публичные RSS-ленты: в них нет чисел, и Reddit
разрешает анонимно 1 запрос в минуту. Ленты чередуются: место поста в «топе часа», «горячем» и «топе дня» даёт
силу по голосам, а общая лента комментариев сабреддита — счёт комментариев. Если есть ключ API (приложение типа
script), положите REDDIT_CLIENT_ID и REDDIT_CLIENT_SECRET в секреты репозитория — сборщик сам перейдёт на
настоящие рейтинги и обновление раз в минуту.
Сборщик работает внутри backend/live.py (воркфлоу «Live collector»): лента для страницы — в Firebase
/live/reddit (страница перечитывает её раз в 90 секунд), полное состояние между запусками — в /reddit/state.
python -m backend.reddit # локально: держать data/reddit.json свежим (страница берёт его через ./run.sh)
python -m backend.reddit --once # один запрос и топ в консоль
backend/developers.json — Discord ID и имена. Новые записи подхватываются при перезапуске;
имя и аватар обновляются из Discord автоматически.
backend/ FastAPI + SQLite: API, сборщик Discord, демо-данные
frontend/ статичная страница (HTML/CSS/JS без сборки)
data/ база SQLite (создаётся при запуске)
| Метод | Путь | Что отдаёт |
|---|---|---|
| GET | /api/dev-messages?q=&authors=&channel=&before=&after=&limit= | лента сообщений |
| GET | /api/developers | разработчики, число сообщений за 7 дней, последняя активность |
| GET | /api/channels | каналы с сообщениями |
| GET | /api/dev-stats | сводка: 24 ч, 7 дней, самый активный, график за 30 дней |
| GET | /api/status | состояние сборщика |
| POST | /api/ingest | приём сообщений от внешнего источника |
| GET | /reddit.json | посты Reddit для страницы (из data/reddit.json) |