Как стать автором
Поиск
Написать публикацию
Обновить

История соседа ч.3

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров1.3K

Наткнулся на интересную статью, где описываются некоторые возможности, которые можно реализовать на Ростелеком домофоне:

https://habr.com/ru/articles/791602/

Как вы, возможно, помните из моих прошлых статей, у нас есть чат «попутчики» где люди ищут себе попутчиков для передвижения в Москву из области и обратно. И вот что я заметил. Очень часто в часы пик, люди фоткают очереди, чтоб уже на подъезде к остановке понять, а нужно ли двигать сейчас домой, может переждать или может даже выбрать самокат вместо маршрутки или такси. По счастливому стечению обстоятельств один из подъездов, оборудованный Ростелеком домофоном захватывает камерой прямо остановку и место за ней, где обычно и скапливается очередь. А значит можно, опираясь на вышеуказанную статью, добавить в чат кнопку «посмотреть очередь», чем я собственно и занялся.

И так для доступа конкретно к стриму камеры необходимо получить stream_token. Чтоб это сделать нам необходим BEARER_TOCKEN, его мы храним статично. Как говорил автор статьи выше — BEARER_TOCKEN живет до 1 года, что вполне устраивает нас. Раз в год можно заходить с акаунта любого пользователя, брать оттуда токен и снова год не знать бед. Собственно метод:

def getStreamTocken() -> str:
    
    headers = {
        "Authorization": config.BEARERTOCKEN
    }
    response = requests.get(config.AUTHRTCAM,
                 headers=headers)
    data = response.json()
    return data['data']['device']['video_data']['stream_token']

Отлично. теперь у нас есть токен для доступа к видео потоку. Сам видео поток приходит в websocket фрагментами. К сожалению я не разобрался что это за фрагменты. Декодирование полученных байтов из WS приводили только к таким картинкам:

результат
результат

Поэтому я пошел другим путем. Видеопоток можно захватить (это также описано в статье, ссылку на которую я оставил выше) с помощью всем известного curl.

cURL — служебная программа командной строки, позволяющая взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.

И здесь нас встречает 2 ограничения.

Первое — сам видеопоток имеет название файла очень длинное, что не пропустить cURL при сохранении.

Второе — видеофаил идет бесконечным потоком. Его нужно как‑то остановить, например на 1 секунде скачивания. Иначе мы просто будем бесконечно загружать дорожку пока не кончится память.

Интересно что на моем Mac в терминале вполне работала такая реализация:

curl --max-filesice 5000000 -o newname https://url.com

Однако в Ubuntu, на которой и крутятся все мои боты, оно не работало и не ограничивала загрузку, иногда ограничивала но не сохраняла фаил, иногда ругалась что слишком длинное название(менял местами конфиг). После 2х дней поисков и разговоров тет-а-тет с GPT-4 я все же нашел рабочее решение:

curl https://url.com | head -c 400000 > live.mp4

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

head -c 400000 — ограничивает размер файла в битах. я для своих нужд путем пробы и ошибок выставил именно 400000, так как это ровно 1 секунда видео потока.

> live.mp4 — указывает на новое имя файла для сохранения.

Прикладываю код всего метода:

def getVideo(*args) -> None:
    
    message: Message = args[0]

    oldMessage = bot.send_message(message.chat.id,
                                  reply_to_message_id=message.id,
                                  text="Загрузка...")
    os.system("curl 'https:url&token=" +
              getStreamTocken() +
              "' | head -c 400000 > live.mp4")
    
    bot.edit_message_text(chat_id = oldMessage.chat.id,
                          message_id = oldMessage.id,
                          text="Еще чучуть...")
    
    videoMessage = bot.send_video_note(message.chat.id, open("live.mp4", "rb"),
                                       reply_to_message_id=message.id,
                                       protect_content=True)
    
    if videoMessage:
        bot.delete_message(oldMessage.chat.id, oldMessage.id)
        os.system("rm live.mp4")
        time.sleep(60)
        bot.delete_message(videoMessage.chat.id, videoMessage.id)
        bot.delete_message(message.chat.id, message.id)

принимает args, потому что я исторически использовал telebot, не асинхронный, поэтому для таких задач использую threads (потоки), так как функция потенциально может на пару секунд положить весь основной функционал.

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

Видео отображается как белый экран на скрине из-за настройки protect_content=True
Видео отображается как белый экран на скрине из-за настройки protect_content=True

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

Теги:
Хабы:
Всего голосов 1: ↑1 и ↓0+3
Комментарии14

Публикации

Ближайшие события