Skrypt do tagowania i konwertowania plików MP3

0

Napisałam dla własnych potrzeb taki program. Na razie może zmieniać tagi wszystkich plików MP3 w danym folderze (docelowo albumy, ale nie tylko), poza tym moze tez konwertowac z FLAC do MP3 i zapisywac z odpowiednimi tagami. Funkcjonalnosci dopisywane w razie potrzeb, choc moze macie jakies pomysly

from sys import argv
import json
import requests
import os
import io
import pathlib
import shutil
import taglib
import pydub
import pathlib

class MusicDirectory:
	def __init__(self,filepath):
		self.filepath=pathlib.Path(filepath)
		self.modes={
			'1':['new album name','ALBUM','change_tag'],
			'2':['from flac to mp3',None,'to_flac']
		}
		self.tags={}
	def take_input(self,mode,variable):
		if variable==None:
			while True:
				print(mode," . Press Y to confirm.")
				y=input()
				if y=='Y' or y=='y' or y=='yes': break
				if y=='n' or y=='N' or y=='no': exit(1)
		else:
			print("Provide {}".format(variable))
			setattr(self, variable,input())
	def change_tag(self,tag='ALBUM',filepath=None):
		if filepath==None: filepath=self.filepath
		for l in os.listdir(filepath):
			print("Changing {} in {}".format(tag,l))
			mp3=taglib.File(str(filepath / l))
			mp3.tags[tag]=[getattr(self, tag)]
			mp3.save()
			print(mp3.tags)
	def collect_existing_tags(self):
		for l in os.listdir(self.filepath):
			#mp3=taglib.File(io.FileIO(self.filepath / l,'rb'))
			if not os.path.isfile(self.filepath/l): break
			mp3=taglib.File(str(self.filepath/l))
			key=l.replace(".flac","")
			self.tags[key]=mp3.tags
	def update_all_tags(self, new_dir):
		self.collect_existing_tags()
		for song in self.tags:
			#mp3=taglib.File(str(new_dir / (song+".mp3")))
			for tag in self.tags[song]:
				self.change_tag(tag=tag,filepath=str(new_dir/(song+'.mp3')))
				#mp3.tags[tag]=self.tags[song][tag]
			#mp3.save()
			print("Song: {} got updated tags: {}".format(song,mp3.tags))

	def to_flac(self):
		mp3dir=self.filepath / "MP3_Version"
		if not os.path.isdir(mp3dir):
			os.makedirs(mp3dir)
		for l in os.listdir(self.filepath):
			if l=="MP3_Version": break
			print(self.filepath / l)
			flac=pydub.AudioSegment.from_file(self.filepath / l)
			mp3_filename=l.replace(".flac",".mp3")
			flac.export(mp3dir / mp3_filename, bitrate='312k')#parameters=['-progress pipe:1'])
		self.update_all_tags(mp3dir)
	def coordinate_input(self,mode):
		self.take_input(self.modes[mode][0],self.modes[mode][1])
		getattr(self,self.modes[mode][2])()
if __name__ == "__main__":
	if len(argv)<=1 or len(argv)>2:
		print(len(argv))
		print("USAGE ./script FILE_DIRECTORY")
		exit()
	url=argv[1]
	#url=url.replace("\\","\\\\")
	print(url)
	md=MusicDirectory(url)
	#d.collect_existing_tags()
	print("Program mode:\n [1 Change album names]\n[2 Convert all files from FLAC to MP3]")
	mode=input()
	md.coordinate_input(mode)

0

Problemy zauważone juz terez z tym kodem:

  1. Wygląda na to że biblioteka pydub w flac=pydub.AudioSegment.from_file(self.filepath / l), nie sprawdza czy input to plik muzyczny. Program sie wywala jesli inputem bedzie np obrazek. Błąd File "C:\Users\lambdadziara\Miniconda3\lib\site-packages\pydub\audio_segment.py", line 691, in from_file
    audio_codec = audio_streams[0].get('codec_name')
    IndexError: list index out of range
    Być może to błąd w bibliotece pydub? Moze powinni sprawdzac czy inputem jest mp3?
  2. Wybór metody następuje w coordinate_input poprzez string:
    getattr(self,self.modes[mode][2])()
    Na razie jedyną metodą jest zmiana tagów, ale co jeżeli będzie wiecej metod? Problem w tym, że w ten sposób nie wiedząc jaka metoda zostanie wybrana,nie możemy jej podać argumentu. Metoda change_tag, bierze jako argument nazwe tagu (artysta, album, itp), i jest wykorzystywana takze w innym miejscu programu. Po przekonwertowaniu FLAC do MP3, pliki sa bez tagow, wiec ta metoda zostaje tez uzywana do przepisaniu tagow z oryginalu. Byc moze lepiej zrobic normalna drabinke if/else do wyboru metody zamiast tego getattr(self,self.modes[mode][2])(), wtedy można by było podac tag jako argument przez self.change_tag(self.modes[mode][1])

PS lepiej chyba nie hardcodowac tego ALBUM, tylko zrobic jedną opcje 1. Change tag, a potem dac uzytkownikowi wpisac tag jaki chce zmienic

2
  1. Kod jest zbity i nie trzyma się żadnej konwencji. Nie ma co się rozpisywać tylko trzeba odpalić na tym flake8.
  2. MusicDirectory niby najpierw dostaje input z góry, ale potem już sam radośnie wywołuje inputy. Mieszasz warstwy.
  3. Nie wykorzystuj None jak zmienną pomocniczą, dodaj flagę w rodzaju is_yes_no_question
  4. getattr/setattr w wielu miejscach. Refleksja nie dość, że zaciemnia kod to jest też niebezpieczna. W tym kodzie można sobie poradzić bez tego.

1 użytkowników online, w tym zalogowanych: 0, gości: 1