Jak mawiała mi babcia: "wnuczku, ucz się nowych języków programowania, dzięki temu poszerzysz horyzonty swojej programistycznej wyobraźni i będziesz mógł na Amidze robić takie cudawianki, że ho ho...". Wziąłem do serca słowa babci i zacząłem uczyć się Pythona. Swoją drogą mądrość starszych pokoleń to rzecz bezcenna! Dzisiaj chciałbym przedstawić wam pewien prosty skrypcik, który spłodziłem w trakcie nauki tego ciekawego języka programowania, jakim jest niewątpliwie Python. Owy skrypt służy do hurtowej zmiany nazw plików w formacie MP3.
Często zdarza się, że pliki MP3 zapisane są pod bardzo finezyjnymi nazwami np.: 05-zero_7-throw_it_all_away[320bps].mp3. To jeszcze pół biedy, niekiedy nazwy są wręcz zaszyfrowane, jak tutaj: 1234567.mp3. Ehh... jakby było miło gdyby plik po prostu nazywał się tak, jak natura chciała, czyli zgodnie z informacjami zapisanymi w tagach "empetrójki", czyli np.: 05 - Throw it all away.mp3. Wbrew pozorom, aby pozbyć się tych wszystkich dziwnych nazw plików, nie trzeba ich zmieniać ręcznie (co byłoby dosyć uciążliwe), ani też odpalać zewnętrznej aplikacji (vel MultiRen). Wystarczy podpiąć pod menu kontekstowe Ambienta pewien krótki skrypt w Pythonie, który zrobi za nas całą brudną robotę. Jednak, aby zatopić zęby w torcie, najpierw trzeba go upiec. Więc przyjaciele - do garów!
Instalacja Pythona pod MorphOS-em
Pobieramy z MorphOS Files port Pythona w wersji 2.5, rozpakowujemy gada i instalujemy. W archiwum znajdziemy trzy katalogi (C, Libs i DevEnv). Zawartość dwóch pierwszych ląduje w katalogach C i Libs na partycji systemowej, trzeci to biblioteki dla programistów C, które opcjonalnie kopiujemy do katalogu GG. Python w wersji 2.x to jedna z dwóch linii rozwojowych tego języka. Drugą jest Python w wersji 3.x, niestety nie obsługiwany jeszcze przez żaden amigowy system. Po instalacji Pythona warto otworzyć okienko konsoli i odpalić na próbę pythonowskiego interpretera. Wywołując go z poziomu CLI, będziemy mogli na "żywca" przekazywać interpreterowi polecenia do wykonania (jest to tzw. tryb interaktywny). Interpreter zachęca nas wtedy do podania kolejnej instrukcji za pomocą tzw. znaku zachęty, zwykle w postaci trzech znaków większości (>>>).
Interpreter Pythona w trybie interaktywnym
Kolejnym krokiem będzie instalacja dodatkowej biblioteki (modułu) do Pythona, która w naszym skrypcie zajmie się grzebaniem po tagach "empetrójki". Moduł ten nazywa się...
EyeD3
I tutaj ujawnia się wspaniała właściwość Pythona. Dzięki zewnętrznym modułom, które importujemy do naszego skryptu, możemy korzystać z bardzo wielu ciekawych i użytecznych funkcji. Innymi słowy, nie musimy tracić czasu, aby zrozumieć jak właściwie kodowane są informacje w tagach MP3. Moduł "EyeD3" robi to za nas - my jedynie, z jego pomocą, wyciągniemy interesujące nas informacje (np. tytuł utworu lub nazwę wykonawcy).
Moduł "EyeD3" w formie spakowanego archiwum znajdziemy na stronie: http://eyed3.nicfit.net. Osobiście korzystałem z najnowszej "paczki" w wersji 0.6.17. Taką też polecam pobrać ze strony projektu. Po rozpakowaniu pliku "eyeD3-0.6.17.tar.gz", wędrujemy do katalogu eyeD3-0.6.17/src. Tam siedzi podkatalog o nazwie "eyeD3". Bierzemy go za fraki i kopiujemy do LIBS:python2.5/site-packages. Ważna uwaga - po skopiowaniu plików musimy zmienić nazwę pliku "__init__.py.in" na "__init__.py" (po prostu usuwamy rozszerzenie ".in"). Fakt, że plik o nazwie __init__.py w ogóle istnieje w katalogu eyeD3, informuje Pythona, że katalog ten ma być traktowany jako pakiet (w razie próby zaimportowania go w kodzie). Swoją drogą taki sposób instalacji modułów Pythona nie jest zbyt elegancki, ale do naszych celów wystarczy.
W ten oto sposób nasz obślizgły, morphosowy python wzbogacił się o dodatkowy moduł, dzięki któremu obsługa tagów MP3 staje się dziecinnie prosta. Aby się o tym przekonać, stwórzmy na boku miniaturowy skrypt odczytujący z podanego pliku MP3 kilka ciekawych informacji (tytuł utworu, artystę i numer ścieżki na płycie). Oczywiście dane pobrane zostaną z tagów "empetrójki". UWAGA! Pamiętajcie, że Python szereguje bloki kodu za pomocą wcięć (a nie tak jak w C/C++ nawiasów klamrowych). Więcej informacji na ten temat znajdziecie tutaj.
Listing: mp3info.py
#!/usr/bin/python import sys # import modulu sys import eyeD3 # import modulu eyeD3 # Sprawdzamy czy w ogóle podane zostały jakieś pliki do przepatrzenia if (len(sys.argv)>1): plik = sys.argv[1] # argument z linii poleceń (ścieżka do pliku mp3) tag = eyeD3.Tag() # tworzymy nową instancję klasy Tag tag.link(plik) # tworzymy uchwyt do pliku # odczytujemy konkretne tagi z podanego pliku mp3 print "Artysta: %s" % tag.getArtist() print "Tytul utworu: %s" % tag.getTitle() print "Numer sciezki: %s" % tag.getTrackNum()[0] exit(0)
Po odpaleniu skryptu z linii poleceń (ze ścieżką do pliku MP3 jako argumentem). Dla przykładu:
python mp3info.py dh3:mp3/depeche_mode_-_in_your_room.mp3
Skrypt powinien wypisać garść informacji w okienku konsoli (o ile oczywiście plik MP3 zawiera w tagach interesujące nas dane) - rysunek obok. Co się dzieje w tym skrypcie? W sumie nic specjalnego. Na początku importujemy do naszego skryptu moduły sys i eyeD3, potem sprawdzamy, czy użytkownik podsunął skryptowi jakikolwiek plik do przeanalizowania (if (len(sys.argv)>1)). Jeśli tak, to ścieżka dostępu do niego zapisana jest w (sys.argv[1]). Przypisujemy ową ścieżkę do zmiennej (plik), po czym w ruch idzie mechanizm obsługi tagów MP3 z modułu EyeD3 (eyeD3.Tag()). Na końcu sama słodycz - dobieramy się do konkretnych tagów "empetrójki" poprzez zgrabne metody getArtist(), getTitle(), getTrackNum(). To jest to, co tygryski lubią najbardziej!
Teraz nie pozostaje już nic innego jak tylko rzucić się na głęboką wodę tego dmuchanego baseniku dla dzieci do lat 5 za 29.99 z Tesco. Naszym zadaniem będzie napisanie kompletnego skryptu do zmiany nazw plików MP3 na tytuły zapisane w tagach mp3. Aby było jeszcze ciekawiej, odczytamy także numery ścieżek (też z tagów) i jeżeli będzie to cyfra z przedziału (0-9), to dodamy wiodące 0 na początku pliku, tak aby zamiast:
1 - Jesteś szalona.mp3
... otrzymać:
01 - Jesteś szalona.mp3
Wykonanie tego zadania zlecimy funkcji rename_mp3_file(), której rzucimy na pożarcie listę plików mp3 (np. zaznaczonych w listerze Ambienta, ale o tym później). Oto i ona:
Listing: mp3rename.py #!/usr/bin/python import sys import os import eyeD3 def rename_mp3_file(plik_wejsciowy): tag = eyeD3.Tag() tag.link(plik_wejsciowy) # Odczyt danych z tagów mp3 i stworzenie nowej nazwy try: tytul = tag.getTitle() numer = tag.getTrackNum()[0] nowa_nazwa_pliku = "%.2d - %s.mp3" % (numer, tytul) except TypeError: print("BLAD TYPU --> %s" % plik_wejsciowy) return # Wydłubanie ścieżki dostępu do katalogu w którym znajduje się plik mp3 katalog = os.path.normpath(os.path.split(plik_wejsciowy)[0]) # Złożenie ścieżki do katalogu z nową nazwa pliku. plik_wyjsciowy = os.path.normpath(os.path.join(katalog,nowa_nazwa_pliku)) # Zmiana nazwy pliku print ("PRZETWARZAM --> %s" % plik_wejsciowy) try: os.rename(plik_wejsciowy, plik_wyjsciowy) except: print("BLAD PRZY ZMIANIE NAZWY --> %s" % plik_wejsciowy)
Funkcja dostaje jako argument stringa kryjącego w sobie ścieżkę dostępu i nazwę pliku, który chcemy poddać przemianowaniu. DH3:MP3/BestOfDiscoPolo/Boys/jestes_szalona.mp3
Następnie próbujemy odczytać tytuł utworu i numer ścieżki. Potem składamy informacje do kupy zapisując je do zmiennej nowa_nazwa_pliku. Numer ścieżki możemy wyświetlić z wiodącym zerem na początku (dlatego numer formatujemy poprzez "%.2d", a nie "%d"). Na wypadek gdyby w pliku MP3 nie było żadnych tagów, otulamy klauzulą try/except całą operację odczytu tagów i budowania nowej nazwy. Jeśli plik nie zawiera żadnych tagów, sypnie błędem typu TypeError, który my przechwycimy i bezpiecznie opuścimy funkcję (no bo z pustego to i Salomon nie naleje...). Jeżeli jednak plik zawiera informacje w tagach, to po przejściu try/except znajdziemy w zmiennej nowa_nazwa_pliku (jak sama nazwa wskazuje) nową nazwę pliku, zbudowaną na podstawie danych z tagów MP3, czyli np.:
01 - Jesteś szalona.mp3
Jednak to tylko wartość zapisana gdzieś w pamięci - plik nadal legitymuje się stara nazwą. Aby zmienić jego nazwę na tę spod nowa_nazwa_pliku, musimy dowiedzieć się w którym konkretnie katalogu plik ten się znajduje. Informacja ta zapisana jest w zmiennej plik_wejsciowy, wystarczy ją tylko "wydłubać". Do tego właśnie służy funkcja os.path.split(), która zwraca krotkę (tuple), czyli niezmienną listę wartości. Wartościami tymi są katalog i plik, wyłuskane z podanego stringa. Zatem zerowy element owej krotki, to po prostu ścieżka do katalogu, w którym siedzi nasz plik mp3 (stąd wywołanie os.path.split(plik_wejsciowy)[0]). Dobrą praktyką jest normalizacja ścieżki za pomocą os.path.normpath(). Funkcja ta powoduje redukcję niepotrzebnych separatorów i odwołań do katalogów nadrzędnych. Chodzi po prostu o jak największe możliwe uproszczenie ścieżki.
No więc mamy już wystarczającą ilość danych, aby ożenić ze sobą starą ścieżkę z nową nazwą pliku. Użyjemy do tego metody os.path.join(). W ten sposób wykorzystując "wydłubaną" ścieżkę do katalogu i zmienną nowa_nazwa_pliku, tworzymy kompletną ścieżkę dostępu ze zmodyfikowaną nazwą pliku mp3 (plik_wyjsciowy). Na koniec wystarczy wprawić w ruch metodę os.rename(). To ona w zgrabny sposób zamieni pierwotną nazwę pliku na nową (zbudowaną na bazie tagów mp3). Funkcja rename_mp3_file(), choć robocza, to jednak nie może działać samoistnie. Trzeba ją jeszcze wywołać (dla każdego pliku jaki podamy w liście argumentów).
if __name__ == '__main__': if (len(sys.argv)>1): # Sprawdzamy czy w ogole podane zostały # jakiekolwiek pliki do przepatrzenia for plik in sys.argv[1:]: # Dla każdego argumentu (począwszy od pierwszego) # sprawdzmy czy pod podaną scieżką kryje się plik if(os.path.isfile(plik)): # JEST PLIK! rename_mp3_file(plik) # odpalamy naszą magiczną funkcję else: print ("BLAD ODCZYTU --> %s" % plik) # nie ma takiego pliku continue
W pętli for przechodzimy po liście argumentów począwszy od pierwszego ([1:]) - zerowy element nie jest nam do niczego potrzebny (zawiera nazwę naszego skryptu). Potem tylko upewniamy się czy plik na pewno istnieje. Jeżeli "empetrójka" przejdzie test pomyślnie, przesyłana jest do funkcji rename_mp3_file(). A co tam się z nią dzieje, to już wiesz...
Poszły konie po betonie...
Przyszedł czas na testy. Z racji tego, że skrypt spokojnie radzi sobie z dowolną liczbą argumentów (plików), możemy rozkazać mu, aby przeanalizował z marszu listę plików mp3. W linii poleceń wyglądałoby to mniej więcej tak:
Python mp3renamer.py dh2:01.mp3 dh3:mp3/02.mp3 Muzyka:03.mp3
Jeżeli pliki zawierają informacje o tytule utworu i numerze ścieżki, to po chwili, te niewiele mówiące nazwy plików, zmienią się na poprawne tytuły utworów z numerami ścieżek. Teraz wystarczy już tylko podpiąć skrypt pod morphosowego Ambienta.
Ambient
Skrypt wygodnie jest uruchamiać z poziomu menu kontekstowego Ambienta. Przykładowo, zaznaczamy w oknie listera kilka "empetrójek", a w menu (po naciśnięciu prawego klawisza myszy) czeka na nas gotowy do odpalenia skrypt. W ustawieniach Ambienta i zakładce MIME odnajdujemy definicję akcji dla plików typu "audio/mpeg" (MPEG Layer-3 Audio).
Okno Ustawień Ambienta dla zakładki MIME
Tworzymy nową akcję o nazwie MP3 Renamer (lub innej), a w linii poleceń umieszczamy wywołanie skryptu, np.:
C:python DH3:mp3renamer.py %sp
Typ zdarzenia to AmigaDOS. Koniecznie zaznaczamy opcję "Wybór łączony", aby skrypt uruchomił się tylko raz i dostał jako argumenty listę ścieżek dostępu do naszych "empetrójek" (w innym wypadku wykona się oddzielnie dla każdego z podanych plików).
Definiowanie nowej akcji w menu kontekstowym dla plików MP3
Zapisujemy ustawienia Ambienta i testujemy nasz skrypt. A testowanie jest banalnie proste. Lokalizujemy gromadkę "empetrójek" i po zaznaczeniu kilku z nich, uruchamiamy skrypt "MP3 Renamer" z menu kontekstowego. Jeśli wszystko poszło dobrze, skrypt powinien otworzyć nowe okno konsoli i poinformować nas o tym, co wyszło z prób przemianowania zaznaczonych plików muzycznych. Ogólnie, jeżeli dana "empetrójka" zawierała wymagane informacje w tagach, to plik został przemianowany - jeżeli nie, pominięty.
Podsumowanie
W ten oto prosty, łatwy i przyjemny sposób można poskromić fantazję miłosników muzyki, którzy z różnych powodów zmuszeni byli okaleczyć oryginalne nazwy plików MP3. Oczywiście przedstawiony wyżej skrypt nie jest absolutnie ucieleśnieniem żadnego geniuszu programistycznego - nawet do tego nie pretenduje. Pretenduje natomiast do miana małego i przydatnego utilka, który ma służyć braci amigowej (a nie doprowadzać do orgazmu ortodoksyjnych programistów języka C ;)
To tyle. Miłej przygody z Pythonem życzy
MarX
fuego@o2.pl
ps. Staropolskim "BIG THX" chciałbym podziękować dla następujących osób: Alekc, Yomgui oraz Korni :)
NA SKRÓTY: Jeżeli nie specjalnie interesują Cię szczegóły działania samego skryptu, ale chciałbyś go używać w swoim systemie, to spokojnie olej prawie cały ten artykuł. Przeczytaj jedynie części dotyczące instalacji Pythona oraz modułu EyeD3, a także integracji skryptu z menu kontektowym Ambienta. Wszystkie niezbędne pliki znajdziesz tutaj. BONUS - MP3 TagView Zdarza się czasem, że nazwy plików są w miarę sensowne, a w tagach mp3 są same śmieci. Wtedy zastosowanie MP3 Renamer`a mija się z celem. Dzięki MP3 TagView, możemy dokładnie podejrzeć co w trawie "piszczy". Skrypt podpinamy do Ambienta tak samo jak MP3 Renamer. Efekt działania MP3 TagView widać na poniższym zdjęciu. Skrypt do pobrania stąd.
Moduł "EyeD3" w formie spakowanego archiwum znaleźć można tutaj. |
Artykuł oryginalnie pojawił się w piątym numerze Polskiego Pisma Amigowego.