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

推荐订阅源

云风的 BLOG
云风的 BLOG
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
IT之家
IT之家
Recent Announcements
Recent Announcements
B
Blog
D
Docker
V
V2EX
GbyAI
GbyAI
L
LangChain Blog
博客园 - Franky
U
Unit 42
T
The Blog of Author Tim Ferriss
A
About on SuperTechFans
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Vercel News
Vercel News
博客园_首页
D
DataBreaches.Net
人人都是产品经理
人人都是产品经理
Y
Y Combinator Blog
量子位
Blog — PlanetScale
Blog — PlanetScale
罗磊的独立博客

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

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет 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 за минуты Опыт разработчика как экономика внимания
Ch4IR: мой 4х канальный видеорекордер на Android который ...
JDJ · 2026-04-24 · via Все публикации подряд на Хабре

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

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

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

Кейс

В далёком 2018г. я целых 24 часа работал на какой то фабрике в Подмосковье. Делающей салаты и другие полуфабрикаты. В каком то отделе, то ли контроля, то ли безопасности. В общем надо было смотреть в камеры видео наблюдения. Ну и вроде всё, сутки через трое. Хотел уйти с 5/2 на 1/3. Но я не согласился, слишком тяжело, слишком. Через 6 лет после тех суток я начну изучать Java и пробовать писать приложения на андроид. Третьим моим пет приложением будет Ch4IR.

Написанный на библиотеке LibVLC и в память о несложивщейся карьере в сесурити.

Он был настоящим RTSP рекордером: отображал 4 потока, писал 4 потока на флешку или usb диск, нарезал куски видео по 60 минут и автоматически удалял записи старше указанной даты. Он умел воспроизводить записи и перематывать их. Но всё изменилось, перед самой публикацией.

dota2, теннис, кино и парковка.

dota2, теннис, кино и парковка.

Мне просто нравилось делать приложение, я не думал и не знал ни о каких лицензиях сторонних библиотек. Как оказалось библиотека LibVLC имеет лицензию LGPL требующую либо открывать код, либо подгружать библиотеку динамически, давая пользователю возможность её заменять. Динамическая подгрузка это что то сложное и не безопасное, а открыть код, как? Как можно открыть такой крутой, сложный код который принесёт мне миллионы, зачем? Вы пошутили? Поэтому я перешёл на встроенный в андроид ExoPlayer с лицензией Apache 2.0. Который не умеет одновременно, и показывать, и писать видео с камеры видеонаблюдения.

Большая часть функционала была потеряна, пришлось придумывает новые функции. Почему то не сразу, но всё таки пришла мысль добавить к воспроизведению RTSP, поддержку m3u8 ссылок для просмотра IPTV. Ну скучно же смотреть весь день на парковку или склад. В самом приложении никакого контента нет, оно просто проигрыватель. Но ссылки на бесплатные каналы можно поискать в сети. И в приложении даже есть один линк на такой репозиторий GitHub. Можно загружать их пачками из файлов txt или m3u.

Добавление плейлистов из файла m3u

Добавление плейлистов из файла m3u

Появление IPTV здорово помогло отладить кнопку Mute и цвет рамок на экране, так как камер с микрофоном у меня не было. Но у кого-то они точно есть. Цветов у рамок экранов, после удаления возможности записи, осталось всего три:

  • белый - stop

  • зеленый - play

  • жёлтый - play + mute

  • красный - record

И это всё ещё был просто онлайн медиапроигрыватель, хоть и в несколько окон. Надо было что то ещё. Очень хотелось добавить YouTube. Но там обязательная авторизация и плюс он скорее про ролики, а не про онлайн стримы. А вот Twitch, Twitch да, он про онлайн, и позволяет смотреть стримы без регистрации, хоть и с рекламными вставками. И делается это довольно просто. Нужна просто одна html страница на любом домене и всё.

Скрытый текст
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Ch4IR</title>
    <script src="https://player.twitch.tv/js/embed/v1.js"></script>
    <style>
        html, body {
          margin: 0;
          padding: 0;
          height: 100%;
          overflow: hidden;
          background-color: black;
        }
        #twitch-embed {
          width: 100vw;
          height: 100vh;
        }
    </style>
</head>
<body>
<div id="twitch-embed"></div>
<script>
    const urlParams = new URLSearchParams(window.location.search);
    const channelName = urlParams.get('channel');

    if (!channelName) {
      document.body.innerHTML = "<p style='color: white; text-align: center;'>Missing channel</p>";
    } else {
      const player = new Twitch.Player("twitch-embed", {
        width: "100%",
        height: "100%",
        channel: channelName,
        autoplay: true,
        parent: ["тут ваш домен"]
      });
    }
</script>
</body>
</html>

и стримы будут работать по ссылкам

https://ваш.домен/?channel=название_канала

Но ExoPlayer не умеет показывать Twitch, правильно, не умеет. Но умеет гугловский WebView. И если у вас нет сервисов Google на устройстве, то стримы твича приложение вам не покажет. Ошибки воспроизведения всех типов ссылок, тоже показывает WebView. Он вообще молодец. Поскольку мой СТУЛЬчик родом из рекордеров, он умеет делать Fullcreen, Zoom и Pan. И даже мышкой. Да мышкой тоже можно управлять. А вот пультом нет, казалось бы, а как же Android TV? Приложение показывающее в 4 экрана IPTV и не поддерживает телик, серьёзно? Ага, серьёзно. У меня нет Android TV, а если и появится, я 8 раз подумаю, стоит ли возиться с ним. Там всё управление завязано на пульт, который захватывает фокус элементов. А у меня одно меню на восемь экранов, семь из которых могут быть скрыты. Хотя это класный вызов, но... я восемь раз подумаю. Тем более что usb или air мышка стоят не дорого, а с ними работает и так.

И так, в приложении на самом деле 8 экранов (4 ExoPlayer + 4 WebView). Они просто появляются или скрываются в зависимости от типа выбранной для отображения ссылки. Меню вызывается при удержании пальца на любом экране. Но если присмотреться, то можно заметить что оно при просмотре IPTV вызывается быстрее, чем при просмотре Twitch. У твича есть свои элементы управления: запуск, остановка, изменение громкости, Mute. Чтоб управлять твичем через его собственные кнопки и не вызывать при этом моё меню, пришлось увеличить время удержания пальца для WebView.

И это было самое сложное, сложнее записи и удаления файлов. Это до сих пор самое сложное что приходит на память, из того что приходилось делать. Связать кнопку громкости твича с моей Mute. Твич отлично присылает события от своих кнопок в моё приложение через JavaScript Bridge. Но если ползунком убрать звук на твиче до 0, а потом нажать Mute. Твич отправит сообщение что звук включен, а громкость у этого звука будет равно 0. Потому что Mute на твиче восстанавливает предыдущее значение громкости, которое ползунком можно сдвинуть в 0. Хотя прошёл уже год, может что то и изменилось за это время у них. Проверил, исправили, а скорее подсмотрели у меня, и тоже выталкивают при анмуте громкость на 10%. Правильно я не хотел открывать код, ну всё таки подсмотрели.

Скрытый текст
private void setTwitchPlayerMute(boolean needMuted) {
        WebView webView = webViewRef != null ? webViewRef.get() : null;
        if (webView != null) {
            webView.evaluateJavascript(WINDOW_PLAYER_READY, value -> {
                //   Log.e(AppController.LOG_TAG, "Твичу пришла команда мут.анму, а твич реди статус = " + value);
                if (TRUE.equals(value)) {
                    if (needMuted) {
                        saveTwitchVolume();
                        webView.evaluateJavascript(TWITCH_MUTE_SCRIPT, null);
                        //   Log.e(AppController.LOG_TAG, "твичу пришла команда сделать мут" );
                    } else {
                        webView.evaluateJavascript(TWITCH_UNMUTE_SCRIPT, null);
                        //   Log.e(AppController.LOG_TAG, "твичу пришла команда сделать анмут" );
                        if (twitchVolume == 0f) {
                          // КАРАУЛ, УКРАЛИ :)
                            webView.evaluateJavascript(String.format(Locale.ENGLISH, TWITCH_SET_VOLUME_SCRIPT, 0.1f), null);
                            //  Log.e(AppController.LOG_TAG, "При анмуте громкость была 0: установлена 0.1" );
                        } else {
                            webView.evaluateJavascript(String.format(Locale.ENGLISH, TWITCH_SET_VOLUME_SCRIPT, twitchVolume), null);
                            // Log.e(AppController.LOG_TAG, "При анмуте установлена громкость" + twitchVolume);
                        }
                    }
                }
            });
        }
    }

Но это пустяки по сравнению с тем что получилось.

2026

Бывшие коллеги могут теперь смотреть спорт, ставки, мультики, танцующих и приседающих девочек на твиче, Джейсона Стэйтема. А ну и за складом тоже. А я нет. Я не смог смотреть за тем производством. Там в 2018 под предлогом важности работы, коллеги в столовую не ходили, а заказывали обед к столу, по звонку. Штрафовали на пятак мойщика за то что камера запотела. Подсовывали в паллет мусор чтоб выжить соперника упаковщика с любовного фронта. И всё это за одну смену стажёра. Я целые сутки просидел в этой копакабане, бесплатно. Тяжело, очень тяжело.

Скачать программу для работы.