Programação, diversão e arte. Por Ricardo Giaviti
Posts tagged automatizacao
Ruby para tudo!
Sep 6th
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)





Recent Comments