Как стать автором
Обновить

Jabber WebCam Bot

Время на прочтение4 мин
Количество просмотров2.4K
Эта идея пришла мне как-то случайно. Получить снимок с вэб камеры, которая находится дома, находясь на работе или в другом городе и при этом не расшаривать камеру через вэб… И не коннектиться по ssh… Забавно… Что, если получить его одним запросом в джаббере! Звучит бредово, но я занялся реализацией этого бреда!

Все вышеописанное не претендует на мануал или инструкцию к действию. Повторение этих плясок с бубном может повредить вашу технику или мозг. Так что будьте осторожны)
Итак, для начала я изучил какие средства борьбы с джаббером существуют. Сначала искал библиотеки для Java. Выбор есть, но почему-то все довольно сложно сделано, а кое-что не работает с отдельно взятыми серверами(jabber.ru, например). Поэтому начал выбирать из этого списка. Выбор пал на… Ruby) Во-первых, потому что я его не знаю, во-вторых, из-за простоты первого же примера. В итоге, я остановился на xmpp4r. В руби я полнейший новичок, так что можете смело критиковать и кидать помидоры) Код в студию:
#!/usr/bin/ruby
require 'xmpp4r/client'

include Jabber

class BasicClient
 MSG_DEFAULT="If your see this message you client doesn`t support html"
 MSG_DENIED="Access denied!"
 
 def initialize(args)
  puts(args[0])
  puts "Jabber WebCamBot initializing"
  @my_jid=args[0]
  @my_pwd=args[1]
  @user_jid=args[2]
  if args[3] == "debug"
   Jabber::debug = true
  end
  puts "Will connect to " + @my_jid + " and accept messages only from " + @user_jid
  do_connect
  do_auth
  start_work
 end

 def do_connect()
  @jid = JID.new(@my_jid)
  @cl = Client.new(@jid)
  @cl.connect
 end

 def do_auth
  @cl.auth(@my_pwd)
  presense = Presence.new(:dnd, "server running")
  @cl.send(presense)
 end
 
 def start_work
  mainthread = Thread.current
  @cl.add_message_callback do |m|
   if m.type != :error
    msg_jid=m.from.node + "@" + m.from.domain
    puts(msg_jid)
    if msg_jid != @user_jid
     puts("Unknown user")
     m2 = Message.new(m.from, MSG_DENIED)
     @cl.send(m2)
    else
     get_image
     m2 = Message.new(m.from, MSG_DEFAULT)
     m2.type = m.type
     h = REXML::Element::new("html")
     h.add_namespace('http://jabber.org/protocol/xhtml-im')
 
     b = REXML::Element::new("body")
     b.add_namespace('http://www.w3.org/1999/xhtml')
     
     t = REXML::Text.new( @cam_image,
     false, nil, true, nil, %r/.^/ )
     b.add(t)
     h.add(b)
     m2.add_element(h)
     puts(m.from)
     @cl.send(m2)
    end
   end
  end
  Thread.stop
 end
 
 def get_image
  system("./make.img")
  image_file = File.new("data.html", "r")
  @cam_image = image_file.read()
 end
end

BasicClient.new(ARGV)


Скрипту передается 4 аргумента:
  • Jabber ID
  • Пароль от него
  • Jabber ID пользователя, которому дозволено смотреть картинки с вашей вэбкамеры
  • Опциональный параметр debug для вывода служебной информации от xmpp4r


Суть этого кода в том, что он коннектится к серверу и ждет, пока ему не придет сообщение от некоторого, заранее известного пользователя(тобишь меня, находящегося на работе). При получении этого сообщения скрипт запускает внешнюю команду ./make.img(о ней будет подробно рассказано далее) и формирует, на основе сгенерированного ею файла data.html, jabber сообщение, в котором в тэге html содержится наша картинка.

Тут мы подходим к самому интересному. Как передать картинку, что бы ее увидеть? Первоначальная моя идея была использовать ascii-арт. Но, попробовав, я понял, что разглядеть что-то будет нереально. Поэтому нам нужно передать html тэг img с инкапсулированными в него данными(через base64 кодирование). Сгенерировать такой пакет нам поможет скрипт make.img:

#!/bin/bash

uvccapture -mv -o out.jpg
convert out.jpg -quality 20 out.jpg
IMG=$(cat out.jpg | base64)
DATE=$(date -R)
echo "Created: $DATE<br /><img src=\"data:image/png;base64,$IMG\" />" > data.html


Этот скрипт захватывает изображение с камеры(uvccapture — тут может быть тысяча вариантов, каждый выбирает то средство захвата, которое работает у него. У меня вот uvccapture заработал). Далее мы понижаем качество его через ImageMagick(нафиг нам высококачественная картинка в джаббере?), потом делаем base64 кодирование и формируем html сообщение.

Но это лишь пол дела. Нужно это сообщение еще где-то увидеть. Я нашел лишь один клиент, который фривольно показывает картинки в сообщениях. Это Synapse. Появился он недавно, и о нем недавно писали на Хабре. Работает он довольно просто, правда между запросом на получение картинки и отрисовкой проходит некоторый промежуток времени — непонятно из-за чего… Ну, и в итоге представляю скриншот нашей с ботом беседы:
webcambot

P.S. Конечно, Вы можете сказать, что лучше чем заниматься такой ерундой искать решение NP-сложных задач, оптимизировать алгоритмы вычислительной физики или создавать стартапы. Может быть, но штука получилась забавная)
P.P.S. Надеюсь код не совсем ужасен и в тексте не так много очепяток)
Теги:
Хабы:
Всего голосов 69: ↑68 и ↓1+67
Комментарии30

Публикации