M3U Playlist-Generator

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
rafael
User
Beiträge: 189
Registriert: Mittwoch 26. Juli 2006, 16:13

Hi,
folgendes Script generiert eine simple M3U-Playliste.

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
    M3U-Playlist Generator
    ----------------------
	
    This script generates a simple M3U playlist from the given directory.
    It works recursive. Just type "python playlist.py [--add|--random] <directory> <target>"
    
    Available options:
    -a, --add       append data to the playlist and don't delete existing data.
    -r, --random    randomize playlist
	

    Author:	2006 Rafael Weber
	
    License: GNU GPL see LICENSE for details
"""


import os
import glob
import random
import sys

from optparse import OptionParser

musicfiles = [] 
musicext = ['*.mp3', '*.MP3','*.ogg', '*.OGG','*.wma',
    '*.WMA', '*.wav', '*.WAV', '*.aac', '*.AAC', '*.flac', '*.FLAC']

parser = OptionParser()
parser.add_option("-r", "--random", action="store_true")
parser.add_option("-a", "--add", action="store_true")

options, args = parser.parse_args()

def add_music(dir):
    for ending in musicext:
        musicfiles.extend(glob.glob(os.path.join(dir,ending)))
    return musicfiles

def randomize():
    random.shuffle(musicfiles)
	
if len(args) < 1:
    print "No directory specified."
elif len(args) != 2:
    print "No target specified."
else: 
    for dirpath, dirnames, filenames in os.walk(args[0]):
        add_music(dirpath)
	
    if options.random:
        randomize()
	
    if len(musicfiles) == 0:
        print "No media files found."
        sys.exit()
	
    try:
        if options.add:
            f = file(args[1], "a")
        else:
            f = file(args[1], "w")

        f.write("\n".join(musicfiles))
        f.close()
        print "Playlist created successfully."
    except IOError:
        print "Error while writing file."

Beispielaufruf:

Code: Alles auswählen

python playlist.py --random /media/hda6/ Desktop/hda6_playlist.py
Anregungen und Kritik erwünscht. :D

MfG
rafael
Zuletzt geändert von rafael am Montag 9. April 2007, 09:27, insgesamt 3-mal geändert.
lunar

Code: Alles auswählen

	if getattr(options, "random") == True:
		randomize()
Warum denn 'getattr(options, 'random'), wenn's doch einfacher und eleganter geht; nämlich über das Attribut direkt: "options.random"?
Außerdem vergleicht man boolsche Wert nicht mit den Konstanten True oder False:

Code: Alles auswählen

# sehr schlecht
if foo == True:
    do_something()
# noch schlechter
if foo is True:
    do_something()
Das Snippet oben sollte also so aussehen:

Code: Alles auswählen

if options.random:
    randomize()	
Sieht doch auch gleich viel schöner aus ;)

Code: Alles auswählen

		if getattr(options, "add") == True:
			f = file(args[1], "a")
Same again...

Code: Alles auswählen

		for song in musicfiles:
			f.write("%s %s"% (song, os.linesep))
		f.close()
Folgendes sieht irgendwie eleganter aus:

Code: Alles auswählen

f.write('\n'.join(musicfiles))
f.close()
Außerdem ist es wahrscheinlich schneller; vor allem, weil du das Zusammenfügen des Strings nicht mehr in Python erledigst, sondern eine schnelle, optimierte C Funktion dafür verwendest.

Ansonsten könnte ich dir noch sagen, dass du den Code zur Ausführung besser in eine Funktion names main() packst und diese dann wie folgt ausführst:

Code: Alles auswählen

if __name__ == '__main__':
    main()
Bei diesem Mini-Skript ist das noch weniger von Bedeutung, aber bei größeren Skripten ist es eine Erleichterung, weil du so das Skript nämlich im interaktiven Interpreter als Modul importieren kannst, ohne das das Skript gleich ausgeführt wird. Dann kannst du jede Funktion und jede Methode einzeln testen...

Zusätzlich zum praktischen noch was stilistisches (auch wenns pingelig ist ;) ): Imports gehören nicht in eine Zeile, sondern jeder Import schon separat (siehe PEP 8, Abschnitt "Imports")

Außerdem solltest du überlange Zeilen meiden. PEP 8 empfiehlt ein Maximum von 79 Zeichen...

Zuguterletzt noch deine Einrückung: Man nimmt keine Tabulatoren: Die sind hässlich, weil sie Einstellungssache sind, und der Code damit von den Einstellungen des Editors bzw. Interpreters abhängt. Der Python Interpreter nimmt für einen Tab 8 Leerzeichen an; ist dein Editor anders eingestellt, kann das zu bösen Überraschungen führen.
Standard sind in der Python-Welt 4 Leerzeichen für jede Einrückungsebene. Das ist eindeutig, und auch gut lesbar.
Wenn du unbedingt Tabulatoren verwenden willst, solltest du vor dem Veröffentlichen wenigstens einmal 'expand -t 4' drüberlaufen lassen.

Uups, ist jetzt doch ein bisschen viel :oops:

Gruß
lunar
Zuletzt geändert von lunar am Mittwoch 13. Dezember 2006, 10:44, insgesamt 1-mal geändert.
rafael
User
Beiträge: 189
Registriert: Mittwoch 26. Juli 2006, 16:13

Ok, danke für die ganzen Tipps. Ich hab den Code darauf upgedatet :)
lunar

Code: Alles auswählen

musicfiles = list()
Dafür ist imo diese Schreibweise üblicher:
musicfiles = []

Code: Alles auswählen

        for song in musicfiles:
            f.write("\n".join(musicfiles))
Hast du das getestet? Wahrscheinlicher eher nicht, oder ;)
Du schreibst die Liste hier nämlich in mehrfacher Ausfertigung in die selbe Datei, und zwar so oft wie die Anzahl der Songs in der Liste.

Das liegt daran, dass du über jeden einzelnen Song iterierst, aber in jedem Durchlauf die gesamte Liste über den Aufruf der join Methode in die Datei schreibst.

Lass also dir for-Schleife weg und verwende nur '\n'.join(musicfiles). Das liefert dir bereits die ganze Liste.

Gruß
lunar
BlackJack

lunar hat geschrieben:

Code: Alles auswählen

musicfiles = list()
Dafür ist imo diese Schreibweise üblicher:
musicfiles = []
Ist Geschmackssache, ich schreibe lieber den Typ aus.

Ich habe auch mal einen Playlistengenerator geschrieben: http://www.python-forum.de/post-20129.html
rafael
User
Beiträge: 189
Registriert: Mittwoch 26. Juli 2006, 16:13

ok, ich hab das noch geändert. Kann ich das Programm auch einfach in eine Klasse oder so fassen? also das ist dann doch so wie das mit dem main(), was lunar schon angesprochen hat, oder?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

rafael hat geschrieben:also das ist dann doch so wie das mit dem main(), was lunar schon angesprochen hat, oder?
Nein, der Import-Hook ist dafür gedacht, dass der Code in einer main()-Funktion nur dann ausgeführt wird, wenn das Programm direkt gestatet wird. Dein COde würde aber auch ausgeführt werden wenn man das Modul importiert was aber ganz sicher so nicht gedacht ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

BlackJack hat geschrieben:Ist Geschmackssache, ich schreibe lieber den Typ aus.
Stimmt schon. Ich hab's halt noch nie so gesehen, und war deswegen etwas überrascht. ;)

Btw, dein Programm ist ja doch etwas umfangreicher...
Da hat rafael ja jetzt einigen Ansporn, noch ein bisschen weiterzuschreiben ;)
Leonidas hat geschrieben:Nein, der Import-Hook ist dafür gedacht, dass der Code in einer main()-Funktion nur dann ausgeführt wird, wenn das Programm direkt gestatet wird. Dein COde würde aber auch ausgeführt werden wenn man das Modul importiert was aber ganz sicher so nicht gedacht ist.
Dazu kann ich noch hinzufügen, dass das Importieren selbst bei eher kleinen Programmen, die nicht als Modul arbeiten sollen, relativ sinnvoll ist.
Du kannst dann nämlich das Programm im Interaktiven Modus importieren und jede einzelne Funktion testen. So kannst du die Funktionsfähigkeit deines Codes überprüfen, ohne gleich aufwändige Dinge wie Unittests oder Debugger anzuschmeißen, die bei solchen Miniprogrammen etwas übertrieben sind.

Gruß
lunar
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Leonidas hat geschrieben:Nein, der Import-Hook ist dafür gedacht, dass der Code in einer main()-Funktion nur dann ausgeführt wird, wenn das Programm direkt gestatet wird. Dein COde würde aber auch ausgeführt werden wenn man das Modul importiert was aber ganz sicher so nicht gedacht ist.
Ich würde die __main__-Konstruktion allerdings nicht als "Import-Hook" bezeichnen. Der Begriff ist in Python schon mit einem ganz anderen Konzept vorbelegt.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

birkenfeld hat geschrieben:Ich würde die __main__-Konstruktion allerdings nicht als "Import-Hook" bezeichnen. Der Begriff ist in Python schon mit einem ganz anderen Konzept vorbelegt.
Ja, sorry - hast du einen passenden, griffigen Begriff für sowas?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
lunar

Leonidas hat geschrieben:
birkenfeld hat geschrieben:Ich würde die __main__-Konstruktion allerdings nicht als "Import-Hook" bezeichnen. Der Begriff ist in Python schon mit einem ganz anderen Konzept vorbelegt.
Ja, sorry - hast du einen passenden, griffigen Begriff für sowas?
Wie wärs mit: Hauptmethode zur Vermeidung der versehentlichen Ausführung von Programmcode beim Importieren des Skriptes als Modul ;)

Das klingt doch enorm behördenmäßig, oder?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

lunar hat geschrieben:Wie wärs mit: Hauptmethode zur Vermeidung der versehentlichen Ausführung von Programmcode beim Importieren des Skriptes als Modul ;)
Passend: +1
Griffgkeit: -1

Dein LEP (Leonidas Enhancement Proposal) wurde abgelehnt, tut mir leid ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Dein LEP (Leonidas Enhancement Proposal) wurde abgelehnt, tut mir leid Wink
Wie wäre es damit? ^^ Ist kurz und griffig xD

Hauptmethode zur Vermeidung der versehentlichen Ausführung von Programmcode beim Importieren des Skriptes als Modul ->
HVAPISM-Hock ^^ *duckundweckrenn*
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Mir hat "__main__-Trick" immer gereicht.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
lunar

birkenfeld hat geschrieben:Mir hat "__main__-Trick" immer gereicht.
Passend: +1
Griffigkeit: +1
Geek-Faktor: -10

;)
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Nichts kann man euch recht machen. ;)

Wenigstens ist effbot dann auch ungeeky: http://effbot.org/pyfaq/tutor-what-is-i ... in-for.htm


Edit: Smiley eingebaut, hier weiß man ja nie.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

birkenfeld hat geschrieben:[...]
Edit: Smiley eingebaut, hier weiß man ja nie.
^^ xD :D ;)
Antworten