惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
Vulnerabilities – Threatpost
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Project Zero
Project Zero
P
Palo Alto Networks Blog
G
GRAHAM CLULEY
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Hacker News: Front Page
Help Net Security
Help Net Security
S
Schneier on Security
A
Arctic Wolf
Know Your Adversary
Know Your Adversary
L
LINUX DO - 热门话题
Security Archives - TechRepublic
Security Archives - TechRepublic
L
LangChain Blog
T
The Exploit Database - CXSecurity.com
V2EX - 技术
V2EX - 技术
罗磊的独立博客
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
有赞技术团队
有赞技术团队
P
Privacy & Cybersecurity Law Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
C
Cybersecurity and Infrastructure Security Agency CISA
T
Threat Research - Cisco Blogs
C
Cyber Attacks, Cyber Crime and Cyber Security
J
Java Code Geeks
量子位
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
云风的 BLOG
云风的 BLOG
SecWiki News
SecWiki News
Hacker News: Ask HN
Hacker News: Ask HN
B
Blog RSS Feed
Hugging Face - Blog
Hugging Face - Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Troy Hunt's Blog
U
Unit 42
N
Netflix TechBlog - Medium
阮一峰的网络日志
阮一峰的网络日志
The Register - Security
The Register - Security
Recorded Future
Recorded Future
爱范儿
爱范儿
Webroot Blog
Webroot Blog
Engineering at Meta
Engineering at Meta

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Пять неочевидных вещей, которые я узнал, запуская кино-соцсеть: от robots.txt-ловушки до 24-мерной математики вкуса
vibemuvik · 2026-04-25 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение7 мин

Охват и читатели347

Кейс

Последние полгода я работаю над VibeMuvik — кино-соцсетью с рецензиями, дебатами и синхронным просмотром фильмов. Одна из тех штук, которые «ну вроде несложно», пока не начинаешь копать.

Эта статья — про неожиданные находки. Не про «как я выбрал стек» (скучно) и не про «туториал по WebRTC» (и без меня есть). Это пять ситуаций, в которых я споткнулся, обнаружил что-то интересное, и подумал «об этом стоит рассказать — другим пригодится».

Поехали.


1. Одна строчка в robots.txt, которая съедает crawl-бюджет Google

Свежий кейс. Смотрю логи сервера — Googlebot тысячу раз за сутки дёргает внутренний XHR-эндпоинт, который фронтенд вызывает при рендеринге. Думаю: «Стоп. Как он вообще туда попал? У меня же в robots.txt запрещено.»

Открываю robots.txt. Читаю. Вроде всё правильно:

User-agent: *Disallow: /api/Disallow: /admin/Disallow: /profile/# ... ещё 15 запретовUser-agent: YandexBotCrawl-delay: 1Allow: /User-agent: GooglebotAllow: /

Disallow: /api/

Disallow: /admin/

Disallow: /profile/

# ... ещё 15 запретов

User-agent: YandexBot

Crawl-delay: 1

Allow: /

User-agent: Googlebot

Allow: /

Логика в голове: «для всех ботов запрещаю то-то, а для именных — разрешаю всё».

А вот нихрена. По RFC 9309 и всему здравому смыслу robots-стандарта бот использует ровно один блок — самый специфичный к его User-Agent. Если есть блок Googlebot — общий * полностью игнорируется.

То есть Googlebot видел одно:

User-agent: GooglebotAllow: /

Allow: /

И радостно шёл индексировать весь /api/*. Включая служебные эндпоинты. Включая трекинг показов рекламы — в статистике показов рекламы у меня стали появляться впечатления от бота, с IP из диапазона Google Crawler.

Фикс простой и неприятный

Нужно продублировать Disallow в каждую именованную секцию:

User-agent: *Allow: /Disallow: /api/# ...User-agent: YandexBotCrawl-delay: 1Allow: /Disallow: /api/   ← это было пропущено# ...User-agent: GooglebotAllow: /Disallow: /api/   ← и это# ...

Allow: /

Disallow: /api/

# ...

User-agent: YandexBot

Crawl-delay: 1

Allow: /

Disallow: /api/ ← это было пропущено

# ...

User-agent: Googlebot

Allow: /

Disallow: /api/ ← и это

# ...

Мораль: если у вас есть именованные секции, каждая должна быть самодостаточной. Не наследует от *. Многие сайты на это попадаются — я проверил robots.txt у десятка русскоязычных SaaS-проектов, у трёх нашёл ту же самую ошибку.

Проверьте свой. Серьёзно.


2. Математика вкуса: почему 24 оси, а не 5 «жанров», и при чём тут косинус

В обычной рекомендательной системе вкус ужимают до жанров: «любит боевики, не любит мелодрамы». Летает на нас с анонсами Netflix «because you watched Fast & Furious» — и промахивается.

Промахи не потому, что ML плохой. Потому что жанр — это на уровне каталога, а не вкуса. Два фильма одного жанра могут быть полярно разными для конкретного человека. «Бегущий по лезвию 2049» и «Трансформеры» — оба «фантастика+боевик». Зайти к любителю «Бегущего» с «Трансформерами» = обидеть.

Что я сделал в Cinema DNA

Разложил вкус на 24 оси — не жанровых, а структурных. Примеры по категориям:

Темп и композиция

  • Темп повествования

  • Терпимость к длинным сценам

  • Сложность нарратива (линейность ↔ фрагментированность)

Эмоциональная природа

  • Эмоциональная плотность

  • Нужен ли катарсис

  • Насколько тяжёлые темы готов смотреть

Форма против содержания

  • Важность визуального стиля

  • Толерантность к авторскому почерку

  • Играет ли фильм с формой

Контекст просмотра

  • Оптимальная длина

  • В компании / одному

  • Настроение

Каждая ось — ползунок. На выходе теста — точка в 24-мерном пространстве.

Почему комбинация метрик, а не только косинус

Первое, что приходит в голову для поиска «похожих» пользователей — косинусная близость: углы между векторами. Работает, но даёт контринтуитивные результаты в граничных случаях.

Простой пример: человек А ответил на все вопросы «50/100» (нейтрально, не задумываясь), а человек Б ответил честно, с разбросом. Косинус между их векторами может выйти 0.95+ (по направлению близки), но на практике это два совершенно разных человека — один не определился, другой имеет чёткий профиль.

Поэтому в расчёте совместимости участвует не только косинус, но и мера расстояния (например, евклидова, нормализованная). Одно говорит о направлении вектора, другое — о «громкости» профиля. Взвешенная комбинация этих двух даёт адекватные результаты:

  • Два случайных юзера — 35-55%

  • Юзеры с пересечением любимых фильмов — 80-95%

  • Полярные профили — ниже 20%

Конкретные веса и нормализацию тюнил эмпирически. Это не открытие, просто напоминание: когда кажется, что одной метрики достаточно — скорее всего, её недостаточно.

Масштабирование

Пока юзеров немного, поиск похожих работает полным перебором O(N). На сотнях тысяч переведу на pgvector с ANN-индексом (ivfflat для старта, hnsw если понадобится качество). Это известная задача, решение найдено, просто до этой точки ещё ехать.


3. Синхронный просмотр: пять вещей, на которых я споткнулся с WebRTC

Фича: «смотрим фильм вместе, когда в разных городах». Два человека заходят в комнату, загружают свою копию фильма, смотрят синхронно, болтают голосом. Звучит как «ну WebRTC + play/pause-события, 2 дня работы». В реальности — три недели.

Пять неожиданных проблем, с которыми столкнулся:

3.1. NAT traversal не решается «из коробки»

Голый peer-to-peer без TURN-сервера не пробивает NAT у 40% домашних роутеров. Я наивно начинал с STUN-only и нескольких итераций «работает у меня, у брата не работает». Причина — симметричный NAT, классика мобильных операторов и некоторых провайдеров.

Решение — свой TURN-сервер. Opensource реализации есть, разворачиваются за вечер. Без TURN — не берите за фичу P2P-видео «для всех пользователей». Только для своих, у кого IPv6 или нормальный NAT.

3.2. captureStream() на  — не волшебная палочка

Да, из DOM-элемента <video> можно получить MediaStream и отправить по WebRTC. Работает. Но:

  • DRM-контент не отдаётся. Вы не сможете стримить Netflix-видео из тега <video> — там поток через EME, и captureStream вернёт либо пустоту, либо чёрный кадр.

  • Браузеры отдают разные частоты кадров. Chrome честно стримит 30-60fps, Firefox иногда ограничивает. Safari до недавнего времени вообще не поддерживал captureStream для HLS-видео.

  • Аудиодорожки в некоторых форматах (многоканальные Dolby) захватываются криво или не целиком.

Урок: всегда тестируйте на 3-4 браузерах с реальными форматами контента, не только с .mp4 + h264 + aac.

3.3. Autoplay policies на гостевой стороне

Когда хост играет видео, гостю приходит поток через WebRTC. Вы делаете guestVideo.srcObject = stream и думаете «всё, готово». Видео не стартует.

Почему: современные браузеры блокируют автоплей видео со звуком без пользовательского действия. Даже если поток пришёл вживую. Решение — гостю нужно самому нажать Play (или muted=true на старте, потом unmute по клику).

Это звучит банально, но я потратил полдня отладки, пока не вспомнил.

3.4. Голос и видео — лучше два отдельных peer connection

Соблазн: один peer connection, в нём и видео фильма, и голоса. Меньше overhead, проще код.

Реальность: юзеры постоянно хотят мьютить звук фильма, чтобы слышать собеседника. С одним peer это превращается в manage отдельных audio track enable/disable, состояния синхронизировать между участниками, и т.д.

Два независимых peer (один — видео фильма с видео+аудио, второй — только голос-peer) — кардинально упрощают UX-логику. Да, немного больше нагрузки на сеть. Но вы получаете чистое разделение «это фильм — могу заглушить» и «это собеседник — не могу потерять».

3.5. Синхронизация play/pause — это не просто «посылай событие»

Хост жмёт паузу в 15:42:18.123. Событие летит через WebSocket на сервер. Сервер рассылает гостям. Гость получает его в 15:42:18.456.

Если у гостя в момент прихода события currentTime = 15:42:18.410 (потому что у него видео шло своим ходом с минимальным дрейфом), а вы просто делаете guestVideo.pause() — они будут стоять на разных кадрах.

Нужно не просто паузить, а выравнивать currentTime по хосту с компенсацией latency. Плюс периодический re-sync — каждые 10 секунд хост шлёт свой currentTime, гости, если ушли на >300ms, подтягиваются.

Мелочь, но именно эти мелочи отделяют «работает прикольно» от «работает и ты забываешь, что фильм показывается через сеть».


4. SEO-грабли на Next.js 14: ISR и 11-тысячный sitemap

Если у вас на сайте больше 1000 страниц контента, которые попадают в sitemap — внимание.

Next.js App Router позволяет сделать sitemap.xml как route в app/sitemap.ts. Вы возвращаете массив URL, Next строит XML. Красиво.

Подводный камень: этот route работает через ISR (incremental static regeneration). Если не поставить export const revalidate = <big number>, то каждый запрос sitemap заставляет пересобирать весь список URL. А чтобы собрать URL, нужно сходить в БД за всеми 11 000 фильмами, 2000 персонами, 300 коллекциями. Каждый запрос.

Я сначала поставил revalidate = 1800 (30 минут), думая «sitemap же не критично свежий, 30 мин хватит». Получил ситуацию: каждые 30 минут мой API генерит 11k-URL ответ на запрос sitemap от GoogleBot, YandexBot, каждого curl от мониторинга и т.д.

Поднял до 86400 (24 часа). Стало нормально. Крутить выше — не надо, Google может решить что ваш sitemap stale.

Ещё подробность: структурированные данные

JSON-LD с @type: Movie и @type: Person на страницах фильмов/людей — сильно улучшает показы в rich results Google. Не поленитесь. Правильные schema.org-поля (actor, director, contentRating, ratingValue) Google использует в карточках поиска. Это +15-30% CTR на страницу фильма по моим наблюдениям.


5. IndexNow — API, который реально работает (и его почему-то мало используют)

IndexNow — протокол, который поддерживают Bing, Yandex, Seznam, Naver и через который вы можете пинговать поисковики при публикации новой страницы. Индексация — за минуты вместо недель.

Протокол простой до идиотизма:

  1. Генерируете случайный ключ

  2. Кладёте файл {ключ}.txt в корень сайта

  3. Шлёте POST на https://api.indexnow.org/indexnow с JSON {host, key, urlList}

Всё. На это у меня ушёл час, включая тесты.

Google IndexNow не поддерживает (у них свой API через Search Console, ручной). Но Bing + Yandex — это уже ~15% российского поискового трафика + международный. И через Bing по цепочке идёт индексация в ChatGPT, DuckDuckGo, Copilot — для LLM-видимости это значимо.

Странно, что об IndexNow так мало пишут. Возможно потому, что Google не в клубе, и русские технические блоги этот протокол часто игнорируют. Зря.


Что в итоге

Пять историй, пять граней одной и той же мысли: проект, который снаружи выглядит «стандартный CRUD + REST», внутри содержит десятки нетривиальных технических решений, про которые в учебниках не написано.

Если интересно посмотреть результат — VibeMuvik открыт, пользование бесплатное, регистрация — минута. Буду рад багрепортам, идеям и критике архитектурных решений.

Хочу написать ещё — есть темы:

  • Как устроены батлы и дебаты (голосование с аргументами, почему это не просто «опрос»)

  • Производительность PostgreSQL: партициирование по времени, материализованные представления для городской статистики, когда CREATE INDEX CONCURRENTLY спасает, а когда — нет

  • Анализ ошибок авторизации и 2FA: что я узнал, читая свой audit log

Если хоть одна из этих тем интересна — пишите в комментариях, какую развернуть следующей.

Спасибо за чтение.