Artigos com o marcador Geral
Primeiro trailer de 24 horas
30/11/08
A série 24 horas foi a série que me fez começar a assistir seriados americanos. Eu assisti a primeira temporada nas madrugadas da Globo quando o programa do Jô estava de férias. Isso lá no ano de 2004 (eu acho). Desde então não parei mais de assistir 24 horas e ainda acho uma das melhores séries já feitas.
A sétima temporada está chegando e liberaram o primeiro trailer oficial. E para quem acompanha a série, o trailer já vem com surpresa sobre o vilão da temporada.
Ruby para tudo!
06/09/08
Fala pessoal!
Hoje eu vou postar um exemplo clássico de como o Ruby pode facilitar nossas vidas de desenvolvedor no dia a dia (por mais idiota que seja a utilização da linguagem).
Podemos utilizar Ruby tanto para fazer aplicações complexas como para fazer um simples script que gere arquivos de playlist. Isso mesmo caro leitor, um script que gera um arquivo de playlist (M3U).
Quando temos várias pastas de músicas (ou vídeos) espalhadas em vários computadores na rede e precisamos criar uma lista de todas essas músicas, por exemplo, podemos adicionar elas no Winamp e salvar a playlist, certo? Depende! Se você quiser esperar o Winamp ler todas as tags ID3 dos arquivos para depois salvar, você pode. Como também pode desenvolver um script Ruby que leia os arquivos para você e monte uma saída para arquivo M3U. Solução bem mais rápida.
Primeiramente o que é um arquivo M3U? O arquivo que possui a extensão “m3u” é um arquivo texto que contém em cada linha o caminho pra um arquivo de mídia. A extensão foi desenvolvida para ser o arquivo de playlist padrão do Winamp, isso lá nos primórdios desse player. Hoje a extensão se tornou um padrão de playlists e é suportada por quase todos os players de mídia.
O M3U pode conter tanto os caminhos relativos dos arquivos de mídia como os caminhos absolutos dos tais arquivos. Eu pessoalmente prefiro sempre usar o caminho absoluto.
Bom, supondo que temos vários computadores em rede e que nesses computadores há pastas compartilhadas (e com acesso claro) com arquivos de mídia. Então queremos gerar um arquivo de playlist com todos os arquivos de mídia que estão nessas pastas compartilhadas. Faremos um script para resolver esse problema.
Primeiramente vamos definir o caminho onde será salvo o arquivo de playlist e também o arquivo de LOG, caso houver erros. Assim iniciamos nosso script da seguinte maneira:
@saida_m3u = 'C:\Documents and Settings\usuario\Desktop\lista.m3u' @log_file = 'C:\Documents and Settings\usuario\Desktop\lista.log'
Também precisamos definir os caminhos que iremos procurar as músicas (pastas) e as extensões que entrarão em nossa playlist. Usaremos um Array para guardar o caminho das pastas que iremos procurar e outro Array para as extensões. Depois de instanciar os Arrays, preenchemos os array com os valores que queremos, nesse caso as Strings de caminho das pastas e também as Strings de extensão.
@saida_m3u = 'C:\Documents and Settings\usuario\Desktop\lista.m3u' @log_file = 'C:\Documents and Settings\usuario\Desktop\lista.log' @midia_ext = Array.new @music_paths = Array.new #--------------------------------------------------------------------- # CAMINHOS PARA O SCAN # Os caminhos abaixo serão percorridos recursivamente pelo script # para procurar arquivos de mídia. Cada caminho absoluto é uma # posição diferente no Array. #--------------------------------------------------------------------- @music_paths << 'D:\MP3\Músicas' @music_paths << '\\computador1\mp3' @music_paths << '\\computador2\musics' #--------------------------------------------------------------------- # EXTENSÕES DE MÍDIA # As extensões listadas abaixo serão usadas pelo script para fazer # a verificação com as extensões dos arquivos que serão adicionados. # Isso serve para que o script não adicione arquivos que não sejam de # mídia como .doc, .exe, .txt # Você pode adicionar outros tipos de extensões se quiser para que o # script ache. #--------------------------------------------------------------------- @midia_ext << '.mp3' @midia_ext << '.ogg' @midia_ext << '.wma' @midia_ext << '.wav' @midia_ext << '.flac' @midia_ext << '.aac'
Daqui para frente vem a lógica da aplicação. O que fizemos até agora foi um cabeçalho onde fica a configuração do script. É onde você pode alterar para que atenda suas necessidades.
Como nós estamos fazendo um script bacana, nós vamos dar algumas estatísticas no final sobre a quantidade de músicas adicionadas, o tempo que durou a busca das mídias etc. Então vamos inicializar algumas variáveis que nós ajudarão nas estatísticas e também declarar a utilização do find que é uma biblioteca de busca de arquivos do Ruby. O find já está no core do Ruby. Se quiser saber mais sobre o Find acesse a documentação do Ruby.
require 'find' @total_musicas = 0 @total_adicionado = 0 @erros_adicao = 0 @usar_log = true
Essas variáveis são alto explicativas e você verá a utilização delas durante o script. Por enquanto nosso script está ficando da seguinte maneira:
@saida_m3u = 'C:\Documents and Settings\Ricardo\Desktop\lista.m3u' @log_file = 'C:\Documents and Settings\Ricardo\Desktop\lista.log' @midia_ext = Array.new @music_paths = Array.new @music_paths << 'D:\MP3\Músicas' @music_paths << '\\computador1\mp3' @music_paths << '\\computador2\musics' @midia_ext << '.mp3' @midia_ext << '.ogg' @midia_ext << '.wma' @midia_ext << '.wav' @midia_ext << '.flac' @midia_ext << '.aac' @total_musicas = 0 @total_adicionado = 0 @erros_adicao = 0 @usar_log = true
Agora, para uma maior legibilidade de código, e manutenção, vamos quebrar toda lógica do script em pequenas funções que fazem pequenos trabalhos, porém de importância extrema para o funcionamento do script.
A primeira função que iremos criar é uma função que checa se uma extensão passada por parâmetro da função está contida no Array de funções que criamos no início do script. Essa função de checagem serve para nós não adicionarmos em nosso arquivo de playlist qualquer arquivo que encontrar. A função ficaria da seguinte maneira:
def check_extension(file_extension) @midia_ext.each do |mid_ext| if (file_extension.downcase.eql?(mid_ext)) return true else return false end end end
Bem simples não acham? Apenas percorremos o Array e vemos se existe a extensão lá dentro. Se existir, retornamos true. Senão retornamos false.
Precisamos também de uma função que sirva para escrever o arquivo de playlist com o caminho da mídia encontrado. Essa função irá escrever o arquivo que nós também definimos no início do script com o objeto @saida_m3u. A função ficaria assim:
def save_to_m3u(path) begin f = File.new(@saida_m3u, "a") f < < path.gsub("/", "\") + "n" @total_adicionado = @total_adicionado + 1 puts "Musica adicionada: #{path.gsub("/", "\")}" rescue puts "Erro ao adicionar: #{path.gsub("/", "\")} ignorando" @erros_adicao = @erros_adicao + 1 if (@usar_log) puts "Adicionando no Log" save_to_log("warn", "Musica NAO adicionada: #{path}") end end end
O que a função faz? Ela cria um novo arquivo (se ele já não tiver sido criado) e escreve nele o caminho recebido através do parâmetro path. Se acontecer qualquer problema que impossibilite a gravação do caminho no arquivo de playlist, será lançada uma exceção e a função irá capturar (por isso do begin..rescue..end). Quando capturado o problema, então chamamos uma função chamada save_to_log e passamos o problema para que seja registrado no LOG. Mas ainda não criamos uma função que salve informações em um log. Vamos criar!
def save_to_log(type, message) begin data_hora = Time.new.strftime("%d/%m/%Y %H:%M") f = File.new(@log_file, "a") f < < "#{data_hora} #{type.upcase} #{message}" rescue puts "Houve um erro na escrita ao LOG." puts "Nao sera mais usado o log na criacao de playlist" @usar_log = false end end
Outra função simples, onde salvamos as informações que vem por parâmetro juntamente com o data e hora atual. Se houver problema na gravação do LOG, então capturamos a exceção e desabilitamos o uso do LOG, já que ele está com problemas. Ta fincando legal!
Bem pessoal, agora vem o “corpo” do script. Agora vem a parte principal. Agora vem o que faz o script funcionar. Agora vem finalmente a parte que percorre as pastas, chama as funções e exibe os resultados.
Agora sim nós usaremos o Find declarado mais acima. Com o find iremos percorrer recursivamente as pastas setadas no Array de caminhos de pastas. Quando percorremos recursivamente, estamos percorrendo todas as subpastas também. Como ficaria esse percorrimento recursivo? Assim:
@music_paths.each do |music_path| begin Find.find(music_path) do |path| if (File.file?(path)) if (check_extension(File.extname(path))) @total_musicas = @total_musicas + 1 save_to_m3u(path) end end end rescue puts "Erro na leitura do caminho: #{path}" save_to_log("ERROR", "Erro na leitura do caminho: #{path}") end end
O que trecho de código faz? Primeiro, é um loop no Array de caminhos de pastas, depois é outro loop com o Find onde o objeto path aponta para um caminho. É feita uma verificação se esse objeto path é um arquivo ou diretório. Se for arquivo então verificamos se a extensão dele usando nossa função check_extension, se a extensão tiver sido verificada com sucesso então incrementamos nossa variável de estatística e salvamos o caminho na nossa playlist. Simples! Muito simples!
Agora para ficar um script mais legal do que já está, vamos fazer uma saída para o usuário via console mesmo com as estatísticas e demais informações. Essa parte é opcional para o funcionamento do script, mas é legal.
puts "n" puts "===================================================" puts " GERACAO DA LISTA FINALIZADA" puts "===================================================" puts "Lista M3U em #{@saida_m3u}" if (@erros_adicao > 0) puts "Houve alguns erros ao adicionar algumas musicas" puts "Verifique o LOG para mais detalhes em #{@log_file}" puts "n" puts "=============================" puts " RESUMO" puts "=============================" puts "Total de musicas: #{@total_musicas}" puts "Total adicionadas: #{@total_adicionado}" puts "Total de erros: #{@erros_adicao}" puts "n" puts "Clique em fechar para sair" else puts "Todas as musicas foram adicionadas com sucesso" puts "============================" puts " RESUMO" puts "============================" puts "Total de musicas: #{@total_musicas}" puts "Total adicionadas: #{@total_adicionado}" puts "Total de erros: #{@erros_adicao}" puts "n" puts "Clique em fechar para sair" end sleep(100000)
Fizemos duas saídas distintas acima. Uma se houve alguma erro durante a execução do script e outra se não houve nenhum erro. Essas saídas não tem segredo, somente alguns “puts“.
Final galera. O script está pronto e já pode ser executado. Juntando todas as partes montamos um script que ficará desse jeito:
@saida_m3u = 'C:\Documents and Settings\Ricardo\Desktop\lista.m3u' @log_file = 'C:\Documents and Settings\Ricardo\Desktop\lista.log' @midia_ext = Array.new @music_paths = Array.new @music_paths << 'D:\MP3\Músicas' @music_paths << '\\computador1\mp3' @music_paths << '\\computador2\musics' @midia_ext << '.mp3' @midia_ext << '.ogg' @midia_ext << '.wma' @midia_ext << '.wav' @midia_ext << '.flac' @midia_ext << '.aac' @total_musicas = 0 @total_adicionado = 0 @erros_adicao = 0 @usar_log = true def check_extension(file_extension) @midia_ext.each do |mid_ext| if (file_extension.downcase.eql?(mid_ext)) return true else return false end end end def save_to_m3u(path) begin f = File.new(@saida_m3u, "a") f << path.gsub("/", "\") + "n" @total_adicionado = @total_adicionado + 1 puts "Musica adicionada: #{path.gsub("/", "\")}" rescue puts "Erro ao adicionar: #{path.gsub("/", "\")} ignorando" @erros_adicao = @erros_adicao + 1 if (@usar_log) puts "Adicionando no Log" save_to_log("warn", "Musica NAO adicionada: #{path}") end end end def save_to_log(type, message) begin data_hora = Time.new.strftime("%d/%m/%Y %H:%M") f = File.new(@log_file, "a") f << "#{data_hora} #{type.upcase} #{message}" rescue puts "Houve um erro na escrita ao LOG." puts "Nao sera mais usado o log na criacao de playlist" @usar_log = false end end @music_paths.each do |music_path| begin Find.find(music_path) do |path| if (File.file?(path)) if (check_extension(File.extname(path))) @total_musicas = @total_musicas + 1 save_to_m3u(path) end end end rescue puts "Erro na leitura do caminho: #{path}" save_to_log("ERROR", "Erro na leitura do caminho: #{path}") end end puts "n" puts "===================================================" puts " GERACAO DA LISTA FINALIZADA" puts "===================================================" puts "Lista M3U em #{@saida_m3u}" if (@erros_adicao > 0) puts "Houve alguns erros ao adicionar algumas musicas" puts "Verifique o LOG para mais detalhes em #{@log_file}" puts "n" puts "=============================" puts " RESUMO" puts "=============================" puts "Total de musicas: #{@total_musicas}" puts "Total adicionadas: #{@total_adicionado}" puts "Total de erros: #{@erros_adicao}" puts "n" puts "Clique em fechar para sair" else puts "Todas as musicas foram adicionadas com sucesso" puts "============================" puts " RESUMO" puts "============================" puts "Total de musicas: #{@total_musicas}" puts "Total adicionadas: #{@total_adicionado}" puts "Total de erros: #{@erros_adicao}" puts "n" puts "Clique em fechar para sair" end sleep(100000)
Lendo XML com o REXML – Ruby
10/07/08
Ruby tem hoje uma das bibliotecas mais impressionantes e fáceis para se manipular informações em formato XML. A biblioteca REXML (Ruby Electric XML).
Essa biblioteca é baseada na biblioteca Electric XML para Java, porém em Ruby é bem mais fácil de se usar tal biblioteca. Aliás, você não fica restrito apenas a manipulação de XML com o REXML, você também poderá usá-la para manipulação de informações no formato XHTML. Como o XHTML tem padrões rigorosos definidos, podemos usar o REXML tranqüilamente. Mas se você precisa manipular HTML, use o hpricot.
Nesse post, eu mostro o básico de uma leitura XML usando a REXML. Em nosso exemplo utilizaremos o webservice de pesquisa do Yahoo. Basicamente iremos ler o XML que o Yahoo nos fornece e iremos exibi-los em console.
Primeiro de tudo vamos ver qual a estrutura do XML que o Yahoo nos fornece para fazermos a leitura. A URL do XML é essa: http://api.search.yahoo.com/WebSearchService/V1/webSearch?appid=YahooDemo&query=metallica&results=5
Repare na URL que eu passei acima as variáveis que passei via GET. Uma é a palavra chave de busca (query) e a outra o número de resultados que eu quero por página (results). Estão com os valores “metallica” e “5” respectivamente. Se quiser se aprofundar na API de busca do Yahoo, consulte o site do developers do Yahoo.
Voltando a XML fornecida pelo Yahoo, vamos analisa-la:
Cada “caixa” em azul representa um nó no XML. Tudo começa com um nó raiz (ResultSet) e depois desce para o nó de resultado (Result). Esse nós repsenta um item do resultado da pesquisa feita no Yahoo. Se houve mais resultados, então o nó Result é repetido.
Em nosso tutorial, vamos ler as informações que estão nos nós “Title”, “Summary”, “Url” e “MimeType” que não se encontra no mapeamento acima porque não houve espaço para colocar todos os nós. De uma olhada no documento do Yahoo que você irá ver lá.
Agora que sabemos as informações que iremos ler, vamos começar a codificar.
Vamos criar uma classe “Buscador” que irá se conectar ao webservice do Yahoo, ler toda a XML e inicializar nossos atributos de instância no construtor. Depois criaremos um método que irá ler os nós específicos do XML que queremos.
Comecemos pelos imports das bibliotecas e pelo construtor:
# Leitura de XML usando a biblioteca REXML # do Ruby. Em nosso exemplo usaremos o # webservice de busca do Yahoo. class Buscador # Import dos GEMs usados e do REXML require 'rubygems' require 'open-uri' require 'rexml/document' #Vamos inicializar as variáveis para a busca e instanciar #nosso objeto REXML que será usado para a busca no Yahoo. def initialize(keywords, resultado_pagina) @keywords = keywords @resultado_pagina = resultado_pagina @url_yahoo = "http://api.search.yahoo.com/WebSearchService/V1/ webSearch?appid=YahooDemo&query=#{@keywords}&results=#{@resultado_pagina}" # Aqui você pode usar o open do gem open-uri ou # a classe net/http. O open é bem mais simples :). xml_data = open(@url_yahoo) @obj_rexml = REXML::Document.new(xml_data.read) end end
Repare no código acima que nosso construtor recebe dois parâmetros. O keywords são as palavras chave que usaremos na busca e o resultado_pagina é o número de resultados que queremos que sejam exibidos no XML. Esse parâmetros são aqueles já explicados acima nesse mesmo post.
Outro detalhe no código é o uso do open. Nele, passamos somente a URL que queremos ler e ele nos retorna os dados com o método read. Incrível. Cada vez mais eu gosto de Ruby!
Logo abaixo do open, está a instanciação do objeto REXML, o qual usaremos para ler o XML no método que criaremos.
Criado o construtor, vamos criar nosso pequeno método que faz a leitura do XML e nos retorna o resultado.
A cada resultado que o Yahoo nos retornar, iremos criar um hash para esse resultado. Preenchido o hash com as informações do XML colocaremos esse hash dentro de um array. Faremos isso até finalizar a leitura do XML. Terminada a leitura, retornaremos o array. Nossos resultados estarão bem estruturados dentro do array.
Vamos ao método da busca:
# Esse método realiza a leitura do xml e retorna um array de hash # com o resultado da leitura. def buscar lista_resultado = Array.new #array com todos os resultados # Caminho dos nos no XML. Dependendo do que você quiser # no XML, vai ser aqui você irá muda. nos = "ResultSet/Result" # Loop entre os nos do XML definido acima @obj_rexml.elements.each(nos) do |elemento| resultado = Hash.new #hash que vai conter um resultado resultado[:titulo] = elemento.text("Title") resultado[:descricao] = elemento.text("Summary") resultado[:link] = elemento.text("Url") resultado[:tipo] = elemento.text("MimeType") # Guarda o hash no array e continua o loop lista_resultado < < resultado end # Retorna o Array com os resultados return lista_resultado end
Explicando o que se passa nesse método:
- lista_resultado: Nosso array onde ficarão os hash de cada resultado individual.
- nos: é o “caminho” no XML que queremos. Tudo o que estiver dentro desse caminho, ele irá nos retornar.
- @obj_rexml.elements.each(nos) do |elemento|: Loop entre os nós dentro do caminho passado.
- resultado: Hash que representa um resultado individual.
- resultado[:titulo] = elemento.text(“Title”): Inserção no Hash (posição :title) o elemento XML que contém um nó chamado “Title”.
- lista_resultado << resultado: Insere o hash no array
- return lista_resultado: Retorna o array com os resultados!
O método .text(nó) chamado pelo objeto elemento significa que queremos o texto que está dentro do nó passado como parâmetro. Quando há um atributo no nó, podemos utilizar o método .attributte(atributo). Por exemplo, supondo que um nó possua um atributo “id=5” da seguinte forma: <title id=”5”>Texto do Título</title>. Então poderíamos utilizar o método assim:
elemento.attributte(“id”)
=> 5
Bem legal!
Pronto! Muito simples. Nossa classe está pronta. No final das contas teremos o seguinte código:
class Buscador require 'rubygems' require 'open-uri' require 'rexml/document' def initialize(keywords, resultado_pagina) @keywords = keywords @resultado_pagina = resultado_pagina @url_yahoo = "http://api.search.yahoo.com/WebSearchService/V1/ webSearch?appid=YahooDemo&query=#{@keywords}&results=#{@resultado_pagina}" xml_data = open(@url_yahoo) @obj_rexml = REXML::Document.new(xml_data.read) end def buscar lista_resultado = Array.new #array com todos os resultados nos = "ResultSet/Result" @obj_rexml.elements.each(nos) do |elemento| resultado = Hash.new #hash que vai conter um resultado resultado[:titulo] = elemento.text("Title") resultado[:descricao] = elemento.text("Summary") resultado[:link] = elemento.text("Url") resultado[:tipo] = elemento.text("MimeType") lista_resultado < < resultado end return lista_resultado end end
Para testarmos a classe recém-criada, você pode implementar o seguinte script logo após o fechamento da classe:
# Configurações do script # As configurações abaixo são configurações básicas para uso no # webservie do Yahoo. keywords = "metallica+one" resultados_por_pagina = 10 busca = Buscador.new(keywords, resultados_por_pagina) resultados = busca.buscar resultados.each do |item_achado| puts "Titulo: #{item_achado[:titulo]}" puts "Descricao: #{item_achado[:descricao]}" puts "Link: #{item_achado[:link]}" puts "Tipo: #{item_achado[:tipo]}" puts "-------------------------------------" end
Executando o nosso exemplo teremos os seguintes exemplos de resultados:
Titulo: One (Metallica song) - Wikipedia, the free encyclopedia
Descricao: Metallica won their first Grammy Award in 1990 for "One", winning Best Metal ... "One" was written in November 1987 by Metallica's principal composers — rhythm ...
Link: http://en.wikipedia.org/wiki/One_(Metallica_song)
Tipo: text/html
-------------------------------------
Titulo: YouTube - Metallica - One
Descricao: Video of One by MetallicAMovie: Johnny Got His Gun ... one of the best songs by MetallicA. kingxwrong (2 hours ago) Show Hide +1. Marked as spam ...
Link: http://www.youtube.com/watch?v=-j39ABZyzek
Tipo: text/html
-------------------------------------
Titulo: YouTube - Metallica- One
Descricao: Metallica's music video "One" ... One - Metallica (Live 1989) 07:00 From: metallicafx. Views: 2,551,898. Loading...
Link: http://www.youtube.com/watch?v=JwW9L_qzqp8
Tipo: text/html
Com esse simples (bem simples mesmo) exemplo que criamos, mostramos a força do REXML. Usando o próprio Yahoo, podemos criar nosso próprio search engine com o Rails baseado no motor de busca do Yahoo. Por que não? Afinal as possibilidade são infinitas.
Se quiser se aprender mais sobre a manipulação de REXML segue alguns links:
- API do REXML: http://www.ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html
- Sobre o Electric XML: http://www.xml.com/pub/r/1098
- Yahoo Developer Network: http://developer.yahoo.com/
- Tutorial um pouco mais complexo: http://www.xml.com/pub/a/2005/11/09/rexml-processing-xml-in-ruby.html
É isso pessoal. Espero que tenham gostado do REXML assim como eu e até o próximo post!





Comentários