Do YouTube para Smartphone – Parte 2

Pesquisa de vídeos de um canal no YouTube

Antes de iniciar minha pesquisa, já sabia que o Google fornecia uma API para acesso aos seus serviços. Não demorou muito e encontrei o serviço Search. Com base no exemplo de código em Python, disponível nessa página, fiz o meu próprio exemplo.

No código de exemplo descobri que precisava de uma chave da API. Deveria cadastrar uma aplicação no Cloud Google Plataform para conseguir utilizar o serviço.

A ideia é fazer um script de linha de comando que, com base nos canais cadastrados, pergunte quais vídeos desejo a extração do mp3. Após essas respostas, o programa deve começar a baixar e extrair o mp3 um a um.

Eu costumo usar o virtualenv para isolar o ambiente Python dos meus projetos. Fique à vontade para fazer o mesmo. No resto do artigo não citarei mais essa ferramenta, seu uso estando implícito.

Outra observação importante: estou usando Python 3 e desenvolvendo principalmente num ambiente rodando Linux Ubuntu.

Coloquei o projeto no Bitbucket. Você pode baixar o projeto e testar em seu computador.

Próximo Passo

A etapa seguinte é usar a API do Twitter para ele me enviar mensagens privadas perguntando se eu desejo extrair o mp3 do vídeo.

 

Programando numa nova framework

A nova framework, pelo menos para mim, é Flask. Estou insatisfeito com a fraca extensibilidade do Web2py, entretanto continua sendo uma excelente framework para quem vai começar e deseja crescer.

Django é a principal framework web Python mas, devo ter dito em outras oportunidades, não me adaptei a ela. Quem se deu bem com ela, tem uma excelente ferramenta em mãos. Quanto à Flask, é uma framework enxuta. Você tem mais trabalho para desenvolver algo rápido e elaborado com ela. Por sua vez, sua extensibilidade é mais elaborada que Web2py, que é o que busco no momento.

Sua leveza tem atraído vários desenvolvedores e me parece que ela é mais flexível a novas tecnologias e formas de programar para web e dispositivos móveis.

Ainda estou no começo da execução do projeto que está na minha mente desde o ano passado. E tenho também pouco tempo disponível para ele. Provavelmente só terei um esqueleto básico em 2017. Junto ao aprendizado da framework, estou estudando AngularJS.

MaginBook sem a infra do Lackey

Mudei de idéia em relação a usar a infraestrutura do LackeyCCG.

Optei por implementar um plugin que dado uma lista de siglas de sets de Magic, acesse um site e carregue as informações dos cards, gravando-as num banco de dado SQLite. Foi uma escolha mais divertida.

Outra vez a biblioteca BeautifulSoup foi incrível. Navegar na árvore de tags HTML e extrair os dados é moleza com ela.

Glade, Mac OS e MaginBook

Ora, as coisas não poderiam ficar melhores. Depois do trabalho de pesquisa que estava tendo para fazer certas coisas com Gtk, descobri que seria possível utilizar o Glade no Mac OS X. Baixei o binário e problema resolvido.

O trabalho é devagar, pois procuro o melhor jeito para desenvolver o MaginBook. Além de um tutorial ou outro sobre Gtk e Glade, consegui um exemplo inesperado, um organizador de decks e cards feito em Python com Gtk! O criador do Magiclibrary escreveu um comentário num post anterior sobre este assunto. Fui atrás dos códigos-fonte da aplicação para saber como ele resolveu certas coisas. O bacana é que ele também utilizou o Glade como ferramenta para montar a interface gráfica.

Só lembrando a vocês que só vou disponibilizar o código da aplicação quando ela estiver conseguindo baixar a descrição das cartas e suas imagens.

Além do mais, é importante salientar que vou usar a infra-estrutura de plugins do LackeyCCG, onde já se fornece praticamente tudo: informações sobre blocos, edições, descrição das cartas e imagens.

Organizador de Decks em Python

Tenho um Nokia N800 que está parado deste que resolvi adotar uma agenda não-eletrônica. O fato do tablet não ter uma bateria de uma boa duração, muitas vezes não tinha a agenda disponível quando realmente precisava.

Bom, desde então fiquei pensando numa maneira de torná-lo útil novamente. Como eu jogo Magic The Gathering, um jogo de cartas colecionáveis, seria interessante ter uma lista de cartas e decks sempre à mão.

As funcionalidades que pretendo implementar para este organizador de decks, que chamarei de Maginbook:

  • Pesquisa de cartas
  • Download de novas cartas
  • Criar e baixar decks da Internet
  • Exportar decks para programas como MWS, LackeyCCG e Apprentice
  • Cotação das cartas

Eu comecei a testar as bibliotecas necessárias para este trabalho. Depois publico o código em algum repositório. Haverá duas versões: uma para Linux/Mac e outro para o Nokia N800 e outros tablets da linha.

DiceDnd 1.1

Depois de um final de semana complicado e acamado, voltei a escrever na segunda-feira os melhoramentos do DiceDnd. Pretendia melhorar o visual, habilitar o modo fullscreen e ainda fazer um pacote debian para distribuir o programa. Devido às dificuldades encontradas, fiquei somente no melhoramento visual. Pois bem, tirei umas fotos do aplicativo funcionando (não descobri uma função print screen no N800) e ainda estou disponibilizando uma nova versão abaixo.

Vou ficar devendo o fullscreen e o pacote.

DiceDnd no Nokia N800
DiceDnd no Nokia N800
DiceDnD com o resultado da jogada de dados
DiceDnD com o resultado da jogada de dados

fonte do dicednd.py (atualizado)

#!/usr/bin/python2.5

import osso
import gtk
import hildon

def labela(texto):
    fonte = '%s'
    etiqueta = gtk.Label(fonte % texto)
    etiqueta.set_use_markup(True)
    return etiqueta

def string_jogada(vezes, dado, soma):
    if soma > 0:
        sinal = '+'
    elif soma == 0:
        sinal = ''
    else:
        sinal = '-'
    return '%dd%d%s%s' % (vezes, dado, sinal, abs(soma) or '')

class DiceDnD(hildon.Program):
    def __init__(self):
        self.dado_atual = 0
        self.vezes = 0
        self.soma = 0
        hildon.Program.__init__(self)
        self.window = hildon.Window()
        self.window.set_title('DiceDnd')
        self.window.set_border_width(40)
        self.window.connect("destroy", self.quit)
        self.add_window(self.window)

        tabela = gtk.Table(5,4,False)
        self.window.add(tabela)        

        self.dado4 = gtk.Button()
        self.dado4.add(labela('4'))
        self.dado6 = gtk.Button()
        self.dado6.add(labela('6'))
        self.dado8 = gtk.Button()
        self.dado8.add(labela('8'))
        self.dado10 = gtk.Button()
        self.dado10.add(labela('10'))
        self.dado12 = gtk.Button()
        self.dado12.add(labela('12'))
        self.dado20 = gtk.Button()
        self.dado20.add(labela('20'))
        self.botaoMais = gtk.Button()
        self.botaoMais.add(labela('+'))
        self.botaoMenos = gtk.Button()
        self.botaoMenos.add(labela('-'))
        self.botaoJogar = gtk.Button()
        self.botaoJogar.add(labela('Jogar'))
        self.frame = gtk.Frame()
        self.montagem = gtk.Label('Jogada')
        self.frame.add(self.montagem)
        
        tabela.attach(self.dado4,0,1,0,1)
        tabela.attach(self.dado6,1,2,0,1)
        tabela.attach(self.dado8,2,3,0,1)
        tabela.attach(self.dado10,0,1,1,2)
        tabela.attach(self.dado12,1,2,1,2)
        tabela.attach(self.dado20,2,3,1,2)
        tabela.attach(self.botaoMais,0,1,2,3)
        tabela.attach(self.botaoJogar,1,2,2,3)
        tabela.attach(self.botaoMenos,2,3,2,3)
        tabela.attach(self.frame,0, 3, 3, 4)
        
        self.dado4.connect('clicked',self.preparar,4)
        self.dado6.connect('clicked',self.preparar,6)
        self.dado8.connect('clicked',self.preparar,8)
        self.dado10.connect('clicked',self.preparar,10)
        self.dado12.connect('clicked',self.preparar,12)
        self.dado20.connect('clicked',self.preparar,20)
        self.botaoMais.connect('clicked',self.incrementar,1)
        self.botaoMenos.connect('clicked',self.incrementar,-1)
        self.botaoJogar.connect('clicked',self.mostrar)
        
        self.window.show_all()
        
    def mostrar(self, button):
        if self.dado_atual == 0:
            return
        import random
        total = 0
        for i in range(self.vezes):
            total += random.randint(1,self.dado_atual)
        total = total + self.soma
        jogada = string_jogada(self.vezes, self.dado_atual, self.soma)
        self.show_message('%s' % total)

    def preparar(self, button,valor):
        if valor  self.dado_atual:
            self.dado_atual = valor
            self.vezes = 1
            self.soma = 0
        else:
            self.vezes += 1
        self.montagem.set_text(string_jogada(self.vezes, self.dado_atual, self.soma))
            
    def incrementar(self, button,valor):
        self.soma = self.soma + valor
        self.montagem.set_text(string_jogada(self.vezes, self.dado_atual, self.soma))


    def show_message(self, message):
        dlg = hildon.Note('information', (self.window, message))
        dlg.run()
        dlg.destroy()
        #pango_markup = '%s\n%s' % ('DiceDnD', message)
        #hildon.hildon_banner_show_information_with_markup(gtk.Label(''), None, pango_markup)

    def quit(self, evt):
        gtk.main_quit()
        
    def run(self):
        gtk.main()

def main():
    prog = DiceDnD()
    prog.run()

if __name__ == "__main__":
    main()

DiceDnd

Os dados usados no RPG D&D
Os dados usados no RPG D&D

A minha idéia exploratória de criar um aplicativo para gerar jogada de dados no meu N800  ocupou umas horas da noite de sexta e início de madrugada do sábado.

O objetivo da aplicação é bem simples. Eu vou voltar a mestrar campanhas de RPG. Comprei o recente D&D 4ª Edição em português mais uma aventura para personagens iniciantes. Não tenho todos os tipos de dados necessários. São 6 tipos, por quantidade de faces: 4, 6, 8, 10, 12 e 20. Assim, queria simular a parada de dados pelo meu N800, um internet tablet da Nokia.

Uma das principais linguagens para programar nesses dispositivos é Python. Apesar de não conhecer muito a biblioteca Gtk (biblioteca gráfica), conheço a linguagem razoavelmente bem, por isso acreditava que conseguiria implementar o aplicativo no final de semana.

A primeira providência foi procurar documentação. A idéia do projeto já estava toda na minha cabeça mas não sabia por onde começar. Depois de um tempo, encontrei algumas coisas. Foram importantes os seguintes documentos:

A versão do sistema operacional é o OS 2008 (Diablo). O Python 2.5 já estava instalado. De fato, não precisei instalar outra coisa. Algumas documentações diziam que eu tinha de instalar o interpretador da linguagem. Talvez eu tenha feito isso algum tempo atrás.

Outra coisa que ajudou bastante, para ir escrevendo e testando rapidamente, foi acessar via SSH o dispositivo pelo Nautilus (num notebook com Ubuntu). Criei o arquivo da aplicação no cartão do N800 e depois abrir com o editor TextFlow. Daí era só escrever, salvar e ir no PDA executar a aplicação.

O cliente e servidor do SSH não vem instalado por default no N800. Nem o terminal. Por ele é que eu rodava o Python. Pelo notebook, eu usava também um terminal para acessar o N800 via ssh. Era útil para testar algumas coisas no interpretador interativo do Python.

As próximas tarefas envolvem melhorar o aspecto visual da aplicação e preparar um instalador para ficar mais fácil de dispobilizar. O código-fonte encontra-se abaixo:

#!/usr/bin/python2.5

import osso
import gtk
import hildon

def string_jogada(vezes, dado, soma):
    if soma > 0:
        sinal = '+'
    elif soma == 0:
        sinal = ''
    else:
        sinal = '-'
    return '%dd%d%s%s' % (vezes, dado, sinal, abs(soma) or '')

class DiceDnD(hildon.Program):
    def __init__(self):
        self.dado_atual = 0
        self.vezes = 0
        self.soma = 0
        hildon.Program.__init__(self)
        self.window = hildon.Window()
        self.window.set_title('DiceDnd')
        self.window.connect("destroy", self.quit)
        self.add_window(self.window)

        tabela = gtk.Table(5,4,True)
        self.window.add(tabela)

        self.dado4 = gtk.Button('4')
        self.dado6 = gtk.Button('6')
        self.dado8 = gtk.Button('8')
        self.dado10 = gtk.Button('10')
        self.dado12 = gtk.Button('12')
        self.dado20 = gtk.Button('20')
        self.botaoMais = gtk.Button('+')
        self.botaoMenos = gtk.Button('-')
        self.botaoJogar = gtk.Button('Jogar')
        self.frame = gtk.Frame()
        self.montagem = gtk.Label('Jogada')
        self.frame.add(self.montagem)

        tabela.attach(self.dado4,0,1,0,1)
        tabela.attach(self.dado6,1,2,0,1)
        tabela.attach(self.dado8,2,3,0,1)
        tabela.attach(self.dado10,0,1,1,2)
        tabela.attach(self.dado12,1,2,1,2)
        tabela.attach(self.dado20,2,3,1,2)
        tabela.attach(self.botaoMais,0,1,2,3)
        tabela.attach(self.botaoJogar,1,2,2,3)
        tabela.attach(self.botaoMenos,2,3,2,3)
        tabela.attach(self.frame,0, 3, 3, 4)

        self.dado4.connect('clicked',self.preparar,4)
        self.dado6.connect('clicked',self.preparar,6)
        self.dado8.connect('clicked',self.preparar,8)
        self.dado10.connect('clicked',self.preparar,10)
        self.dado12.connect('clicked',self.preparar,12)
        self.dado20.connect('clicked',self.preparar,20)
        self.botaoMais.connect('clicked',self.incrementar,1)
        self.botaoMenos.connect('clicked',self.incrementar,-1)
        self.botaoJogar.connect('clicked',self.mostrar)

        self.window.show_all()

    def mostrar(self, button):
        if self.dado_atual == 0:
            return
        import random
        total = 0
        for i in range(self.vezes):
            total += random.randint(1,self.dado_atual)
        total = total + self.soma
        jogada = string_jogada(self.vezes, self.dado_atual, self.soma)
        self.show_message('%s' % total)

    def preparar(self, button,valor):
        if valor  self.dado_atual:
            self.dado_atual = valor
            self.vezes = 1
            self.soma = 0
        else:
            self.vezes += 1
        self.montagem.set_text(string_jogada(self.vezes, self.dado_atual, self.soma))

    def incrementar(self, button,valor):
        self.soma = self.soma + valor
        self.montagem.set_text(string_jogada(self.vezes, self.dado_atual, self.soma))

    def show_message(self, message):
        dlg = hildon.Note('information', (self.window, message))
        dlg.run()
        dlg.destroy()
        #pango_markup = '%s\n%s' % ('DiceDnD', message)
        #hildon.hildon_banner_show_information_with_markup(gtk.Label(''), None, pango_markup)

    def quit(self, evt):
        gtk.main_quit()

    def run(self):
        gtk.main()

def main():
    prog = DiceDnD()
    prog.run()

if __name__ == "__main__":
    main()

Idéia exploratória

Uma boa idéia me surgiu agora, útil para o momento e ótima pedida para iniciar a exploração no mundo da programação de dispositivos Nokia que usam o sistema operacional Maemo: um rolador de dados.

Bobo, né? Inclusive, acho que já existe um. Mas é diferente do que eu estou pensando.

Gostaria que a tela do aplicativo mostrasse um quadrado com todos os tipos de dados usados no RPG D&D ou seja, os de 4, 6, 8, 10, 12 e 20 faces. E mais três botões: para o sinal de mais, o de menos e o de igual.

Ao apertar um dos dados ele saberá que quero jogar com ele. Ele esperará eu apertar no sinal de igual para a operação randômica executar. Os sinais servem para aumentar ou diminuir o que resultar do dado. Cada vez que eu apertar num deles incrementa-se ou descrementa-se em um.

Logicamente vou escrever esse aplicativo em Python. Vamos ver se tenho a sorte e produtividade de terminá-lo ainda neste final de semana. Quando concluir, posto por aqui.

Comunidade de Jogadores e Desportistas

O Mosaico Livre é essencialmente um blog sobre programação, engenharia de software, software livre. Ultimamente venho negligenciando esta essência. É como se tivesse perdido o rumo.

O barco, no entanto, deve seguir seu rumo correto.

Já há algum tempo, por curiosidade, li alguns tutoriais e assistir alguns vídeos sobre o Google App Engine, uma plataforma para desenvolver aplicações web que podem usar a infraestrutura do Google. Ou seja, podemos hospedar nossas aplicações nos servidores do Google.

O Google App Engine é implementado em Python. Um fator importante para que eu rapidamente pudesse desenvolver alguma coisa. Logo será possível usar outras linguagens. Até lá o interesse em aprender Python continuará.

E como Python cresceu desde 1999, o ano em que comecei a programar nesta linguagem! Ela já está entre as linguagens modernas mais comentadas. A falta de uma empresa forte que a utilizasse ou pelo menos incentivasse seu uso era um dos motivos para as pessoas não quererem conhecê-la. O Google mudou isso.

Atualmente desenvolvo uma aplicação para Google App Engine. Na verdade, é um portal para concentrar informações sobre esportes e jogos em geral, seja amador ou profissional. Um local onde o pessoal possa conhecer outros praticantes. Por exemplo, sinto necessidade de conhecer pessoas na minha cidade que joguem Go, um jogo de tabuleiro difundido no oriente, mas pouco por aqui. No site, posso informar os jogos que pratico. Quem tiver interessado em jogar comigo, pode enviar um e-mail. Depois, podemos informar no site o local onde jogaremos para que outras pessoas possam comparecer para apreciar a partida.

É raro encontrar algum portal da imprensa que dedique um espaço a esportes com poucos praticantes. A minha idéia é preencher esta lacuna.

Assim que eu tiver terminado, passo o endereço para vocês.

Primeiro contato com TurboGears 2

Como o Twitter não está muito bem, vai ser por aqui mesmo que informo aos amigos e colegas pythonistas que tive pela primeira vez contato com o TurboGears 2 hoje. Acabei de fazer o exemplo da Wiki.

Aos poucos, devo começar a me aprofundar no uso dele, uma vez que estamos pensando em adotar o framework para o desenvolvimento de um projeto. Queremos que nossa aplicação acompanhe o desenvolvimento do TurboGears, mesmo que isso seja arriscado.

Tive um razoável trabalho para instalá-lo na minha máquina. O trabalho não se deveu ao fato de tê-lo de obter via Subversion, mas sim porque alguns pacotes não estavam sendo encontrados pelo easy_install. Também precisei usar o Paver para baixar umas dependências. Isso a documentação de instalação não explicou. Devo fazer a instalação também no notebook do Stênio. Não anotei nada, espero conseguir.

Apesar dele manter a API bastante semelhante ao TurboGears 1, há componentes novos. A curiosidade foi aguçada por conta disso. Estava tão por fora, que somente agora fiquei sabendo sobre o Paver, criado pelo próprio Kevin Dangoor. Parece-me um melhoramento sobre o processo de instalação/distribuição/empacotamento.

Deixemos para outros posts demais conclusões sobre o TG2.