class HistoriqueTests( unittest.TestCase ): ## Initialisation def setUp( self ): self.historique = Historique() ## Fin def tearDown( self ): pass def testSingleton( self ): """Test si le pattern singleton est bien en place""" self.assertEqual( id( self.historique ), id( Historique() ) ) def testMauvaisType( self ): """Test si l'historique renvoit bien faux si on lui demande s'il contient une variable qui n'est pas un fichier""" variable = "jeSuisUnString" self.assertEqual( self.historique.comparerHistorique( variable ), False ) def testPresenceElement( self ): """Test si l'historique est capable de retrouver un element""" element = Fichier( "Napoleon", "1804", "Notre Dame", "Sacre Napoleon" ) # On ajoute l'element a l'historique self.historique.ajouterHistorique( element ) # On verifie si l'element y est present self.assertEqual( self.historique.comparerHistorique( element ), True )
class HistoriqueTests(unittest.TestCase): ## Initialisation def setUp(self): self.historique = Historique() ## Fin def tearDown(self): pass def testSingleton(self): """Test si le pattern singleton est bien en place""" self.assertEqual(id(self.historique), id(Historique())) def testMauvaisType(self): """Test si l'historique renvoit bien faux si on lui demande s'il contient une variable qui n'est pas un fichier""" variable = "jeSuisUnString" self.assertEqual(self.historique.comparerHistorique(variable), False) def testPresenceElement(self): """Test si l'historique est capable de retrouver un element""" element = Fichier("Napoleon", "1804", "Notre Dame", "Sacre Napoleon") # On ajoute l'element a l'historique self.historique.ajouterHistorique(element) # On verifie si l'element y est present self.assertEqual(self.historique.comparerHistorique(element), True)
def __init__( self, m3u8URL, nomFichier, navigateur, stopDownloadEvent, progressFnct ): self.m3u8URL = m3u8URL self.nomFichier = nomFichier self.navigateur = navigateur self.stopDownloadEvent = stopDownloadEvent self.progressFnct = progressFnct self.historique = Historique() self.nomFichierFinal = "%s.mkv" % ( self.nomFichier[ :-3 ] )
def __init__( self, manifestURL, nomFichier, navigateur, stopDownloadEvent, progressFnct ): self.manifestURL = manifestURL self.nomFichier = nomFichier self.navigateur = navigateur self.stopDownloadEvent = stopDownloadEvent self.progressFnct = progressFnct self.historique = Historique() self.configuration = Configuration() self.hmacKey = self.configuration[ "hmac_key" ].decode( "hex" ) self.playerHash = self.configuration[ "player_hash" ]
def __init__(self, m3u8Url, outDir, codeProgramme, timeStamp, navigateur, stopDownloadEvent, progressFnct): self.m3u8Url = m3u8Url super(DlM3u8, self).__init__(outDir, codeProgramme, timeStamp, "ts", navigateur, stopDownloadEvent, progressFnct) self.historique = Historique()
def __init__(self): # On cree l'instance de la classe dialog self.dialog = Dialog() self.dialog.setBackgroundTitle("TVDownloader") # On recupere l'instance de API self.api = API.getInstance() # On instancie le gestionnaire de download self.downloader = Downloader() # On instancie le gestionnaire d'historique self.historique = Historique() # On instancie le gestionnaire de preferences self.preferences = Preferences() # Liste des telechargements self.listeTelechargements = [] # Quand le programme se termine, on execute la fonction actionsAvantQuitter atexit.register(self.actionsAvantQuitter) # On commence self.bouclePrincipale()
def __init__(self, manifestUrl, manifestUrlToken, outDir, codeProgramme, timeStamp, navigateur, stopDownloadEvent, progressFnct): self.manifestUrl = manifestUrl self.manifestUrlToken = manifestUrlToken super(DlF4m, self).__init__(outDir, codeProgramme, timeStamp, "tmp.flv", navigateur, stopDownloadEvent, progressFnct) self.historique = Historique() self.configuration = Configuration() self.hmacKey = self.configuration["hmac_key"].decode("hex") self.playerHash = self.configuration["player_hash"]
def Menu_principal(): os.system('cls') print("--".center(92, "-")) print("{0:^32}".format("RESTO DU PEUPLE").center(92, "-")) print("{0:^32}".format("18 RUE DU CUL").center(92, "-")) print("{0:^32}".format("TOMBOUKTOU").center(92, "-")) print("--".center(92, "-")) print("\nMENU PRINCIPAL :\n") print("1. PRISE DE COMMANDE") print("2. GESTION DES STOCK") print("3. GESTION DU MENU") print("4. HISTORIQUE DES COMMANDES") print("5. QUITTER") choice = 0 while choice != 5: choice = int(input("\nQUE VOULEZ VOUS FAIRE ? (1-5) : ")) if choice == 1: Commande() Menu_principal() return elif choice == 2: Stock() Menu_principal() return elif choice == 3: Gestionnaire_menu() Menu_principal() return elif choice == 4: Historique() Menu_principal() return
def __init__(self): # Appel au constructeur de la classe mere QtGui.QMainWindow.__init__(self) ########### # Fenetre # ########### ### # Reglages de la fenetre principale ### # Nom de la fenetre self.setWindowTitle("TVDownloader") # Mise en place de son icone self.setWindowIcon(QtGui.QIcon("ico/TVDownloader.png")) ### # Mise en place des widgets dans la fenetre ### # Widget central qui contiendra tout self.centralWidget = QtGui.QWidget(self) # # Barre du haut # # Layout horizontal qui contiendra les listes deroulantes self.horizontalLayoutBarreHaut = QtGui.QHBoxLayout() # Liste deroulante pour choisir le site (plugin) self.comboBoxSite = QtGui.QComboBox(self.centralWidget) self.horizontalLayoutBarreHaut.addWidget(self.comboBoxSite) # Liste deroulante pour choisir une chaine du site courant self.comboBoxChaine = QtGui.QComboBox(self.centralWidget) self.horizontalLayoutBarreHaut.addWidget(self.comboBoxChaine) # Liste deroulante pour choisir une emission de la chaine courante self.comboBoxEmission = QtGui.QComboBox(self.centralWidget) self.horizontalLayoutBarreHaut.addWidget(self.comboBoxEmission) # # Onglets # # Gestionnaire onglets self.tabWidget = QtGui.QTabWidget(self.centralWidget) # Onglet Fichiers self.tabFichiers = QtGui.QSplitter( self.centralWidget) # L'onglet Fichier contient un splitter self.tabWidget.addTab(self.tabFichiers, u"Choix des fichiers") # Onglet Telechargements self.tabTelechargements = QtGui.QWidget(self.centralWidget) self.tabWidget.addTab(self.tabTelechargements, u"Téléchargements") # # Liste des fichiers # # Layout de grille qui contient le tableau qui liste les fichiers + boutons self.gridLayoutFichiers = QtGui.QGridLayout(self.tabFichiers) # Tableau qui contient la liste des fichiers disponibles pour l'emission courante self.tableWidgetFichier = MyQTableWidget(self.tabFichiers) # Il a 4 colonnes et 0 ligne (pour l'instant) self.tableWidgetFichier.setColumnCount(3) self.tableWidgetFichier.setRowCount(0) # On ajoute les titres self.tableWidgetFichier.setHorizontalHeaderItem( 0, self.tableWidgetFichier.creerItem("")) self.tableWidgetFichier.setHorizontalHeaderItem( 1, self.tableWidgetFichier.creerItem("Date")) self.tableWidgetFichier.setHorizontalHeaderItem( 2, self.tableWidgetFichier.creerItem("Emission")) # On l'ajoute au layout self.gridLayoutFichiers.addWidget(self.tableWidgetFichier, 0, 1, 6, 1) # Icones du tableWidget self.iconeFichier = QtGui.QIcon("ico/gtk-file.svg") self.iconeAjoute = QtGui.QIcon("ico/gtk-add.svg") self.iconeTelecharge = QtGui.QIcon("ico/gtk-apply.svg") # Bouton pour ajouter tous les fichiers a la liste des telechargements self.pushButtonToutAjouter = MyQPushButton(self.tabFichiers) self.pushButtonToutAjouter.setIcon(QtGui.QIcon("ico/gtk-add.svg")) self.pushButtonToutAjouter.setToolTip( u"Ajouter tous les fichiers à la liste des téléchargements") self.gridLayoutFichiers.addWidget(self.pushButtonToutAjouter, 0, 0, 2, 1) # Bouton pour rafraichir le plugin courant self.pushButtonRafraichirPlugin = MyQPushButton(self.tabFichiers) self.pushButtonRafraichirPlugin.setIcon( QtGui.QIcon("ico/gtk-refresh.svg")) self.pushButtonRafraichirPlugin.setToolTip("Rafraichir le plugin") self.gridLayoutFichiers.addWidget(self.pushButtonRafraichirPlugin, 2, 0, 2, 1) # Bouton pour ouvrir la fenetre des preferences du plugin courant self.pushButtonPreferencesPlugin = MyQPushButton(self.tabFichiers) self.pushButtonPreferencesPlugin.setIcon( QtGui.QIcon("ico/gtk-preferences.svg")) self.pushButtonPreferencesPlugin.setToolTip( u"Ouvrir les préférences du plugin") self.gridLayoutFichiers.addWidget(self.pushButtonPreferencesPlugin, 4, 0, 2, 1) # On met en place ce layout sur un widget (pour le splitter) self.widgetFichiers = QtGui.QWidget() self.widgetFichiers.setLayout(self.gridLayoutFichiers) # # Descriptif des fichiers # # Layout de grille self.gridLayoutDescriptif = QtGui.QGridLayout() # Label pour afficher un logo self.logoFichierDefaut = QtGui.QPixmap() self.logoFichierDefaut.load("img/gtk-dialog-question.svg") self.labelLogo = QtGui.QLabel(self.centralWidget) self.labelLogo.setPixmap( self.logoFichierDefaut.scaled(QtCore.QSize(150, 150), QtCore.Qt.KeepAspectRatio)) self.gridLayoutDescriptif.addWidget(self.labelLogo, 0, 0, 1, 1) # Zone de texte pour afficher un descriptif self.plainTextEdit = QtGui.QPlainTextEdit(self.centralWidget) self.gridLayoutDescriptif.addWidget(self.plainTextEdit, 0, 1, 1, 2) # On met en place ce layout sur un widget (pour le splitter) self.widgetDescriptif = QtGui.QWidget() self.widgetDescriptif.setLayout(self.gridLayoutDescriptif) # Onrientation verticale du splitter self.tabFichiers.setOrientation(QtCore.Qt.Vertical) # On ajoute les 2 elements au splitter (qui est notre onglet) self.tabFichiers.addWidget(self.widgetFichiers) self.tabFichiers.addWidget(self.widgetDescriptif) # # Liste des telechargements # # Layout de grille qui contient le tableau qui liste les fichiers a telecharger + les boutons pour le controller self.gridLayoutTelechargement = QtGui.QGridLayout( self.tabTelechargements) # Tableau qui contient la liste des fichiers a telecharger self.tableWidgetTelechargement = MyQTableWidget( self.tabTelechargements) # Il a 5 colonnes et 0 ligne (pour l'instant) self.tableWidgetTelechargement.setColumnCount(3) self.tableWidgetTelechargement.setRowCount(0) # On ajoute le titre des 5 colonnes self.tableWidgetTelechargement.setHorizontalHeaderItem( 0, self.tableWidgetTelechargement.creerItem("Date")) self.tableWidgetTelechargement.setHorizontalHeaderItem( 1, self.tableWidgetTelechargement.creerItem("Emission")) self.tableWidgetTelechargement.setHorizontalHeaderItem( 2, self.tableWidgetTelechargement.creerItem("Etat")) # On l'ajoute au layout self.gridLayoutTelechargement.addWidget(self.tableWidgetTelechargement, 0, 1, 4, 1) # Bouton pour monter l'element selectionne tout en haut de la liste self.pushButtonExtremiteMonter = MyQPushButton(self.tabTelechargements) self.pushButtonExtremiteMonter.setIcon( QtGui.QIcon("ico/gtk-jump-to-rtl.svg")) self.pushButtonExtremiteMonter.setToolTip( u"Placer l'élément sélectionné tout en haut") self.gridLayoutTelechargement.addWidget(self.pushButtonExtremiteMonter, 0, 0, 1, 1) # Bouton pour monter l'element selectionne d'un cran dans la liste self.pushButtonMonter = MyQPushButton(self.tabTelechargements) self.pushButtonMonter.setIcon(QtGui.QIcon("ico/gtk-go-up.svg")) self.pushButtonMonter.setToolTip(u"Monter l'élément sélectionné") self.gridLayoutTelechargement.addWidget(self.pushButtonMonter, 1, 0, 1, 1) # Bouton pour descendre l'element selectionne d'un cran dans la liste self.pushButtonDescendre = MyQPushButton(self.tabTelechargements) self.pushButtonDescendre.setIcon(QtGui.QIcon("ico/gtk-go-down.svg")) self.pushButtonDescendre.setToolTip(u"Descendre l'élément selectionné") self.gridLayoutTelechargement.addWidget(self.pushButtonDescendre, 2, 0, 1, 1) # Bouton pour descendre l'element selectionne tout en bas de la liste self.pushButtonExtremiteDescendre = MyQPushButton( self.tabTelechargements) self.pushButtonExtremiteDescendre.setIcon( QtGui.QIcon("ico/gtk-jump-to-ltr.svg")) self.pushButtonExtremiteDescendre.setToolTip( u"Placer l'élément sélectionné tout en bas") self.gridLayoutTelechargement.addWidget( self.pushButtonExtremiteDescendre, 3, 0, 1, 1) # Bouton pour supprimer tous les elements de la liste self.pushButtonToutSupprimer = MyQPushButton(self.tabTelechargements) self.pushButtonToutSupprimer.setIcon(QtGui.QIcon("ico/gtk-cancel.svg")) self.pushButtonToutSupprimer.setToolTip( u"Supprimer tous les téléchargements") self.gridLayoutTelechargement.addWidget(self.pushButtonToutSupprimer, 0, 2, 1, 1) # Bouton pour supprimer de la liste les telechargements termines self.pushButtonNettoyer = MyQPushButton(self.tabTelechargements) self.pushButtonNettoyer.setIcon(QtGui.QIcon("ico/gtk-delete-full.svg")) self.pushButtonNettoyer.setToolTip( u"Supprimer les téléchargement terminés") self.gridLayoutTelechargement.addWidget(self.pushButtonNettoyer, 1, 2, 1, 1) # Bouton pour ouvrir le dossier des telechargements self.pushButtonOuvrirDossierTelechargement = MyQPushButton( self.tabTelechargements) self.pushButtonOuvrirDossierTelechargement.setIcon( QtGui.QIcon("ico/gtk-folder.svg")) self.pushButtonOuvrirDossierTelechargement.setToolTip( u"Ouvrir le dossier des téléchargements") self.gridLayoutTelechargement.addWidget( self.pushButtonOuvrirDossierTelechargement, 2, 2, 1, 1) # # Barre progression de telechargement d'un fichier # self.progressBarTelechargementFichier = QtGui.QProgressBar( self.centralWidget) self.progressBarTelechargementFichier.setProperty("value", 0) # # Barre de progression de telechargement des fichiers # self.progressBarTelechargement = QtGui.QProgressBar(self.centralWidget) self.progressBarTelechargement.setProperty("value", 0) # # Boutons du bas pour gerer ajouter/supprimer/lancer telechargements # # Layout horizontal qui contiendra les boutons self.horizontalLayoutBarreBas = QtGui.QHBoxLayout() # Bouton pour lancer les telechargements self.pushButtonLancer = QtGui.QPushButton( QtGui.QIcon("ico/gtk-media-play-ltr.svg"), u"Lancer téléchargement", self.centralWidget) self.horizontalLayoutBarreBas.addWidget(self.pushButtonLancer) # Bouton pour stopper les telechargements self.pushButtonStop = QtGui.QPushButton( QtGui.QIcon("ico/gtk-media-stop.svg"), u"Stopper le téléchargement", self.centralWidget) self.pushButtonStop.setEnabled(False) self.horizontalLayoutBarreBas.addWidget(self.pushButtonStop) ### # Positionnement des differents widgets/layouts sur le layout de grille ### # Layout de grille dans lequel on va placer nos widgets/layouts self.gridLayout = QtGui.QGridLayout(self.centralWidget) # On ajoute la barre du haut self.gridLayout.addLayout(self.horizontalLayoutBarreHaut, 0, 0, 1, 3) # On ajoute le gestionnaire d'onglets self.gridLayout.addWidget(self.tabWidget, 1, 0, 1, 3) # On ajoute la barre de progression de telechargement d'un fichier self.gridLayout.addWidget(self.progressBarTelechargementFichier, 2, 0, 1, 3) # On ajoute la barre de progression de telechargement des fichiers self.gridLayout.addWidget(self.progressBarTelechargement, 3, 0, 1, 3) # On ajoute les boutons ajouter/supprimer/lancer self.gridLayout.addLayout(self.horizontalLayoutBarreBas, 4, 0, 1, 3) ### # Mise en place le central widget dans la fenetre ### self.setCentralWidget(self.centralWidget) ### # Mise en place du menu ### # Menu barre self.menubar = QtGui.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 480, 25)) # Menu Fichier self.menuFichier = QtGui.QMenu("&Fichier", self.menubar) self.menubar.addAction(self.menuFichier.menuAction()) # Action Fichier -> Quitter self.actionQuitter = QtGui.QAction(QtGui.QIcon("ico/gtk-quit.svg"), "&Quitter", self) self.actionQuitter.setIconVisibleInMenu(True) self.menuFichier.addAction(self.actionQuitter) # Menu Edition self.menuEdition = QtGui.QMenu("&Edition", self.menubar) self.menubar.addAction(self.menuEdition.menuAction()) # Action Edition -> Mise a jour self.actionMAJ = QtGui.QAction(QtGui.QIcon("ico/gtk-refresh.svg"), u"&Mise à jour des plugins", self) self.actionMAJ.setIconVisibleInMenu(True) self.menuEdition.addAction(self.actionMAJ) # Action Edition -> Preferences self.actionPreferences = QtGui.QAction( QtGui.QIcon("ico/gtk-preferences.svg"), u"&Préférences", self) self.actionPreferences.setIconVisibleInMenu(True) self.menuEdition.addAction(self.actionPreferences) # Menu Aide self.menuAide = QtGui.QMenu("&Aide", self.menubar) self.menubar.addAction(self.menuAide.menuAction()) # Action Aide -> A propos self.actionAPropos = QtGui.QAction(QtGui.QIcon("ico/gtk-about.svg"), u"À p&ropos", self) self.actionAPropos.setIconVisibleInMenu(True) self.menuAide.addAction(self.actionAPropos) # Ajout du menu a l'interface self.setMenuBar(self.menubar) ### # Signaux provenants de l'interface ### QtCore.QObject.connect(self.tableWidgetFichier, QtCore.SIGNAL("cellClicked(int,int)"), self.afficherInformationsFichier) QtCore.QObject.connect(self.tableWidgetFichier, QtCore.SIGNAL("cellDoubleClicked(int,int)"), self.gererTelechargement) QtCore.QObject.connect(self.pushButtonToutAjouter, QtCore.SIGNAL("clicked()"), self.ajouterTousLesFichiers) QtCore.QObject.connect(self.pushButtonRafraichirPlugin, QtCore.SIGNAL("clicked()"), self.rafraichirPlugin) QtCore.QObject.connect(self.tableWidgetTelechargement, QtCore.SIGNAL("cellDoubleClicked(int,int)"), self.supprimerTelechargement) QtCore.QObject.connect( self.pushButtonExtremiteMonter, QtCore.SIGNAL("clicked()"), lambda versLeHaut=True, extremite=True: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect( self.pushButtonMonter, QtCore.SIGNAL("clicked()"), lambda versLeHaut=True, extremite=False: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect( self.pushButtonDescendre, QtCore.SIGNAL("clicked()"), lambda versLeHaut=False, extremite=False: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect( self.pushButtonExtremiteDescendre, QtCore.SIGNAL("clicked()"), lambda versLeHaut=False, extremite=True: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect(self.pushButtonToutSupprimer, QtCore.SIGNAL("clicked()"), self.supprimerTousLesTelechargements) QtCore.QObject.connect(self.pushButtonNettoyer, QtCore.SIGNAL("clicked()"), self.nettoyer) QtCore.QObject.connect(self.pushButtonLancer, QtCore.SIGNAL("clicked()"), self.lancerTelechargement) QtCore.QObject.connect(self.pushButtonStop, QtCore.SIGNAL("clicked()"), self.stopperTelechargement) QtCore.QObject.connect(self.actionQuitter, QtCore.SIGNAL("triggered()"), self.close) ################################################ # Instanciations + initialisation de variables # ################################################ # Fenetre About self.aProposDialog = None # Fenetre des preferences du logiciel self.preferencesDialog = None # Fenetre de mise a jour des plugins self.updateManagerDialog = None # Nom plugin courant self.nomPluginCourant = "" # Liste des fichiers self.listeFichiers = [] # Liste des fichiers a telecharger self.listeFichiersATelecharger = [] # Cache des images descriptive # Clef : urlImage Valeur : image (binaire) self.cacheImage = {} # On intancie le lanceur de signaux self.signaux = Signaux() # On instancie le gestionnaire de preferences self.preferences = Preferences() # On instancie le gestionnaire de preferences des plugins self.preferencesPluginDialog = PreferencePluginDialog(self) # On instancie le gestionnaire de download self.downloader = Downloader(self.signaux) # On recupere l'instance de API self.api = API.getInstance() # On instancie le gestionnaire d'historique self.historique = Historique() # On instancie la fenetre d'attente self.fenetreAttenteProgressDialog = FenetreAttenteProgressDialog(self) # On instancie le gest # # Fenetre de confirmation pour quitter le logiciel # self.quitterMessageBox = QtGui.QMessageBox(self) self.quitterMessageBox.setWindowTitle("Fermeture de TVDownloader") self.quitterMessageBox.setText( u"Voulez-vous réellement quitter TVDownloader ?") self.quitterMessageBox.setInformativeText( u"Votre liste de téléchargement sera perdue") self.quitterMessageBox.addButton("Oui", QtGui.QMessageBox.AcceptRole) self.quitterMessageBox.addButton("Non", QtGui.QMessageBox.RejectRole) ############################################################ # On connecte les signaux des instances precedements crees # ############################################################ QtCore.QObject.connect(self.pushButtonOuvrirDossierTelechargement, QtCore.SIGNAL("clicked()"), self.ouvrirRepertoireTelechargement) QtCore.QObject.connect(self.comboBoxSite, QtCore.SIGNAL("activated(QString)"), self.listerChaines) QtCore.QObject.connect(self.comboBoxChaine, QtCore.SIGNAL("activated(QString)"), self.listerEmissions) QtCore.QObject.connect(self.comboBoxEmission, QtCore.SIGNAL("activated(QString)"), self.listerFichiers) QtCore.QObject.connect(self.pushButtonPreferencesPlugin, QtCore.SIGNAL("clicked()"), self.ouvrirPreferencesPlugin) QtCore.QObject.connect(self.actionPreferences, QtCore.SIGNAL("triggered()"), self.ouvrirPreferencesLogiciel) QtCore.QObject.connect(self.actionMAJ, QtCore.SIGNAL("triggered()"), self.ouvrirFenetreMiseAJour) QtCore.QObject.connect(self.actionAPropos, QtCore.SIGNAL("triggered()"), self.ouvrirFenetreAPropos) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL("debutActualisation(PyQt_PyObject)"), self.fenetreAttenteProgressDialog.ouvrirFenetreAttente) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL("finActualisation()"), self.fenetreAttenteProgressDialog.fermerFenetreAttente) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("actualiserListesDeroulantes()"), self.actualiserListesDeroulantes) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("listeChaines(PyQt_PyObject)"), self.ajouterChaines) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("listeEmissions(PyQt_PyObject)"), self.ajouterEmissions) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("listeFichiers(PyQt_PyObject)"), self.ajouterFichiers) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("nouvelleImage(PyQt_PyObject)"), self.mettreEnPlaceImage) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("debutTelechargement(int)"), self.debutTelechargement) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("finTelechargement(int)"), self.finTelechargement) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("finDesTelechargements()"), self.activerDesactiverInterface) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("pourcentageFichier(int)"), self.progressBarTelechargementFichier.setValue) ######### # Début # ######### # La fenetre prend la dimension qu'elle avait a sa fermeture taille = self.preferences.getPreference("tailleFenetre") self.resize(taille[0], taille[1]) # Si aucun plugin n'est active, on ouvre la fenetre des preferences if (len(self.preferences.getPreference("pluginsActifs")) == 0): self.ouvrirPreferencesLogiciel() # On actualise tous les plugins self.rafraichirTousLesPlugins()
class MainWindow(QtGui.QMainWindow): ## Constructeur # Le constructeur va creer la fenetre principale en y ajoutant tous les widgets necessaires au programme def __init__(self): # Appel au constructeur de la classe mere QtGui.QMainWindow.__init__(self) ########### # Fenetre # ########### ### # Reglages de la fenetre principale ### # Nom de la fenetre self.setWindowTitle("TVDownloader") # Mise en place de son icone self.setWindowIcon(QtGui.QIcon("ico/TVDownloader.png")) ### # Mise en place des widgets dans la fenetre ### # Widget central qui contiendra tout self.centralWidget = QtGui.QWidget(self) # # Barre du haut # # Layout horizontal qui contiendra les listes deroulantes self.horizontalLayoutBarreHaut = QtGui.QHBoxLayout() # Liste deroulante pour choisir le site (plugin) self.comboBoxSite = QtGui.QComboBox(self.centralWidget) self.horizontalLayoutBarreHaut.addWidget(self.comboBoxSite) # Liste deroulante pour choisir une chaine du site courant self.comboBoxChaine = QtGui.QComboBox(self.centralWidget) self.horizontalLayoutBarreHaut.addWidget(self.comboBoxChaine) # Liste deroulante pour choisir une emission de la chaine courante self.comboBoxEmission = QtGui.QComboBox(self.centralWidget) self.horizontalLayoutBarreHaut.addWidget(self.comboBoxEmission) # # Onglets # # Gestionnaire onglets self.tabWidget = QtGui.QTabWidget(self.centralWidget) # Onglet Fichiers self.tabFichiers = QtGui.QSplitter( self.centralWidget) # L'onglet Fichier contient un splitter self.tabWidget.addTab(self.tabFichiers, u"Choix des fichiers") # Onglet Telechargements self.tabTelechargements = QtGui.QWidget(self.centralWidget) self.tabWidget.addTab(self.tabTelechargements, u"Téléchargements") # # Liste des fichiers # # Layout de grille qui contient le tableau qui liste les fichiers + boutons self.gridLayoutFichiers = QtGui.QGridLayout(self.tabFichiers) # Tableau qui contient la liste des fichiers disponibles pour l'emission courante self.tableWidgetFichier = MyQTableWidget(self.tabFichiers) # Il a 4 colonnes et 0 ligne (pour l'instant) self.tableWidgetFichier.setColumnCount(3) self.tableWidgetFichier.setRowCount(0) # On ajoute les titres self.tableWidgetFichier.setHorizontalHeaderItem( 0, self.tableWidgetFichier.creerItem("")) self.tableWidgetFichier.setHorizontalHeaderItem( 1, self.tableWidgetFichier.creerItem("Date")) self.tableWidgetFichier.setHorizontalHeaderItem( 2, self.tableWidgetFichier.creerItem("Emission")) # On l'ajoute au layout self.gridLayoutFichiers.addWidget(self.tableWidgetFichier, 0, 1, 6, 1) # Icones du tableWidget self.iconeFichier = QtGui.QIcon("ico/gtk-file.svg") self.iconeAjoute = QtGui.QIcon("ico/gtk-add.svg") self.iconeTelecharge = QtGui.QIcon("ico/gtk-apply.svg") # Bouton pour ajouter tous les fichiers a la liste des telechargements self.pushButtonToutAjouter = MyQPushButton(self.tabFichiers) self.pushButtonToutAjouter.setIcon(QtGui.QIcon("ico/gtk-add.svg")) self.pushButtonToutAjouter.setToolTip( u"Ajouter tous les fichiers à la liste des téléchargements") self.gridLayoutFichiers.addWidget(self.pushButtonToutAjouter, 0, 0, 2, 1) # Bouton pour rafraichir le plugin courant self.pushButtonRafraichirPlugin = MyQPushButton(self.tabFichiers) self.pushButtonRafraichirPlugin.setIcon( QtGui.QIcon("ico/gtk-refresh.svg")) self.pushButtonRafraichirPlugin.setToolTip("Rafraichir le plugin") self.gridLayoutFichiers.addWidget(self.pushButtonRafraichirPlugin, 2, 0, 2, 1) # Bouton pour ouvrir la fenetre des preferences du plugin courant self.pushButtonPreferencesPlugin = MyQPushButton(self.tabFichiers) self.pushButtonPreferencesPlugin.setIcon( QtGui.QIcon("ico/gtk-preferences.svg")) self.pushButtonPreferencesPlugin.setToolTip( u"Ouvrir les préférences du plugin") self.gridLayoutFichiers.addWidget(self.pushButtonPreferencesPlugin, 4, 0, 2, 1) # On met en place ce layout sur un widget (pour le splitter) self.widgetFichiers = QtGui.QWidget() self.widgetFichiers.setLayout(self.gridLayoutFichiers) # # Descriptif des fichiers # # Layout de grille self.gridLayoutDescriptif = QtGui.QGridLayout() # Label pour afficher un logo self.logoFichierDefaut = QtGui.QPixmap() self.logoFichierDefaut.load("img/gtk-dialog-question.svg") self.labelLogo = QtGui.QLabel(self.centralWidget) self.labelLogo.setPixmap( self.logoFichierDefaut.scaled(QtCore.QSize(150, 150), QtCore.Qt.KeepAspectRatio)) self.gridLayoutDescriptif.addWidget(self.labelLogo, 0, 0, 1, 1) # Zone de texte pour afficher un descriptif self.plainTextEdit = QtGui.QPlainTextEdit(self.centralWidget) self.gridLayoutDescriptif.addWidget(self.plainTextEdit, 0, 1, 1, 2) # On met en place ce layout sur un widget (pour le splitter) self.widgetDescriptif = QtGui.QWidget() self.widgetDescriptif.setLayout(self.gridLayoutDescriptif) # Onrientation verticale du splitter self.tabFichiers.setOrientation(QtCore.Qt.Vertical) # On ajoute les 2 elements au splitter (qui est notre onglet) self.tabFichiers.addWidget(self.widgetFichiers) self.tabFichiers.addWidget(self.widgetDescriptif) # # Liste des telechargements # # Layout de grille qui contient le tableau qui liste les fichiers a telecharger + les boutons pour le controller self.gridLayoutTelechargement = QtGui.QGridLayout( self.tabTelechargements) # Tableau qui contient la liste des fichiers a telecharger self.tableWidgetTelechargement = MyQTableWidget( self.tabTelechargements) # Il a 5 colonnes et 0 ligne (pour l'instant) self.tableWidgetTelechargement.setColumnCount(3) self.tableWidgetTelechargement.setRowCount(0) # On ajoute le titre des 5 colonnes self.tableWidgetTelechargement.setHorizontalHeaderItem( 0, self.tableWidgetTelechargement.creerItem("Date")) self.tableWidgetTelechargement.setHorizontalHeaderItem( 1, self.tableWidgetTelechargement.creerItem("Emission")) self.tableWidgetTelechargement.setHorizontalHeaderItem( 2, self.tableWidgetTelechargement.creerItem("Etat")) # On l'ajoute au layout self.gridLayoutTelechargement.addWidget(self.tableWidgetTelechargement, 0, 1, 4, 1) # Bouton pour monter l'element selectionne tout en haut de la liste self.pushButtonExtremiteMonter = MyQPushButton(self.tabTelechargements) self.pushButtonExtremiteMonter.setIcon( QtGui.QIcon("ico/gtk-jump-to-rtl.svg")) self.pushButtonExtremiteMonter.setToolTip( u"Placer l'élément sélectionné tout en haut") self.gridLayoutTelechargement.addWidget(self.pushButtonExtremiteMonter, 0, 0, 1, 1) # Bouton pour monter l'element selectionne d'un cran dans la liste self.pushButtonMonter = MyQPushButton(self.tabTelechargements) self.pushButtonMonter.setIcon(QtGui.QIcon("ico/gtk-go-up.svg")) self.pushButtonMonter.setToolTip(u"Monter l'élément sélectionné") self.gridLayoutTelechargement.addWidget(self.pushButtonMonter, 1, 0, 1, 1) # Bouton pour descendre l'element selectionne d'un cran dans la liste self.pushButtonDescendre = MyQPushButton(self.tabTelechargements) self.pushButtonDescendre.setIcon(QtGui.QIcon("ico/gtk-go-down.svg")) self.pushButtonDescendre.setToolTip(u"Descendre l'élément selectionné") self.gridLayoutTelechargement.addWidget(self.pushButtonDescendre, 2, 0, 1, 1) # Bouton pour descendre l'element selectionne tout en bas de la liste self.pushButtonExtremiteDescendre = MyQPushButton( self.tabTelechargements) self.pushButtonExtremiteDescendre.setIcon( QtGui.QIcon("ico/gtk-jump-to-ltr.svg")) self.pushButtonExtremiteDescendre.setToolTip( u"Placer l'élément sélectionné tout en bas") self.gridLayoutTelechargement.addWidget( self.pushButtonExtremiteDescendre, 3, 0, 1, 1) # Bouton pour supprimer tous les elements de la liste self.pushButtonToutSupprimer = MyQPushButton(self.tabTelechargements) self.pushButtonToutSupprimer.setIcon(QtGui.QIcon("ico/gtk-cancel.svg")) self.pushButtonToutSupprimer.setToolTip( u"Supprimer tous les téléchargements") self.gridLayoutTelechargement.addWidget(self.pushButtonToutSupprimer, 0, 2, 1, 1) # Bouton pour supprimer de la liste les telechargements termines self.pushButtonNettoyer = MyQPushButton(self.tabTelechargements) self.pushButtonNettoyer.setIcon(QtGui.QIcon("ico/gtk-delete-full.svg")) self.pushButtonNettoyer.setToolTip( u"Supprimer les téléchargement terminés") self.gridLayoutTelechargement.addWidget(self.pushButtonNettoyer, 1, 2, 1, 1) # Bouton pour ouvrir le dossier des telechargements self.pushButtonOuvrirDossierTelechargement = MyQPushButton( self.tabTelechargements) self.pushButtonOuvrirDossierTelechargement.setIcon( QtGui.QIcon("ico/gtk-folder.svg")) self.pushButtonOuvrirDossierTelechargement.setToolTip( u"Ouvrir le dossier des téléchargements") self.gridLayoutTelechargement.addWidget( self.pushButtonOuvrirDossierTelechargement, 2, 2, 1, 1) # # Barre progression de telechargement d'un fichier # self.progressBarTelechargementFichier = QtGui.QProgressBar( self.centralWidget) self.progressBarTelechargementFichier.setProperty("value", 0) # # Barre de progression de telechargement des fichiers # self.progressBarTelechargement = QtGui.QProgressBar(self.centralWidget) self.progressBarTelechargement.setProperty("value", 0) # # Boutons du bas pour gerer ajouter/supprimer/lancer telechargements # # Layout horizontal qui contiendra les boutons self.horizontalLayoutBarreBas = QtGui.QHBoxLayout() # Bouton pour lancer les telechargements self.pushButtonLancer = QtGui.QPushButton( QtGui.QIcon("ico/gtk-media-play-ltr.svg"), u"Lancer téléchargement", self.centralWidget) self.horizontalLayoutBarreBas.addWidget(self.pushButtonLancer) # Bouton pour stopper les telechargements self.pushButtonStop = QtGui.QPushButton( QtGui.QIcon("ico/gtk-media-stop.svg"), u"Stopper le téléchargement", self.centralWidget) self.pushButtonStop.setEnabled(False) self.horizontalLayoutBarreBas.addWidget(self.pushButtonStop) ### # Positionnement des differents widgets/layouts sur le layout de grille ### # Layout de grille dans lequel on va placer nos widgets/layouts self.gridLayout = QtGui.QGridLayout(self.centralWidget) # On ajoute la barre du haut self.gridLayout.addLayout(self.horizontalLayoutBarreHaut, 0, 0, 1, 3) # On ajoute le gestionnaire d'onglets self.gridLayout.addWidget(self.tabWidget, 1, 0, 1, 3) # On ajoute la barre de progression de telechargement d'un fichier self.gridLayout.addWidget(self.progressBarTelechargementFichier, 2, 0, 1, 3) # On ajoute la barre de progression de telechargement des fichiers self.gridLayout.addWidget(self.progressBarTelechargement, 3, 0, 1, 3) # On ajoute les boutons ajouter/supprimer/lancer self.gridLayout.addLayout(self.horizontalLayoutBarreBas, 4, 0, 1, 3) ### # Mise en place le central widget dans la fenetre ### self.setCentralWidget(self.centralWidget) ### # Mise en place du menu ### # Menu barre self.menubar = QtGui.QMenuBar(self) self.menubar.setGeometry(QtCore.QRect(0, 0, 480, 25)) # Menu Fichier self.menuFichier = QtGui.QMenu("&Fichier", self.menubar) self.menubar.addAction(self.menuFichier.menuAction()) # Action Fichier -> Quitter self.actionQuitter = QtGui.QAction(QtGui.QIcon("ico/gtk-quit.svg"), "&Quitter", self) self.actionQuitter.setIconVisibleInMenu(True) self.menuFichier.addAction(self.actionQuitter) # Menu Edition self.menuEdition = QtGui.QMenu("&Edition", self.menubar) self.menubar.addAction(self.menuEdition.menuAction()) # Action Edition -> Mise a jour self.actionMAJ = QtGui.QAction(QtGui.QIcon("ico/gtk-refresh.svg"), u"&Mise à jour des plugins", self) self.actionMAJ.setIconVisibleInMenu(True) self.menuEdition.addAction(self.actionMAJ) # Action Edition -> Preferences self.actionPreferences = QtGui.QAction( QtGui.QIcon("ico/gtk-preferences.svg"), u"&Préférences", self) self.actionPreferences.setIconVisibleInMenu(True) self.menuEdition.addAction(self.actionPreferences) # Menu Aide self.menuAide = QtGui.QMenu("&Aide", self.menubar) self.menubar.addAction(self.menuAide.menuAction()) # Action Aide -> A propos self.actionAPropos = QtGui.QAction(QtGui.QIcon("ico/gtk-about.svg"), u"À p&ropos", self) self.actionAPropos.setIconVisibleInMenu(True) self.menuAide.addAction(self.actionAPropos) # Ajout du menu a l'interface self.setMenuBar(self.menubar) ### # Signaux provenants de l'interface ### QtCore.QObject.connect(self.tableWidgetFichier, QtCore.SIGNAL("cellClicked(int,int)"), self.afficherInformationsFichier) QtCore.QObject.connect(self.tableWidgetFichier, QtCore.SIGNAL("cellDoubleClicked(int,int)"), self.gererTelechargement) QtCore.QObject.connect(self.pushButtonToutAjouter, QtCore.SIGNAL("clicked()"), self.ajouterTousLesFichiers) QtCore.QObject.connect(self.pushButtonRafraichirPlugin, QtCore.SIGNAL("clicked()"), self.rafraichirPlugin) QtCore.QObject.connect(self.tableWidgetTelechargement, QtCore.SIGNAL("cellDoubleClicked(int,int)"), self.supprimerTelechargement) QtCore.QObject.connect( self.pushButtonExtremiteMonter, QtCore.SIGNAL("clicked()"), lambda versLeHaut=True, extremite=True: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect( self.pushButtonMonter, QtCore.SIGNAL("clicked()"), lambda versLeHaut=True, extremite=False: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect( self.pushButtonDescendre, QtCore.SIGNAL("clicked()"), lambda versLeHaut=False, extremite=False: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect( self.pushButtonExtremiteDescendre, QtCore.SIGNAL("clicked()"), lambda versLeHaut=False, extremite=True: self. tableWidgetTelechargement.deplacerLigne(versLeHaut, extremite)) QtCore.QObject.connect(self.pushButtonToutSupprimer, QtCore.SIGNAL("clicked()"), self.supprimerTousLesTelechargements) QtCore.QObject.connect(self.pushButtonNettoyer, QtCore.SIGNAL("clicked()"), self.nettoyer) QtCore.QObject.connect(self.pushButtonLancer, QtCore.SIGNAL("clicked()"), self.lancerTelechargement) QtCore.QObject.connect(self.pushButtonStop, QtCore.SIGNAL("clicked()"), self.stopperTelechargement) QtCore.QObject.connect(self.actionQuitter, QtCore.SIGNAL("triggered()"), self.close) ################################################ # Instanciations + initialisation de variables # ################################################ # Fenetre About self.aProposDialog = None # Fenetre des preferences du logiciel self.preferencesDialog = None # Fenetre de mise a jour des plugins self.updateManagerDialog = None # Nom plugin courant self.nomPluginCourant = "" # Liste des fichiers self.listeFichiers = [] # Liste des fichiers a telecharger self.listeFichiersATelecharger = [] # Cache des images descriptive # Clef : urlImage Valeur : image (binaire) self.cacheImage = {} # On intancie le lanceur de signaux self.signaux = Signaux() # On instancie le gestionnaire de preferences self.preferences = Preferences() # On instancie le gestionnaire de preferences des plugins self.preferencesPluginDialog = PreferencePluginDialog(self) # On instancie le gestionnaire de download self.downloader = Downloader(self.signaux) # On recupere l'instance de API self.api = API.getInstance() # On instancie le gestionnaire d'historique self.historique = Historique() # On instancie la fenetre d'attente self.fenetreAttenteProgressDialog = FenetreAttenteProgressDialog(self) # On instancie le gest # # Fenetre de confirmation pour quitter le logiciel # self.quitterMessageBox = QtGui.QMessageBox(self) self.quitterMessageBox.setWindowTitle("Fermeture de TVDownloader") self.quitterMessageBox.setText( u"Voulez-vous réellement quitter TVDownloader ?") self.quitterMessageBox.setInformativeText( u"Votre liste de téléchargement sera perdue") self.quitterMessageBox.addButton("Oui", QtGui.QMessageBox.AcceptRole) self.quitterMessageBox.addButton("Non", QtGui.QMessageBox.RejectRole) ############################################################ # On connecte les signaux des instances precedements crees # ############################################################ QtCore.QObject.connect(self.pushButtonOuvrirDossierTelechargement, QtCore.SIGNAL("clicked()"), self.ouvrirRepertoireTelechargement) QtCore.QObject.connect(self.comboBoxSite, QtCore.SIGNAL("activated(QString)"), self.listerChaines) QtCore.QObject.connect(self.comboBoxChaine, QtCore.SIGNAL("activated(QString)"), self.listerEmissions) QtCore.QObject.connect(self.comboBoxEmission, QtCore.SIGNAL("activated(QString)"), self.listerFichiers) QtCore.QObject.connect(self.pushButtonPreferencesPlugin, QtCore.SIGNAL("clicked()"), self.ouvrirPreferencesPlugin) QtCore.QObject.connect(self.actionPreferences, QtCore.SIGNAL("triggered()"), self.ouvrirPreferencesLogiciel) QtCore.QObject.connect(self.actionMAJ, QtCore.SIGNAL("triggered()"), self.ouvrirFenetreMiseAJour) QtCore.QObject.connect(self.actionAPropos, QtCore.SIGNAL("triggered()"), self.ouvrirFenetreAPropos) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL("debutActualisation(PyQt_PyObject)"), self.fenetreAttenteProgressDialog.ouvrirFenetreAttente) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL("finActualisation()"), self.fenetreAttenteProgressDialog.fermerFenetreAttente) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("actualiserListesDeroulantes()"), self.actualiserListesDeroulantes) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("listeChaines(PyQt_PyObject)"), self.ajouterChaines) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("listeEmissions(PyQt_PyObject)"), self.ajouterEmissions) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("listeFichiers(PyQt_PyObject)"), self.ajouterFichiers) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("nouvelleImage(PyQt_PyObject)"), self.mettreEnPlaceImage) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("debutTelechargement(int)"), self.debutTelechargement) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("finTelechargement(int)"), self.finTelechargement) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("finDesTelechargements()"), self.activerDesactiverInterface) QtCore.QObject.connect(self.signaux, QtCore.SIGNAL("pourcentageFichier(int)"), self.progressBarTelechargementFichier.setValue) ######### # Début # ######### # La fenetre prend la dimension qu'elle avait a sa fermeture taille = self.preferences.getPreference("tailleFenetre") self.resize(taille[0], taille[1]) # Si aucun plugin n'est active, on ouvre la fenetre des preferences if (len(self.preferences.getPreference("pluginsActifs")) == 0): self.ouvrirPreferencesLogiciel() # On actualise tous les plugins self.rafraichirTousLesPlugins() ## Methode qui execute les actions necessaires avant de quitter le programme def actionsAvantQuitter(self): # On sauvegarde les options des plugins self.api.fermeture() # On sauvegarde la taille de la fenetre taille = self.size() self.preferences.setPreference( "tailleFenetre", [taille.width(), taille.height()]) # On sauvegarde les options du logiciel self.preferences.sauvegarderConfiguration() # On sauvegarde l'historique self.historique.sauverHistorique() # On stoppe les telechargements self.stopperTelechargement() ######################################### # Surcharge des methodes de QMainWindow # ######################################### ## Surcharge de la methode appelee lors de la fermeture de la fenetre # Ne doit pas etre appele explicitement # @param evenement Evenement qui a provoque la fermeture def closeEvent(self, evenement): # On affiche une fenetre pour demander la fermeture si des fichiers sont dans la liste de telechargement if (self.tableWidgetTelechargement.rowCount() > 0): # On affiche une fenetre qui demande si on veut quitter retour = self.quitterMessageBox.exec_() # Si on veut quitter if (retour == 0): # On execute les actions necessaires self.actionsAvantQuitter() # On accept la fermeture evenement.accept() else: # On refuse la fermeture evenement.ignore() else: # S'il n'y a pas de fichier # On execute les actions necessaires self.actionsAvantQuitter() # On accept la fermeture evenement.accept() ############################################## # Methodes pour remplir les menus deroulants # ############################################## ## Methode qui actualise les listes deroulantes def actualiserListesDeroulantes(self): # On lance juste l'ajout des sites en se basant sur les plugins actifs self.ajouterSites(self.preferences.getPreference("pluginsActifs")) ## Methode qui lance le listage des chaines # @param site Nom du plugin/site pour lequel on va lister les chaines def listerChaines(self, site): def threadListerChaines(self, nomPlugin): self.signaux.signal("debutActualisation", nomPlugin) listeChaines = self.api.getPluginListeChaines(nomPlugin) self.signaux.signal("listeChaines", listeChaines) self.signaux.signal("finActualisation") if (site != ""): self.nomPluginCourant = qstringToString(site) threading.Thread(target=threadListerChaines, args=(self, self.nomPluginCourant)).start() # On active (ou pas) le bouton de preference du plugin self.pushButtonPreferencesPlugin.setEnabled( self.api.getPluginListeOptions(self.nomPluginCourant) != []) ## Methode qui lance le listage des emissions # @param chaine Nom de la chaine pour laquelle on va lister les emissions def listerEmissions(self, chaine): def threadListerEmissions(self, nomPlugin, chaine): self.signaux.signal("debutActualisation", nomPlugin) listeEmissions = self.api.getPluginListeEmissions( nomPlugin, chaine) self.signaux.signal("listeEmissions", listeEmissions) self.signaux.signal("finActualisation") if (chaine != ""): threading.Thread(target=threadListerEmissions, args=(self, self.nomPluginCourant, qstringToString(chaine))).start() ## Methode qui lance le listage des fichiers # @param emission Nom de l'emission pour laquelle on va lister les fichiers def listerFichiers(self, emission): def threadListerFichiers(self, nomPlugin, emission): self.signaux.signal("debutActualisation", nomPlugin) listeFichiers = self.api.getPluginListeFichiers( nomPlugin, emission) self.signaux.signal("listeFichiers", listeFichiers) self.signaux.signal("finActualisation") if (emission != ""): threading.Thread(target=threadListerFichiers, args=(self, self.nomPluginCourant, qstringToString(emission))).start() ## Methode qui met en place une liste de sites sur l'interface # @param listeSites Liste des sites a mettre en place def ajouterSites(self, listeSites): # On efface la liste des sites self.comboBoxSite.clear() # On met en place les sites for site in listeSites: self.comboBoxSite.addItem(stringToQstring(site)) # On selectionne par defaut celui choisis dans les preference index = self.comboBoxSite.findText( stringToQstring(self.preferences.getPreference("pluginParDefaut"))) if (index != -1): self.comboBoxSite.setCurrentIndex(index) # On lance l'ajout des chaines self.listerChaines(self.comboBoxSite.currentText()) ## Methode qui met en place une liste de chaines sur l'interface # @param listeChaines Liste des chaines a mettre en place def ajouterChaines(self, listeChaines): # On trie la liste des chaines listeChaines.sort() # On efface la liste des chaines self.comboBoxChaine.clear() # On efface la liste des emissions self.comboBoxEmission.clear() # On efface la liste des fichiers self.tableWidgetFichier.toutSupprimer() # On met en place les chaines for chaine in listeChaines: self.comboBoxChaine.addItem(stringToQstring(chaine)) # Si on a juste une seule chaine if (self.comboBoxChaine.count() == 1): # On lance l'ajout des emissions self.listerEmissions(self.comboBoxChaine.currentText()) else: # On ne selectionne pas de chaine self.comboBoxChaine.setCurrentIndex(-1) ## Methode qui met en place une liste d'emissions sur l'interface # @param listeEmissions Liste des emissions a mettre en place def ajouterEmissions(self, listeEmissions): # On trie la liste des emissions listeEmissions.sort() # On efface la liste des emissions self.comboBoxEmission.clear() # On efface la liste des fichiers self.tableWidgetFichier.toutSupprimer() # On met en place la liste des emissions for emission in listeEmissions: self.comboBoxEmission.addItem(stringToQstring(emission)) # Si on a juste une seule emission if (self.comboBoxEmission.count() == 1): # On lance l'ajout des fichiers self.listerFichiers(self.comboBoxEmission.currentText()) else: # On ne selectionne pas d'emission self.comboBoxEmission.setCurrentIndex(-1) ############################################### # Methodes pour remplir la liste des fichiers # ############################################### ## Methode pour ajouter des fichiers a l'interface # @param listeFichiers Liste des fichiers a ajouter def ajouterFichiers(self, listeFichiers): self.listeFichiers = listeFichiers # On efface la liste des fichiers self.tableWidgetFichier.toutSupprimer() # On commence au depart ligneCourante = 0 # On met en place chacun des fichiers for fichier in listeFichiers: # On ajoute une ligne self.tableWidgetFichier.insertRow(ligneCourante) # On ajoute les informations au tableWidgetFichier liste = [] liste.append(self.tableWidgetFichier.creerItem("")) liste.append( self.tableWidgetFichier.creerItem(getattr(fichier, "date"))) liste.append( self.tableWidgetFichier.creerItem(getattr(fichier, "nom"))) self.tableWidgetFichier.setLigne(ligneCourante, liste) # On met en place l'icone qui va bien self.gererIconeListeFichier(fichier) ligneCourante += 1 # On adapte la taille des colonnes self.tableWidgetFichier.adapterColonnes() ## Methode qui rafraichit le plugin courant def rafraichirPlugin(self): def threadRafraichirPlugin(self, nomPlugin): self.signaux.signal("debutActualisation", nomPlugin) self.api.pluginRafraichir(nomPlugin) self.signaux.signal("finActualisation") threading.Thread(target=threadRafraichirPlugin, args=(self, self.nomPluginCourant)).start() ## Methode qui met en place l'image de la description d'un fichier # @param image Image a mettre en place (binaire) def mettreEnPlaceImage(self, image): logoFichier = QtGui.QPixmap() logoFichier.loadFromData(image) self.labelLogo.setPixmap( logoFichier.scaled(QtCore.QSize(150, 150), QtCore.Qt.KeepAspectRatio)) ## Methode qui affiche des informations sur le fichier selectionne def afficherInformationsFichier(self, ligne, colonne): def threadRecupererImage(self, urlImage): image = self.api.getPage(urlImage) self.cacheImage[urlImage] = image self.signaux.signal("nouvelleImage", image) fichier = self.listeFichiers[ligne] # On recupere le lien de l'image et le texte descriptif urlImage = getattr(fichier, "urlImage") texteDescriptif = getattr(fichier, "descriptif") self.plainTextEdit.clear() # Si on a un texte descriptif, on l'affiche if (texteDescriptif != ""): self.plainTextEdit.appendPlainText( stringToQstring(texteDescriptif)) else: self.plainTextEdit.appendPlainText( u"Aucune information disponible") # Si on n'a pas d'image if (urlImage == ""): # On met en place celle par defaut self.logoFichier = self.logoFichierDefaut self.labelLogo.setPixmap( self.logoFichier.scaled(QtCore.QSize(150, 150), QtCore.Qt.KeepAspectRatio)) else: # Si on en a une # Si elle est dans le cache des images if (self.cacheImage.has_key(urlImage)): self.mettreEnPlaceImage(self.cacheImage[urlImage]) else: # Sinon # On lance le thread pour la recuperer threading.Thread(target=threadRecupererImage, args=(self, urlImage)).start() ## Methode qui gere l'icone d'un fichier dans la liste des telechargements # Il y a 3 icones possible : # - C'est un fichier # - C'est un fichier present dans l'historique (donc deja telecharge) # - C'est un fichier present dans la liste des telechargements # @param fichier Fichier a gerer def gererIconeListeFichier(self, fichier): if (fichier in self.listeFichiers): ligneFichier = self.listeFichiers.index(fichier) # On cherche quel icone mettre en place if (fichier in self.listeFichiersATelecharger): icone = self.iconeAjoute elif (self.historique.comparerHistorique(fichier)): icone = self.iconeTelecharge else: icone = self.iconeFichier # On met en place l'icone self.tableWidgetFichier.item(ligneFichier, 0).setIcon(icone) ###################################################### # Methodes pour remplir la liste des telechargements # ###################################################### ## Methode qui gere la liste des telechargements # @param ligne Numero de la ligne (dans la liste des fichiers) de l'element a ajouter # @param colonne Numero de colonne (inutile, juste pour le slot) def gererTelechargement(self, ligne, colonne=0): fichier = self.listeFichiers[ligne] # Si le fichier est deja dans la liste des telechargements if (fichier in self.listeFichiersATelecharger): ligneTelechargement = self.listeFichiersATelecharger.index(fichier) self.supprimerTelechargement(ligneTelechargement) else: # S'il n'y est pas, on l'ajoute self.listeFichiersATelecharger.append(fichier) numLigne = self.tableWidgetTelechargement.rowCount() # On insere une nouvelle ligne dans la liste des telechargements self.tableWidgetTelechargement.insertRow(numLigne) # On y insere les elements qui vont biens self.tableWidgetTelechargement.setLigne(numLigne, [ self.tableWidgetTelechargement.creerItem( getattr(fichier, "date")), self.tableWidgetTelechargement.creerItem( getattr(fichier, "nom")), self.tableWidgetTelechargement.creerItem( u"En attente de téléchargement") ]) # On adapte la taille des colonnes self.tableWidgetTelechargement.adapterColonnes() # On modifie l'icone dans la liste des fichiers self.gererIconeListeFichier(fichier) ## Methode qui ajoute tous les fichiers a la liste des telechargements def ajouterTousLesFichiers(self): for i in range(self.tableWidgetFichier.rowCount()): self.gererTelechargement(i) ## Methode qui supprime un fichier de la liste des telechargements # @param ligne Numero de la ligne a supprimer # @param colonne Numero de colonne (inutile, juste pour le slot) def supprimerTelechargement(self, ligne, colonne=0): fichier = self.listeFichiersATelecharger[ligne] # On supprime l'element du tableWidgetTelechargement self.tableWidgetTelechargement.removeRow(ligne) # On supprime l'element de la liste des fichiers a telecharger self.listeFichiersATelecharger.remove(fichier) # On modifie l'icone dans la liste des fichiers self.gererIconeListeFichier(fichier) ## Methode qui supprime tous les telechargement de la liste des telechargements def supprimerTousLesTelechargements(self): for i in range(self.tableWidgetTelechargement.rowCount() - 1, -1, -1): self.supprimerTelechargement(i) ## Methode qui lance le telechargement des fichiers def lancerTelechargement(self): # On liste les emissions a telecharger avec leurs numeros de ligne listeFichiers = [] for i in range(self.tableWidgetTelechargement.rowCount() ): # Pour chaque ligne fichier = self.listeFichiersATelecharger[i] listeFichiers.append([ i, getattr(fichier, "lien"), getattr(fichier, "nomFichierSortie") ]) nbATelecharger = len(listeFichiers) # Si on a des elements a charger if (nbATelecharger > 0): # On met en place la valeur du progressBar self.progressBarTelechargement.setMaximum(nbATelecharger) self.progressBarTelechargement.setValue(0) # On lance le telechargement threading.Thread(target=self.downloader.lancerTelechargement, args=(listeFichiers, )).start() # On active/desactive ce qui va bien sur l'interface self.activerDesactiverInterface(True) ## Methode qui stoppe le telechargement def stopperTelechargement(self): # On stoppe le telechargement self.downloader.stopperTelechargement() ############################################ # Methodes pour ouvrir les autres fenetres # ############################################ # # Fenetre About # ## Methode pour afficher la fenetre About def ouvrirFenetreAPropos(self): if (self.aProposDialog == None): self.aProposDialog = AProposDialog() self.aProposDialog.show() # # Fenetre de preference du logiciel # ## Methode pour ouvrir les preferences du logiciel def ouvrirPreferencesLogiciel(self): if (self.preferencesDialog == None): self.preferencesDialog = PreferencesDialog(self, self.signaux) self.preferencesDialog.afficher() # # Fenetre de mise a jour des plugins # ## Methode pour ouvrir la fenetre de mise a jour des plugins def ouvrirFenetreMiseAJour(self): if (self.updateManagerDialog == None): self.updateManagerDialog = UpdateManagerDialog(self) self.updateManagerDialog.afficher() # # Fenetre de preference des plugins # ## Methode pour ouvrir les preferences du plugin courant def ouvrirPreferencesPlugin(self): listeOptions = self.api.getPluginListeOptions(self.nomPluginCourant) self.preferencesPluginDialog.ouvrirDialogPreferences( self.nomPluginCourant, listeOptions) ######### # Slots # ######### ## Methode qui ouvre le repertoire de telechargement def ouvrirRepertoireTelechargement(self): QtGui.QDesktopServices.openUrl( QtCore.QUrl.fromLocalFile( self.preferences.getPreference("repertoireTelechargement"))) ## Methode qui rafraichit le plugin courant def rafraichirPlugin(self): def threadRafraichirPlugin(self, nomPlugin): self.signaux.signal("debutActualisation", nomPlugin) self.api.pluginRafraichir(nomPlugin) self.signaux.signal("finActualisation") threading.Thread(target=threadRafraichirPlugin, args=(self, self.nomPluginCourant)).start() ## Methode qui rafraichit tous les plugins # A utiliser au lancement du programme def rafraichirTousLesPlugins(self): def threadRafraichirTousLesPlugins(self): self.signaux.signal("debutActualisation", "TVDownloader") self.api.pluginRafraichirAuto() self.signaux.signal("finActualisation") self.signaux.signal("actualiserListesDeroulantes") threading.Thread(target=threadRafraichirTousLesPlugins, args=(self, )).start() ## Slot qui active/desactive des elements de l'interface pendant un telechargement # @param telechargementEnCours Indique si on telecharge ou pas def activerDesactiverInterface(self, telechargementEnCours=False): # Les boutons self.pushButtonLancer.setEnabled(not telechargementEnCours) self.pushButtonStop.setEnabled(telechargementEnCours) self.pushButtonExtremiteMonter.setEnabled(not telechargementEnCours) self.pushButtonMonter.setEnabled(not telechargementEnCours) self.pushButtonDescendre.setEnabled(not telechargementEnCours) self.pushButtonExtremiteDescendre.setEnabled(not telechargementEnCours) self.pushButtonToutSupprimer.setEnabled(not telechargementEnCours) self.pushButtonNettoyer.setEnabled(not telechargementEnCours) # Le table widget self.tableWidgetTelechargement.setEnabled(not telechargementEnCours) ## Slot appele lors ce qu'un le debut d'un telechargement commence # @param numero Position dans la liste des telechargement du telechargement qui commence def debutTelechargement(self, numero): self.tableWidgetTelechargement.item(numero, 2).setText( stringToQstring(u"Téléchargement en cours...")) self.tableWidgetTelechargement.adapterColonnes() self.progressBarTelechargementFichier.setValue(0) ## Slot appele lorsqu'un telechargement se finit # @param numero Position dans la liste des telechargement du telechargement qui se finit def finTelechargement(self, numero): fichier = self.listeFichiersATelecharger[numero] # On ajoute le fichier a l'historique self.historique.ajouterHistorique(fichier) # On modifie l'icone dans la liste des fichiers self.gererIconeListeFichier(fichier) # On modifie l'interface self.tableWidgetTelechargement.item(numero, 2).setText( stringToQstring(u"Fini !")) self.progressBarTelechargement.setValue( self.progressBarTelechargement.value() + 1) self.tableWidgetTelechargement.adapterColonnes() self.progressBarTelechargementFichier.setValue(100) ## Slot qui nettoie la liste des telechargements de tous les telechargements finis def nettoyer(self): for i in range(self.tableWidgetTelechargement.rowCount() - 1, -1, -1): # [ nbLignes - 1, nbLignes - 2, ..., 1, 0 ] if (self.tableWidgetTelechargement.item( i, 2).text() == u"Fini !"): # Si c'est telecharge self.supprimerTelechargement(i)
def __init__(self, session): self.sessionLogin = session Historique.__init__(self)
def setUp( self ): self.historique = Historique()
class PluzzDLF4M( object ): """ Telechargement des liens f4m """ adobePlayer = "http://fpdownload.adobe.com/strobe/FlashMediaPlayback_101.swf" def __init__( self, manifestURL, nomFichier, navigateur, stopDownloadEvent, progressFnct ): self.manifestURL = manifestURL self.nomFichier = nomFichier self.navigateur = navigateur self.stopDownloadEvent = stopDownloadEvent self.progressFnct = progressFnct self.historique = Historique() self.configuration = Configuration() self.hmacKey = self.configuration[ "hmac_key" ].decode( "hex" ) self.playerHash = self.configuration[ "player_hash" ] def parseManifest( self ): """ Parse le manifest """ try : arbre = xml.etree.ElementTree.fromstring( self.manifest ) # Duree self.duree = float( arbre.find( "{http://ns.adobe.com/f4m/1.0}duration" ).text ) self.pv2 = arbre.find( "{http://ns.adobe.com/f4m/1.0}pv-2.0" ).text media = arbre.findall( "{http://ns.adobe.com/f4m/1.0}media" )[ -1 ] # Bitrate self.bitrate = int( media.attrib[ "bitrate" ] ) # URL des fragments urlbootstrap = media.attrib[ "url" ] self.urlFrag = "%s%sSeg1-Frag" % ( self.manifestURLToken[ : self.manifestURLToken.find( "manifest.f4m" ) ], urlbootstrap ) # Header du fichier final self.flvHeader = base64.b64decode( media.find( "{http://ns.adobe.com/f4m/1.0}metadata" ).text ) except : raise PluzzDLException( "Impossible de parser le manifest" ) def ouvrirNouvelleVideo( self ): """ Creer une nouvelle video """ try : # Ouverture du fichier self.fichierVideo = open( self.nomFichier, "wb" ) except : raise PluzzDLException( "Impossible d'écrire dans le répertoire %s" % ( os.getcwd() ) ) # Ajout de l'en-tête FLV self.fichierVideo.write( binascii.a2b_hex( "464c56010500000009000000001200010c00000000000000" ) ) # Ajout de l'header du fichier self.fichierVideo.write( self.flvHeader ) self.fichierVideo.write( binascii.a2b_hex( "00000000" ) ) # Padding pour avoir des blocs de 8 def ouvrirVideoExistante( self ): """ Ouvre une video existante """ try : # Ouverture du fichier self.fichierVideo = open( self.nomFichier, "a+b" ) except : raise PluzzDLException( "Impossible d'écrire dans le répertoire %s" % ( os.getcwd() ) ) def decompressSWF( self, swfData ): """ Decompresse un fichier swf """ # Adapted from : # Prozacgod # http://www.python-forum.org/pythonforum/viewtopic.php?f=2&t=14693 if( type( swfData ) is str ): swfData = StringIO.StringIO( swfData ) swfData.seek( 0, 0 ) magic = swfData.read( 3 ) if( magic == "CWS" ): return "FWS" + swfData.read( 5 ) + zlib.decompress( swfData.read() ) else: return None def getPlayerHash( self ): """ Recupere le sha256 du player flash """ # Get SWF player playerData = self.navigateur.getFichier( "http://static.francetv.fr/players/Flash.H264/player.swf" ) # Uncompress SWF player playerDataUncompress = self.decompressSWF( playerData ) # Perform sha256 of uncompressed SWF player hashPlayer = hashlib.sha256( playerDataUncompress ).hexdigest() # Perform base64 return base64.encodestring( hashPlayer.decode( 'hex' ) ) def debutVideo( self, fragID, fragData ): """ Trouve le debut de la video dans un fragment """ # Skip fragment header start = fragData.find( "mdat" ) + 4 # For all fragment (except frag1) if( fragID > 1 ): # Skip 2 FLV tags for dummy in range( 2 ): tagLen, = struct.unpack_from( ">L", fragData, start ) # Read 32 bits (big endian) tagLen &= 0x00ffffff # Take the last 24 bits start += tagLen + 11 + 4 # 11 = tag header len ; 4 = tag footer len return start def telecharger( self ): # Verifie si le lien du manifest contient la chaine "media-secure" if( self.manifestURL.find( "media-secure" ) != -1 ): raise PluzzDLException( "pluzzdl ne sait pas gérer ce type de vidéo (utilisation de DRMs)..." ) # Lien du manifest (apres le token) self.manifestURLToken = self.navigateur.getFichier( "http://hdfauth.francetv.fr/esi/urltokengen2.html?url=%s" % ( self.manifestURL[ self.manifestURL.find( "/z/" ) : ] ) ) # Recupere le manifest self.manifest = self.navigateur.getFichier( self.manifestURLToken ) # Parse le manifest self.parseManifest() # Calcul les elements self.hdnea = self.manifestURLToken[ self.manifestURLToken.find( "hdnea" ) : ] self.pv20, self.hdntl = self.pv2.split( ";" ) self.pvtokenData = r"st=0000000000~exp=9999999999~acl=%2f%2a~data=" + self.pv20 + "!" + self.playerHash self.pvtoken = "pvtoken=%s~hmac=%s" % ( urllib.quote( self.pvtokenData ), hmac.new( self.hmacKey, self.pvtokenData, hashlib.sha256 ).hexdigest() ) # # Creation de la video # self.premierFragment = 1 self.telechargementFini = False video = self.historique.getVideo( self.urlFrag ) # Si la video est dans l'historique if( video is not None ): # Si la video existe sur le disque if( os.path.exists( self.nomFichier ) ): if( video.finie ): logger.info( "La vidéo a déjà été entièrement téléchargée" ) return else: self.ouvrirVideoExistante() self.premierFragment = video.fragments logger.info( "Reprise du téléchargement de la vidéo au fragment %d" % ( video.fragments ) ) else: self.ouvrirNouvelleVideo() logger.info( "Impossible de reprendre le téléchargement de la vidéo, le fichier %s n'existe pas" % ( self.nomFichier ) ) else: # Si la video n'est pas dans l'historique self.ouvrirNouvelleVideo() # Calcul l'estimation du nombre de fragments self.nbFragMax = round( self.duree / 6 ) logger.debug( "Estimation du nombre de fragments : %d" % ( self.nbFragMax ) ) # Ajout des fragments logger.info( "Début du téléchargement des fragments" ) try : i = self.premierFragment self.navigateur.appendCookie( "hdntl", self.hdntl ) while( not self.stopDownloadEvent.isSet() ): # frag = self.navigateur.getFichier( "%s%d?%s&%s&%s" %( self.urlFrag, i, self.pvtoken, self.hdntl, self.hdnea ) ) frag = self.navigateur.getFichier( "%s%d" % ( self.urlFrag, i ), referer = self.adobePlayer ) debut = self.debutVideo( i, frag ) self.fichierVideo.write( frag[ debut : ] ) # Affichage de la progression self.progressFnct( min( int( ( i / self.nbFragMax ) * 100 ), 100 ) ) i += 1 except urllib2.URLError, e : if( hasattr( e, 'code' ) ): if( e.code == 403 ): if( e.reason == "Forbidden" ): logger.info( "Le hash du player semble invalide ; calcul du nouveau hash" ) newPlayerHash = self.getPlayerHash() if( newPlayerHash != self.playerHash ): self.configuration[ "player_hash" ] = newPlayerHash self.configuration.writeConfig() logger.info( "Un nouveau hash a été trouvé ; essayez de relancer l'application" ) else: logger.critical( "Pas de nouveau hash disponible..." ) else: logger.critical( "Impossible de charger la vidéo" ) elif( e.code == 404 ): self.progressFnct( 100 ) self.telechargementFini = True logger.info( "Fin du téléchargement" ) except KeyboardInterrupt: logger.info( "Interruption clavier" )
class PluzzDLM3U8( object ): """ Telechargement des liens m3u8 """ def __init__( self, m3u8URL, nomFichier, navigateur, stopDownloadEvent, progressFnct ): self.m3u8URL = m3u8URL self.nomFichier = nomFichier self.navigateur = navigateur self.stopDownloadEvent = stopDownloadEvent self.progressFnct = progressFnct self.historique = Historique() self.nomFichierFinal = "%s.mkv" % ( self.nomFichier[ :-3 ] ) def ouvrirNouvelleVideo( self ): """ Creer une nouvelle video """ try : # Ouverture du fichier self.fichierVideo = open( self.nomFichier, "wb" ) except : raise PluzzDLException( "Impossible d'écrire dans le répertoire %s" % ( os.getcwd() ) ) # Ajout de l'en-tête # Fait dans creerMKV def ouvrirVideoExistante( self ): """ Ouvre une video existante """ try : # Ouverture du fichier self.fichierVideo = open( self.nomFichier, "a+b" ) except : raise PluzzDLException( "Impossible d'écrire dans le répertoire %s" % ( os.getcwd() ) ) def creerMKV( self ): """ Creer un mkv a partir de la video existante (cree l'en-tete de la video) """ logger.info( "Création du fichier MKV (vidéo finale) ; veuillez attendre quelques instants" ) try: if( os.name == "nt" ): commande = "ffmpeg.exe -i %s -vcodec copy -acodec copy %s 1>NUL 2>NUL" % ( self.nomFichier, self.nomFichierFinal ) else: commande = "ffmpeg -i %s -vcodec copy -acodec copy %s 1>/dev/null 2>/dev/null" % ( self.nomFichier, self.nomFichierFinal ) if( os.system( commande ) == 0 ): os.remove( self.nomFichier ) logger.info( "Fin !" ) else: logger.warning( "Problème lors de la création du MKV avec FFmpeg ; le fichier %s est néanmoins disponible" % ( self.nomFichier ) ) except: raise PluzzDLException( "Impossible de créer la vidéo finale" ) def telecharger( self ): # Recupere le fichier master.m3u8 self.m3u8 = self.navigateur.getFichier( self.m3u8URL ) # Extrait l'URL de base pour tous les fragments self.urlBase = "/".join( self.m3u8URL.split( "/" )[ :-1 ] ) # Recupere le lien avec le plus gros bitrate try: self.listeFragmentsURL = re.findall( ".+?\.m3u8.*", self.m3u8 )[ -1 ] if "://" not in self.listeFragmentsURL: self.listeFragmentsURL = "%s/%s" % ( self.urlBase, self.listeFragmentsURL ) except: raise PluzzDLException( "Impossible de trouver le lien vers la liste des fragments" ) # Recupere la liste des fragments self.listeFragmentsPage = self.navigateur.getFichier( self.listeFragmentsURL ) # Extrait l'URL de tous les fragments self.listeFragments = re.findall( ".+?\.ts", self.listeFragmentsPage ) # # Creation de la video # self.premierFragment = 1 self.telechargementFini = False video = self.historique.getVideo( self.listeFragmentsURL ) # Si la video est dans l'historique if( video is not None ): # Si la video existe sur le disque if( os.path.exists( self.nomFichier ) or os.path.exists( self.nomFichierFinal ) ): if( video.finie ): logger.info( "La vidéo a déjà été entièrement téléchargée" ) if( not os.path.exists( self.nomFichierFinal ) ): self.creerMKV() return else: self.ouvrirVideoExistante() self.premierFragment = video.fragments logger.info( "Reprise du téléchargement de la vidéo au fragment %d" % ( video.fragments ) ) else: self.ouvrirNouvelleVideo() logger.info( u"Impossible de reprendre le téléchargement de la vidéo, le fichier %s n'existe pas" % ( self.nomFichier ) ) else: # Si la video n'est pas dans l'historique self.ouvrirNouvelleVideo() # Nombre de fragments self.nbFragMax = float( len( self.listeFragments ) ) logger.debug( "Nombre de fragments : %d" % ( self.nbFragMax ) ) # Ajout des fragments logger.info( "Début du téléchargement des fragments" ) try : i = self.premierFragment while( i <= self.nbFragMax and not self.stopDownloadEvent.isSet() ): fragURL = self.listeFragments[ i - 1 ] if "://" not in fragURL: fragURL = "%s/%s" % ( self.urlBase, fragURL ) frag = self.navigateur.getFichier( fragURL ) self.fichierVideo.write( frag ) # Affichage de la progression self.progressFnct( min( int( ( i / self.nbFragMax ) * 100 ), 100 ) ) i += 1 if( i == self.nbFragMax + 1 ): self.progressFnct( 100 ) self.telechargementFini = True logger.info( "Fin du téléchargement" ) self.creerMKV() except KeyboardInterrupt: logger.info( "Interruption clavier" ) except: logger.critical( "Erreur inconnue" ) finally : # Ajout dans l'historique self.historique.ajouter( Video( lien = self.listeFragmentsURL, fragments = i, finie = self.telechargementFini ) ) # Fermeture du fichier self.fichierVideo.close()
class PluzzDL( object ): def __init__( self, url, useFragments = False, proxy = None, resume = False, progressFnct = lambda x : None, stopDownloadEvent = threading.Event(), outDir = ".", manifest = False, playlist = False ): self.url = url self.useFragments = useFragments self.proxy = proxy self.resume = resume self.progressFnct = progressFnct self.stopDownloadEvent = stopDownloadEvent self.outDir = outDir self.navigateur = Navigateur( self.proxy ) self.historique = Historique() self.configuration = Configuration() self.lienMMS = None self.lienRTMP = None self.manifestURL = None self.drm = None if playlist: self.mode = "playlist" self.ext = "ts" else: self.mode = "manifest" self.ext = "flv" self.hmacKey = self.configuration[ "hmac_key" ].decode( "hex" ) self.playerHash = self.configuration[ "player_hash" ] if( re.match( "http://www.pluzz.fr/[^\.]+?\.html", self.url ) ): # Recupere l'ID de l'emission self.getID() # Recupere la page d'infos de l'emission self.pageInfos = self.navigateur.getFichier( "http://www.pluzz.fr/appftv/webservices/video/getInfosOeuvre.php?mode=zeri&id-diffusion=%s" %( self.id ) ) # Parse la page d'infos self.parseInfos() # Petit message en cas de DRM if( self.drm == "oui" ): logger.warning( "La vidéo posséde un DRM ; elle sera sans doute illisible" ) # Lien MMS trouve if( self.lienMMS is not None ): logger.info( "Lien MMS : %s\nUtiliser par exemple mimms ou msdl pour la recuperer directement ou l'option -f de pluzzdl pour essayer de la charger via ses fragments" %( self.lienMMS ) ) # Lien RTMP trouve if( self.lienRTMP is not None ): logger.info( "Lien RTMP : %s\nUtiliser par exemple rtmpdump pour la recuperer directement ou l'option -f de pluzzdl pour essayer de la charger via ses fragments" %( self.lienRTMP ) ) # N'utilise pas les fragments si cela n'a pas ete demande et que des liens directs ont ete trouves if( ( ( self.lienMMS is not None ) or ( self.lienRTMP is not None ) ) and not self.useFragments ): sys.exit( 0 ) if self.mode == "manifest": # Lien du manifest non trouve if( self.manifestURL is None ): logger.critical( "Pas de lien vers le manifest" ) sys.exit( -1 ) if self.mode == "playlist": # Lien de la playlist M3U8 non trouve if( self.playlistM3U8 is None ): logger.critical( "Pas de lien vers la playlist" ) sys.exit( -1 ) self.nomFichier = os.path.join( self.outDir, "%s.%s" %( re.findall( "http://www.pluzz.fr/([^\.]+?)\.html", self.url )[ 0 ], self.ext ) ) else: if self.mode == "manifest": page = self.navigateur.getFichier( self.url ) try: self.manifestURL = re.findall( "(http://.+?manifest.f4m)", page )[ 0 ] except: logger.critical( "Pas de lien vers le manifest" ) sys.exit( -1 ) try: self.nomFichier = os.path.join( self.outDir, "%s.flv" %( self.url.split( "/" )[ -1 ] ) ) except: self.nomFichier = os.path.join( self.outDir, "video.flv" ) self.generateNomFichier() if self.mode == "manifest": self.getVideoViaManifest() if self.mode == "playlist": self.getVideoViaPlaylist() def getVideoViaManifest( self ): # Verifie si le lien du manifest contient la chaine "media-secure" if( self.manifestURL.find( "media-secure" ) != -1 ): logger.critical( "pluzzdl ne sait pas encore gérer ce type de vidéo..." ) sys.exit( 0 ) # Lien du manifest (apres le token) self.manifestURLToken = self.navigateur.getFichier( "http://hdfauth.francetv.fr/esi/urltokengen2.html?url=%s" %( self.manifestURL[ self.manifestURL.find( "/z/" ) : ] ) ) # Recupere le manifest self.manifest = self.navigateur.getFichier( self.manifestURLToken ) # Parse le manifest self.parseManifest() # Calcul les elements self.hdnea = self.manifestURLToken[ self.manifestURLToken.find( "hdnea" ) : ] self.pv20, self.hdntl = self.pv2.split( ";" ) self.pvtokenData = r"st=0000000000~exp=9999999999~acl=%2f%2a~data=" + self.pv20 + "!" + self.playerHash self.pvtoken = "pvtoken=%s~hmac=%s" %( urllib.quote( self.pvtokenData ), hmac.new( self.hmacKey, self.pvtokenData, hashlib.sha256 ).hexdigest() ) # # Creation de la video # self.premierFragment = 1 self.telechargementFini = False # S'il faut reprendre le telechargement if( self.resume ): video = self.historique.getVideo( self.urlFrag ) # Si la video est dans l'historique if( video is not None ): # Si la video existe sur le disque if( os.path.exists( self.nomFichier ) ): if( video.finie ): logger.info( "La vidéo a déjà été entièrement téléchargée" ) sys.exit( 0 ) else: self.ouvrirVideoExistante() self.premierFragment = video.fragments logger.info( "Reprise du téléchargement de la vidéo au fragment %d" %( video.fragments ) ) else: self.ouvrirNouvelleVideo() logger.info( "Impossible de reprendre le téléchargement de la vidéo, le fichier %s n'existe pas" %( self.nomFichier ) ) else: # Si la video n'est pas dans l'historique self.ouvrirNouvelleVideo() else: # S'il ne faut pas reprendre le telechargement self.ouvrirNouvelleVideo() # Calcul l'estimation du nombre de fragments self.nbFragMax = round( self.duree / 6 ) logger.debug( "Estimation du nombre de fragments : %d" %( self.nbFragMax ) ) # Ajout des fragments logger.info( "Début du téléchargement des fragments" ) try : i = self.premierFragment while( not self.stopDownloadEvent.isSet() ): frag = self.navigateur.getFichier( "%s%d?%s&%s&%s" %( self.urlFrag, i, self.pvtoken, self.hdntl, self.hdnea ) ) debut = self.debutVideo( i, frag ) self.fichierVideo.write( frag[ debut : ] ) # Affichage de la progression self.progressFnct( min( int( ( i / self.nbFragMax ) * 100 ), 100 ) ) i += 1 except urllib2.URLError, e : if( hasattr( e, 'code' ) ): if( e.code == 403 ): if( e.reason == "Forbidden" ): logger.info( "Le hash du player semble invalide ; calcul du nouveau hash" ) newPlayerHash = self.getPlayerHash() if( newPlayerHash != self.playerHash ): self.configuration[ "player_hash" ] = newPlayerHash self.configuration.writeConfig() logger.info( "Un nouveau hash a été trouvé ; essayez de relancer l'application" ) else: logger.critical( "Pas de nouveau hash disponible..." ) else: logger.critical( "Impossible de charger la vidéo" ) elif( e.code == 404 ): self.progressFnct( 100 ) self.telechargementFini = True logger.info( "Fin du téléchargement" ) self.convertVideo() except KeyboardInterrupt: logger.info( "Interruption clavier" )
class CLIDialog(): ## Constructeur def __init__(self): # On cree l'instance de la classe dialog self.dialog = Dialog() self.dialog.setBackgroundTitle("TVDownloader") # On recupere l'instance de API self.api = API.getInstance() # On instancie le gestionnaire de download self.downloader = Downloader() # On instancie le gestionnaire d'historique self.historique = Historique() # On instancie le gestionnaire de preferences self.preferences = Preferences() # Liste des telechargements self.listeTelechargements = [] # Quand le programme se termine, on execute la fonction actionsAvantQuitter atexit.register(self.actionsAvantQuitter) # On commence self.bouclePrincipale() ## Debut def bouclePrincipale(self): choix = (1, "") while (choix != (0, "Quitter")): # On affiche le menu principal choix = self.dialog.menu( text="Menu Principal", choices=[ ["Commencer", "Afficher la liste des plugins"], ["Téléchargements", "Gérer les téléchargements"], ["Préférences", "Modifier les préférences"], ["Quitter", "Quitter TVDownloader"], ]) # On lance la methode qui va bien if (choix == (0, "Commencer")): self.utilisationPlugins() elif (choix == (0, "Téléchargements")): self.utlisationTelechargements() elif (choix == (0, "Préférences")): pass elif (choix == (0, "Quitter")): # Rien a faire, atexit gere cela pass ## Methode pour selectionner les fichiers a telecharger avec les plugins def utilisationPlugins(self): # Liste des plugins actifs listePlugins = [] for nomPlugin in self.preferences.getPreference("pluginsActifs"): listePlugins.append([nomPlugin, ""]) choixPlugin = (0, "") while (choixPlugin[0] != 1): # On affiche le menu de selection de plugins choixPlugin = self.dialog.menu( text="De quelle plugin voulez-vous voir les chaines ?", choices=listePlugins) if (choixPlugin[0] != 1): # Liste des chaines du plugin listeChaines = [] for nomChaine in self.api.getPluginListeChaines( choixPlugin[1]): listeChaines.append([nomChaine, ""]) choixChaine = (0, "") while (choixChaine[0] != 1): # On affiche le menu de selection de la chaine choixChaine = self.dialog.menu( text= "De quelle chaine voulez-vous voir les emissions ?", choices=listeChaines) if (choixChaine[0] != 1): # Liste des emissions de la chaine listeEmissions = [] for nomEmission in self.api.getPluginListeEmissions( choixPlugin[1], choixChaine[1]): listeEmissions.append([nomEmission, ""]) choixEmission = (0, "") while (choixEmission[0] != 1): # On affiche le menu de selection de l'emission choixEmission = self.dialog.menu( text= "De quelle emission voulez-vous voir les fichiers ?", choices=listeEmissions) if (choixEmission[0] != 1): listeFichiersAAfficher = [] listeFichiersCoches = [] listeFichiersPrecedementCoches = [] listeFichiersAPI = self.api.getPluginListeFichiers( choixPlugin[1], choixEmission[1]) i = 0 for fichier in listeFichiersAPI: texteAAfficher = "(%s) %s" % (getattr( fichier, "date"), getattr(fichier, "nom")) if (fichier in self.listeTelechargements): listeFichiersPrecedementCoches.append( fichier) cochee = 1 else: cochee = 0 listeFichiersAAfficher.append( [str(i), texteAAfficher, cochee]) i += 1 choixFichiers = (0, []) while (choixFichiers[0] != 1): choixFichiers = self.dialog.checklist( text= "Quels fichiers voulez-vous ajouter à la liste des téléchargements ?", choices=listeFichiersAAfficher) if (choixFichiers[0] != 1): for numeroFichier in choixFichiers[1]: fichier = listeFichiersAPI[int( numeroFichier)] listeFichiersCoches.append(fichier) for fichier in listeFichiersCoches: if not (fichier in listeFichiersPrecedementCoches ): self.listeTelechargements.append( fichier) for fichier in listeFichiersPrecedementCoches: if not (fichier in listeFichiersCoches): self.listeTelechargements.remove( fichier) # On retourne au menu precedent choixFichiers = (1, "") ## Methode qui gere le gestionnaire de telechargement def utlisationTelechargements(self): choix = (0, "") while (choix[0] != 1): # On affiche le menu principal choix = self.dialog.menu( text="Gestionnaire de téléchargement", choices=[["Consulter", "Consulter la liste"], ["Lancer", "Lancer les téléchargements"]]) # On lance la methode qui va bien if (choix == (0, "Consulter")): if (len(self.listeTelechargements) > 0): texte = "" for fichier in self.listeTelechargements: texte += "(%s) %s\n" % (getattr( fichier, "date"), getattr(fichier, "nom")) else: texte = "La liste des téléchargements est vide" # On affiche la liste des fichiers a telecharger self.dialog.msgbox(text=texte) elif (choix == (0, "Lancer")): if (len(self.listeTelechargements) > 0): liste = [] for fichier in self.listeTelechargements: lien = getattr(fichier, "lien") nomFichierSortie = getattr(fichier, "nomFichierSortie") if ( nomFichierSortie == "" ): # Si le nom du fichier de sortie n'existe pas, on l'extrait de l'URL nomFichierSortie = os.path.basename(lien) liste.append([0, lien, nomFichierSortie]) # On lance le telechargement self.downloader.lancerTelechargement(liste) self.dialog.msgbox( text="Fin du téléchargement des fichiers") del self.listeTelechargements[:] else: self.dialog.msgbox(text="Aucun fichier à télécharger") ## Methode qui execute les actions necessaires avant de quitter le programme def actionsAvantQuitter(self): print "Fermeture" # On sauvegarde les options des plugins self.api.fermeture() # On sauvegarde l'historique self.historique.sauverHistorique() # On sauvegarde les options du logiciel self.preferences.sauvegarderConfiguration()
def __init__(self, DLlist): # On instancie le gestionnaire de preferences et sa fenetre self.preferences = Preferences() # On instancie le gestionnaire de download self.downloader = Downloader() # On instancie le gestionnaire d'historique et sa fenetre self.historique = Historique() current=0 global choice choice='' while choice!='r' and choice!='R': if choice=='s' or choice=='S': os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\tSupprimer tous les fichiers de la liste de telchargement" #pour chaque fichier de la liste ***(len(DLlist))!=0 while len(DLlist)>0: print "Supprimer le fichier :",DLlist[0].nom #supprimer le fichier de la liste DLlist.remove(DLlist[0]) #ajouter le fichier au log time.sleep (1) if choice=='t' or choice=='T': os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\ttelecharger tous les fichiers" #pour chaque fichier de la liste ***(len(DLlist))!=0 while len(DLlist)>0: if not self.historique.comparerHistorique(DLlist[0]): os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\ttelecharger le fichier :",DLlist[0].nom if(DLlist[0].nomFichierSortie=="" ): DLlist[0].nomFichierSortie=os.path.basename(getattr(DLlist[0],"lien" )) #telecharger le fichier self.downloader.lancerTelechargement([[0,DLlist[0].lien,DLlist[0].nomFichierSortie]]) #ajouter le fichier a l'historique de telechargement self.historique.ajouterHistorique(DLlist[0]) else: os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\tFichier deja telecharge" #supprimer le fichier de la liste DLlist.remove(DLlist[0]) time.sleep (1) elif choice=='q' or choice=='Q': quitter() elif choice.isdigit() and len(DLlist)>int(choice)+10*current and int(choice)>=0: value='' while (value!='r' and value!='t' and value!='s'): os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\tFichier :",DLlist[int(choice)+10*current].nom,"\n\n\tQue voulez vous faire?\n\n\t\tt:telecharger le fichier\n\t\ts:supprimer le fichier de la liste de telechargement\n\t\tr:retour a liste de telechargement\n\n\n\n\n" value=getch() if value=='t': if not self.historique.comparerHistorique(DLlist[int(choice)+10*current]): os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\ttelecharger le fichier :",DLlist[int(choice)].nom # Si le nom du fichier de sortie n'existe pas, on l'extrait de l'URL if(DLlist[int(choice)+10*current].nomFichierSortie=="" ): DLlist[int(choice)+10*current].nomFichierSortie=os.path.basename(getattr(DLlist[int(choice)+10*current],"lien" )) #telecharger le fichier self.historique.ajouterHistorique(DLlist[int(choice)+10*current]) self.downloader.lancerTelechargement([[0,DLlist[int(choice)].lien,DLlist[int(choice)].nomFichierSortie]]) #ajouter le fichier a l'historique de telechargement else: os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\tFichier deja telecharge" time.sleep(1) #supprimer le fichier de la liste DLlist.remove(DLlist[int(choice)]) elif value=='s': os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\tSuppression de la liste de telechargement du fichier :\n\n\t\t",DLlist[int(choice)].nom #supprimer le fichier de la liste DLlist.remove(DLlist[int(choice)]) elif value=='r': os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\tRetour a la liste de telechargement" #ajouter le fichier au log time.sleep(1) elif choice=='*' : value='' os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\n\n\tQue voulez vous faire?\n\n\t\tt:telecharger les fichiers\n\t\ts:supprimer les fichiers de la liste de telechargement\n\n\n\n\n\n" value=getch() while len(DLlist)>0: if value=='t': if not self.historique.comparerHistorique(DLlist[0]): os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\ttelecharger le fichier :",DLlist[0].nom # Si le nom du fichier de sortie n'existe pas, on l'extrait de l'URL if(DLlist[0].nomFichierSortie=="" ): DLlist[0].nomFichierSortie=os.path.basename(getattr(DLlist[0],"lien" )) #telecharger le fichier self.downloader.lancerTelechargement([[0,DLlist[0].lien,DLlist[0].nomFichierSortie]]) #ajouter le fichier a l'historique de telechargement self.historique.ajouterHistorique(DLlist[0]) else: os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\tFichier deja telecharge" time.sleep(0.5) #supprimer le fichier de la liste DLlist.remove(DLlist[0]) #ajouter le fichier au log elif choice=='+': if len(DLlist)>current*10+10: current+=1 elif choice=='-': if current!=0: current-=1 choice='' #sauvegarder l'historique de telechargement self.historique.sauverHistorique() #affichage a l'ecran de la liste header ('','','Liste de telechargement\t') for i in range(10): if len(DLlist)>i+10*current: if len(DLlist[int(i+10*current)].nom)>74: print " ",i,":",DLlist[int(i+10*current)].nom[:71]+"..." elif len(DLlist[int(i+10*current)].nom)<=74: print " ",i,":",DLlist[int(i+10*current)].nom else: print "" if len(DLlist)>10:print "\n\t+:fichiers suivants\t-:fichiers precedents (page",current+1,"/",len(DLlist)/10+1,",",len(DLlist),"chaines)" else:print"\n" print "\n\tt:telecharger tous les fichiers s:supprimer tous les fichiers" footer() if len(DLlist)==0: os.system(['clear','cls'][os.name == 'nt']) header ('','','Liste de telechargement\t') print "\n\n\n\n\n\t\tAucun fichier dans la liste" footer() choice='r' time.sleep(1) if not choice:choice=getch()
class MainWindow( QtGui.QMainWindow ): ## Constructeur # Le constructeur va creer la fenetre principale en y ajoutant tous les widgets necessaires au programme def __init__( self ): # Appel au constructeur de la classe mere QtGui.QMainWindow.__init__( self ) ########### # Fenetre # ########### ### # Reglages de la fenetre principale ### # Nom de la fenetre self.setWindowTitle( "TVDownloader" ) # Mise en place de son icone self.setWindowIcon( QtGui.QIcon( "ico/TVDownloader.png" ) ) ### # Mise en place des widgets dans la fenetre ### # Widget central qui contiendra tout self.centralWidget = QtGui.QWidget( self ) # # Barre du haut # # Layout horizontal qui contiendra les listes deroulantes self.horizontalLayoutBarreHaut = QtGui.QHBoxLayout() # Liste deroulante pour choisir le site (plugin) self.comboBoxSite = QtGui.QComboBox( self.centralWidget ) self.horizontalLayoutBarreHaut.addWidget( self.comboBoxSite ) # Liste deroulante pour choisir une chaine du site courant self.comboBoxChaine = QtGui.QComboBox( self.centralWidget) self.horizontalLayoutBarreHaut.addWidget( self.comboBoxChaine ) # Liste deroulante pour choisir une emission de la chaine courante self.comboBoxEmission = QtGui.QComboBox( self.centralWidget ) self.horizontalLayoutBarreHaut.addWidget( self.comboBoxEmission ) # # Onglets # # Gestionnaire onglets self.tabWidget = QtGui.QTabWidget( self.centralWidget ) # Onglet Fichiers self.tabFichiers = QtGui.QSplitter( self.centralWidget ) # L'onglet Fichier contient un splitter self.tabWidget.addTab( self.tabFichiers, u"Choix des fichiers" ) # Onglet Telechargements self.tabTelechargements = QtGui.QWidget( self.centralWidget ) self.tabWidget.addTab( self.tabTelechargements, u"Téléchargements" ) # # Liste des fichiers # # Layout de grille qui contient le tableau qui liste les fichiers + boutons self.gridLayoutFichiers = QtGui.QGridLayout( self.tabFichiers ) # Tableau qui contient la liste des fichiers disponibles pour l'emission courante self.tableWidgetFichier = MyQTableWidget( self.tabFichiers ) # Il a 4 colonnes et 0 ligne (pour l'instant) self.tableWidgetFichier.setColumnCount( 3 ) self.tableWidgetFichier.setRowCount( 0 ) # On ajoute les titres self.tableWidgetFichier.setHorizontalHeaderItem( 0, self.tableWidgetFichier.creerItem( "" ) ) self.tableWidgetFichier.setHorizontalHeaderItem( 1, self.tableWidgetFichier.creerItem( "Date" ) ) self.tableWidgetFichier.setHorizontalHeaderItem( 2, self.tableWidgetFichier.creerItem( "Emission" ) ) # On l'ajoute au layout self.gridLayoutFichiers.addWidget( self.tableWidgetFichier, 0, 1, 6, 1 ) # Icones du tableWidget self.iconeFichier = QtGui.QIcon( "ico/gtk-file.svg" ) self.iconeAjoute = QtGui.QIcon( "ico/gtk-add.svg" ) self.iconeTelecharge = QtGui.QIcon( "ico/gtk-apply.svg" ) # Bouton pour ajouter tous les fichiers a la liste des telechargements self.pushButtonToutAjouter = MyQPushButton( self.tabFichiers ) self.pushButtonToutAjouter.setIcon( QtGui.QIcon( "ico/gtk-add.svg" ) ) self.pushButtonToutAjouter.setToolTip( u"Ajouter tous les fichiers à la liste des téléchargements" ) self.gridLayoutFichiers.addWidget( self.pushButtonToutAjouter, 0, 0, 2, 1 ) # Bouton pour rafraichir le plugin courant self.pushButtonRafraichirPlugin = MyQPushButton( self.tabFichiers ) self.pushButtonRafraichirPlugin.setIcon( QtGui.QIcon( "ico/gtk-refresh.svg" ) ) self.pushButtonRafraichirPlugin.setToolTip( "Rafraichir le plugin" ) self.gridLayoutFichiers.addWidget( self.pushButtonRafraichirPlugin, 2, 0, 2, 1 ) # Bouton pour ouvrir la fenetre des preferences du plugin courant self.pushButtonPreferencesPlugin = MyQPushButton( self.tabFichiers ) self.pushButtonPreferencesPlugin.setIcon( QtGui.QIcon( "ico/gtk-preferences.svg" ) ) self.pushButtonPreferencesPlugin.setToolTip( u"Ouvrir les préférences du plugin" ) self.gridLayoutFichiers.addWidget( self.pushButtonPreferencesPlugin, 4, 0, 2, 1 ) # On met en place ce layout sur un widget (pour le splitter) self.widgetFichiers = QtGui.QWidget() self.widgetFichiers.setLayout( self.gridLayoutFichiers ) # # Descriptif des fichiers # # Layout de grille self.gridLayoutDescriptif = QtGui.QGridLayout() # Label pour afficher un logo self.logoFichierDefaut = QtGui.QPixmap() self.logoFichierDefaut.load( "img/gtk-dialog-question.svg" ) self.labelLogo = QtGui.QLabel( self.centralWidget ) self.labelLogo.setPixmap( self.logoFichierDefaut.scaled( QtCore.QSize( 150, 150 ), QtCore.Qt.KeepAspectRatio ) ) self.gridLayoutDescriptif.addWidget( self.labelLogo, 0, 0, 1, 1 ) # Zone de texte pour afficher un descriptif self.plainTextEdit = QtGui.QPlainTextEdit( self.centralWidget ) self.gridLayoutDescriptif.addWidget( self.plainTextEdit, 0, 1, 1, 2 ) # On met en place ce layout sur un widget (pour le splitter) self.widgetDescriptif = QtGui.QWidget() self.widgetDescriptif.setLayout( self.gridLayoutDescriptif ) # Onrientation verticale du splitter self.tabFichiers.setOrientation( QtCore.Qt.Vertical ) # On ajoute les 2 elements au splitter (qui est notre onglet) self.tabFichiers.addWidget( self.widgetFichiers ) self.tabFichiers.addWidget( self.widgetDescriptif ) # # Liste des telechargements # # Layout de grille qui contient le tableau qui liste les fichiers a telecharger + les boutons pour le controller self.gridLayoutTelechargement = QtGui.QGridLayout( self.tabTelechargements ) # Tableau qui contient la liste des fichiers a telecharger self.tableWidgetTelechargement = MyQTableWidget( self.tabTelechargements ) # Il a 5 colonnes et 0 ligne (pour l'instant) self.tableWidgetTelechargement.setColumnCount( 3 ) self.tableWidgetTelechargement.setRowCount( 0 ) # On ajoute le titre des 5 colonnes self.tableWidgetTelechargement.setHorizontalHeaderItem( 0, self.tableWidgetTelechargement.creerItem( "Date" ) ) self.tableWidgetTelechargement.setHorizontalHeaderItem( 1, self.tableWidgetTelechargement.creerItem( "Emission" ) ) self.tableWidgetTelechargement.setHorizontalHeaderItem( 2, self.tableWidgetTelechargement.creerItem( "Etat" ) ) # On l'ajoute au layout self.gridLayoutTelechargement.addWidget( self.tableWidgetTelechargement, 0, 1, 4, 1 ) # Bouton pour monter l'element selectionne tout en haut de la liste self.pushButtonExtremiteMonter = MyQPushButton( self.tabTelechargements ) self.pushButtonExtremiteMonter.setIcon( QtGui.QIcon( "ico/gtk-jump-to-rtl.svg" ) ) self.pushButtonExtremiteMonter.setToolTip( u"Placer l'élément sélectionné tout en haut" ) self.gridLayoutTelechargement.addWidget( self.pushButtonExtremiteMonter, 0, 0, 1, 1 ) # Bouton pour monter l'element selectionne d'un cran dans la liste self.pushButtonMonter = MyQPushButton( self.tabTelechargements ) self.pushButtonMonter.setIcon( QtGui.QIcon( "ico/gtk-go-up.svg" ) ) self.pushButtonMonter.setToolTip( u"Monter l'élément sélectionné" ) self.gridLayoutTelechargement.addWidget( self.pushButtonMonter, 1, 0, 1, 1 ) # Bouton pour descendre l'element selectionne d'un cran dans la liste self.pushButtonDescendre = MyQPushButton( self.tabTelechargements ) self.pushButtonDescendre.setIcon( QtGui.QIcon( "ico/gtk-go-down.svg" ) ) self.pushButtonDescendre.setToolTip( u"Descendre l'élément selectionné" ) self.gridLayoutTelechargement.addWidget( self.pushButtonDescendre, 2, 0, 1, 1 ) # Bouton pour descendre l'element selectionne tout en bas de la liste self.pushButtonExtremiteDescendre = MyQPushButton( self.tabTelechargements ) self.pushButtonExtremiteDescendre.setIcon( QtGui.QIcon( "ico/gtk-jump-to-ltr.svg" ) ) self.pushButtonExtremiteDescendre.setToolTip( u"Placer l'élément sélectionné tout en bas" ) self.gridLayoutTelechargement.addWidget( self.pushButtonExtremiteDescendre, 3, 0, 1, 1 ) # Bouton pour supprimer tous les elements de la liste self.pushButtonToutSupprimer = MyQPushButton( self.tabTelechargements ) self.pushButtonToutSupprimer.setIcon( QtGui.QIcon( "ico/gtk-cancel.svg" ) ) self.pushButtonToutSupprimer.setToolTip( u"Supprimer tous les téléchargements" ) self.gridLayoutTelechargement.addWidget( self.pushButtonToutSupprimer, 0, 2, 1, 1 ) # Bouton pour supprimer de la liste les telechargements termines self.pushButtonNettoyer = MyQPushButton( self.tabTelechargements ) self.pushButtonNettoyer.setIcon( QtGui.QIcon( "ico/gtk-delete-full.svg" ) ) self.pushButtonNettoyer.setToolTip( u"Supprimer les téléchargement terminés" ) self.gridLayoutTelechargement.addWidget( self.pushButtonNettoyer, 1, 2, 1, 1 ) # Bouton pour ouvrir le dossier des telechargements self.pushButtonOuvrirDossierTelechargement = MyQPushButton( self.tabTelechargements ) self.pushButtonOuvrirDossierTelechargement.setIcon( QtGui.QIcon( "ico/gtk-folder.svg" ) ) self.pushButtonOuvrirDossierTelechargement.setToolTip( u"Ouvrir le dossier des téléchargements" ) self.gridLayoutTelechargement.addWidget( self.pushButtonOuvrirDossierTelechargement, 2, 2, 1, 1 ) # # Barre progression de telechargement d'un fichier # self.progressBarTelechargementFichier = QtGui.QProgressBar( self.centralWidget ) self.progressBarTelechargementFichier.setProperty( "value", 0 ) # # Barre de progression de telechargement des fichiers # self.progressBarTelechargement = QtGui.QProgressBar( self.centralWidget ) self.progressBarTelechargement.setProperty( "value", 0 ) # # Boutons du bas pour gerer ajouter/supprimer/lancer telechargements # # Layout horizontal qui contiendra les boutons self.horizontalLayoutBarreBas = QtGui.QHBoxLayout() # Bouton pour lancer les telechargements self.pushButtonLancer = QtGui.QPushButton( QtGui.QIcon( "ico/gtk-media-play-ltr.svg" ), u"Lancer téléchargement", self.centralWidget ) self.horizontalLayoutBarreBas.addWidget( self.pushButtonLancer ) # Bouton pour stopper les telechargements self.pushButtonStop = QtGui.QPushButton( QtGui.QIcon( "ico/gtk-media-stop.svg" ), u"Stopper le téléchargement", self.centralWidget ) self.pushButtonStop.setEnabled( False ) self.horizontalLayoutBarreBas.addWidget( self.pushButtonStop ) ### # Positionnement des differents widgets/layouts sur le layout de grille ### # Layout de grille dans lequel on va placer nos widgets/layouts self.gridLayout = QtGui.QGridLayout( self.centralWidget ) # On ajoute la barre du haut self.gridLayout.addLayout( self.horizontalLayoutBarreHaut, 0, 0, 1, 3 ) # On ajoute le gestionnaire d'onglets self.gridLayout.addWidget( self.tabWidget, 1, 0, 1, 3 ) # On ajoute la barre de progression de telechargement d'un fichier self.gridLayout.addWidget( self.progressBarTelechargementFichier, 2, 0, 1, 3 ) # On ajoute la barre de progression de telechargement des fichiers self.gridLayout.addWidget( self.progressBarTelechargement, 3, 0, 1, 3 ) # On ajoute les boutons ajouter/supprimer/lancer self.gridLayout.addLayout( self.horizontalLayoutBarreBas, 4, 0, 1, 3 ) ### # Mise en place le central widget dans la fenetre ### self.setCentralWidget( self.centralWidget ) ### # Mise en place du menu ### # Menu barre self.menubar = QtGui.QMenuBar( self ) self.menubar.setGeometry( QtCore.QRect( 0, 0, 480, 25 ) ) # Menu Fichier self.menuFichier = QtGui.QMenu( "&Fichier", self.menubar ) self.menubar.addAction( self.menuFichier.menuAction() ) # Action Fichier -> Quitter self.actionQuitter = QtGui.QAction( QtGui.QIcon( "ico/gtk-quit.svg" ), "&Quitter", self ) self.actionQuitter.setIconVisibleInMenu( True ) self.menuFichier.addAction( self.actionQuitter ) # Menu Edition self.menuEdition = QtGui.QMenu( "&Edition", self.menubar ) self.menubar.addAction( self.menuEdition.menuAction() ) # Action Edition -> Mise a jour self.actionMAJ = QtGui.QAction( QtGui.QIcon( "ico/gtk-refresh.svg" ), u"&Mise à jour des plugins", self ) self.actionMAJ.setIconVisibleInMenu( True ) self.menuEdition.addAction( self.actionMAJ ) # Action Edition -> Preferences self.actionPreferences = QtGui.QAction( QtGui.QIcon( "ico/gtk-preferences.svg" ), u"&Préférences", self ) self.actionPreferences.setIconVisibleInMenu( True ) self.menuEdition.addAction( self.actionPreferences ) # Menu Aide self.menuAide = QtGui.QMenu( "&Aide", self.menubar ) self.menubar.addAction( self.menuAide.menuAction() ) # Action Aide -> A propos self.actionAPropos = QtGui.QAction( QtGui.QIcon( "ico/gtk-about.svg" ), u"À p&ropos", self ) self.actionAPropos.setIconVisibleInMenu( True ) self.menuAide.addAction( self.actionAPropos ) # Ajout du menu a l'interface self.setMenuBar( self.menubar ) ### # Signaux provenants de l'interface ### QtCore.QObject.connect( self.tableWidgetFichier, QtCore.SIGNAL( "cellClicked(int,int)" ), self.afficherInformationsFichier ) QtCore.QObject.connect( self.tableWidgetFichier, QtCore.SIGNAL( "cellDoubleClicked(int,int)" ), self.gererTelechargement ) QtCore.QObject.connect( self.pushButtonToutAjouter, QtCore.SIGNAL( "clicked()" ), self.ajouterTousLesFichiers ) QtCore.QObject.connect( self.pushButtonRafraichirPlugin, QtCore.SIGNAL( "clicked()" ), self.rafraichirPlugin ) QtCore.QObject.connect( self.tableWidgetTelechargement, QtCore.SIGNAL( "cellDoubleClicked(int,int)" ), self.supprimerTelechargement ) QtCore.QObject.connect( self.pushButtonExtremiteMonter, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = True, extremite = True : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonMonter, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = True, extremite = False : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonDescendre, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = False, extremite = False : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonExtremiteDescendre, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = False, extremite = True : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonToutSupprimer, QtCore.SIGNAL( "clicked()" ), self.supprimerTousLesTelechargements ) QtCore.QObject.connect( self.pushButtonNettoyer, QtCore.SIGNAL( "clicked()" ), self.nettoyer ) QtCore.QObject.connect( self.pushButtonLancer, QtCore.SIGNAL( "clicked()" ), self.lancerTelechargement ) QtCore.QObject.connect( self.pushButtonStop, QtCore.SIGNAL( "clicked()" ), self.stopperTelechargement ) QtCore.QObject.connect( self.actionQuitter, QtCore.SIGNAL( "triggered()" ), self.close ) ################################################ # Instanciations + initialisation de variables # ################################################ # Fenetre About self.aProposDialog = None # Fenetre des preferences du logiciel self.preferencesDialog = None # Fenetre de mise a jour des plugins self.updateManagerDialog = None # Nom plugin courant self.nomPluginCourant = "" # Liste des fichiers self.listeFichiers = [] # Liste des fichiers a telecharger self.listeFichiersATelecharger = [] # Cache des images descriptive # Clef : urlImage Valeur : image (binaire) self.cacheImage = {} # On intancie le lanceur de signaux self.signaux = Signaux() # On instancie le gestionnaire de preferences self.preferences = Preferences() # On instancie le gestionnaire de preferences des plugins self.preferencesPluginDialog = PreferencePluginDialog( self ) # On instancie le gestionnaire de download self.downloader = Downloader( self.signaux ) # On recupere l'instance de API self.api = API.getInstance() # On instancie le gestionnaire d'historique self.historique = Historique() # On instancie la fenetre d'attente self.fenetreAttenteProgressDialog = FenetreAttenteProgressDialog( self ) # On instancie le gest # # Fenetre de confirmation pour quitter le logiciel # self.quitterMessageBox = QtGui.QMessageBox( self ) self.quitterMessageBox.setWindowTitle( "Fermeture de TVDownloader" ) self.quitterMessageBox.setText( u"Voulez-vous réellement quitter TVDownloader ?" ) self.quitterMessageBox.setInformativeText( u"Votre liste de téléchargement sera perdue" ) self.quitterMessageBox.addButton( "Oui", QtGui.QMessageBox.AcceptRole ) self.quitterMessageBox.addButton( "Non", QtGui.QMessageBox.RejectRole ) ############################################################ # On connecte les signaux des instances precedements crees # ############################################################ QtCore.QObject.connect( self.pushButtonOuvrirDossierTelechargement, QtCore.SIGNAL( "clicked()" ), self.ouvrirRepertoireTelechargement ) QtCore.QObject.connect( self.comboBoxSite, QtCore.SIGNAL( "activated(QString)" ), self.listerChaines ) QtCore.QObject.connect( self.comboBoxChaine, QtCore.SIGNAL( "activated(QString)" ), self.listerEmissions ) QtCore.QObject.connect( self.comboBoxEmission, QtCore.SIGNAL( "activated(QString)" ), self.listerFichiers ) QtCore.QObject.connect( self.pushButtonPreferencesPlugin, QtCore.SIGNAL( "clicked()" ), self.ouvrirPreferencesPlugin ) QtCore.QObject.connect( self.actionPreferences, QtCore.SIGNAL( "triggered()" ), self.ouvrirPreferencesLogiciel ) QtCore.QObject.connect( self.actionMAJ, QtCore.SIGNAL( "triggered()" ), self.ouvrirFenetreMiseAJour ) QtCore.QObject.connect( self.actionAPropos, QtCore.SIGNAL( "triggered()" ), self.ouvrirFenetreAPropos ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "debutActualisation(PyQt_PyObject)" ) , self.fenetreAttenteProgressDialog.ouvrirFenetreAttente ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "finActualisation()" ) , self.fenetreAttenteProgressDialog.fermerFenetreAttente ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "actualiserListesDeroulantes()" ) , self.actualiserListesDeroulantes ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "listeChaines(PyQt_PyObject)" ) , self.ajouterChaines ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "listeEmissions(PyQt_PyObject)" ) , self.ajouterEmissions ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "listeFichiers(PyQt_PyObject)" ) , self.ajouterFichiers ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "nouvelleImage(PyQt_PyObject)" ) , self.mettreEnPlaceImage ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "debutTelechargement(int)" ) , self.debutTelechargement ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "finTelechargement(int)" ) , self.finTelechargement ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "finDesTelechargements()" ) , self.activerDesactiverInterface ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "pourcentageFichier(int)" ) , self.progressBarTelechargementFichier.setValue ) ######### # Début # ######### # La fenetre prend la dimension qu'elle avait a sa fermeture taille = self.preferences.getPreference( "tailleFenetre" ) self.resize( taille[ 0 ], taille[ 1 ] ) # Si aucun plugin n'est active, on ouvre la fenetre des preferences if( len( self.preferences.getPreference( "pluginsActifs" ) ) == 0 ): self.ouvrirPreferencesLogiciel() # On actualise tous les plugins self.rafraichirTousLesPlugins() ## Methode qui execute les actions necessaires avant de quitter le programme def actionsAvantQuitter( self ): # On sauvegarde les options des plugins self.api.fermeture() # On sauvegarde la taille de la fenetre taille = self.size() self.preferences.setPreference( "tailleFenetre", [ taille.width(), taille.height() ] ) # On sauvegarde les options du logiciel self.preferences.sauvegarderConfiguration() # On sauvegarde l'historique self.historique.sauverHistorique() # On stoppe les telechargements self.stopperTelechargement() ######################################### # Surcharge des methodes de QMainWindow # ######################################### ## Surcharge de la methode appelee lors de la fermeture de la fenetre # Ne doit pas etre appele explicitement # @param evenement Evenement qui a provoque la fermeture def closeEvent( self, evenement ): # On affiche une fenetre pour demander la fermeture si des fichiers sont dans la liste de telechargement if( self.tableWidgetTelechargement.rowCount() > 0 ): # On affiche une fenetre qui demande si on veut quitter retour = self.quitterMessageBox.exec_() # Si on veut quitter if( retour == 0 ): # On execute les actions necessaires self.actionsAvantQuitter() # On accept la fermeture evenement.accept() else: # On refuse la fermeture evenement.ignore() else: # S'il n'y a pas de fichier # On execute les actions necessaires self.actionsAvantQuitter() # On accept la fermeture evenement.accept() ############################################## # Methodes pour remplir les menus deroulants # ############################################## ## Methode qui actualise les listes deroulantes def actualiserListesDeroulantes( self ): # On lance juste l'ajout des sites en se basant sur les plugins actifs self.ajouterSites( self.preferences.getPreference( "pluginsActifs" ) ) ## Methode qui lance le listage des chaines # @param site Nom du plugin/site pour lequel on va lister les chaines def listerChaines( self, site ): def threadListerChaines( self, nomPlugin ): self.signaux.signal( "debutActualisation", nomPlugin ) listeChaines = self.api.getPluginListeChaines( nomPlugin ) self.signaux.signal( "listeChaines", listeChaines ) self.signaux.signal( "finActualisation" ) if( site != "" ): self.nomPluginCourant = qstringToString( site ) threading.Thread( target = threadListerChaines, args = ( self, self.nomPluginCourant ) ).start() # On active (ou pas) le bouton de preference du plugin self.pushButtonPreferencesPlugin.setEnabled( self.api.getPluginListeOptions( self.nomPluginCourant ) != [] ) ## Methode qui lance le listage des emissions # @param chaine Nom de la chaine pour laquelle on va lister les emissions def listerEmissions( self, chaine ): def threadListerEmissions( self, nomPlugin, chaine ): self.signaux.signal( "debutActualisation", nomPlugin ) listeEmissions = self.api.getPluginListeEmissions( nomPlugin, chaine ) self.signaux.signal( "listeEmissions", listeEmissions ) self.signaux.signal( "finActualisation" ) if( chaine != "" ): threading.Thread( target = threadListerEmissions, args = ( self, self.nomPluginCourant, qstringToString( chaine ) ) ).start() ## Methode qui lance le listage des fichiers # @param emission Nom de l'emission pour laquelle on va lister les fichiers def listerFichiers( self, emission ): def threadListerFichiers( self, nomPlugin, emission ): self.signaux.signal( "debutActualisation", nomPlugin ) listeFichiers = self.api.getPluginListeFichiers( nomPlugin, emission ) self.signaux.signal( "listeFichiers", listeFichiers ) self.signaux.signal( "finActualisation" ) if( emission != "" ): threading.Thread( target = threadListerFichiers, args = ( self, self.nomPluginCourant, qstringToString( emission ) ) ).start() ## Methode qui met en place une liste de sites sur l'interface # @param listeSites Liste des sites a mettre en place def ajouterSites( self, listeSites ): # On efface la liste des sites self.comboBoxSite.clear() # On met en place les sites for site in listeSites: self.comboBoxSite.addItem( stringToQstring( site ) ) # On selectionne par defaut celui choisis dans les preference index = self.comboBoxSite.findText( stringToQstring( self.preferences.getPreference( "pluginParDefaut" ) ) ) if( index != -1 ): self.comboBoxSite.setCurrentIndex( index ) # On lance l'ajout des chaines self.listerChaines( self.comboBoxSite.currentText() ) ## Methode qui met en place une liste de chaines sur l'interface # @param listeChaines Liste des chaines a mettre en place def ajouterChaines( self, listeChaines ): # On trie la liste des chaines listeChaines.sort() # On efface la liste des chaines self.comboBoxChaine.clear() # On efface la liste des emissions self.comboBoxEmission.clear() # On efface la liste des fichiers self.tableWidgetFichier.toutSupprimer() # On met en place les chaines for chaine in listeChaines: self.comboBoxChaine.addItem( stringToQstring( chaine ) ) # Si on a juste une seule chaine if( self.comboBoxChaine.count() == 1 ): # On lance l'ajout des emissions self.listerEmissions( self.comboBoxChaine.currentText() ) else: # On ne selectionne pas de chaine self.comboBoxChaine.setCurrentIndex( -1 ) ## Methode qui met en place une liste d'emissions sur l'interface # @param listeEmissions Liste des emissions a mettre en place def ajouterEmissions( self, listeEmissions ): # On trie la liste des emissions listeEmissions.sort() # On efface la liste des emissions self.comboBoxEmission.clear() # On efface la liste des fichiers self.tableWidgetFichier.toutSupprimer() # On met en place la liste des emissions for emission in listeEmissions: self.comboBoxEmission.addItem( stringToQstring( emission ) ) # Si on a juste une seule emission if( self.comboBoxEmission.count() == 1 ): # On lance l'ajout des fichiers self.listerFichiers( self.comboBoxEmission.currentText() ) else: # On ne selectionne pas d'emission self.comboBoxEmission.setCurrentIndex( -1 ) ############################################### # Methodes pour remplir la liste des fichiers # ############################################### ## Methode pour ajouter des fichiers a l'interface # @param listeFichiers Liste des fichiers a ajouter def ajouterFichiers( self, listeFichiers ): self.listeFichiers = listeFichiers # On efface la liste des fichiers self.tableWidgetFichier.toutSupprimer() # On commence au depart ligneCourante = 0 # On met en place chacun des fichiers for fichier in listeFichiers: # On ajoute une ligne self.tableWidgetFichier.insertRow( ligneCourante ) # On ajoute les informations au tableWidgetFichier liste = [] liste.append( self.tableWidgetFichier.creerItem( "" ) ) liste.append( self.tableWidgetFichier.creerItem( getattr( fichier, "date" ) ) ) liste.append( self.tableWidgetFichier.creerItem( getattr( fichier, "nom" ) ) ) self.tableWidgetFichier.setLigne( ligneCourante, liste ) # On met en place l'icone qui va bien self.gererIconeListeFichier( fichier ) ligneCourante += 1 # On adapte la taille des colonnes self.tableWidgetFichier.adapterColonnes() ## Methode qui rafraichit le plugin courant def rafraichirPlugin( self ): def threadRafraichirPlugin( self, nomPlugin ): self.signaux.signal( "debutActualisation", nomPlugin ) self.api.pluginRafraichir( nomPlugin ) self.signaux.signal( "finActualisation" ) threading.Thread( target = threadRafraichirPlugin, args = ( self, self.nomPluginCourant ) ).start() ## Methode qui met en place l'image de la description d'un fichier # @param image Image a mettre en place (binaire) def mettreEnPlaceImage( self, image ): logoFichier = QtGui.QPixmap() logoFichier.loadFromData( image ) self.labelLogo.setPixmap( logoFichier.scaled( QtCore.QSize( 150, 150 ), QtCore.Qt.KeepAspectRatio ) ) ## Methode qui affiche des informations sur le fichier selectionne def afficherInformationsFichier( self, ligne, colonne ): def threadRecupererImage( self, urlImage ): image = self.api.getPage( urlImage ) self.cacheImage[ urlImage ] = image self.signaux.signal( "nouvelleImage", image ) fichier = self.listeFichiers[ ligne ] # On recupere le lien de l'image et le texte descriptif urlImage = getattr( fichier, "urlImage" ) texteDescriptif = getattr( fichier, "descriptif" ) self.plainTextEdit.clear() # Si on a un texte descriptif, on l'affiche if( texteDescriptif != "" ): self.plainTextEdit.appendPlainText( stringToQstring( texteDescriptif ) ) else: self.plainTextEdit.appendPlainText( u"Aucune information disponible" ) # Si on n'a pas d'image if( urlImage == "" ): # On met en place celle par defaut self.logoFichier = self.logoFichierDefaut self.labelLogo.setPixmap( self.logoFichier.scaled( QtCore.QSize( 150, 150 ), QtCore.Qt.KeepAspectRatio ) ) else: # Si on en a une # Si elle est dans le cache des images if( self.cacheImage.has_key( urlImage ) ): self.mettreEnPlaceImage( self.cacheImage[ urlImage ] ) else: # Sinon # On lance le thread pour la recuperer threading.Thread( target = threadRecupererImage, args = ( self, urlImage ) ).start() ## Methode qui gere l'icone d'un fichier dans la liste des telechargements # Il y a 3 icones possible : # - C'est un fichier # - C'est un fichier present dans l'historique (donc deja telecharge) # - C'est un fichier present dans la liste des telechargements # @param fichier Fichier a gerer def gererIconeListeFichier( self, fichier ): if( fichier in self.listeFichiers ): ligneFichier = self.listeFichiers.index( fichier ) # On cherche quel icone mettre en place if( fichier in self.listeFichiersATelecharger ): icone = self.iconeAjoute elif( self.historique.comparerHistorique( fichier ) ): icone = self.iconeTelecharge else: icone = self.iconeFichier # On met en place l'icone self.tableWidgetFichier.item( ligneFichier, 0 ).setIcon( icone ) ###################################################### # Methodes pour remplir la liste des telechargements # ###################################################### ## Methode qui gere la liste des telechargements # @param ligne Numero de la ligne (dans la liste des fichiers) de l'element a ajouter # @param colonne Numero de colonne (inutile, juste pour le slot) def gererTelechargement( self, ligne, colonne = 0 ): fichier = self.listeFichiers[ ligne ] # Si le fichier est deja dans la liste des telechargements if( fichier in self.listeFichiersATelecharger ): ligneTelechargement = self.listeFichiersATelecharger.index( fichier ) self.supprimerTelechargement( ligneTelechargement ) else: # S'il n'y est pas, on l'ajoute self.listeFichiersATelecharger.append( fichier ) numLigne = self.tableWidgetTelechargement.rowCount() # On insere une nouvelle ligne dans la liste des telechargements self.tableWidgetTelechargement.insertRow( numLigne ) # On y insere les elements qui vont biens self.tableWidgetTelechargement.setLigne( numLigne, [ self.tableWidgetTelechargement.creerItem( getattr( fichier, "date" ) ), self.tableWidgetTelechargement.creerItem( getattr( fichier, "nom" ) ), self.tableWidgetTelechargement.creerItem( u"En attente de téléchargement" ) ] ) # On adapte la taille des colonnes self.tableWidgetTelechargement.adapterColonnes() # On modifie l'icone dans la liste des fichiers self.gererIconeListeFichier( fichier ) ## Methode qui ajoute tous les fichiers a la liste des telechargements def ajouterTousLesFichiers( self ): for i in range( self.tableWidgetFichier.rowCount() ): self.gererTelechargement( i ) ## Methode qui supprime un fichier de la liste des telechargements # @param ligne Numero de la ligne a supprimer # @param colonne Numero de colonne (inutile, juste pour le slot) def supprimerTelechargement( self, ligne, colonne = 0 ): fichier = self.listeFichiersATelecharger[ ligne ] # On supprime l'element du tableWidgetTelechargement self.tableWidgetTelechargement.removeRow( ligne ) # On supprime l'element de la liste des fichiers a telecharger self.listeFichiersATelecharger.remove( fichier ) # On modifie l'icone dans la liste des fichiers self.gererIconeListeFichier( fichier ) ## Methode qui supprime tous les telechargement de la liste des telechargements def supprimerTousLesTelechargements( self ): for i in range( self.tableWidgetTelechargement.rowCount() -1, -1, -1 ): self.supprimerTelechargement( i ) ## Methode qui lance le telechargement des fichiers def lancerTelechargement( self ): # On liste les emissions a telecharger avec leurs numeros de ligne listeFichiers = [] for i in range( self.tableWidgetTelechargement.rowCount() ): # Pour chaque ligne fichier = self.listeFichiersATelecharger[ i ] listeFichiers.append( [ i, getattr( fichier, "lien" ), getattr( fichier, "nomFichierSortie" ) ] ) nbATelecharger = len( listeFichiers ) # Si on a des elements a charger if( nbATelecharger > 0 ): # On met en place la valeur du progressBar self.progressBarTelechargement.setMaximum( nbATelecharger ) self.progressBarTelechargement.setValue( 0 ) # On lance le telechargement threading.Thread( target = self.downloader.lancerTelechargement, args = ( listeFichiers, ) ).start() # On active/desactive ce qui va bien sur l'interface self.activerDesactiverInterface( True ) ## Methode qui stoppe le telechargement def stopperTelechargement( self ): # On stoppe le telechargement self.downloader.stopperTelechargement() ############################################ # Methodes pour ouvrir les autres fenetres # ############################################ # # Fenetre About # ## Methode pour afficher la fenetre About def ouvrirFenetreAPropos( self ): if( self.aProposDialog == None ): self.aProposDialog = AProposDialog() self.aProposDialog.show() # # Fenetre de preference du logiciel # ## Methode pour ouvrir les preferences du logiciel def ouvrirPreferencesLogiciel( self ): if( self.preferencesDialog == None ): self.preferencesDialog = PreferencesDialog( self, self.signaux ) self.preferencesDialog.afficher() # # Fenetre de mise a jour des plugins # ## Methode pour ouvrir la fenetre de mise a jour des plugins def ouvrirFenetreMiseAJour( self ): if( self.updateManagerDialog == None ): self.updateManagerDialog = UpdateManagerDialog( self ) self.updateManagerDialog.afficher() # # Fenetre de preference des plugins # ## Methode pour ouvrir les preferences du plugin courant def ouvrirPreferencesPlugin( self ): listeOptions = self.api.getPluginListeOptions( self.nomPluginCourant ) self.preferencesPluginDialog.ouvrirDialogPreferences( self.nomPluginCourant, listeOptions ) ######### # Slots # ######### ## Methode qui ouvre le repertoire de telechargement def ouvrirRepertoireTelechargement( self ): QtGui.QDesktopServices.openUrl( QtCore.QUrl.fromLocalFile( self.preferences.getPreference( "repertoireTelechargement" ) ) ) ## Methode qui rafraichit le plugin courant def rafraichirPlugin( self ): def threadRafraichirPlugin( self, nomPlugin ): self.signaux.signal( "debutActualisation", nomPlugin ) self.api.pluginRafraichir( nomPlugin ) self.signaux.signal( "finActualisation" ) threading.Thread( target = threadRafraichirPlugin, args = ( self, self.nomPluginCourant ) ).start() ## Methode qui rafraichit tous les plugins # A utiliser au lancement du programme def rafraichirTousLesPlugins( self ): def threadRafraichirTousLesPlugins( self ): self.signaux.signal( "debutActualisation", "TVDownloader" ) self.api.pluginRafraichirAuto() self.signaux.signal( "finActualisation" ) self.signaux.signal( "actualiserListesDeroulantes" ) threading.Thread( target = threadRafraichirTousLesPlugins, args = ( self, ) ).start() ## Slot qui active/desactive des elements de l'interface pendant un telechargement # @param telechargementEnCours Indique si on telecharge ou pas def activerDesactiverInterface( self, telechargementEnCours = False ): # Les boutons self.pushButtonLancer.setEnabled( not telechargementEnCours ) self.pushButtonStop.setEnabled( telechargementEnCours ) self.pushButtonExtremiteMonter.setEnabled( not telechargementEnCours ) self.pushButtonMonter.setEnabled( not telechargementEnCours ) self.pushButtonDescendre.setEnabled( not telechargementEnCours ) self.pushButtonExtremiteDescendre.setEnabled( not telechargementEnCours ) self.pushButtonToutSupprimer.setEnabled( not telechargementEnCours ) self.pushButtonNettoyer.setEnabled( not telechargementEnCours ) # Le table widget self.tableWidgetTelechargement.setEnabled( not telechargementEnCours ) ## Slot appele lors ce qu'un le debut d'un telechargement commence # @param numero Position dans la liste des telechargement du telechargement qui commence def debutTelechargement( self, numero ): self.tableWidgetTelechargement.item( numero, 2 ).setText( stringToQstring( u"Téléchargement en cours..." ) ) self.tableWidgetTelechargement.adapterColonnes() self.progressBarTelechargementFichier.setValue( 0 ) ## Slot appele lorsqu'un telechargement se finit # @param numero Position dans la liste des telechargement du telechargement qui se finit def finTelechargement( self, numero ): fichier = self.listeFichiersATelecharger[ numero ] # On ajoute le fichier a l'historique self.historique.ajouterHistorique( fichier ) # On modifie l'icone dans la liste des fichiers self.gererIconeListeFichier( fichier ) # On modifie l'interface self.tableWidgetTelechargement.item( numero, 2 ).setText( stringToQstring( u"Fini !" ) ) self.progressBarTelechargement.setValue( self.progressBarTelechargement.value() + 1 ) self.tableWidgetTelechargement.adapterColonnes() self.progressBarTelechargementFichier.setValue( 100 ) ## Slot qui nettoie la liste des telechargements de tous les telechargements finis def nettoyer( self ): for i in range( self.tableWidgetTelechargement.rowCount() - 1, -1, -1 ): # [ nbLignes - 1, nbLignes - 2, ..., 1, 0 ] if( self.tableWidgetTelechargement.item( i, 2 ).text() == u"Fini !" ): # Si c'est telecharge self.supprimerTelechargement( i )
def setUp(self): self.historique = Historique()
def __init__( self ): # Appel au constructeur de la classe mere QtGui.QMainWindow.__init__( self ) ########### # Fenetre # ########### ### # Reglages de la fenetre principale ### # Nom de la fenetre self.setWindowTitle( "TVDownloader" ) # Mise en place de son icone self.setWindowIcon( QtGui.QIcon( "ico/TVDownloader.png" ) ) ### # Mise en place des widgets dans la fenetre ### # Widget central qui contiendra tout self.centralWidget = QtGui.QWidget( self ) # # Barre du haut # # Layout horizontal qui contiendra les listes deroulantes self.horizontalLayoutBarreHaut = QtGui.QHBoxLayout() # Liste deroulante pour choisir le site (plugin) self.comboBoxSite = QtGui.QComboBox( self.centralWidget ) self.horizontalLayoutBarreHaut.addWidget( self.comboBoxSite ) # Liste deroulante pour choisir une chaine du site courant self.comboBoxChaine = QtGui.QComboBox( self.centralWidget) self.horizontalLayoutBarreHaut.addWidget( self.comboBoxChaine ) # Liste deroulante pour choisir une emission de la chaine courante self.comboBoxEmission = QtGui.QComboBox( self.centralWidget ) self.horizontalLayoutBarreHaut.addWidget( self.comboBoxEmission ) # # Onglets # # Gestionnaire onglets self.tabWidget = QtGui.QTabWidget( self.centralWidget ) # Onglet Fichiers self.tabFichiers = QtGui.QSplitter( self.centralWidget ) # L'onglet Fichier contient un splitter self.tabWidget.addTab( self.tabFichiers, u"Choix des fichiers" ) # Onglet Telechargements self.tabTelechargements = QtGui.QWidget( self.centralWidget ) self.tabWidget.addTab( self.tabTelechargements, u"Téléchargements" ) # # Liste des fichiers # # Layout de grille qui contient le tableau qui liste les fichiers + boutons self.gridLayoutFichiers = QtGui.QGridLayout( self.tabFichiers ) # Tableau qui contient la liste des fichiers disponibles pour l'emission courante self.tableWidgetFichier = MyQTableWidget( self.tabFichiers ) # Il a 4 colonnes et 0 ligne (pour l'instant) self.tableWidgetFichier.setColumnCount( 3 ) self.tableWidgetFichier.setRowCount( 0 ) # On ajoute les titres self.tableWidgetFichier.setHorizontalHeaderItem( 0, self.tableWidgetFichier.creerItem( "" ) ) self.tableWidgetFichier.setHorizontalHeaderItem( 1, self.tableWidgetFichier.creerItem( "Date" ) ) self.tableWidgetFichier.setHorizontalHeaderItem( 2, self.tableWidgetFichier.creerItem( "Emission" ) ) # On l'ajoute au layout self.gridLayoutFichiers.addWidget( self.tableWidgetFichier, 0, 1, 6, 1 ) # Icones du tableWidget self.iconeFichier = QtGui.QIcon( "ico/gtk-file.svg" ) self.iconeAjoute = QtGui.QIcon( "ico/gtk-add.svg" ) self.iconeTelecharge = QtGui.QIcon( "ico/gtk-apply.svg" ) # Bouton pour ajouter tous les fichiers a la liste des telechargements self.pushButtonToutAjouter = MyQPushButton( self.tabFichiers ) self.pushButtonToutAjouter.setIcon( QtGui.QIcon( "ico/gtk-add.svg" ) ) self.pushButtonToutAjouter.setToolTip( u"Ajouter tous les fichiers à la liste des téléchargements" ) self.gridLayoutFichiers.addWidget( self.pushButtonToutAjouter, 0, 0, 2, 1 ) # Bouton pour rafraichir le plugin courant self.pushButtonRafraichirPlugin = MyQPushButton( self.tabFichiers ) self.pushButtonRafraichirPlugin.setIcon( QtGui.QIcon( "ico/gtk-refresh.svg" ) ) self.pushButtonRafraichirPlugin.setToolTip( "Rafraichir le plugin" ) self.gridLayoutFichiers.addWidget( self.pushButtonRafraichirPlugin, 2, 0, 2, 1 ) # Bouton pour ouvrir la fenetre des preferences du plugin courant self.pushButtonPreferencesPlugin = MyQPushButton( self.tabFichiers ) self.pushButtonPreferencesPlugin.setIcon( QtGui.QIcon( "ico/gtk-preferences.svg" ) ) self.pushButtonPreferencesPlugin.setToolTip( u"Ouvrir les préférences du plugin" ) self.gridLayoutFichiers.addWidget( self.pushButtonPreferencesPlugin, 4, 0, 2, 1 ) # On met en place ce layout sur un widget (pour le splitter) self.widgetFichiers = QtGui.QWidget() self.widgetFichiers.setLayout( self.gridLayoutFichiers ) # # Descriptif des fichiers # # Layout de grille self.gridLayoutDescriptif = QtGui.QGridLayout() # Label pour afficher un logo self.logoFichierDefaut = QtGui.QPixmap() self.logoFichierDefaut.load( "img/gtk-dialog-question.svg" ) self.labelLogo = QtGui.QLabel( self.centralWidget ) self.labelLogo.setPixmap( self.logoFichierDefaut.scaled( QtCore.QSize( 150, 150 ), QtCore.Qt.KeepAspectRatio ) ) self.gridLayoutDescriptif.addWidget( self.labelLogo, 0, 0, 1, 1 ) # Zone de texte pour afficher un descriptif self.plainTextEdit = QtGui.QPlainTextEdit( self.centralWidget ) self.gridLayoutDescriptif.addWidget( self.plainTextEdit, 0, 1, 1, 2 ) # On met en place ce layout sur un widget (pour le splitter) self.widgetDescriptif = QtGui.QWidget() self.widgetDescriptif.setLayout( self.gridLayoutDescriptif ) # Onrientation verticale du splitter self.tabFichiers.setOrientation( QtCore.Qt.Vertical ) # On ajoute les 2 elements au splitter (qui est notre onglet) self.tabFichiers.addWidget( self.widgetFichiers ) self.tabFichiers.addWidget( self.widgetDescriptif ) # # Liste des telechargements # # Layout de grille qui contient le tableau qui liste les fichiers a telecharger + les boutons pour le controller self.gridLayoutTelechargement = QtGui.QGridLayout( self.tabTelechargements ) # Tableau qui contient la liste des fichiers a telecharger self.tableWidgetTelechargement = MyQTableWidget( self.tabTelechargements ) # Il a 5 colonnes et 0 ligne (pour l'instant) self.tableWidgetTelechargement.setColumnCount( 3 ) self.tableWidgetTelechargement.setRowCount( 0 ) # On ajoute le titre des 5 colonnes self.tableWidgetTelechargement.setHorizontalHeaderItem( 0, self.tableWidgetTelechargement.creerItem( "Date" ) ) self.tableWidgetTelechargement.setHorizontalHeaderItem( 1, self.tableWidgetTelechargement.creerItem( "Emission" ) ) self.tableWidgetTelechargement.setHorizontalHeaderItem( 2, self.tableWidgetTelechargement.creerItem( "Etat" ) ) # On l'ajoute au layout self.gridLayoutTelechargement.addWidget( self.tableWidgetTelechargement, 0, 1, 4, 1 ) # Bouton pour monter l'element selectionne tout en haut de la liste self.pushButtonExtremiteMonter = MyQPushButton( self.tabTelechargements ) self.pushButtonExtremiteMonter.setIcon( QtGui.QIcon( "ico/gtk-jump-to-rtl.svg" ) ) self.pushButtonExtremiteMonter.setToolTip( u"Placer l'élément sélectionné tout en haut" ) self.gridLayoutTelechargement.addWidget( self.pushButtonExtremiteMonter, 0, 0, 1, 1 ) # Bouton pour monter l'element selectionne d'un cran dans la liste self.pushButtonMonter = MyQPushButton( self.tabTelechargements ) self.pushButtonMonter.setIcon( QtGui.QIcon( "ico/gtk-go-up.svg" ) ) self.pushButtonMonter.setToolTip( u"Monter l'élément sélectionné" ) self.gridLayoutTelechargement.addWidget( self.pushButtonMonter, 1, 0, 1, 1 ) # Bouton pour descendre l'element selectionne d'un cran dans la liste self.pushButtonDescendre = MyQPushButton( self.tabTelechargements ) self.pushButtonDescendre.setIcon( QtGui.QIcon( "ico/gtk-go-down.svg" ) ) self.pushButtonDescendre.setToolTip( u"Descendre l'élément selectionné" ) self.gridLayoutTelechargement.addWidget( self.pushButtonDescendre, 2, 0, 1, 1 ) # Bouton pour descendre l'element selectionne tout en bas de la liste self.pushButtonExtremiteDescendre = MyQPushButton( self.tabTelechargements ) self.pushButtonExtremiteDescendre.setIcon( QtGui.QIcon( "ico/gtk-jump-to-ltr.svg" ) ) self.pushButtonExtremiteDescendre.setToolTip( u"Placer l'élément sélectionné tout en bas" ) self.gridLayoutTelechargement.addWidget( self.pushButtonExtremiteDescendre, 3, 0, 1, 1 ) # Bouton pour supprimer tous les elements de la liste self.pushButtonToutSupprimer = MyQPushButton( self.tabTelechargements ) self.pushButtonToutSupprimer.setIcon( QtGui.QIcon( "ico/gtk-cancel.svg" ) ) self.pushButtonToutSupprimer.setToolTip( u"Supprimer tous les téléchargements" ) self.gridLayoutTelechargement.addWidget( self.pushButtonToutSupprimer, 0, 2, 1, 1 ) # Bouton pour supprimer de la liste les telechargements termines self.pushButtonNettoyer = MyQPushButton( self.tabTelechargements ) self.pushButtonNettoyer.setIcon( QtGui.QIcon( "ico/gtk-delete-full.svg" ) ) self.pushButtonNettoyer.setToolTip( u"Supprimer les téléchargement terminés" ) self.gridLayoutTelechargement.addWidget( self.pushButtonNettoyer, 1, 2, 1, 1 ) # Bouton pour ouvrir le dossier des telechargements self.pushButtonOuvrirDossierTelechargement = MyQPushButton( self.tabTelechargements ) self.pushButtonOuvrirDossierTelechargement.setIcon( QtGui.QIcon( "ico/gtk-folder.svg" ) ) self.pushButtonOuvrirDossierTelechargement.setToolTip( u"Ouvrir le dossier des téléchargements" ) self.gridLayoutTelechargement.addWidget( self.pushButtonOuvrirDossierTelechargement, 2, 2, 1, 1 ) # # Barre progression de telechargement d'un fichier # self.progressBarTelechargementFichier = QtGui.QProgressBar( self.centralWidget ) self.progressBarTelechargementFichier.setProperty( "value", 0 ) # # Barre de progression de telechargement des fichiers # self.progressBarTelechargement = QtGui.QProgressBar( self.centralWidget ) self.progressBarTelechargement.setProperty( "value", 0 ) # # Boutons du bas pour gerer ajouter/supprimer/lancer telechargements # # Layout horizontal qui contiendra les boutons self.horizontalLayoutBarreBas = QtGui.QHBoxLayout() # Bouton pour lancer les telechargements self.pushButtonLancer = QtGui.QPushButton( QtGui.QIcon( "ico/gtk-media-play-ltr.svg" ), u"Lancer téléchargement", self.centralWidget ) self.horizontalLayoutBarreBas.addWidget( self.pushButtonLancer ) # Bouton pour stopper les telechargements self.pushButtonStop = QtGui.QPushButton( QtGui.QIcon( "ico/gtk-media-stop.svg" ), u"Stopper le téléchargement", self.centralWidget ) self.pushButtonStop.setEnabled( False ) self.horizontalLayoutBarreBas.addWidget( self.pushButtonStop ) ### # Positionnement des differents widgets/layouts sur le layout de grille ### # Layout de grille dans lequel on va placer nos widgets/layouts self.gridLayout = QtGui.QGridLayout( self.centralWidget ) # On ajoute la barre du haut self.gridLayout.addLayout( self.horizontalLayoutBarreHaut, 0, 0, 1, 3 ) # On ajoute le gestionnaire d'onglets self.gridLayout.addWidget( self.tabWidget, 1, 0, 1, 3 ) # On ajoute la barre de progression de telechargement d'un fichier self.gridLayout.addWidget( self.progressBarTelechargementFichier, 2, 0, 1, 3 ) # On ajoute la barre de progression de telechargement des fichiers self.gridLayout.addWidget( self.progressBarTelechargement, 3, 0, 1, 3 ) # On ajoute les boutons ajouter/supprimer/lancer self.gridLayout.addLayout( self.horizontalLayoutBarreBas, 4, 0, 1, 3 ) ### # Mise en place le central widget dans la fenetre ### self.setCentralWidget( self.centralWidget ) ### # Mise en place du menu ### # Menu barre self.menubar = QtGui.QMenuBar( self ) self.menubar.setGeometry( QtCore.QRect( 0, 0, 480, 25 ) ) # Menu Fichier self.menuFichier = QtGui.QMenu( "&Fichier", self.menubar ) self.menubar.addAction( self.menuFichier.menuAction() ) # Action Fichier -> Quitter self.actionQuitter = QtGui.QAction( QtGui.QIcon( "ico/gtk-quit.svg" ), "&Quitter", self ) self.actionQuitter.setIconVisibleInMenu( True ) self.menuFichier.addAction( self.actionQuitter ) # Menu Edition self.menuEdition = QtGui.QMenu( "&Edition", self.menubar ) self.menubar.addAction( self.menuEdition.menuAction() ) # Action Edition -> Mise a jour self.actionMAJ = QtGui.QAction( QtGui.QIcon( "ico/gtk-refresh.svg" ), u"&Mise à jour des plugins", self ) self.actionMAJ.setIconVisibleInMenu( True ) self.menuEdition.addAction( self.actionMAJ ) # Action Edition -> Preferences self.actionPreferences = QtGui.QAction( QtGui.QIcon( "ico/gtk-preferences.svg" ), u"&Préférences", self ) self.actionPreferences.setIconVisibleInMenu( True ) self.menuEdition.addAction( self.actionPreferences ) # Menu Aide self.menuAide = QtGui.QMenu( "&Aide", self.menubar ) self.menubar.addAction( self.menuAide.menuAction() ) # Action Aide -> A propos self.actionAPropos = QtGui.QAction( QtGui.QIcon( "ico/gtk-about.svg" ), u"À p&ropos", self ) self.actionAPropos.setIconVisibleInMenu( True ) self.menuAide.addAction( self.actionAPropos ) # Ajout du menu a l'interface self.setMenuBar( self.menubar ) ### # Signaux provenants de l'interface ### QtCore.QObject.connect( self.tableWidgetFichier, QtCore.SIGNAL( "cellClicked(int,int)" ), self.afficherInformationsFichier ) QtCore.QObject.connect( self.tableWidgetFichier, QtCore.SIGNAL( "cellDoubleClicked(int,int)" ), self.gererTelechargement ) QtCore.QObject.connect( self.pushButtonToutAjouter, QtCore.SIGNAL( "clicked()" ), self.ajouterTousLesFichiers ) QtCore.QObject.connect( self.pushButtonRafraichirPlugin, QtCore.SIGNAL( "clicked()" ), self.rafraichirPlugin ) QtCore.QObject.connect( self.tableWidgetTelechargement, QtCore.SIGNAL( "cellDoubleClicked(int,int)" ), self.supprimerTelechargement ) QtCore.QObject.connect( self.pushButtonExtremiteMonter, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = True, extremite = True : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonMonter, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = True, extremite = False : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonDescendre, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = False, extremite = False : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonExtremiteDescendre, QtCore.SIGNAL( "clicked()" ), lambda versLeHaut = False, extremite = True : self.tableWidgetTelechargement.deplacerLigne( versLeHaut, extremite ) ) QtCore.QObject.connect( self.pushButtonToutSupprimer, QtCore.SIGNAL( "clicked()" ), self.supprimerTousLesTelechargements ) QtCore.QObject.connect( self.pushButtonNettoyer, QtCore.SIGNAL( "clicked()" ), self.nettoyer ) QtCore.QObject.connect( self.pushButtonLancer, QtCore.SIGNAL( "clicked()" ), self.lancerTelechargement ) QtCore.QObject.connect( self.pushButtonStop, QtCore.SIGNAL( "clicked()" ), self.stopperTelechargement ) QtCore.QObject.connect( self.actionQuitter, QtCore.SIGNAL( "triggered()" ), self.close ) ################################################ # Instanciations + initialisation de variables # ################################################ # Fenetre About self.aProposDialog = None # Fenetre des preferences du logiciel self.preferencesDialog = None # Fenetre de mise a jour des plugins self.updateManagerDialog = None # Nom plugin courant self.nomPluginCourant = "" # Liste des fichiers self.listeFichiers = [] # Liste des fichiers a telecharger self.listeFichiersATelecharger = [] # Cache des images descriptive # Clef : urlImage Valeur : image (binaire) self.cacheImage = {} # On intancie le lanceur de signaux self.signaux = Signaux() # On instancie le gestionnaire de preferences self.preferences = Preferences() # On instancie le gestionnaire de preferences des plugins self.preferencesPluginDialog = PreferencePluginDialog( self ) # On instancie le gestionnaire de download self.downloader = Downloader( self.signaux ) # On recupere l'instance de API self.api = API.getInstance() # On instancie le gestionnaire d'historique self.historique = Historique() # On instancie la fenetre d'attente self.fenetreAttenteProgressDialog = FenetreAttenteProgressDialog( self ) # On instancie le gest # # Fenetre de confirmation pour quitter le logiciel # self.quitterMessageBox = QtGui.QMessageBox( self ) self.quitterMessageBox.setWindowTitle( "Fermeture de TVDownloader" ) self.quitterMessageBox.setText( u"Voulez-vous réellement quitter TVDownloader ?" ) self.quitterMessageBox.setInformativeText( u"Votre liste de téléchargement sera perdue" ) self.quitterMessageBox.addButton( "Oui", QtGui.QMessageBox.AcceptRole ) self.quitterMessageBox.addButton( "Non", QtGui.QMessageBox.RejectRole ) ############################################################ # On connecte les signaux des instances precedements crees # ############################################################ QtCore.QObject.connect( self.pushButtonOuvrirDossierTelechargement, QtCore.SIGNAL( "clicked()" ), self.ouvrirRepertoireTelechargement ) QtCore.QObject.connect( self.comboBoxSite, QtCore.SIGNAL( "activated(QString)" ), self.listerChaines ) QtCore.QObject.connect( self.comboBoxChaine, QtCore.SIGNAL( "activated(QString)" ), self.listerEmissions ) QtCore.QObject.connect( self.comboBoxEmission, QtCore.SIGNAL( "activated(QString)" ), self.listerFichiers ) QtCore.QObject.connect( self.pushButtonPreferencesPlugin, QtCore.SIGNAL( "clicked()" ), self.ouvrirPreferencesPlugin ) QtCore.QObject.connect( self.actionPreferences, QtCore.SIGNAL( "triggered()" ), self.ouvrirPreferencesLogiciel ) QtCore.QObject.connect( self.actionMAJ, QtCore.SIGNAL( "triggered()" ), self.ouvrirFenetreMiseAJour ) QtCore.QObject.connect( self.actionAPropos, QtCore.SIGNAL( "triggered()" ), self.ouvrirFenetreAPropos ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "debutActualisation(PyQt_PyObject)" ) , self.fenetreAttenteProgressDialog.ouvrirFenetreAttente ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "finActualisation()" ) , self.fenetreAttenteProgressDialog.fermerFenetreAttente ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "actualiserListesDeroulantes()" ) , self.actualiserListesDeroulantes ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "listeChaines(PyQt_PyObject)" ) , self.ajouterChaines ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "listeEmissions(PyQt_PyObject)" ) , self.ajouterEmissions ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "listeFichiers(PyQt_PyObject)" ) , self.ajouterFichiers ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "nouvelleImage(PyQt_PyObject)" ) , self.mettreEnPlaceImage ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "debutTelechargement(int)" ) , self.debutTelechargement ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "finTelechargement(int)" ) , self.finTelechargement ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "finDesTelechargements()" ) , self.activerDesactiverInterface ) QtCore.QObject.connect( self.signaux, QtCore.SIGNAL( "pourcentageFichier(int)" ) , self.progressBarTelechargementFichier.setValue ) ######### # Début # ######### # La fenetre prend la dimension qu'elle avait a sa fermeture taille = self.preferences.getPreference( "tailleFenetre" ) self.resize( taille[ 0 ], taille[ 1 ] ) # Si aucun plugin n'est active, on ouvre la fenetre des preferences if( len( self.preferences.getPreference( "pluginsActifs" ) ) == 0 ): self.ouvrirPreferencesLogiciel() # On actualise tous les plugins self.rafraichirTousLesPlugins()
def testSingleton(self): """Test si le pattern singleton est bien en place""" self.assertEqual(id(self.historique), id(Historique()))
def __init__( self, url, useFragments = False, proxy = None, resume = False, progressFnct = lambda x : None, stopDownloadEvent = threading.Event(), outDir = ".", manifest = False, playlist = False ): self.url = url self.useFragments = useFragments self.proxy = proxy self.resume = resume self.progressFnct = progressFnct self.stopDownloadEvent = stopDownloadEvent self.outDir = outDir self.navigateur = Navigateur( self.proxy ) self.historique = Historique() self.configuration = Configuration() self.lienMMS = None self.lienRTMP = None self.manifestURL = None self.drm = None if playlist: self.mode = "playlist" self.ext = "ts" else: self.mode = "manifest" self.ext = "flv" self.hmacKey = self.configuration[ "hmac_key" ].decode( "hex" ) self.playerHash = self.configuration[ "player_hash" ] if( re.match( "http://www.pluzz.fr/[^\.]+?\.html", self.url ) ): # Recupere l'ID de l'emission self.getID() # Recupere la page d'infos de l'emission self.pageInfos = self.navigateur.getFichier( "http://www.pluzz.fr/appftv/webservices/video/getInfosOeuvre.php?mode=zeri&id-diffusion=%s" %( self.id ) ) # Parse la page d'infos self.parseInfos() # Petit message en cas de DRM if( self.drm == "oui" ): logger.warning( "La vidéo posséde un DRM ; elle sera sans doute illisible" ) # Lien MMS trouve if( self.lienMMS is not None ): logger.info( "Lien MMS : %s\nUtiliser par exemple mimms ou msdl pour la recuperer directement ou l'option -f de pluzzdl pour essayer de la charger via ses fragments" %( self.lienMMS ) ) # Lien RTMP trouve if( self.lienRTMP is not None ): logger.info( "Lien RTMP : %s\nUtiliser par exemple rtmpdump pour la recuperer directement ou l'option -f de pluzzdl pour essayer de la charger via ses fragments" %( self.lienRTMP ) ) # N'utilise pas les fragments si cela n'a pas ete demande et que des liens directs ont ete trouves if( ( ( self.lienMMS is not None ) or ( self.lienRTMP is not None ) ) and not self.useFragments ): sys.exit( 0 ) if self.mode == "manifest": # Lien du manifest non trouve if( self.manifestURL is None ): logger.critical( "Pas de lien vers le manifest" ) sys.exit( -1 ) if self.mode == "playlist": # Lien de la playlist M3U8 non trouve if( self.playlistM3U8 is None ): logger.critical( "Pas de lien vers la playlist" ) sys.exit( -1 ) self.nomFichier = os.path.join( self.outDir, "%s.%s" %( re.findall( "http://www.pluzz.fr/([^\.]+?)\.html", self.url )[ 0 ], self.ext ) ) else: if self.mode == "manifest": page = self.navigateur.getFichier( self.url ) try: self.manifestURL = re.findall( "(http://.+?manifest.f4m)", page )[ 0 ] except: logger.critical( "Pas de lien vers le manifest" ) sys.exit( -1 ) try: self.nomFichier = os.path.join( self.outDir, "%s.flv" %( self.url.split( "/" )[ -1 ] ) ) except: self.nomFichier = os.path.join( self.outDir, "video.flv" ) self.generateNomFichier() if self.mode == "manifest": self.getVideoViaManifest() if self.mode == "playlist": self.getVideoViaPlaylist()
class DlM3u8(Downloader): """ Téléchargement des liens m3u8 """ def __init__(self, m3u8Url, outDir, codeProgramme, timeStamp, navigateur, stopDownloadEvent, progressFnct): self.m3u8Url = m3u8Url super(DlM3u8, self).__init__(outDir, codeProgramme, timeStamp, "ts", navigateur, stopDownloadEvent, progressFnct) self.historique = Historique() def telecharger(self): # Récupère le fichier master.m3u8 self.m3u8 = self.navigateur.getFichier(self.m3u8Url) # Extrait l'URL de tous les fragments self.listeFragments = re.findall(".+?\.ts", self.m3u8) # # Création de la vidéo # self.premierFragment = 1 self.telechargementFini = False video = self.historique.getVideo(self.m3u8Url) # Si la vidéo est dans l'historique if(video is not None): # Si la vidéo existe sur le disque if(os.path.exists(self.nomFichier)): if(video.finie): logger.info("La vidéo a déjà été entièrement téléchargée") return else: self.ouvrirVideoExistante() self.premierFragment = video.fragments logger.info("Reprise du téléchargement de la vidéo au fragment %d" % (video.fragments)) else: self.ouvrirNouvelleVideo() logger.info("Impossible de reprendre le téléchargement de la vidéo, le fichier %s n'existe pas" % (self.nomFichier)) else: # Si la vidéo n'est pas dans l'historique self.ouvrirNouvelleVideo() # Nombre de fragments self.nbFragMax = float(len(self.listeFragments)) logger.debug("Nombre de fragments: %d" % (self.nbFragMax)) # Ajout des fragments logger.info("Début du téléchargement des fragments") try: i = self.premierFragment while(i <= self.nbFragMax and not self.stopDownloadEvent.isSet()): frag = self.navigateur.getFichier("%s" % ( self.listeFragments[i - 1])) self.fichierVideo.write(frag) # Affichage de la progression self.progressFnct(min(int((i / self.nbFragMax) * 100), 100)) i += 1 if(i == self.nbFragMax + 1): self.progressFnct(100) self.telechargementFini = True logger.info("Fin du téléchargement") except KeyboardInterrupt: logger.info("Interruption clavier") except Exception as inst: logger.critical("Erreur inconnue %s" % inst) finally: # Ajout dans l'historique self.historique.ajouter(Video(lien = self.m3u8Url, fragments = i, finie = self.telechargementFini)) # Fermeture du fichier self.fichierVideo.close()
class PluzzDLM3U8(object): """ Telechargement des liens m3u8 """ def __init__(self, m3u8URL, nomFichier, navigateur, stopDownloadEvent, progressFnct): self.m3u8URL = m3u8URL self.nomFichier = nomFichier self.navigateur = navigateur self.stopDownloadEvent = stopDownloadEvent self.progressFnct = progressFnct self.historique = Historique() self.nomFichierFinal = "%s.mp4" % (self.nomFichier[:-3]) def ouvrirNouvelleVideo(self): """ Creer une nouvelle video """ try: # Ouverture du fichier print "Nom Fichier:", self.nomFichier # fullPathFile = os.path.join(os.getcwd(), self.nomFichier) # print "fullPathFile:", fullPathFile self.fichierVideo = open(self.nomFichier, "wb") # self.fichierVideo = open( fullPathFile, "wb" ) except: raise PluzzDLException("Impossible d'écrire dans le répertoire %s" % (os.getcwd())) # Ajout de l'en-tête # Fait dans creerMKV def ouvrirVideoExistante(self): """ Ouvre une video existante """ try: # Ouverture du fichier self.fichierVideo = open(self.nomFichier, "a+b") except: raise PluzzDLException("Impossible d'écrire dans le répertoire %s" % (os.getcwd())) def creerMKV(self): """ Creer un mkv a partir de la video existante (cree l'en-tete de la video) """ logger.info("Création du fichier MKV (vidéo finale); veuillez attendre quelques instants") logger.info("Convert: %s -> %s" % (self.nomFichier, self.nomFichierFinal)) commande = "ffmpeg -i %s -c:a aac -strict -2 -vcodec copy %s" % (self.nomFichier, self.nomFichierFinal) try: if (os.system(commande) == 0): os.remove(self.nomFichier) logger.info("Fin !") else: logger.warning( "Problème lors de la création du MKV avec FFmpeg ; le fichier %s est néanmoins disponible" % ( self.nomFichier)) except: raise PluzzDLException("Impossible de créer la vidéo finale") def telecharger(self): # Recupere le fichier master.m3u8 self.m3u8 = self.navigateur.getFichier(self.m3u8URL) # Extrait l'URL de tous les fragments self.listeFragments = re.findall(".+?\.ts", self.m3u8) if not self.listeFragments: self.listeFragments = [] self.listeM3U8 = re.findall(".+?index_2_av\.m3u8", self.m3u8) for m3u8 in self.listeM3U8: m3u8data = self.navigateur.getFichier(m3u8) self.listeFragments.extend(re.findall(".+?\.ts", m3u8data)) # # Creation de la video # self.premierFragment = 1 self.telechargementFini = False video = self.historique.getVideo(self.m3u8URL) # Si la video est dans l'historique if (video is not None): # Si la video existe sur le disque if (os.path.exists(self.nomFichier) or os.path.exists(self.nomFichierFinal)): if (video.finie): logger.info("La vidéo a déjà été entièrement téléchargée") if (not os.path.exists(self.nomFichierFinal)): self.creerMKV() return else: self.ouvrirVideoExistante() self.premierFragment = video.fragments logger.info("Reprise du téléchargement de la vidéo au fragment %d" % (video.fragments)) else: self.ouvrirNouvelleVideo() logger.info(u"Impossible de reprendre le téléchargement de la vidéo, le fichier %s n'existe pas" % ( self.nomFichier)) else: # Si la video n'est pas dans l'historique self.ouvrirNouvelleVideo() # Nombre de fragments self.nbFragMax = float(len(self.listeFragments)) logger.debug("Nombre de fragments : %d" % (self.nbFragMax)) # Ajout des fragments logger.info("Début du téléchargement des fragments") try: i = self.premierFragment while (i <= self.nbFragMax and not self.stopDownloadEvent.isSet()): frag = self.navigateur.getFichier("%s" % (self.listeFragments[i - 1])) self.fichierVideo.write(frag) # Affichage de la progression self.progressFnct(min(int((i / self.nbFragMax) * 100), 100)) i += 1 if (i == self.nbFragMax + 1): self.progressFnct(100) self.telechargementFini = True logger.info("Fin du téléchargement") self.creerMKV() except KeyboardInterrupt: logger.info("Interruption clavier") except Exception as inst: logger.critical("Erreur inconnue %s" % inst) finally: # Ajout dans l'historique self.historique.ajouter(Video(lien=self.m3u8URL, fragments=i, finie=self.telechargementFini)) # Fermeture du fichier self.fichierVideo.close()
class PluzzDLM3U8( object ): """ Telechargement des liens m3u8 """ def __init__( self, m3u8URL, nomFichier, navigateur, stopDownloadEvent, progressFnct ): self.m3u8URL = m3u8URL self.nomFichier = nomFichier self.navigateur = navigateur self.stopDownloadEvent = stopDownloadEvent self.progressFnct = progressFnct self.historique = Historique() self.nomFichierFinal = "%s.mkv" % ( self.nomFichier[ :-3 ] ) def ouvrirNouvelleVideo( self ): """ Creer une nouvelle video """ try : # Ouverture du fichier self.fichierVideo = open( self.nomFichier, "wb" ) except : raise PluzzDLException( "Impossible d'écrire dans le répertoire %s" % ( os.getcwd() ) ) # Ajout de l'en-tête # Fait dans creerMKV def ouvrirVideoExistante( self ): """ Ouvre une video existante """ try : # Ouverture du fichier self.fichierVideo = open( self.nomFichier, "a+b" ) except : raise PluzzDLException( "Impossible d'écrire dans le répertoire %s" % ( os.getcwd() ) ) def creerMKV( self ): """ Creer un mkv a partir de la video existante (cree l'en-tete de la video) """ logger.info( "Création du fichier MKV (vidéo finale) ; veuillez attendre quelques instants" ) try: if( os.name == "nt" ): commande = "ffmpeg.exe -i %s -vcodec copy -acodec copy %s 1>NUL 2>NUL" % ( self.nomFichier, self.nomFichierFinal ) else: commande = "ffmpeg -i %s -vcodec copy -acodec copy %s 1>/dev/null 2>/dev/null" % ( self.nomFichier, self.nomFichierFinal ) if( os.system( commande ) == 0 ): os.remove( self.nomFichier ) logger.info( "Fin !" ) else: logger.warning( "Problème lors de la création du MKV avec FFmpeg ; le fichier %s est néanmoins disponible" % ( self.nomFichier ) ) except: raise PluzzDLException( "Impossible de créer la vidéo finale" ) def telecharger( self ): # Recupere le fichier master.m3u8 self.m3u8 = self.navigateur.getFichier( self.m3u8URL ) # Extrait l'URL de base pour tous les fragments self.urlBase = "/".join( self.m3u8URL.split( "/" )[ :-1 ] ) # Recupere le lien avec le plus gros bitrate try: self.listeFragmentsURL = "%s/%s" % ( self.urlBase, re.findall( ".+?\.m3u8.*", self.m3u8 )[ -1 ] ) except: raise PluzzDLException( "Impossible de trouver le lien vers la liste des fragments" ) # Recupere la liste des fragments self.listeFragmentsPage = self.navigateur.getFichier( self.listeFragmentsURL ) # Extrait l'URL de tous les fragments self.listeFragments = re.findall( ".+?\.ts", self.listeFragmentsPage ) # # Creation de la video # self.premierFragment = 1 self.telechargementFini = False video = self.historique.getVideo( self.listeFragmentsURL ) # Si la video est dans l'historique if( video is not None ): # Si la video existe sur le disque if( os.path.exists( self.nomFichier ) or os.path.exists( self.nomFichierFinal ) ): if( video.finie ): logger.info( "La vidéo a déjà été entièrement téléchargée" ) if( not os.path.exists( self.nomFichierFinal ) ): self.creerMKV() return else: self.ouvrirVideoExistante() self.premierFragment = video.fragments logger.info( "Reprise du téléchargement de la vidéo au fragment %d" % ( video.fragments ) ) else: self.ouvrirNouvelleVideo() logger.info( u"Impossible de reprendre le téléchargement de la vidéo, le fichier %s n'existe pas" % ( self.nomFichier ) ) else: # Si la video n'est pas dans l'historique self.ouvrirNouvelleVideo() # Nombre de fragments self.nbFragMax = float( len( self.listeFragments ) ) logger.debug( "Nombre de fragments : %d" % ( self.nbFragMax ) ) # Ajout des fragments logger.info( "Début du téléchargement des fragments" ) try : i = self.premierFragment while( i <= self.nbFragMax and not self.stopDownloadEvent.isSet() ): frag = self.navigateur.getFichier( "%s/%s" % ( self.urlBase, self.listeFragments[ i - 1 ] ) ) self.fichierVideo.write( frag ) # Affichage de la progression self.progressFnct( min( int( ( i / self.nbFragMax ) * 100 ), 100 ) ) i += 1 if( i == self.nbFragMax + 1 ): self.progressFnct( 100 ) self.telechargementFini = True logger.info( "Fin du téléchargement" ) self.creerMKV() except KeyboardInterrupt: logger.info( "Interruption clavier" ) except: logger.critical( "Erreur inconnue" ) finally : # Ajout dans l'historique self.historique.ajouter( Video( lien = self.listeFragmentsURL, fragments = i, finie = self.telechargementFini ) ) # Fermeture du fichier self.fichierVideo.close()