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.

 

Do YouTube para o Smartphone – Parte 1

Conversando com um amigo sobre desenvolvimento de software, desenvolvimento dirigido a testes,integração contínua, entre outras coisas, veio a vontade de automatizar um processo de extração de mp3 de vídeos do Youtube e depois enviar o arquivo do notebook para o smartphone, a fim de ouvi-lo com um aplicativo para podcasts.

Até agora não escrevi nada, tão pouco pesquisei profundamente sobre as bibliotecas e ferramentas necessárias. Vou explicar aqui apenas as ideias que tenho no momento.

Problema

Eu tenho pouco tempo para assistir vídeos mas tenho conseguido ouvir meus podcasts favoritos. Por isso, para continuar consumindo alguns canais do Youtube, estou extraindo o mp3 dos vídeos para ouvir no smartphone. Depois eu jogo esses arquivos no Dropbox ou diretamente do smartphone via USB. O aplicativo para ouvir podcasts que uso atualmente é Podcast Addict. Eu trato uma pasta como um fonte de podcasts.

Módulo Desktop

Eu tenho um notebook Dell rodando a última versão do Ubuntu no momento da edição desse post.

Atualmente uso o programa de linha de comando youtube-dl para extrair o mp3 dos vídeos do Youtube.

Minha ideia é escrever um programa que acesse os canais do Youtube que consumo e verifique se há novos vídeos. Gostaria aqui de usar a API do Twitter para me enviar uma mensagem privada me perguntando se eu gostaria do mp3 do vídeo. Eu responderia por mensagem, igualmente, um sim ou um não.

Se a resposta for sim, o programa executaria o youtube-dl e jogaria o arquivo para uma determinada pasta do Dropbox.

Módulo Smartphone

Eu tenho um smartphone Quantum Go rodando Android Lollipop no momento da edição desse post.

Do lado do smartphone, basta ter o Dropbox instalado e uma de suas pastas servindo como fonte de podcasts do Podcast Addict. Terei de pesquisar se o Addict conseguirá acessar o mp3, uma vez que no dispositivo móvel o download é sob demanda.

Nos próximos posts, continuaremos a tratar desse assunto com o resultado de pesquisas e códigos.

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.

Python for Unix and Linux System Administration

Estou lendo o livro Python for Unix and Linux System Administration e estou gostando muito, por isso estou aqui escrevendo sobre ele.

Este livro da editora O’Reilly, escrito por Noah Gift e Jeremy M. Jones é uma coleção de problemas-solução em Python. Nele você encontra de quase tudo. Seu lançamento recente (Agosto de 2008) contempla as novidades do Python 2.5, apesar de já estamos com Python 2.6 pronto para instalarmos em nossas máquinas.

Ele está voltado para administradores de sistemas que precisam resolver problemas recorrentes e repetitivos e necessitam de uma ferramente ágil e completa. Python pareceu ser a escolha adequada, apesar dos autores confessarem que a escolha ter sido bem subjetiva.

Ao ler suas páginas fica claro que  o material contido nele serve para todos os programadores. É uma forma maravilhosa de conhecer bibliotecas e funções nunca antes utilizadas por nós, ou descobrirmos novas formas de fazer as coisas com as que já conhecíamos (eu descobri).

Logicamente, tem coisas que são quase exclusivamente para administradores de redes e nos deleitamos como tarefas complexas podem ser resolvidas em poucas linhas de código. Sinaliza também o fato de que a vida de um administrador de redes já é dura e não precisa ficar pior. Desenvolver suas próprias ferramentas em Python é algo prazeroso.

Há um maravilhoso capítulo chamado Package Management explanando coisas como Setuptools e os Python Eggs, os ovos de cobra, os conhecidos arquivos de distribuição. Só por este capítulo eu compraria o livro.

E tem mais. Sobre persistência de dados, temos o simples shelve, o ZODB, SQLite, Storm ORM e SQLAlchemy. É uma aula de atualidades do mundo Python.

Há coisas que já li a respeito mas não me aprofundei, como, por exemplo, Buildout, Twisted, Scapy, entre outros.

Vou continuar lendo. Leitura recomendada.