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.

 

Anúncios

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()