Будни разработчика
14.6K subscribers
1.18K photos
337 videos
7 files
2.02K links
Блог Lead JS-разработчика из Хельсинки
Автор: @bekharsky

По рекламе: https://telega.in/channels/htmlshit/card?r=GLOiHluU или https://yangx.top/it_adv

Чат: https://yangx.top/htmlshitchat

№5001017849, https://www.gosuslugi.ru/snet/679b74f8dad2d930d2eaa978
加入频道
#фишка дня

Надоело читать это: «To push the current branch and set the remote as upstream, use
git push --set-upstream origin fix/bug-1359»?

А всё потому что git на сервере не знает ничего о ветках на вашей машине. Нужно явно указать: «Хочу создать ветку на удаленном сервере с указанным названием и связать её с локальной». Названия даже могут отличаться, но чаще всего — совпадают. Ну, у меня, во всяком случае.

Поэтому, глядите чо: https://git-scm.com/docs/git-config#Documentation/git-config.txt-pushautoSetupRemote

Ну или просто взгляните на КДПВ.

#git #remote
8👍4👎2👏1
#крутое дня

Не то чтоб я собирался всё же сходу показывать дизайн будущего пульта целиком, думал, буду сразу стили на Flutter набрасывать и выкладывать в песочницу, но пара подписчиков захотела это ещё и на HTML/CSS отверстать. Да, @mazya? :)

Не могу сказать, что я прям принимаю вызов, процесс у меня будет двигаться медленно. Но чо бы и нет, мне эти стили пригодятся 😊

В общем, смотрим, комментируем: https://www.figma.com/file/ZEOa8mgVHabB3pgiEuwCm4/mi-tv-remote-app-control-(Copy)

#flutter #figma #remote
🔥12👍42
#заметка дня

Щас будет линкдамп. Потому что ну надо мне структурировать информацию в голове.

Собственно, как вы в курсе, я пытаюсь писать приложение на Flutter для управления своим телевизором Samsung. Довольно старая модель, года 2018, но на TIzen OS, Smart TV.

Почему я это делаю? Дочь грызёт пульт и рано или поздно она его сгрызёт. У меня уже запасной есть, но так неинтересно.

Вторая причина — это просто интересная задача, которую можно решить несколькими способами, а само приложение легко расширять в сторону поддержки DLNA (шарить экран или медиа с телефона, короче).

Итак, как же можно управлять современным Smart TV?

1. ИК-пульт. Не вариант в моём случае, потому что не у всех телефонов он есть. У моего второго — есть, впрочем. стандартное приложение отлично работает.

2. Bluetooth-пульт, из поставки ТВ или от братьев-китайцев. Протокол обмена ключами мне сходу нагуглить не удалось, но что-то мне подсказывает, что это в любом случае буквально обычная клавиатура.

3. TCP/IP, по сети. А конкретно — вебсокеты. Устанавливаешь соединение, получаешь токен — отправляешь жисончик. Протокол в доках я не нашёл, но есть множество реализаций:
https://github.com/Toxblh/samsung-tv-control
https://github.com/ollo69/ha-samsungtv-smart
https://github.com/dahuby/iobroker.samsung_tizen
https://github.com/stephensli/samsung-tv-api

Понятное дело, что тут проблема в том, что если телевизор ушёл в глубокий спящий режим, сетевые функции будут отключены. И это ещё предстоит решать. Ходят слухи, что у Samsung есть специальный API для этого, т. е. в сон уходит не до конца. Ну или можно отключить энергосбережение.

Можете поставить себе одну из реализаций и побаловаться с компа, если у вас Samsung.

4. Ну и специальный API с названием Samsung SmartThings. Требуют получения токена через сервера Samsung, используя их же учётку. Официальное приложение его и использует. Ужасно медленно работает, впрочем :( И всё так же неясно с состоянием спящего режима.

Реализация тоже имеется:
https://github.com/pegatron89/smartthingstv

Я пока буду делать на вебсокетах, а дальше посмотрим, куда меня это всё заведёт. Возможно, следующий шаг будет попытка в DLNA и шаринг экрана, а возможно, пойду изучать, как работает Bluetooth.

#flutter #samsung #remote
8👍7
#заметка дня

Вы думали, я забыл про своё приложение-пульт для телевизора?

Ну вот ещё, нет, конечно. Месяц выдался тяжёлым, но UI давно готов и пришла пора сетевой части.

Начнём с простого. Как вообще найти телевизор в локальной сети? Как быстро узнать его IP, список сервисов, которые телевизор предоставляет, идентификаторы и методы подписи?

На помощь придут протоколы SSDP (Simple Service Discovery Protocol) и UPnP (Universal Plug-n-Play). Вот с SSDP сегодня и начнём.

SSDP предназначен для быстрого поиска устройств и предоставляемых ими протоколов управления по сети. Чаще всего при обнаружении устройства можно получить ссылку на XML-файл с описанием нужного API.

Каждое устройство, поддерживающее SSDP, держит открытым порт 1900 и откликается на особым образом составленный запрос.

Всё, что нам требуется, это отправить в эфир широковещательное сообщение, собрать ответы устройств и найти среди них нужный нам сервис.

Вот пример кода для Node.js: https://gist.github.com/bekharsky/3e6fd2dd265b89817d5f08ff21f3f544

Я его честно взял из реализации подобного сервиса для React Native, поскольку нашей целью не является хакинг всего протокола телевизора.

Если вы возьмёте пример и бездумно запустите сразу — вряд ли что получите, поисковая строка там заточена под телевизоры Samsung. Но вы можете послать запрос ssdp:all, который выдаст вам список всех устройств и сервисов в вашей сети. Попробуйте, это забавно. Откроете для себя много нового :) Например, что ваш роутер умнее, чем кажется.

Собственно, меня, как вы уже поняли если открыли код, волнует сервис RemoteControlReceiver. О том, что это такое и как с ним поступить — в следующих постах.

А моя задача пока переписать JS-код на Dart под Flutter и вывести список телевизоров в настройках.

До связи, котаны.

#tv #remote #protocol #ssdp
👍25🔥41
#фишка дня

Надоело читать это: «To push the current branch and set the remote as upstream, use
git push --set-upstream origin fix/bug-1359»?

А всё потому что git на сервере не знает ничего о ветках на вашей машине. Нужно явно указать: «Хочу создать ветку на удаленном сервере с указанным названием и связать её с локальной». Названия даже могут отличаться, но чаще всего — совпадают. Ну, у меня, во всяком случае.

Поэтому, глядите чо: https://git-scm.com/docs/git-config#Documentation/git-config.txt-pushautoSetupRemote

Ну или просто взгляните на КДПВ.

Завезли с версии 2.37.0, так что проверьте сначала. Спасибо за уточнение подписчику :)

#git #remote
👍6🔥2
#фишка дня

Надоело читать это: «To push the current branch and set the remote as upstream, use
git push --set-upstream origin fix/bug-1359»?

А всё потому что git на сервере не знает ничего о ветках на вашей машине. Нужно явно указать: «Хочу создать ветку на удаленном сервере с указанным названием и связать её с локальной». Названия даже могут отличаться, но чаще всего — совпадают. Ну, у меня, во всяком случае.

Поэтому, глядите чо: https://git-scm.com/docs/git-config#Documentation/git-config.txt-pushautoSetupRemote

Ну или просто взгляните на КДПВ.

#git #remote
👍15
#заметка дня

Вы что, реально думали, что я забросил свой проект пульта для телевизора Samsung на Flutter?

Ну, так-то, да... забросил. Но вернулся на днях!

Напомню, что тогда дочка грызла основной пульт и я захотел сделать альтернативу, заодно изучив Flutter. Кинул клич в канале в поиске дизайнеров, быстренько сверстал получившееся на Dart.

Итак, я остановился на том, что научился посылать широковещательное сообщение в локальную сеть и собирать отклики. Следующим шагом стало бы получение информации о телевизоре: IP-адрес, название модели и телевизора, уникальный id на всякий случай. И здесь имеются два варианта:

1. Широковещательный поиск по SSDP-запросу (если у вас дома есть телевизор Samsung, можете попробовать код из этого поста) urn:samsung.com:device:RemoteControlReceiver:1 отдаёт некий интересный адрес http://192.168.3.6:7676/rcr/. Несложно догадаться, что rcr это receiver, приёмник. И там имеется XML со всей необходимой информацией, включая поддердживаемые протоколы. Но, честно, покажите мне человека, который любит разгребать XML? Да и пакет отдельный надо ставить, давно уже формат не в фаворе... Но если интересно, как это делают на Dart — могу рассказать.

Но за этим API толком больше ничего не стоит, документация Samsung прям скудная, надо искать по крупицам. Но есть второй вариант!

2. На телевизорах с 2016 года имеется web-API! http://192.168.3.6:8001/api/v2/ (не спрашивайте, куда делся v1).

У меня ушёл час чтобы понять, что в конце слэш обязателен. Впрочем, ничего нового.

И вот GET-запрос на этот адрес отдаёт, кто бы мог подумать, JSON. А поддержка JSON в Dart нативная.

Запихиваем ответ в ChatGPT, просим создать класс и фабрику из JSON. Вы серьёзно думали, что я определения типов в 2023 году буду сам писать? Нейронка отлично справилась, создав на каждый вложенный объект по классу, адекватно их назвала, преобразовала булевы строки в нормальные значения и вообще умница.

Но, как я уже сказал, документация Samsung на всю эту тему максимально ужасная. Нет ни слова насчёт того, как же запустить, например, приложение или получить их список.

Благо, на Reddit есть целые сообщества, которые ищут такую информацию. Вот, например, один такой пост: https://www.reddit.com/r/homeassistant/comments/fxddeh/controlling_a_samsung_tv/

Итого, чтобы запустить, например, Netflix мне нужно или совершить пустой POST-запрос на http://192.168.1.145:8001/ws/apps/Netflix или пустой POST-запрос на http://192.168.3.6:8001/api/v2/applications/11101200001

А GET-запросы просто выдадут состояния этих приложений. Их перебором можно узнать, что на телевизоре установлено. Самое смешное, опять же, то XML, то JSON соответственно. А ответ на POST в первом случае — 200 и URL, а во втором — 200 и true 🤡 Так что ваши API не настолько и плохи, как вы думаете.

Как ищутся все эти ID типа 11101200001? Удивительное дело, но в вашем аккаунте в Samsung есть страничка с устройствами, которая больше напоминает домашнюю страницу роутера. И там показано, какой вид активности сейчас на телевизоре происходит. Ну а конкретно адреса API ищутся внутри скачиваемого SDK. Документации (хором) нет.

Кажется, я и так уже достаточно много написал. Можем с вами договориться, например, что я буду писать по одному посту про Flutter в неделю. Таким образом у меня будет мотивация что-то делать и посты могут стать более приземлёнными. Отпишитесь в комментариях.

Вариантов постов много: как работает навигация во Flutter-приложениях, как сделать аналог BottomSheet из iOS, как совершить запрос и разобрать XML/JSON, как верстать UI... Задавайте ваши ответы.

#flutter #remote
🔥235💩2👍1
#заметка дня

Мобильная разработка, как ни крути, выходит ближе к железу и понимать в ней нужно чуть больше.

Да, это опять я со своим нытьём про Dart и Flutter, которое можно найти по тегу #remote. И сегодня мы поговорим о сокетах. Конкретно — WebSockets.

Вы наверняка должны были задуматься, откуда в вебсокетах приставка "веб". И ответ на самом деле простой: потому что они реализованы поверх протокола HTTP, для чего используется, очевидно, некий HTTP-клиент. В браузерах свой, в Node.js свой, в мобильных фреймворках свой.

Что из этого следует, например? Ну, что сертификаты наруливаются согласно спецификации HTTPS. И тут начинается самое интересное.

Нода и браузеры вам прощают вообще все. Предполагается, что веб-разработчику вообще не надо толком думать, а что там внутри.

Вот у телевизоров Samsung сертификат самоподписанный. Вебсокеты по протоколу wss (websocket secure) работать с таким откажутся, но всё, что надо сделать в JS — передать опцию allowUnauthorized. Всё, полетели жисоны.

Что надо сделать в том же Dart/Flutter?

Перегрузить (заменить, override) библиотечный HTTP-клиент!

Вот так:

class SamsungHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext? context) {
return super.createHttpClient(context)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
}
}


И дальше есть выбор, делать это на глобальном уровне, или передать в конструктор. В моём случае — глобально, поскольку API тоже спрятан за самоподписанным сертификатом:

HttpOverrides.global = SamsungHttpOverrides();

И такое на каждом шагу. Нельзя просто так взять и...

Может, поэтому мобильным разработчикам зачастую больше платят? 🤔

#flutter #remote #dart #websocket
😱8
#инструмент дня

Если вам этим утром было так же нечего делать, как и мне, вы могли поуправлять своим ноутбуком с электронной читалки!

Кроме шуток :) Оказывается, есть такой инструмент удалённого доступа: noVNC. Это реализация VNC-клиента для браузера.

И в Windows, и в MacOS и уж тем более в Linux есть средства удалённого доступа, поддерживающие этот протокол. На примере MacOS он называется Remote Management.

Ещё не так давно он не поддерживал VNC, но уже некоторое время всё отлично работает.

Правда, конфигурация его контринтуитивна. По-умолчанию запрещено вообще всё, но система просто говорит тебе, что пароль неверен.

Итак, в чём же была основная сложность?

А в том, что VNC-поток должен шифроваться. И если в обычных браузерах есть Web Crypto API, что позволяет ходить на сервер без HTTPS, то вот браузер в Kindle, пусть и был недавно прокачан (и теперь похож на настоящий), эту самую криптографию не поддерживает.

А мне почему-то очень было интересно посмотреть, как это — дополнительный E-ink экран.

Пришлось генерировать сертификат самостоятельно, на эту мысль меня навёл Роберт Андерберг, показавший саму идею в Твитере:

openssl req -x509 -nodes -newkey rsa:2048 -keyout novnc.pem -out novnc.pem -days 365


...ответив по пути на кучу бестолковых вопросов «ты кто такой»...

Ну и запускаем сервер нашего клиента:

./utils/novnc_proxy --vnc localhost:5900 --ssl-only --cert novnc.pem


И всё проходит прекрасно. К сожалению, на Kindle не поддерживается поворот экрана в браузере. Даже ковыряние в SQLite-базе настроек не помогло...

Но! Можно выключить масштабирование и использовать скроллбары. Или подключить Kindle к Raspberry Pi c медиатекой или умным домом, там разрешение неважно.

В общем, меня это ковыряние очень позабавило. Надо попробовать протащить в noVNC поворот холста, и будет совсем хорошо.

Как часто на вас находят подобные эксперименты, котаны?

#vnc #remote #eink
👍71🤩1
#заметка дня

Я подумал, раз уж выкатил выше видео с пультом на Flutter, почему бы не рассказать о процессе создания некоторых элементов оттуда.

Чтобы не напрягать всех лишний раз, примеры будут на JavaScript и Canvas. Ну, вдруг кому-то пригодится нечто похожее.

Да и выглядит такой код чуток попроще, чем на CustomPainter во Flutter (хотя по факту-то тоже просто холст).

Итак, для пульта я решил сделать D-pad (он же джойстик или directional pad). На моём пульте он состоит из четырех кнопок по кольцу и одной центральной.

Чаще всего, d-pad-ом называют всем известную крестовину, которая не всегда обладает отдельным центром.

Проще всего достичь такого эффекта, разделив весь круг на четыре сектора. Каждый сектор — это дуга, занимающая угол
90°. Чтобы они визуально отделялись, добавляем контуры между дугами, а поверх всего накладываем центральный круг — он становится кнопкой.

Для корректного размещения делим полный угол 360° на количество дуг — четыре — и задаём начальный угол сдвига -45°. Он нужен, чтобы первый сектор смотрел строго вверх. А то а чо он.

В результате получаем симметричный D-pad, где каждый сегмент и центр выделены визуально: https://codepen.io/alinaki/pen/oNKmxNe?editors=0010

Ладно, ладно. Это на бумаге кажется, что всё действительно просто. На деле же я жёстко тупил.

1. Я не очень понимал, как обрабатывать клики, поэтому думал в сторону пяти отдельных элементов. А значит, об уравнении арки.
2. Потом я никак не мог врубиться, как же мне сделать отступы одинаковой ширины. Мысль, что это просто контур, граница, вообще не сразу мне в голову пришла.
3. Вроде, в школе учат, как определять, попала ли точка в контур, заданный неким уравнением, но вспоминаешь это тоже далеко не сразу.

В следующих постах расскажу, как решил уравнение в пункте 3, добавив подсветку нужного сегмента при нажатии.

Не переключайтесь, котаны!

#canvas #paint #remote
👍141
This media is not supported in your browser
VIEW IN TELEGRAM
#заметка дня

Ну что, будем долбиться в холст и аналитическую геометрию?

Продолжаем разработку D-pad'а aka крестовины. И сегодня на повестке дня — определение попадания координат клика в нужный нам сектор. Ну и подсветка сектора заодно.

В прошлый раз мы нарисовали крестовину (я честно не знаю, как d-pad ещё называть), а сегодня пришла пора по нему покликать. Ссылка для тех, кто забыл: https://yangx.top/htmlshit/3279

Как я уже писал, основным откровением стало понимание, что мне не нужно пять разных фигур, описывающих виджеты. В данном случае мне повезло и граница между элементами не должна была быть прозрачной. Иначе, пришлось бы решать иными методами.

Заодно мы получили бесконечно возможное число секторов.

Математику отрисовки мы обсудили в прошлом посте. Итак, что же делаем по клику?

Для зануд: мы тут в декартовых координатах работаем.

1️⃣Определяем, не ткнули ли мы в центральную кнопку.

Это довольно просто: уравнение окружности у нас (х – х0)² + (y – y0)² = R², где x0 и y0 — координаты центра, а R, соответственно, радиус.

Ну и получается, что пока левая часть меньше правой, мы ткнули в центр. Тут всё просто.

2️⃣ Если попали не в центр, то уже однозначно, в какой-то из секторов.

Здесь задача сводится, опять же, к двум вещам: провести луч из центра окружности в точку, чтобы определить его угол относительно оси абсцисс (горизонтали) и простым сравнением определить, в какой же из секторов попали.

Не забыв про то, что мы повернули окружность на 45° влево, чтобы задать верное направление крестовины.

И для этого существует функция Math.atan2 (Википедия на английском или на русском вот тут): арктангенс для заданных координат, в радианах.

Радианы — просто всё умножается на π.

Ну и всё, перерисовали с учётом нового цвета.

Как всегда, демка на CodePen: https://codepen.io/alinaki/pen/Yzmoyyr?editors=0010

Что делаем в следующий раз, анимируем?

#canvas #javascript #remote
Please open Telegram to view this post
VIEW IN TELEGRAM
👍54
#фишка дня

Надоело читать это: «To push the current branch and set the remote as upstream, use
git push --set-upstream origin fix/bug-1359»?

А всё потому что git на сервере не знает ничего о ветках на вашей машине. Нужно явно указать: «Хочу создать ветку на удаленном сервере с указанным названием и связать её с локальной». Названия даже могут отличаться, но чаще всего — совпадают. Ну, у меня, во всяком случае.

Поэтому, глядите чо: https://git-scm.com/docs/git-config#Documentation/git-config.txt-pushautoSetupRemote

Ну или просто взгляните на КДПВ.

Завезли с версии 2.37.0, так что проверьте сначала. Спасибо за уточнение подписчику :)

#git #remote #бородач
12👍3
#инструмент дня

Когда вы последний раз дизассемблировали React Native приложение?

А я вчера.

Вот так вот решил закончить череду постов этото года лёгким хардкором. На полшишечки.


Давайте по порядку. Как вы все, должно быть, помните, я уже довольно давно пишу свой пульт для телевизора Samsung на Flutter.

Почему Samsung? Ну потому что он дома стоит.

И да, хоть это всё и происходит крайне медленно, минимальный набор функций имеется. Я постоянно им пользуюсь, когда нужно что-то переключить ребёнку или мне, а настоящий пульт искать лень.

Но у пары конкурентных приложений были функции, которые кажутся весьма уместными. И речь даже не о DLNA-стриминге фотографий и видео с телефона на телевизор, это-то как раз понятно и хорошо документированно.

А вот, например, такая простая штука, как получение списка всех приложений. Ну или, например, иные методы поиска телевизоров. В моём-то приложении список приложений и иконок к ним тупо захардкожен.

И не сказать, что я их не знаю — в начале разработки провёл огромную работу по поиску нужных API, но руки всё равно чесались.

И тут очень к месту пришлась возможность использования приложений для iPhone на макбуках с м-процессорами. Запускаешь приложение параллельно с Wireshark и мониторишь запросы. Очень удобно (на иллюстрации).

Но я не учёл такой простой вещи, как шифрование.

Да-да, практически все вебсокет-запросы оказались зашифрованы протоколом TLS 1.2 (wss://).

Кто бы мог подумать, а. Ведь я сам обходил это в своей имплементации: сертификаты на телевизорах свои, и, зачастую, протухшие давно.

Пусть это и не самый надёжный в 2024 году протокол, но всё же опыта расшифровки у меня нет. На самом-то деле в телевизорах есть и несекьюрные API, позволяющие даже запустить приложение, но они не всегда доступны без dev-режима. Да и нужного среди них не оказалось. А я так надеялся, что есть что-то простое.

Впрочем, строки поиска SSDP я себе выписал. LG, ты следующий.

Итак, но приложение же вот оно, лежит в каталоге Applications. А это что значит?

А это значит, можно посмотреть содержимое пакета! Да, если вы не знали, приложения в macOS и iOS (и на Android) это, по факту, просто архив.

Распаковав, я обнаружил подозрительный каталог node_modules и нечто под названием main.jsbundle.

Надо же, самый крутой конкурент оказался ни чем иным, как приложением на React Native!

А что я с ним делал дальше — напишу через несколько часов, иначе как-то длинно получается. Оставайтесь на связи :)

#remote #flutter #reactnative
👍194🤩4
#инструмент дня

Типичная айтишная история: кто-то на митинге шарит сверхширокий экран. Или вроде бы шарит окно, но забывается и растягивает его до невообразимого размера.

А коллеги с ноутбуками и телефонами страдают! Всё мелко, картинка сыпется.

Конечно, можно шарить с ноутбука, но я могу понять неудобство.

Есть сумасшедшие, кто с десктопа вообще сидит!

Поэтому, предлагаю решение! Виртуальный монитор, буквально.

Для macOS, например, это будет DeskPad: https://github.com/Stengo/DeskPad

Как работает? Создаёт окошко, которое будет работать как виртуальный монитор заранее заданного разрешения. Туда просто перетаскивается нужное приложение и шарится.

Для других ОС наверняка есть аналогичные решения. Если кто-то знает — накидайте в комментариях, я попозже и сам принесу.

Пошарил — и никаких проблем, работай как работается. И коллегам приятно.

#macos #display #remote
👍20🫡21🤡1