terça-feira, 4 de agosto de 2009

IRC Twitter - Envie updates para o Twitter de dentro do X-Chat/mIRC

O suporte à scripts dos clientes de IRC é com certeza uma das maiores facilidades já criadas, permitindo estender muito o cliente básico, transformando estes clientes em verdadeiras plataformas de comunicação. O X-Chat é um desses clientes, que suportam uma miríade de linguagens de escript diferentes, entre elas, a linguagem Python.

Eu já vi vários scripts para as mais diversas finalidades, de informações de sistema à risadas automatizadas. No entanto, até o momento não vi nenhum plugin que permitisse alguma forma de integração com o Twitter.

Por incrível que pareça, o Twitter compartilha algumas características que as redes de IRC já usam há muitos anos. Entre elas, a formação de comunidades em torno de assuntos populares (os trend topics) e a proximidade que existe entre os participantes.

Como atualmente eu ando estudando bastante as ferramentas para Web para Python, usando como alvo o Twitter (E que num futuro próximo, renderá um novo cliente Twitter cheio de recursos desnecessários hehehe), resolvi fazer um script bem simples para o X-Chat, só pra envio de mensagens.

O X-Chat é uma excelente plataforma que eu poderia usar para misturar conversas dos knais com mensagens no Twitter, mas deixo por enquanto isso para um futuro mais distante.

No momento, vamos ser K.I.S.S...



Nesse script que estou postando para vocês hoje, eu usei a API do X-Chat para Python em conjunto com a API Web do Twitter (em Json) para criar um simples comando, que se autentica no Twitter e envia o update. Só isso. Nada de verificar atualizações, nada de replies ou retweets. A idéia é deixar o uso tão simples, porque sempre aparecem pérolas no IRC que queremos de alguma forma guardar !! E é esse o pensamento que eu tive.

Ao usar o comando /tw no X-Chat, o mesmo enviará uma mensagem na janela corrente, e em seguida irá fazer o update no Twitter:
* Vndmtrx enviou um tweet: Esse eh meu teste do Twitter X-Chat ;) (http://twitter.com/vindemiatrix)

Dentre os recursos que eu usei nesse script, o que se destaca mais é o uso do ConfigParser para guardar as configurações de usuário e senha. O script pode ser simples, mas não vamos ser simplórios (e nem imbecis) de guardar um login e senha em uma estrutura dentro do script que, a cada alteração de usuário, seja necessário editar o script, né ??

Para usar o script a primeira vez, é necessário usar o comando /twconf , para podermos enviar os updates para o usuário.

O uso de urllib e urllib2 não vou comentar pq é básico. A única coisa a mais que vale ser comentada é a dificuldade para conseguir passar um dicionário para a função str.format(). Como usava muito pouco, havia me esquecido dos **kwargs.

P.S.: Durante os testes com o script, eu via que, dependendo da conexão e do horário, o script congelava o X-Chat por vários minutos. Então, pensando nesse problema, eu coloquei o envio da mensagem dentro de uma thread, que é chamada a cada envio, acabando com o delay causado pelo urllib2.

Fica aí então a dica para aqueles que, advindos do antigo formatador de strings com "%", que para acessar itens de dicionário, a sintaxe é "{chave1}, {chave2}".format(**dicionario), desde que chave1 e chave2 existam dentro do mesmo.

Algumas correções foram sugeridas pelo meu amigo JimmySkull e as mesmas já se encontram no código revisado, abaixo.

No mais, é só isso mesmo. Mais pra frente eu prometo um cliente mais poderoso que esse, com suporte a mais opções e, quem sabe, até uma GUI (Feita em wxPython ou, se eu tiver coragem suficiente, em PyGtk).

Abração. Aproveitem o código, abaixo.

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

##*MIT License. Copyright (c) 2009 Vindemiatrix Almuredin, Jimmy Skull
##*
##* Permission is hereby granted, free of charge, to any person obtaining a copy of this
##* software and associated documentation files (the "Software"), to deal in the Software
##* without restriction, including without limitation the rights to use, copy, modify, merge,
##* publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
##* to whom the Software is furnished to do so, subject to the following conditions:
##* Except as contained in this notice, the name(s) of the above copyright holders shall
##* not be used in advertising or otherwise to promote the sale, use or other dealings in
##* this Software without prior written authorization.
##*
##* The above copyright notice and this permission notice shall be included in all copies or
##* substantial portions of the Software.
##*
##* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
##* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
##* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
##* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
##* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
##* DEALINGS IN THE SOFTWARE

from threading import Thread
import xchat
import urllib2
import urllib
import base64
import ConfigParser

__module_name__ = "X-Chat Twitter"
__module_version__ = "1.6.6.1327635287"
__module_description__ = "Envia mensagens para o Twitter pelo X-Chat"

config = ConfigParser.RawConfigParser()

def salvasenha(texto, texto_eol, dados):
if not config.has_section('Twitter'):
config.add_section('Twitter')
config.set('Twitter', 'Usuario', texto[1])
config.set('Twitter', 'Senha', texto[2])
with open('twitter.conf', 'wb') as configfile:
config.write(configfile)
print 'Configuracoes Salvas!'
return xchat.EAT_ALL

def twitar(texto, texto_eol, dados):
try:
config.read('twitter.conf')
if config.has_section('Twitter'):
login = dict()
login['usuario'] = config.get('Twitter', 'Usuario')
login['senha'] = config.get('Twitter', 'Senha')

if len(texto_eol[1]) < 140:
# Gera string de login para enviar no cabeçalho HTTP
auth = base64.encodestring("{usuario}:{senha}".format(**login)).strip()

# Mostra o "tweet" no canal ativo no momento
xchat.command("me enviou um tweet: {0} (http://twitter.com/{1})".format(texto_eol[1], login['usuario']))

# Monta a requisicao a ser enviada
req = urllib2.Request("http://twitter.com/statuses/update.json",
urllib.urlencode({"status":texto_eol[1]}),
{"Authorization": "Basic {0}".format(auth), "X-Twitter-Client": __module_name__})

# Transmite a mensagem para o Twitter
urllib2.urlopen(req)
else:
print "Sua mensagem tem mais de 140 caracteres."

else:
print 'Eh necessario gravar um usuario e senha para poder usar esse comando ("/twconf ")'
except HTTPError, e:
if e.code == 401:
print 'Falha na autenticacao. Verifique seu usuario e senha antes de prosseguir. ({0})'.format(e.reason)
else:
print 'Erro de comunicacao. ({0})'.format(e.reason)
except:
print 'Erro desconhecido.'

def tw(texto, texto_eol, dados):
t = Thread(target=twitar, args=(texto, texto_eol, dados))
t.start()
return xchat.EAT_ALL

xchat.hook_command("tw", tw, help="/tw [mensagem]")
xchat.hook_command("twconf", salvasenha, help="/twconf [usuario] [senha]")


Tb encontrável em http://pastebin.ca/1518306

Só fazendo uma adição de última hora, muitas pessoas me perguntaram se esse script existia para o mIRC e eu disse que não. Então essas pessoas me falaram que adorariam usar o script no mIRC. Em vista disso, estou botando minha versão do mesmo, ainda altamente experimental, pq não uso o mIRC e não pude testá-lo.

Obrigado ao site Dooyoo por me ajudar a completar essa tarefa. Agora, posto abaixo o script para o mIRC:
; No Aliases do mIRC Script Editor

twconf {
set %tw.usuario $1
set %tw.senha $2
echo -a Usuário e Senha do Twitter guardados.
}

tweet {
if ($len(%tw.usuario) < 1) {
echo -a Eh necessario setar um usuário e senha antes de usar o comando. /twconf usuario senha
} else {
if ($len($1-) > 140) {
echo -a A sua mensagem têm mais de 140 caracteres. Tamanho atual: $calc($len($1-)-140).
halt
}

set %auth $encode($+(%tw.usuario,:,%tw.senha),m)
sockclose twsocket
sockopen twsocket twitter.com 80
.timertwitter 1 5 twitter_timeout
set %tweet $$1-
me enviou um tweet: %tweet http://twitter.com/ $+ %tw.usuario
}
}

; Urlencode e Urldecode para o mIRC (foda ele não ter !!)
urlencode return $regsubex($1-,/\G(.)/g,$iif(($prop && \1 !isalnum) || !$prop,$chr(37) $+ $base($asc(\1),10,16),\1))
urldecode return $replace($regsubex($1-,/%(\w\w)/g,$chr($iif($base(\t,16,10) != 32,$v1,1))),$chr(1),$chr(32))

; ... e os dados da conexão não chegarem, kill the socket! kill the socket!
twitter_timeout {
sockclose twsocket
}


; No Remote do mIRC Script Editor

; ... e tivermos dados, mensagem enviada !!
on *:sockread:twsocket: {
.timertwitter off
sockread -f %string
sockclose twitter
}

; ... quando o socket aceitar a conexão ...
on *:sockopen:twsocket:{
sockwrite -n twsocket POST /statuses/update.json HTTP/1.1
sockwrite -n twsocket Host: twitter.com
sockwrite -n twsocket User-Agent: Mozilla/5.0 Gecko/20090715 Firefox/3.5.1 GTB5
sockwrite -n twsocket Content-Length: $calc($len($urlencode(%tweet)) + 9)
sockwrite -n twsocket Authorization: Basic %auth
sockwrite -n twsocket $crlf
sockwrite twsocket status=
sockwrite -n twsocket $urlencode(%tweet)
sockwrite twsocket $crlf
sockwrite twsocket $crlf
}


Tb encontrável em http://pastebin.ca/1504337