31 may. 2011

Banshee y su superioridad sobre iTunes



Mucha gente vive matada por estos productos de apple pero cuando se trata de software Banshee le da tres patadas a iTunes y es un apartado fundamental para la felicidad del usuario.

Pero para mostrar porque Banshee es superior que iTunes es necesario ver donde están las ventajas.

Resulta que tengo una colección musical grande y unos 160 vídeos musicales mas o menos. Para mi es importante que toda mi música este organizada en todo momento, con eso me refiero a metadatos, portadas de albums y carpetas. Ya en este punto esta ganando Banshee porque me permite tener mi jerarquía de carpetas de la siguiente forma. 


Se equivoca el que piensa que eso lo hace el usuario. Eso es una labor que hace Banshee, el organiza automáticamente cada que ingresa una canción a mi colección creando la carpeta del artista, la carpeta del álbum y renombrado el archivo con Artista - Titulo. extensión. 

Es lo que se dice un proceso indoloro para mi como usuario, aparte de hacer esto, detecta automáticamente los Pulsos Por Minuto (PPM) para que después cree listas inteligentes y automáticas basadas en estos pulsos.

En las preferencias Banshee tiene algunas, bien interesantes.
Escribe automáticamente los metadatos en los archivos como por ejemplo, portada, numero de reproducciones, artista, titulo, año, numero de estrellas (favoritos), actualiza los nombres de los archivos en las carpetas que vimos anteriormente, corrige automáticamente el sonido si esta muy bajo con ReplayGain y reproduce de forma continua y sin huecos entre las canciones.

Y se equivocan si creen que eso es todo, hasta este momento, el usuario ha tenido muy poco que preocuparse por hacer cosas para el programa. Este es el que hace cosas por el usuario de forma automática y así es como debería ser.

A veces tenemos unas canciones de las cuales tenemos unos datos erróneos, quizás el nombre del artista esta mal o falto una tilde o alguna cosa, pues bueno Banshee lo hace todo por ti. Si tienes cuenta en Last FM, Banshee detecta que canciones tienen metadatos erróneos y te ofrece corregirlos de forma automática, tu solo le das click en reparar y el hace todo el trabajo pesado.


Para algunos metódicos como yo, tener las portadas de todos los albums es importante, porque nos permite tener una idea visual de nuestra música. Eso de meter el jpeg a cada archivo de música es para usuarios de la era de piedra. Banshee se conecta con 5 centrales que almacenan portadas y con solo meter la música busca y descarga las portadas.

Ademas te permite ver la música que otros computadores en tu red compartan por DAAP y ni que hablar de permitir importar tus listas y música desde iTunes, Amarok, Rhythmbox.

Si de comprar música se trata todos los que tienen iTunes están atados al servicio de Apple. Pues bueno con Banshee NO. Puedes usar Ubuntu Music, Emusic, Amazon MP3, comprar y automáticamente descarga, tagea y guarda en carpetas.


Y siempre podras ver muestras de tu musica a comprar.
Que te gusta mucho Last FM y no quiere descargar un plugin para que tu reproductor funcione con este servicio, pues Banshee lo tiene y cuando lo actives envía información de que estas escuchando a LastFM.


Que quieres que banshee sea tu DJ personal, pues también lo puede hacer, solamente le dices que criterio quieres y el crea una reproducción continua de 10 en 10 canciones que sean compatibles por genero, artista, puntuación o como quieras.

Que quieres una interfaz sencilla, Banshee te la ofrece.

Y hasta te ofrece 3 diferentes UI's para que disfrutes tu música al máximo, cada una pensada para distintos casos.
La Interfaz para netbooks que puedes activar con dar click en Banshee-Meego se ve bien limpia y ligera para mostrarte mucha información, teniendo en cuanta la limitación de espacio en los netbooks y tablets.

La interfaz Muinshee esta pensada para los teléfonos Nokia pero también se puede usar dentro del escritorio siendo esta muy simple y pequeña..



Que eres muy chilletas y quieres tener cover flow de iTunes, pues Banshee lo tiene.


No solo hace eso, también te descarga la letra de la canción que estés escuchando y te permite entrar a Wikipedia desde el mismo reproductor para que veas información del artista.


Te gusta que te recomienden música ?. A quien no. Pues Banshee con Last FM lo hace para ti.


Al algunas personas les gusta descargar Podcast, Presentaciones, Libros y demás. Banshee viene con un sistema llamado Internet Archive que permite buscar este tipo de archivos que tengan licencias libres y te permite descargar entre una colección gigantesca de archivos.

Esto es solo una parte de las cosas que Banshee tiene que lo hacen mil veces una mejor opción a iTunes. Y no solo lo puedes tener en Linux, también esta disponible para Mac y en versión Beta para Windows.

Y si ya se que me van a decir que para sincronizar el Ipod o Ipad requieren iTunes. Sin duda lo requieren si como yo tienen un dispositivo de Apple superior a G5. Banshee es capaz de sincronizar Ipods G1, G2, G3 Y G4 y cualquier dispositivo Android y con una particularidad superior a iTunes y es que no requiere borrar la música sincronizada en otro equipo.

Se me olvidaba que en Synaptic Banshee cuenta con 25 plugins adicionales, que permiten extender las funcionalidades de este reproductor fabuloso.

Todo esto y mas hacen de Banshee un mejor reproductor a iTunes. Si quieren argumentar, ahí están los comentarios abiertos.

18 may. 2011

Dhcp3 muy Fácil en Ubuntu 11.04 y Compartir Internet


Un servidor DHCP es un servicio de red que permite que computadores huespedes conectados a un servidor reciban de forma transparente la configuración de red de un servidor.

En ubuntu es relativamente fácil activar un servidor DHCP, voy a explicar que hay que hacer y que significa cada elemento paso a paso.

Lo primero seria instalar nuestro servidor dhcp3, para ello buscamos en centro de software en synaptic o desde el terminal con el comando.

sudo apt-get install dhcp3-server

El siguiente paso es editar el archivo de configuracion del dhcp3-server para ello en el terminal.

sudo gedit /etc/dhcp/dhcpd.conf

Vamos a cambiar las linea 24 que se encarga de habilitar y dar autorización al servidor dhcp3 para encargarse de los clientes.
De la linea 53-60 voy a explicar.

Linea 53: Define la red que crearemos desde nuestro servidor.
Linea 54: Define el rango de unidades ip que nuestro servidor entregara a los clientes, en este caso el primero cliente que se conecte tendrá 192.168.1.5 y el ultimo 192.168.1.100, si solo tenemos 10 computadores clientes en vez de 95 podemos usar 192.168.1.15 y eso permitirá 10 clientes.
Linea 55: Esta linea define el nombre del servidor pueden poner cualquier cosa que se les ocurra.
Linea 56: Define el nombre interno del servidor.
Linea 57: La puerta de enlace predeterminada al servidor o router cuando usan un router.
Linea 58: La puerta de salida, si vamos a ofrecer internet debemos cerrarla en el valor de cierre del netmas es decir que seria 255, algunas personas usan 254 y también es valido.
Linea 59: Define el tiempo mínimo de estadía de un cliente con un IP
Linea 60: Define el tiempo máximo que un cliente tendrá un numero IP asignado por el servidor o router.

# # Sample configuration file for ISC dhcpd for Debian # # Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as # configuration file instead of this file. # # # The ddns-updates-style parameter controls whether or not the server will # attempt to do a DNS update when a lease is confirmed. We default to the # behavior of the version 2 packages ('none', since DHCP v2 didn't # have support for DDNS.) ddns-update-style none; # option definitions common to all supported networks... option domain-name "example.org"; option domain-name-servers ns1.example.org, ns2.example.org; default-lease-time 600; max-lease-time 7200; # If this DHCP server is the official DHCP server for the local # network, the authoritative directive should be uncommented. authoritative; # Use this to send dhcp log messages to a different log file (you also # have to hack syslog.conf to complete the redirection). log-facility local7; # No service will be given on this subnet, but declaring it helps the # DHCP server to understand the network topology. #subnet 10.152.187.0 netmask 255.255.255.0 { #} # This is a very basic subnet declaration. #subnet 10.254.239.0 netmask 255.255.255.224 { # range 10.254.239.10 10.254.239.20; # option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; #} # This declaration allows BOOTP clients to get dynamic addresses, # which we don't really recommend. #subnet 10.254.239.32 netmask 255.255.255.224 { # range dynamic-bootp 10.254.239.40 10.254.239.60; # option broadcast-address 10.254.239.31; # option routers rtr-239-32-1.example.org; #} # A slightly different configuration for an internal subnet. subnet 192.168.1.0 netmask 255.255.255.0 { range 192.168.1.5 192.168.1.100; option domain-name-servers servidor.interno.org; option domain-name "interno.org"; option routers 192.168.1.1; option broadcast-address 192.168.1.255; default-lease-time 600; max-lease-time 7200; #} # Hosts which require special configuration options can be listed in # host statements. If no address is specified, the address will be # allocated dynamically (if possible), but the host-specific information # will still come from the host declaration. #host passacaglia { # hardware ethernet 0:0:c0:5d:bd:95; # filename "vmunix.passacaglia"; # server-name "toccata.fugue.com"; #} # Fixed IP addresses can also be specified for hosts. These addresses # should not also be listed as being available for dynamic assignment. # Hosts for which fixed IP addresses have been specified can boot using # BOOTP or DHCP. Hosts for which no fixed address is specified can only # be booted with DHCP, unless there is an address range on the subnet # to which a BOOTP client is connected which has the dynamic-bootp flag # set. #host fantasia { # hardware ethernet 08:00:07:26:c0:a5; # fixed-address fantasia.fugue.com; #} # You can declare a class of clients and then do address allocation # based on that. The example below shows a case where all clients # in a certain class get addresses on the 10.17.224/24 subnet, and all # other clients get addresses on the 10.0.29/24 subnet. #class "foo" { # match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; #} #shared-network 224-29 { # subnet 10.17.224.0 netmask 255.255.255.0 { # option routers rtr-224.example.org; # } # subnet 10.0.29.0 netmask 255.255.255.0 { # option routers rtr-29.example.org; # } # pool { # allow members of "foo"; # range 10.17.224.10 10.17.224.250; # } # pool { # deny members of "foo"; # range 10.0.29.10 10.0.29.230; # } #}
Con eso hemos terminado de configurar el servidor DHCP, existen aplicaciones que lo hacen de forma gráfica.

Ahora vamos con lo del internet, si el computador servidor cuenta con una tarjeta de salida capaz de prestar internet, con lo anterior sera suficiente, pero si lo que tenemos es dos tarjetas o tres tarjetas de red tendremos que hacer algunas cosas.

Lo primero sera tener instalado el network-manager
Y lo configuramos como se ve en la imagen, poniendo en metodo compartir con otros equipos o si es solo con un equipo adicional le damos en enlace local. Estos pasos son útiles si no te interesa de a mucho como obtiene la Ip el computador cliente y si tu idea es solo conectar dos laptops y que una le de internet a la otra sin estar usando nada DHCP y esas cosas.


Otra forma de realizar el mismo paso, si deseas tener mas control es instalar Firestarter

sudo apt-get install firestarter

Este tiene un asistente.
En el paso 1 te pide que le digas como obtienes el internet, en mi caso es desde la inalambrica.
En el paso 2 te pide que le digas porque dispositivo quieres compartir Internet, en mi caso es desde la tarjeta de red a donde le voy a conectar otra laptop
Con esos dos pasos es suficiente.

Espero que les ayude este tutorial.

14 may. 2011

GtkBuilder y Python 8

Si estas mirando esta entrada, es buena idea que revises las anteriores.

En este nueva entrada vamos a trabajar sobre el dialogo de guardar, vamos a refinarlo y vamos dejarlo listo para configurar los últimos elementos de la interfaz, lo demás sera refinar el código en algunas partes.
Voy entonces a explicar cada uno de los elementos del codigo.
Las lineas 3, 4, 5, 6 Básicamente están definiendo un formato de archivo a guardar, este caso el formato tiene como nombre Lista Multimedia y la extensión es pls que es básicamente una extensión que programas como Banshee y Totem usan para contenido multimedia diverso.

Como en el caso de los diálogos de abrir y seleccionar carpeta si la respuesta es afirmativa (-5) lo primero que tenemos que hacer es obtener el nombre que el usuario le ponga a la lista, esto se hace con la linea 12 usando el comando .get_filename().
La linea 13 es particularmente importante porque se utiliza para crear cualquier tipo de archivos, ya sea de texto, lista de música, base de datos y todo lo que se puedan imaginar, el comando open(filename + ".pls", w) lo que hace es crear un archivo con el nombre que se obtenga de la variable filename y lo terminara con la extensión .pls, la letra W quiere decir Write lo que significa que le damos permiso a este archivo de escribir.
La linea 14 le va a poner un header o titulo al archivo que hemos creado, el formato pls siempre tiene un titulo en corchetes con el nombre playlist y el valor que le sigue es básicamente es igual a dar un enter dentro del archivo.

#Definicion del comando Guardar Permite guardar una lista def showSave(self, widget): self.filterbox.set_name("Lista Multimedia") self.filterbox.add_pattern("*.pls") self.save.add_filter(self.filterbox) respt = self.save.run() self.save.remove_filter(self.filterbox) self.save.hide() if respt == -5: n = 0 filename = self.save.get_filename() playlistsaved = open(filename + '.pls', 'w') playlistsaved.write("[playlist]" + "\n") iter=self.medialist.get_iter_first() while iter: n+=1 rutas = self.medialist.get_value(iter,1) archivoss = self.medialist.get_value(iter,0) allmusicfiles = rutas+"/"+archivos pathname = urllib.pathname2url(os.path.abspath(allmusicfiles)) playlistsaved.write("File"+str(n)+"=file://"+pathname.encode('utf-8') + "\n") iter = self.medialist.iter_next(iter)


En la linea 16 vamos a crear un iter de la medialist y vamos iterar por cada uno de los elementos de la lista y vamos a obtener de esta la columna 0 y 1, para crear un listado completo de los archivos con nombre y ruta.

En la linea 23 vamos a transformar todos las rutas a Uris. Yo se alguien me puede preguntar porque vamos a hacer esta transformación y porque en vez de hacer esto no usamos desde el principio get_uris() en vez de get_filenames(), voy a explicar con un ejemplo y dare la respuesta con el ejemplo.

Ejemplo:
El resultado del comando get_filenames() es este: /home/geojorg/Música/Pink/Pink - Just Like a Pill.mp3
El resultado del comando get_uris() es: file:///home/geojorg/M%C3%BAsica/Pink/Pink%20%26%20-Just%20Like%20a%20Pill.mp3

Ambos resultados son archivos y ambos son validos en todo el sentido de la palabra, el problema de trabajar con Uris es que toca hacerles una pequeña transformación antes de poder usarlos, lo primero seria eliminar file:// y pasar el resto del  nombre a utf8 y para exportarlos nuevamente toca transformarlos. Por recomendación la mayoría de las personas que saben del tema recomiendan trabajar con Uris, pero yo tengo una aproximación distinta y voy a dar la explicación. Yo siempre prefiero agregar código a quitar código, cuando uno ve un código por primera vez es muy difícil quitar cosas. Si quitas algo puedes dañar lo demás y se vuelve un lió.

Con agregar la linea 23 convertimos el nombre de los archivos a Uris, esto se hace con dos comandos.
os.path.abspath() Este convierte cualquier ruta a un archivo en un elemento absoluto que este ligado desde la raiz / o c: si se trabaja en windows.
urllib.pathname2url() es un comando que convierte cualquier /home/geojorg en file:///home/geojorg es decir de pathname a url, para ello tenemos que importar el modulo urllib de python con el comando

import urllib

Finalmente la linea 24 guarda un vinculo a un archivo de la siguiente forma, n es un valor iterativo numérico que se usa en este formato de archivo .pls

File1=file:///home/geojorg/M%C3%BAsica/Pink/Pink%20%26%20-Just%20Like%20a%20Pill.mp3

La linea 25 lo que hace es iterar al siguiente elemento y termina cuando ya no hay mas elementos porque todos estos están dentro de un while, pueden guardar alguna lista y usar totem para reproducir lo que acaban de guardar y verán que funciona perfectamente.

En la próxima entrada vamos a configurar los botones de play, stop y cerrar.

El código final es el siguiente:
#!/usr/bin/python import os from gi.repository import Gtk from random import shuffle import urllib filepattern = ( ("MP3","*.mp3"), ("AVI","*.avi"), ("MPEG-4","*.mp4"), ("FLV ","*.flv"), ("OGG","*.ogg"), ) pattern = (".mp3",".mp4",".avi",".flv",".ogg") class main: def __init__(self): # Crea la ventana de trabajo Principal y obtiene los objetos en Glade builder = Gtk.Builder() builder.add_from_file("Multiplay.ui") self.addfile = builder.get_object("Add") self.addfolder = builder.get_object("AddFolder") self.save = builder.get_object("Save") self.about = builder.get_object("About") self.medialist = builder.get_object("MediaList") self.combolist = builder.get_object("combobox1") self.treeview = builder.get_object("TextView") self.up = builder.get_object("Up") self.down = builder.get_object("Down") self.filterbox = Gtk.FileFilter() # Diccionario de eventos y Conexion de los mismos. dict = {"on_Add_clicked": self.showAddFile, "on_AddFolder_clicked": self.showAddFolder, "on_Saved_clicked": self.showSave, "on_About_clicked": self.showAbout, "on_Clearone_clicked": self.clearone, "on_Clearlist_clicked": self.clearlist, "on_Up_clicked": self.updown_move, "on_Down_clicked": self.updown_move, "on_ComboOrder_changed": self.newList, } builder.connect_signals(dict) #Definicion del comando Agregar def showAddFile(self, widget): self.filterbox.set_name("Media Files") for name, pattern in filepattern: self.filterbox.add_pattern(pattern) self.addfile.add_filter(self.filterbox) respt = self.addfile.run() self.addfile.remove_filter(self.filterbox) self.addfile.hide() if respt == -5: fileselected = self.addfile.get_filenames() for files in fileselected: (dirs,files)= os.path.split(files) self.medialist.append([files,dirs]) #Definicion del comando Abrir Carpeta def showAddFolder(self, widget): self.filterbox.set_name("All Media Files") for names, patterns in filepattern: self.filterbox.add_pattern(patterns) self.addfolder.add_filter(self.filterbox) respt = self.addfolder.run() self.addfolder.remove_filter(self.filterbox) self.addfolder.hide() if respt == -5: addmultiple = self.addfolder.get_filename() for root, dirs, filelist in os.walk(addmultiple): for allfiles in [f for f in filelist if f.endswith(pattern)]: self.medialist.append([allfiles,root]) #Definicion del comando Borrar un Archivo def clearone(self, *args): clearone = self.treeview.get_selection() (model, rows) = clearone.get_selected_rows() for i in rows: iteration=model.get_iter(i) print iteration self.medialist.remove(iteration) #Definicion del comando Borrar Lista def clearlist(self, *args): self.medialist.clear() #Definicion del comando Arriba y Abajo def updown_move(self, button): line = self.treeview.get_selection() (model, rows) = line.get_selected_rows() if button == self.up: for path1 in rows: path2 = int(str(path1))-1 if path2 < 0: return else: iter1 = model.get_iter(path1) iter2 = model.get_iter(path2) model.swap(iter1,iter2) if button == self.down: for path1 in rows: iter1 = model.get_iter(path1) iter2 = model.iter_next(iter1) if iter2 == None: return else: model.swap(iter1,iter2) #Definicion para ordernar la lista def newList(self, widget): var = self.combolist.get_active() #Si se activa Aleatorio if var == 0: n = 0 for musicfiles in self.medialist: n += 1 index = range(0, n) shuffle(index) #Reorganiza la lista de musica llamad medialist if len(index) > 1: self.medialist.reorder(index) #Si se activa Alfabetico if var == 1: iter=self.medialist.get_iter_first() newlistfiles = [] while iter: files = self.medialist.get_value(iter,0) source = self.medialist.get_value(iter,1) newlistfiles.append([files,source]) iter = self.medialist.iter_next(iter) newlistfiles = sorted(newlistfiles) self.medialist.clear() for files,source in newlistfiles: self.medialist.append([files,source]) #Definicion del comando Guardar Permite guardar una lista def showSave(self, widget): self.filterbox.set_name("Lista Multimedia") self.filterbox.add_pattern("*.pls") self.save.add_filter(self.filterbox) respt = self.save.run() self.save.remove_filter(self.filterbox) self.save.hide() if respt == -5: n = 0 filename = self.save.get_filename() playlistsaved = open(filename + '.pls', 'w') playlistsaved.write("[playlist]" + "\n") iter=self.medialist.get_iter_first() while iter: n+=1 rutas = self.medialist.get_value(iter,1) archivos = self.medialist.get_value(iter,0) allmusicfiles = rutas+"/"+archivos pathname = urllib.pathname2url(os.path.abspath(allmusicfiles)) playlistsaved.write("File"+str(n)+"=file://"+pathname.encode('utf-8') + "\n") iter = self.medialist.iter_next(iter) #Definicion del Comando Acerca de: def showAbout(self, widget, data=None): self.about.run() self.about.hide() #Ejecucion del programa if __name__ == "__main__": main() Gtk.main()

11 may. 2011

GtkBuilder y Python Parte 5

Si estas leyendo esta entrada quizás te interesaría revisar las anteriores.

Esta entrada quizás es la mas relevante para el buen funcionamiento del programa, hasta este punto hemos configurado los diálogos de abrir y seleccionar carpeta. Por suerte para nosotros Python ha creado módulos que hacen el trabajo bastante simple, lo que vamos a configurar es quizas una de las características más difíciles de trabajar cuando se hace en Pygtk, me estoy refiriendo al Gtk.Treeview que es sin duda alguna una pesadilla, pero les voy a mostrar de forma fácil como trabajar esto.

Gracias a Glade ya nosotros creamos un modelo que se llama MediaList y otro que se llama OrderList los TreeView básicamente permiten construir modelos dentro de ellos, esto suele ser un tema altamente complejo porque en Pygtk es un monstruo esto.

Nosotros contamos con la suerte de haber creado un Gtk.Liststore y asociarlo a un Gtk.Treeview y a su vez dentro del Liststore hemos creado dos gchararray, si yo se que suena todo de una forma miedoso pero todo eso lo hicimos en glade en el tutorial 3 sin necesidad de crear todo una cadena de códigos en Pygtk.
Hemos reducido todo este texto a una sola linea y nos hemos ahorrado usar Pygtk que es una tecnología que ya no se esta usando y permanecemos con tecnología moderna como Gtk 3 y Gtk 2 dentro de GtkBuilder

self.medialist = builder.get_object("MediaList")

Esta linea que esta en roja va justo donde hemos llamado los GtkBuilders quedando ubicada como la linea numero 9 de nuestro codigo.

def __init__(self): # Crea la ventana de trabajo Principal y obtiene los objetos en Glade builder = Gtk.Builder() builder.add_from_file("Multiplay.ui") self.addfile = builder.get_object("Add") self.addfolder = builder.get_object("AddFolder") self.save = builder.get_object("Save") self.about = builder.get_object("About") self.medialist = builder.get_object("MediaList") self.filterbox = Gtk.FileFilter()



Ya se que aun no entienden que hemos logrado, pero les voy a dar el ejemplo más claro, vamos a terminar de configurar definitivamente los dialogos de Abrir y Seleccionar Carpeta y vamos a mostrar cada uno de los archivos que seleccionemos dentro del programa en el Gtk.Treeview.

Para ello tenemos que importar un modulo que trabaja con archivos y permitirá ahorrar mucho trabajo, este modulo es usado para todo lo relacionado con archivos, cosas como abrir, ver rutas, guardar y demás, la belleza de python reside en que existe muchos módulos que hacen la vida tan simple.

import os


Esta linea la ponemos antes de from gi.repository import Gtk


Ahora debemos recordar la definición del comando Agregar, como pueden notar ahora las lineas 14, 15 y 16 han sido agregadas, la linea 14 lo que hace es iterar con todos los nombres de archivos seleccionados, recuerden que en la linea 13 usamos get_filenames() que obtiene todos los nombres de archivos seleccionados en oposición a get_filename() que solo obtiene el nombre de un archivo seleccionado. La linea 15 va a crear una tupla con dos columnas, la primera contendrá las direcciones y la segunda contendrá el nombre de los archivo, la función os.path.split(files) es una función que divide en dos columnas el nombre de un archivo de la siguiente forma.

Ejemplo:
Seleccionamos el archivo siguiente:
/home/geojorg/Música/Aerosmith/Aerosmith - Just Push Play.mp3
Al aplicar os.path.split a la dirección anterior nos mostrara lo siguiente.("/home/geojorg/Música/Aerosmith/" , "Aerosmith - Just Push Play.mp3")
Como pueden ver creo una tupla con dos columnas, en la primera esta la ruta del archivo y en la segunda el nombre del archivo.

#Definicion del comando Agregar def showAddFile(self, widget): self.filterbox.set_name("Media Files") for name, pattern in filepattern: self.filterbox.add_pattern(pattern) self.addfile.add_filter(self.filterbox) respt = self.addfile.run() self.addfile.remove_filter(self.filterbox) self.addfile.hide() if respt == -5: fileselected = self.addfile.get_filenames() for files in fileselected: (dirs,files)= os.path.split(files) self.medialist.append([files,dirs])


Ahora que hemos creado la tupla con la linea 15 lo ideal es es que la linea 16 agregue estos dos elementos a nuestro Gtk.Treeview, lo agregara de la siguiente forma, la primera columna es la 0 y esa columna contendrá los nombres del archivo, en nuestro ejemplo seria Aerosmith - Just Push Play.mp3 y la columna 1 no es visible pero en ella guardara la Ruta /home/geojorg/Música/Aerosmith/ se preguntaran porque esto. Les debo decir que la respuesta esta en el tutorial 2, se acuerdan que pusimos un valor de 0 al crear el TextView, bueno eso básicamente hace que solo se pueda ver la columna 0 y esa es la idea.

Ahora en la definición de Seleccionar Carpeta vamos a hacer unos cambios también. Hemos agregado la linea 16, 17 y 18. Vamos a explicar entonces.
La linea 16 va iterar en la carpeta seleccionada con la linea 14, para carpetas siempre usamos get_filename() porque solo vamos a seleccionar una y de ahí seleccionamos todas la hijas que estén dentro de esta, se puede lograr esto usando el comando os.walk que es un comando que funciona de forma iterativa y recursiva hacia abajo. Para que quede un poco mas claro vamos a hacer un ejemplo.


Ejemplo:
Supongamos que vamos a seleccionar la carpeta Música y esta carpeta contiene 3 más. Las carpetas hijas son: Aerosmith, Pink, Rolling Stones y cada una de estas tiene varios archivos dentro.
os.walk es capaz de buscar dentro de Música las 3 carpetas y ver que archivos hay dentro de estas, al final arroja 3 parámetros root, dirs, filelist.

Root indica cual es la fuente, en nuestro caso sera:
/home/geojorg/Música

Dirs indica todas las carpetas dentro de Root
["Aerosmith","Pink","Rolling Stones"]

Filelist indica todos los archivos dentro de Dirs
["Aerosmith - Just Push Play.ogg ","Pink - Just Like a Pill.mp3","Rolling Stones - Angie.mp3"]


Como pueden ver os.path no crea tuplas, crea listas y esto no es ideal, por eso hay que agregar la linea 16.


La linea 16 funciona de la siguiente forma. Para todos los archivos que están dentro de un valor que esta almacenado en filelist va a buscar algo. Ese algo es este comando endswith. Voy a explicar que hace entonces con un ejemplo


Ejemplo:
Tenemos los 3 archivos y ya los tenemos en una lista en columna que fue lo que logramos con el comando f for f in filelist
Quedaron representados entonces tal como se ve más abajo, el comando endswith se traduce al español de forma similar a "termina en" y lo que hace es buscar un patrón final dentro de un listado, en este caso lo que va a buscar es que la lista tenga archivos que terminen en "mp3, mpeg, avi, ogg" y los que terminen en alguna de esas extensiones los pondrá como validos (True) , los que no terminen en esas extensiones no serán validos (False) entonces los eliminara de la lista. El comando endswith siempre se aplica a una variable, en este caso se lo aplicamos a f por eso queda f.endswith y dentro del paréntesis estarán todos las extensiones (mp3,mpeg y demas) pero para evitar meter todo una lista de extensiones es más fácil crear una variable que contenga todas las extensiones que nos interese.

pattern = (".mp3",".mp4",".avi",".flv",".ogg")

Aerosmith - Just Push Play.ogg
Pink - Just Like a Pill.mp3
Rolling Stones - Angie.mp3

#Definicion del comando Abrir Carpeta def showAddFolder(self, widget): self.filterbox.set_name("All Media Files") for names, patterns in filepattern: self.filterbox.add_pattern(patterns) self.addfolder.add_filter(self.filterbox) respt = self.addfolder.run() self.addfolder.remove_filter(self.filterbox) self.addfolder.hide() if respt == -5: addmultiple = self.addfolder.get_filename() for root, dirs, filelist in os.walk(addmultiple): for allfiles in [f for f in filelist if f.endswith(pattern)]: self.medialist.append([allfiles,root])

Finalmente la linea 18 pondrá dentro del Gtk.Treeview los archivos y la ruta respectivamente en la columna 0 y 1.

En el próximo tutorial vamos a aprender que son los Gtk Tree Iters  y como se relacionan con el Gtk.Treeview, terminaremos entonces de organizar algunos botones que hacen falta como Limpiar, Arriba, Abajo y eliminar.

Cualquier duda no duden en ponerla en los comentarios.

GtkBuilder y Python Parte 4

Si estas mirando esta cuarta entrega es porque de alguna forma ya leíste las anteriores

Aprendiendo GtkBuilder y Python Parte 1

GtkBuilder, Glade y Python Parte 2

GtkBuilder, Glade y Python Parte 3


Como ya pudieron notar en el tutorial 3 entramos ya en el terreno de python y ahora ya no lo vamos a abandonar hasta que terminemos de construir nuestra aplicación, en esta nueva entrada lo que vamos es a refinar algunas cosas de lo que tenemos.

Lo primero que les voy a enseñar es a manejar archivos en python, hasta el momento solo podemos invocar  la ventana que muestra el selector de archivos pero como pueden notar esto no hace absolutamente nada cuando presionamos doble click sobre un archivo. Lo primero que queremos hacer es permitirle al botón abrir hacer alguna cosa, en este caso simplemente le vamos a dar la habilidad de obtener el nombre de los archivos que se seleccionen, esto se hace con el comando get_filenames() que lo que hace es obtener los nombres de los archivos seleccionados por la interfaz self.addfile. Se acuerdan que al botón cerrar y aceptar le pusimos un id de -6 y -5 respectivamente. Bueno el -6 por defecto siempre es cerrar y el -5 implica una respuesta positiva, por eso usamos un if que simplemente hace algo si la respuesta es -5.
#Definicion del comando Agregar def showAddFile(self, widget): respt = self.addfile.run() self.addfile.hide() if respt == -5: fileselected = self.addfile.get_filenames() print fileselected


En este caso si la respuesta del botón es afirmativa (-5) entonces en la variable fileselected va a guardar los nombres de los mismos y los va a imprimir en el terminal con el comando print, mas adelante vamos a mejorar esto importando algunos módulos de python pero por ahora vamos a dejar esta parte así.

Como muchos de ustedes han  notado la mayoría de diálogos de abrir tienen un filtro en la parte de abajo, como se ve en la imagen justo arriba del boton de abrir donde dice Media Files.

Vamos a crear este filtro para nuestra aplicacion, este tipo de filtros se llama Gtk.FileFilter() y lo ideal seria que lo invocáramos debajo de los builders para poder usarlo varias veces en la ventana de abrir carpeta y en la de guardar. Lo invocamos con self.filterbox = Gtk.FileFilter() como se ve en la linea 8

def __init__(self): # Crea la ventana de trabajo Principal y obtiene los objetos en Glade builder = Gtk.Builder() builder.add_from_file("Multiplay.ui") self.addfile = builder.get_object("Add") self.addfolder = builder.get_object("AddFolder") self.save = builder.get_object("Save") self.about = builder.get_object("About") self.filterbox = Gtk.FileFilter()


Con esto listo volvemos a trabajar, para ello vamos a crear una tupla, que es básicamente una lista que contiene dos elementos en forma de columna, a esta tupla le vamos a poner el nombre filepattern o en español seria algo como patronesdearchivo  y lo vamos a ubicar justo antes de la clase main. La primera columna contiene el nombre (name) de los archivos MP3, AVI y la segunda contiene el patron de los archivos (pattern) *.mp3, *.avi

#!/usr/bin/python from gi.repository import Gtk filepattern = ( ("MP3","*.mp3"), ("AVI","*.avi"), ("MPEG-4","*.mp4"), ("FLV ","*.flv"), ("OGG","*.ogg"), ) class main:

Una vez creada esta tupla vamos a continuar trabajando en el dialogo de abrir archivos, para cada elemento en la tupla vamos a crear dos nuevas variables una de nombre Name y la otra de nombre Pattern y todo esto es posible porque usamos un for name, pattern in filepattern: Esto permite iterar sobre la tupla y el comando self.filterbox.add_pattern(pattern) lo que hace es crear el patrón en el filtro. El comando self.addfile.add_filter(self.filterbox) lo que hace es agregar el filtro a la base de nuestro dialogo de abrir archivos, cada vez que creamos un filtro al cerrar la aplicación debemos eliminarlo por eso en la linea 10 agregamos el comando self.addfile.remove_filter(self.filterbox) que lo que hace es eliminar el filtro al cerrar el dialogo.


#Definicion del comando Agregar def showAddFile(self, widget): self.filterbox.set_name("Media Files") for name, pattern in filepattern: self.filterbox.add_pattern(pattern) self.addfile.add_filter(self.filterbox) respt = self.addfile.run() self.addfile.remove_filter(self.filterbox) self.addfile.hide() if respt == -5: fileselected = self.addfile.get_filenames() print fileselected



Hacemos el mismo procedimiento para abrir carpetas y al final nuestro programa queda de la siguiente forma. Por ahora hemos terminado la parte 4 que trataba de mejorar los diálogos de abrir archivos

#!/usr/bin/python from gi.repository import Gtk filepattern = ( ("MP3","*.mp3"), ("AVI","*.avi"), ("MPEG-4","*.mp4"), ("FLV ","*.flv"), ("OGG","*.ogg"), ) class main: def __init__(self): # Crea la ventana de trabajo Principal y obtiene los objetos en Glade builder = Gtk.Builder() builder.add_from_file("Multiplay.ui") self.addfile = builder.get_object("Add") self.addfolder = builder.get_object("AddFolder") self.save = builder.get_object("Save") self.about = builder.get_object("About") self.filterbox = Gtk.FileFilter() # Diccionario de eventos y Conexion de los mismos. dict = {"on_Add_clicked": self.showAddFile, "on_AddFolder_clicked": self.showAddFolder, "on_Saved_clicked": self.showSave, "on_About_clicked": self.showAbout, } builder.connect_signals(dict) #Definicion del comando Agregar def showAddFile(self, widget): self.filterbox.set_name("Media Files") for name, pattern in filepattern: self.filterbox.add_pattern(pattern) self.addfile.add_filter(self.filterbox) respt = self.addfile.run() self.addfile.remove_filter(self.filterbox) self.addfile.hide() if respt == -5: fileselected = self.addfile.get_filenames() print fileselected #Definicion del comando Abrir Carpeta def showAddFolder(self, widget): self.filterbox.set_name("All Media Files") for names, patterns in filepattern: self.filterbox.add_pattern(patterns) self.addfolder.add_filter(self.filterbox) respt = self.addfolder.run() self.addfolder.remove_filter(self.filterbox) self.addfolder.hide() if respt == -5: addmultiple = self.addfolder.get_filename() #Definicion del comando Guardar Permite guardar una lista def showSave(self, widget): self.save.run() self.save.hide() #Definicion del Comando Acerca de: def showAbout(self, widget, data=None): self.about.run() self.about.hide() #Ejecucion del programa if __name__ == "__main__": main() Gtk.main()