Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 28/09/2006, à 20:39

foch

[Résolu] Bugs graphiques avec Python et PyGTK

Hello,

à la suite de ce post : http://forum.ubuntu-fr.org/viewtopic.php?id=61019
où je présente mon programme de téléchargement de musique sur RadioBlogClub, j'aimerais bien un peu d'aide pour m'aider à corriger les bugs graphiques !
J'ai remarqué que souvent, au deuxième téléchargement, le changement de bureau ou l'utilisation de l'ascenceur fait planter le bouzin.

#!/usr/bin/env python

###
#
# RBCD - RadioBlogClub Downloader - Download songs from RadioBlogClub.
# Copyright (C) 2006 Julien Faucher <faucherj AT gmail DOT com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
###

__version__ = "1.0-beta1b"
__date__ = "27/09/2006"

import urllib, re, sys, gobject, gtk, threading, os

# download folder
result_folder = "~/rbcd_result"

(COLUMN_NUMBER, COLUMN_DOWNLOAD, COLUMN_NAME) = range(3)


class UserInterface(gtk.Window):
    def __init__(self, parent=None):
        """ Create window and model """
        
        # create window, etc
        gtk.Window.__init__(self)
        try:
            self.set_screen(parent.get_screen())
        except AttributeError:
            self.connect('destroy', lambda *w: gtk.main_quit())
        self.set_title('RadioBlogClub Downloader')

        self.set_border_width(8)
        self.set_default_size(300, 250)

        vbox = gtk.VBox(False, 8)
        self.add(vbox)

        # top part of window
        box_top = gtk.HBox(False, 5)

        self.label = gtk.Label('Enter keywords :')
        self.entry = gtk.Entry(max=0)
        self.search = gtk.Button(stock=gtk.STOCK_FIND)

        box_top.pack_start(self.label, False, False)
        box_top.pack_start(self.entry, False, False)
        box_top.pack_start(self.search, False, False)

        self.search.connect("clicked", self.searchSongs, None)
        self.entry.connect("activate", self.searchSongs, None)
          
        vbox.pack_start(box_top, False, False)

        # middle part of window
        sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        vbox.pack_start(sw)

        # create tree model
        self.model = gtk.ListStore(gobject.TYPE_INT,
                                   gobject.TYPE_BOOLEAN,
                                   gobject.TYPE_STRING)
        
        # create tree view
        self.treeview = gtk.TreeView(self.model)
        self.treeview.set_rules_hint(True)
        self.treeview.set_search_column(COLUMN_NAME)

        sw.add(self.treeview)

        # down part of window
        box_down = gtk.HBox(False, 5)
        
        self.state_label = gtk.Label('')
        download = gtk.Button('Download')
        exitb = gtk.Button(stock=gtk.STOCK_QUIT)
        aboutb = gtk.Button(stock=gtk.STOCK_DIALOG_INFO)
        
        box_down.pack_end(exitb, False, False)
        box_down.pack_end(aboutb, False, False)   
        box_down.pack_end(download, False, False)

        box_down.pack_start(self.state_label, False, False)
        
        exitb.connect_object("clicked", gtk.Widget.destroy, self)
        download.connect("clicked", self.download, None)
        aboutb.connect("clicked", self.about, None)
        
        vbox.pack_start(box_down, False, False)

        # create columns
        self.add_columns(self.treeview)

        # change window size
        self.resize(800, 500)

        # print everything
        self.show_all()

    def add_columns(self, treeview):
        """ Add the 3 columns """

        # column for fixed toggles
        renderer = gtk.CellRendererToggle()
        renderer.connect('toggled', self.select_toggled, self.model)

        column = gtk.TreeViewColumn('Select', renderer, active=COLUMN_DOWNLOAD)

        # set this column to a fixed sizing(of 50 pixels)
        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
        column.set_fixed_width(50)
        treeview.append_column(column)
        
        # column for description
        column = gtk.TreeViewColumn('#', gtk.CellRendererText(),
                                     text=COLUMN_NUMBER)
        column.set_sort_column_id(COLUMN_NUMBER)
        treeview.append_column(column)
        
        # column for description
        column = gtk.TreeViewColumn('Song name', gtk.CellRendererText(),
                                     text=COLUMN_NAME)
        column.set_sort_column_id(COLUMN_NAME)
        treeview.append_column(column)

    def select_toggled(self, cell, path, model):
        """ Change the select status """
        
        # get toggled iter
        iter = model.get_iter((int(path),))
        download = model.get_value(iter, COLUMN_DOWNLOAD)

        # do something with the value
        download = not download

        # set new value
        model.set(iter, COLUMN_DOWNLOAD, download)

    def searchSongs(self, widget, data=None):
        """ Start searching songs according to the given key words """

        self.setStateText("Starting research...")
        print "Starting research..."
        
        text = self.entry.get_text()
        (self.songs, self.data) = Search.getListSongs(text.split(" "))
        self.clearList()
        self.createList()

        self.setStateText("Research done.")
        print "Research done."

    def download(self, widget, data=None):
        """ Start downloading the selected songs """
        
        down = Download(self, self.songs, self.model)
        down.start()

    def createList(self):
        """ Create the song list """
        
        for item in self.data:
            iter = self.model.append()
            self.model.set(iter,
                           COLUMN_NUMBER, item[COLUMN_NUMBER],      
                           COLUMN_DOWNLOAD, item[COLUMN_DOWNLOAD],
                           COLUMN_NAME, Search.shortName(item[COLUMN_NAME]))

    def clearList(self):
        """ Clear the song list """
        
        self.model.clear()

    def setStateText(self, text):
        """ Change state text """
        
        self.state_label.set_text(text)

    def about(self, widget, data=None):
        """ Print an about dialog window"""
        
        dialog = gtk.AboutDialog()
        dialog.set_name("RBCD")
        dialog.set_comments("A program to download songs from RadioBlogClub")
        dialog.set_copyright("\302\251 Copyright 2006 Julien Faucher")
        dialog.set_website("http://www.dobitchu.info/blog")
        dialog.set_license('GNU General Public License version 2')
        dialog.set_version(__version__)
        dialog.set_authors(['Julien Faucher <faucherj@gmail.com>'])
        
        # close dialog on user response
        dialog.connect("response", lambda d, r: d.destroy())
        dialog.show()

    def main(self):
        """ Main function, one to rule them all """
        
        # create download folder
        if not os.path.isdir(os.path.expanduser(result_folder)):
            os.mkdir (os.path.expanduser(result_folder)) 

        gobject.threads_init()
        gtk.main()
        return 0


class Search:
    @staticmethod
    def changeRBSExtension(file):
        """ Change the RBS extension to MP3 """
        
        name = file.split("/")[-1].split(".")

        # remove some extensions
        name = [part for part in name
                if not part.lower() in ("rbs", "mp3")]
            
        # the file is a mp3, add .mp3 at the end of the name
        name.append("mp3")
        return ".".join(name)

    @staticmethod
    def searchURL(i, params):
        """ Return the URL to search the MP3 """

        url = "http://www.radioblogclub.com/search/" + str(i) + "/" + params
        
        try:
            return urllib.urlopen(url).read()
        except IOError:
            print "Error : could not connect"
            sys.exit(1)
            
    @staticmethod
    def shortName(name):
        """ Cut out too long name """
        
        if len(name) > 80:
            name = name[0:79] + "..."
        
        return name

    @staticmethod
    def getListSongs(text):
        """ Main function, one to rule them all """

        # get the webpage data
        data = Search.searchURL(0, "_".join(text))
        lines = data.split('\n')

        # regular expression to find the number of songs
        reg1 = re.compile('^.*of about <b>(.*)</b> tracks for.*$')

        n_songs = 0
    
        # get the number of songs
        for line in lines:
            if reg1.match(line):
                n_songs = int(reg1.search(line).groups()[0])
                break

        # if no song is found, exit
        if n_songs == 0:
            return ([], [])

        # get the number of pages to browse
        n_pages = n_songs / 50 + 1

        # download the pages
        pages = []
        pages.append(lines)
        numbers = [i * 50 for i in range(1, n_pages)]
        for i in numbers:
            pages.append(Search.searchURL(i, "_".join(text)).split('\n'))

        # regular expression to find the song URLs
        reg2 = re.compile('^.*<td><a href=\"(/open/.*)\">(.*)</a></td>.*$')
        songs = []
        data = []
        i = 0
    
        # parse the HTML data to find the songs and save in a list
        for page in pages:
            for line in page:
                if reg2.match(line):
                    result = reg2.search(line).groups()
                    try:
                        url = unicode(result[0], "utf-8")
                        name = unicode(result[1], "utf-8")
                        songs.append((url, name))
                        data.append((i + 1, False, name))
                        i += 1
                    except UnicodeDecodeError:
                        # encoding error: skip song
                        print name + " : Encoding error. Skipping song."

        return (songs, data)


class Download(threading.Thread):
    def __init__(self, parent, songs, model):
        """ Init the thread """
        
        threading.Thread.__init__(self)
        self.parent = parent
        self.songs = songs
        self.model = model
        
    def run(self):
        """ Thread main function """
        
        gtk.threads_enter()

        # clear state text 
        self.parent.setStateText("")

        # init the counters
        counter_ok = 0
        counter_all = 0

        # iter on all the paths
        iter = self.model.get_iter_first()
        while iter is not None:
            number = self.model.get_value(iter, 0)
            selected = self.model.get_value(iter, 1)
            iter = self.model.iter_next(iter)

            # if the song is selected for download...
            if selected:
                counter_all += 1
                name = self.songs[number - 1][1]
                name_search = name.replace('(', '\(').replace(')', '\)')\
                              .replace('[', '\[').replace(']', '\]')\
                              .replace('\'', '\\\\\'')

                # change the extension to .mp3
                name = Search.changeRBSExtension(name)

                self.parent.setStateText("Downloading %s..." % (Search.shortName(name), ))

                url = "http://www.radioblogclub.com" + self.songs[number - 1][0]\
                      .replace(' ', '%20')

                print "Downloading %s" % (name, )
                print "from %s" % (url, )

                # get the HTML file with the RBS adress
                playlist = urllib.urlopen(url).read().split('\n')

                # get the RBS file URL
                reg3 = re.compile('^.*blogThis\(\'(.*' + name_search + '\.rbs)\'.*$')

                # find the URL
                url = ""
                for line in playlist:
                    if reg3.match(line):
                        url = reg3.search(line).groups()[0]\
                              .replace('\\', '').replace(' ', '%20')
                        break

                # the RBS file was not found
                if url == "":
                    self.parent.setStateText("Song not found. (Maybe the file was a SWF)")
                    print "Song not found. (Maybe the file was a SWF)"
                    continue

                # download the file
                try:
                    print "Downloading to %s..." % (result_folder, )
                    urllib.urlretrieve(url, os.path.join(os.path.expanduser(result_folder),
                                                         name))

                    ### TODO : check out if the file is a valid mp3

                    counter_ok += 1
                    print "Download successful."
                except IOError:
                    self.parent.setStateText("Download failed.")
                    print "Download failed."

                print

        result = "Downloaded %i song%sout of %i." % (counter_ok,
                                                     counter_ok > 1 and 's ' or ' ',
                                                     counter_all)
        self.parent.setStateText(result)
        print result
        
        gtk.threads_leave()


# program entry point
if __name__ == "__main__":
    GUI = UserInterface()
    GUI.main()

Si une ame charitable pouvait bien me fournir quelques conseils pour améliorer mon code, je lui en serais très reconnaissant !

Merci big_smile

EDIT : Trouvé ! En fait il fallait lire la doc !
http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq20.006.htp

Dernière modification par foch (Le 01/10/2006, à 12:24)


De retour sous Ubuntu après quelques années sous ArchLinux.

Programme de téléchargement de musique qui ne marche plus vraiment.

Hors ligne