Bonjour,
Suite à la perte de mon téléphone, je me suis retrouvé avec un petit nouveau et une carte SD toute vide, sans musique.
Et j'aime la musique! J'ai plein de playlists que j'adore.
Alors évidement j'ai voulue tranférer les mp3 de mes playlists dans la carte sd du petit nouveau.
En gros: Prendre la playlist, et sauvegarder les mp3 présent dans un répertoire 'destination' pour ensuite les copier sur mon télephone.
J'ai beau chercher une option dans vlc, je n'ai rien trouvé. Pareil sur le net, sauf un bout de code en php-cli.
Il y a de superbes dépêches sur python en ce moment, alors je me suis pourquoi pas coder un petit truc!
C'est sans prétention, je ne suis pas un dev python et je n'y ai pas touché depuis 2 ans, mais ca juste marche chez moi.
Je suis ouvert à toutes les critiques, justement j'aimerais bien avoir un retour sur ce code.
J'envisage ensuite de supporter d'autres format(m3u etc)
Enfin, ca y est, j'ai un répértoire à copier sur ma carte SD et je vais pouvoir ecouter mes playlists partout!
Usage: pl2mp3 playlist repertoire
(Les liens doivent être locaux)
Ca donne un truc comme ca
#!/usr/bin/env python3
import argparse
import shutil
import os
import urllib.parse
from bs4 import BeautifulSoup
class Pl2mp3(object):
args = False
def __init__(self):
pass
def start(self):
self.argparse()
#Openning the playlist file
try:
pf1 = open(self.args.playlist)
pls = pf1.read()
except IOError:
print("Can't open playlist ", self.args.playlist)
return
#Creating output directory if not exists
if not os.path.exists(self.args.outputdirectory):
try:
os.makedirs(self.args.outputdirectory)
print("Creating output directory", self.args.outputdirectory)
except OSError:
print("Can't create output directory", self.args.outputdirectory)
return
xspf = Xspf()
for location in xspf.parse(pls):
print(location)
try:
shutil.copy2(location, self.args.outputdirectory)
except IOError:
print("Cant' copy ", location)
pass
#et la on try except sur la copie c'est tout
pf1.close()
def argparse(self):
parser = argparse.ArgumentParser()
parser.add_argument("playlist", help="Path to the playlist file")
parser.add_argument("outputdirectory", help="Path to the output directory")
self.args = parser.parse_args()
class Xspf(object):
def __init__(self):
pass
def parse(self, content):
soup = BeautifulSoup(content,'xml')
for result in soup.find_all('track'):
location = urllib.parse.unquote(result.location.string)
if location.startswith("file://"):
location = location.replace("file://", '')
yield location
if __name__ == '__main__':
main = Pl2mp3()
main.start()
# .
Posté par raphj . Évalué à 6.
Je vois, dans ce code, une belle illustration de l'utilisation de argparse, de BeautifulSoup (que je ne connais que de nom) pour traiter du XML, et des itérateurs avec
yield
.[^] # Re: .
Posté par Panhwein . Évalué à 1. Dernière modification le 30 septembre 2019 à 20:29.
Merci :)
# Urllib
Posté par Panhwein . Évalué à 1.
Je suis en train de regarder sans avoir vraiement le temps!
Il n'y aurait pas un AttributeError(de tête je ne sais plus) à attraper sur result.location.string (Xspf.parse)?
Si result.location.string n'existe pas, je ne sais pas ce que ca donne.
Je vais m'y pencher ce soir, j'ai bien envie de faire la classe m3u on attaquer les formats exotique.
Et si je rajoute /dev/random dans ma playlist…
[^] # Re: Urllib
Posté par raphj . Évalué à 3. Dernière modification le 01 octobre 2019 à 17:14.
Tu vas effectivement certainement te payer une exception sur
result.location.string
silocation
n’existe pas. D’autant que ça a l’air autorisé par la spécification :http://xspf.org/xspf-v1.html#rfc.section.4.1.1.2.14.1.1.1.1
Donc il faut gérer le cas. Quoi faire ? Afficher un avertissement ? Que faire s’il y en a plusieurs ?
Bon courage pour M3U, je crois que c’est beaucoup moins bien spécifié que XSPF et de mémoire il y a de légères incompatibilités entre lecteurs. Il y a peut-être des bibliothèques pour ça. Pour XSPF aussi d’ailleurs.
[^] # Re: Urllib
Posté par Panhwein . Évalué à 0.
Oui un avertissement, mais il va être noyé dans la masse de l'affichage. Donc un dictionnaire pour afficher les résultats à la fin. Les morceaux copiés, les erreurs, tout.
Je vois bien le problème pour le m3u.
Il y à des lecteurs qui apparemment ne se base pas sur le chemin absolu, mais en relatif sur le path qu'ils connaissent, ou ont par default.
Une option --force-mp3-directory ça pourrait faire l'affaire. S'ils sont en dehors, ils vont utiliser des chemins absolus.
Je réfléchie, et je m'éclate avec ce truc!
# Merci olivier_h
Posté par Panhwein . Évalué à 2. Dernière modification le 01 octobre 2019 à 15:33.
Ce petit bout de code, c'était plus un exercice de style qu'autre chose.
Une occasion de s’y remettre un petit peu. Et d’essayer de faire les choses le plus proprement possible.
J'aurais pu me contenter du bout de code en php-cli mais j'ai eu une envie de python.
C'est aussi ca coder, tu as juste un besoin perso, mais tu va prendre ton pied à essayer de faire en sorte que ca puisse resservir. Et je me suis régalé, bien loin de ma vie quotidienne. J'en avais presque oublié ce plaisir, coder pour soi(et pour les autres, s'il y à un besoin).
Et ça, c'est grâce aux superbes dépêches dont olivier_h et les contributeurs nous régalent depuis la rentrée. Et il en a beaucoup en rédaction apparemment.
Merci à vous!
(Et éventuellement si vous vous ennuyer malgrès tout ça, l'air de rien, "Gérer son code Python chez gitlab/github")
PS: Un troll est caché dans les parenteses, sauras-tu le dessiner en suivant les pointilles?
# remarques en passant
Posté par flan (site web personnel) . Évalué à 7.
[^] # Re: remarques en passant
Posté par Panhwein . Évalué à 0.
L'exception il devrait y en avoir une oui! Pas eu le temps hier.
Alors là, j'apprends des choses:
-Plus besoin d'hériter d'object en Python 3!
-C'est noté pour with open()!
Par contre là je comprends pas: "Ça manque de passage par black pour homogénéiser le code" ?
[^] # Re: remarques en passant
Posté par raphj . Évalué à 2. Dernière modification le 02 octobre 2019 à 17:38.
Black est un formateur de code Python: https://github.com/psf/black
Tu semble preneur de retours, alors parmi les éléments de style que tu peux regarder :
#
mais tout le monde ne le fait pas.except IOError:
se finit par une instruction "pass", que tu peux simplement enlever.Et là, ce qui suit est plus une opinion et un ensemble de suggestions plutôt que des règles.
Tu fais une classe instanciée qu'une fois :
Pl2mp3
. Ça peut être utile d'avoir une classe réutilisable, mais dans ce cas je ne ferais pas le traitement des arguments demain
dedans. Si la classe n'est pas destinée à être réutilisée, j'aurais tendance à ne pas du tout faire de classe pour simplifier le code : une fonctionmain
remplacerait avantageusement la méthode start de la classePl2mp3
.Ensuite,
devient :
Tu peux garder la méthode
argparse
et en faire une fonctionargparse
, et tu peux te débarrasser du membreself.args
: la fonction produit le résultat de l'analyse des arguments et retourne ces résultats au lieu de les affecter à un membre. Ensuite,self.argparse()
devientargs = argparse()
etargs
devient une variable locale de ta fonctionmain
(ou de ta méthodestart
). Paf, un membre de moins, moins d'état "global" (attaché à la classe), le code devient plus facile à lire parce que les choses sont moins dispersées. Pas besoin de garder les arguments dans l'état de ta classe si tu ne t'en sers pas ailleurs.Amuse-toi bien :-)
[^] # Re: remarques en passant
Posté par Panhwein . Évalué à 1.
Beaucoup de bon conseils et de bonnes idées!
Et tout cas, merci d'avoir pris le temps d'écrire.
Oui, je fais ça somme un salop. On m'à conseillé d'utiliser black pour formater le code, superbe découverte!
Bon mes commentaires ils son pour moi, histoire de savoir ou j'en suis. Et ça ne sert pas aux autres. A corriger
Par contre, là, except IOError, le pass est juste énorme, merci!!!
Après, au niveau des classes à réutiliser, je ne vais pas m'interesser spécialement à Pl2mp3, plutot à celle qui gère un type de playlist(il devrait il y avoir 4).
Hier j'ai rajouté les stats, nombres de fichier copié, warnings, errors.
Là je suis en pleine méditation devant m3u. Et ses chemins relatifs en fonction de l'emplacement de la playlist
Think twice, code once
Et vraiement merci, de bonnes critiques constructive.
[^] # Re: remarques en passant
Posté par raphj . Évalué à 3. Dernière modification le 03 octobre 2019 à 12:07.
Beaucoup de codes commencent par de l'expérimentation, et son améliorés par la suite. Je pense que la démarche est bonne et en tout cas c'est totalement comme ça que je fonctionne :-)
Le code que tu présentes dans ton journal n'est pas parfait, mais il a deux qualités importantes :
Ton objectif est de garder ces deux points valides alors que le code grossit et se complexifie.
Les codes parfaits, c'est rare. Un code pas idéal qui rend service, c'est mieux qu'un code qui n'existe pas. Et puis, on est là pour s'amuser !
En tout cas bravo pour faire l'effort de présenter ta démarche et ton code, c'est pas forcément facile de s'exposer au public comme ça. Le journal et les commentaires ici peuvent être bénéfiques à qui tombera dessus, ça peut susciter des inspirations, donc ne n'est pas forcément utile que pour toi. Alors, merci !
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.