ubuntuusers.de

Aktueller Titel von mpg123

Status: Gelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

DrCrow

Anmeldungsdatum:
2. November 2017

Beiträge: Zähle...

Hallo und guten Morgen,

ich bin auf das Forum über die guten Wiki-Seiten gekommen. Ich quäle mich aktuell mit der Steuerung des mpg123 in der Kommandozeile.

Folgendes Szenario: Ich habe einen Ordner mit Musik. Diese Musik spiele ich zufällig ab und verschiebe den Prozess in den Hintergrund:

1
(mpg123 -Z -q *mp3) &

Jetzt würde ich mir gerne den aktuellen Titel ausgeben lassen. Die Ausgabe stoppen und fortsetzen mache ich über den Namen des Prozesses:

pkill -STOP mpg123 und pkill -CONT mpg123

Im ersten Versuch habe ich über alle möglichen Wege versucht mir den Titel in eine Textdatei zu schreiben und habe es nicht wirklich hinbekommen. Eine Hilfe hatte ich schon gefunden, bei denen ich die kompletten Argumente von mpg123 bekomme. Das sind aber dann alle Titel in der Wiedergabeliste. Auch hat mir die API von mpg123 nicht wirklich weitergeholfen. Da ich auch recht neu in der Welt von Linux bin, habe ich hier nicht genug Erfahrung.

Ich hoffe mal ich bin hier im richtigen Unterforum und ihr könnt mir weiterhelfen ☺

Gruß

Moderiert von XM-Franz:

Dieses Thema ist verschoben worden. Bitte beachte die als wichtig markierten Themen („Welche Themen gehören hier her und welche nicht?“)!

dirkolus

Anmeldungsdatum:
17. Mai 2011

Beiträge: 2146

Wohnort: dahoam

Moin,

DrCrow schrieb:

Jetzt würde ich mir gerne den aktuellen Titel ausgeben lassen.

Wenn Du Deine Frage wie folgt umformulierst, kommst Du vielleicht weiter:

1
2
3
4
Ich habe einen Ordner mit Musikdateien und würde gerne
 * jede Datei abspielen und
 * den Titel ausgeben 
lassen.

auf diese Weise kannst Du nicht nur einen Befehl auf Deine Musikdateien loslassen, sondern mehrere - und damit sind wir bei der Shell-Programmierung.

1
(mpg123 -Z -q *mp3) &

Das *mp3 wird von der Shell selbst ersetzt durch eine Liste von Dateien, die auf 'mp3' enden (offensichtlich). Das müssten wir ersetzen durch ein Konstrukt, das jeden Listeneintrag einzeln behandelt - in einer for-Schleife:

1
(for a in *mp3; do mpg123 -Z -q $a; done) &

Zwischen do und done kannst Du dann mit der Musikdatei machen was Du willst: aktuelle Zeit ausgeben, Dir ne Mail schicken oder eben mit echo $a den aktuellen Dateinamen ausgeben lassen.

Dirk

P.S.: Wozu Du dafür die Ausgabe stoppen und fortsetzen willst, ist mir leider nicht ganz klar ...

DrCrow

(Themenstarter)

Anmeldungsdatum:
2. November 2017

Beiträge: 6

En Gude Dirk,

erstmal vielen Dank für die Antwort. Du hast mir für mein Verständnis sehr geholfen.

Mit deiner Hilfe konnte ich schon Musik abspielen. Leider stört mich eins. Der Titel ist nicht zufällig. Was natürlich auch Sinn macht, da ich mit der For-Schleife über die einzelnen Dateien gehe und diese nach dem Alphabet sortiert sind. Der Parameter [-z] im mpg123 hat keine Auswirkung und kann deshalb auch weggelassen werden. Ich hatte es so versucht:

for a in *mp3; do mpg123 "$a"; done

Die Musik ist schön hintereinander abgelaufen, so wie die einzelnen Titel auch im Ordner sortiert werden.

Hier meine Fragen:

  1. Gibt es eine Möglichkeit diese auch zufällig auszugeben?

  2. Gibt es eine Möglichkeit über die PID das aktuelle Argument zu holen, welches abgespielt wird? In der Konsole bekomme ich ja auch den Titel angezeigt.

  3. Wäre es möglich alle Konsolen-Ausgaben in eine txt-Datei zu schreiben? So könnte ich vielleicht versuchen mir das hieraus zu filtern

Ausblick: Aktuell versuche ich über ein python-Skript die Titel zufällig Zahlen zuzuordnen und diese dann abzuspielen.

Gruß

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4650

Wohnort: Berlin

@DrCrow: Wenn Du schon mit Python arbeitest könntest Du auch gleich ein Programm schreiben das all Deine ”Probleme” löst.

Für's mischen gibt es das shuf-Kommando, hier zum Beispiel mit der -e-Option:

1
for file in shuf -e *.mp3; do mpg123 "$file" ; done

Ad 2.: Ich denke nicht, solange mpg123 da nicht etwas für vorsieht, und da habe ich nichts gefunden.

Ad 3.: Ja, das wäre möglich, aber ich denke nicht dass das wirklich zielführend ist. Statt das Programm in den Hintergrund zu schicken, würde ich es eher im Vordergrund in einer eigenen Shell laufen lassen. Die meisten Terminalemulatoren können mehrere Shells in Reitern anzeigen, dann braucht man keine zusätzlichen Fenster. Oder man lässt es in *einem* Terminalfenster laufen und verwendet byobu, tmux, oder screen um dort dann mehr als ein Terminal drin zu haben. Das macht wesentlich weniger umstände. IMHO.

dirkolus

Anmeldungsdatum:
17. Mai 2011

Beiträge: 2146

Wohnort: dahoam

Moin,

Ich vermute mal, dass Du irgendein Display über Serielle Schnitte versorgen willst - also cat $file > /dev/ttyn oder so? Das kann man ja einfach einbauen - oder aber in eine Datei in /tmp schreiben und ein anderer Prozess liest dann dieses File aus. Wenn's denn unbedingt die PID sein muss, dann halt in einem zweiten Prozess abfragen: ps -ef | grep mpg123 | grep -v grep | ...

@Marc:

könntest Du auch gleich ein Programm schreiben das all Deine ”Probleme” löst.

"Anforderungen"! 😉

Dirk

P.S.: Dateiname ist nicht schön genug? Vielleicht können ID3 Tags der Musikdateien ausgewertet werden: Siehe http://www.linux-community.de/Internal/Artikel/Print-Artikel/EasyLinux/2014/03/Musik-Metadaten-in-der-Shell-bearbeiten

DrCrow

(Themenstarter)

Anmeldungsdatum:
2. November 2017

Beiträge: 6

Hallo,

erstmal vielen Dank für die Anregungen. Ich habe einen Weg gefunden 👍

@Marc_BlackJack_Rintsch Das mit dem Mischen war eine wirklich Gute Information. Danke dir ☺ Auch haben mich deine Antworten zu den gestellten Fragen weitergebracht. In Zukunft werde ich meine Fragen so aufbauen 😬

Gibt es hier eine Funktion den Leuten direkt zu danken? Habe sowas glaube ich schon mal in einem anderen Forum gesehen. Aber weiter im Text...

@dirkolus Du hast richtig vermutet. Es soll ein Display mit Informationen gefüttert werden ☺ und hier sind auch gleich meine Anforderungen an mein Programm:

  1. Musiktitel zufällig abspielen

  2. Die letzten drei Titel sollen sich unterscheiden

  3. Aktuell laufender Musiktitel in eine Textdatei schreiben

Zu Anforderung 1 Zuerst erstelle ich mir eine Liste mit allen Dateien im Musikordner. Anschließend generiere ich mir zufällig eine Zahl, welche dann mein Index für die Liste ist.

1
2
3
liste = os.listdir("/home/pi/bgm")
zufallTitelNr = randint(0,len(liste)-1)
b = liste[zufallTitelNr]

Dann schicke ich den Befehl für mpg123 mit dem Ordnerpfad und Musiktitel ab. Hier hatte ich einige Schwierigkeiten mit der Notation von Hochkommata und Anführungszeichen. Dadurch, dass die Musiktitel auch Leerzeichen enthalten kam es öfters zu Fehlinterpretationen. Denke aber, dass es falsch von mir verstanden wurde und in verschiedenen Kombinationen zufällig gelungen ist.

1
2
3
c = '/home/pi/bgm/'
d = '"' + c + b + '"'
a = os.popen('mpg123 ' + d)

Ich habe es hier mal einfach zusammengesetzt, dass man mein Problem verstehen kann.

Zu Anforderung 2 Es kann echt störend sein, wenn der selbe Musiktitel zwei oder dreimal hintereinander kommt 🤣 Habe es mir recht einfach gemacht und einfach die letzten drei Musiktitel bzw. deren Indizes abgespeichert. Dann solange in einer while-Schleife den aktuellen Titel angepasst, bis diese ungleich der vergangenen war.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# ---------deklarieren und initialisieren-------- #
zufallTitelNr = -1
musikTitelN1 = -1
musikTitelN2 = -1
musikTitelN3 = -1
# ---vergleich aktueller Titel mit vergangenen--- #
while ((zufallTitelNr == musikTitelN1)or(zufallTitelNr == musikTitelN2)or(zufallTitelNr == musikTitelN3)):
    zufallTitelNr = randint(0,len(liste)-1)
# ------------vergangene Titel merken------------ #
musikTitelN3 = musikTitelN2
musikTitelN2 = musikTitelN1
musikTitelN1 = zufallTitelNr

Zu Anforderung 3 Hier habe ich es der Einfachheit dabei belassen es in eine Textdatei zu schreiben.

1
f = os.popen('echo ' + b + ' > aktuellerMusiktitel.txt')

Den komplette Code habe ich hier http://www.thebeatyouneed2day.de/wordpress/index.php/2017/11/03/mpg123-aktueller-titel-ausgeben/ gezeigt. Meine komplette Lösung zu zeigen ist vielleicht nicht jedermanns Sache. So kann man nochmal selbst Gehirnschmalz verbraten.

Ich weiß natürlich nicht ob das die beste Lösung ist. Sie funktioniert aber für mich und ist damit ausreichend. Sollte sich daran was ändern oder ich Fehler feststellen, teile ich es euch aber mit. 😊

Viele Grüße und besten Dank

Roland

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4650

Wohnort: Berlin

@DrCrow: Statt randint() hätte man randrange() verwenden können. Oder man spart sich das mit den Indexwerten komplett und mischt die Liste mit der shuffle-Funktion aus dem random-Modul. Indexwerte sind in Python eher selten und oft ein Zeichen das man etwas komisches versucht und nicht wirklich in Python programmiert.

os.popen() ist das falsche Werkzeug. Es gibt das subprocess-Modul, das all die anderen Möglichkeiten externe Programme zu starten ersetzt und wo man auch keine unnötige zusätzliche Shell zwischen dem Python-Programm und dem was man extern ausführen möchte braucht, womit dann auch die Probleme mit Anführungszeichen, Leerzeichen & Co in den Dateinamen entfallen, weil die nicht noch zwischendurch noch mal von einer Shell interpretiert werden bevor sie dem eigentlichen Programm übergeben werden.

Pfadteile setzt man in Python mit os.path.join() zusammen und nicht mit +.

1
process = subprocess.Popen(['mpg123', os.path.join(MUSIC_PATH, dateiname)])

Den Pfad zu den Musikdateien sollte man nur einmal im Programm stehen haben, am besten als Konstante. Dann kann man den an *einer* Stelle ändern und es besteht auch nicht die Gefahr das man bei Änderungen eine Stelle vergisst oder nicht alle exakt gleich verändert.

Die Namen sind schlecht gewählt und/oder entsprechen nicht den Konventionen unter Python. Ein Name soll dem Leser verraten was der Wert bedeutet. Einbuchstabige Namen tun das in aller Regel nicht. Und auch so etwas wie liste nicht, denn man möchte ja nicht wissen das es eine Liste ist, sondern was die Werte darin für eine Bedeutung haben. music_filenames zum Beispiel. Wenn man sinnvolle Namen verwendet, braucht man auch nicht in Kommentaren beschreiben was da passiert, denn das ist dann auch ohne Kommentar in der Regel ersichtlich. Kommentare sollten nicht beschreiben was der Code macht, denn das steht da ja schon als Code, sondern warum der Code das so macht — sofern das nicht offensichtlich ist.

Bei aus mehreren Worten zusammengesetzten Namen verwendet man in Python worte_in_kleinbuchstaben_mit_unterstrichen. Ausgenommen Klassennamen (MixedCase) und Konstanten (KOMPLETT_GROSS).

Wenn man anfängt Namen durchzunummerieren, will man entweder bessere Namen oder gar keine einzelnen Namen sondern eine Datenstruktur wie eine Liste oder in diesem Fall vielleicht auch eine Queue (collections.deque).

Bei dem while sind viel zu viele unnötige Klammern. Ausserdem ist das zu umständlich formuliert, denn man könnte auch den in-Operator verwenden um zu testen ob zufall_titel_nr in einer Liste oder einem Tupel (oder einer Queue) von Werten enthalten ist. Also beispielsweise:

1
2
3
while True:
    while zufalls_titel in [musik_titel_n1, musik_titel_n2, musik_titel_n3]:
        # ...

Beziehungsweise wenn man die letzten Werte sowieso schon in einer Sequenzdatenstruktur stehen hat, einfach:

1
2
3
4
5
6
letzte_titel = deque(maxlen=3)
while True:
    while zufalls_titel in letzte_titel:
        zufalls_titel = random.choice(musik_dateinamen)
    letzte_titel.append(zufalls_titel)
    # ...

Das Programm bekommt an der Stelle übrigens ein Problem mit einer Endlosschleife wenn es nur drei oder weniger Dateinamen in dem Verzeichnis gibt. Ein Grund mehr warum ich das einfach mit random.shuffle() auf der Liste mit den Dateinamen lösen würde, also:

1
2
3
4
while True:
    random.shuffle(musik_dateinamen)
    for dateiname in musik_dateinamen:
        # ...

Du benutzt viel zu oft os.popen(). Also auch für Fälle wo man das nicht mit dem subprocess-Modul ersetzt, sondern für Sachen für die es total unsinnig ist eine externe Shell mit einem Kommando zu starten. Beispielweise das Schreiben von einem Dateinamen in eine Datei. Man kann in Python durchaus Dateien öffnen und dort etwas hineinschreiben. Dazu muss man keine Shell starten die das dann mit echo und einer Umleitung in eine Datei macht. Wobei Dir auch hier wieder (unnötigerweise) Probleme durch Zeichen in den Musik-Dateinamen entstehen können, weil das ja an der Shell vorbei muss.

Ich würde das ganze generell nicht wirklich als Python-Programm sehen, denn Python wird dort kaum tatsächlich verwendet. Das ist eher ein als Python verkleidetes Shell-Skript.

DrCrow

(Themenstarter)

Anmeldungsdatum:
2. November 2017

Beiträge: 6

Hallo,

@Marc_BlackJack_Rintsch Erstmal vielen Dank für deine ausführliche Hilfe. Sowas bringt mich weiter =)

Das mit den drei Titeln im Verzeichnis sehe ich nicht so schlimm. Viel eher sehe ich ein Problem, wenn es keine Datei mit mp3-Endung ist. Gibt es hier auch einen einfachen Weg das zu Prüfen? Hatte einfach den Namen angeschaut und mp3 im String mit .find('mp3') gesucht.

Danke schon mal =)

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4650

Wohnort: Berlin

@DrCrow: Das ”globbing” von Shells nach Mustern kann man mit dem glob-Modul aus der Python-Standardbibliothek machen. Ungetestet:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python
# coding: utf-8
from __future__ import absolute_import, division, print_function
import os
import random
import subprocess
from glob import glob

MUSIC_PATH = '/home/pi/bgm'


def main():
    music_filenames = glob(os.path.join(MUSIC_PATH, '*.mp3'))
    player = None
    try:
        while True:
            random.shuffle(music_filenames)
            for music_filename in music_filenames:
                music_path = os.path.join(MUSIC_PATH, music_filename)
                with open('aktuellerMusiktitel.txt', 'w') as title_file:
                    title_file.write(music_path + '\n')
                player = subprocess.Popen(['mpg123', music_path])
                player.wait()
    except KeyboardInterrupt:
        if player is not None:
            player.terminate()


if __name__ == '__main__':
    main()

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4650

Wohnort: Berlin

Und hier der Grund warum ich das auch mit nur einem gestarteten externen Programm eher für ein Shell-Skript halte das sich als Python-Programm verkleidet hat:

1
2
3
4
5
6
7
8
9
#!/bin/sh
readonly music_path='/home/pi/bgm'

while true; do
    for music_file in $(shuf -e "$music_path/"*.mp3); do
        echo "$music_file" > aktuellerMusiktitel.txt
        mpg123 "$music_file"
    done
done

Das lässt sich als Shell-Skript einfacher ausdrücken.

DrCrow

(Themenstarter)

Anmeldungsdatum:
2. November 2017

Beiträge: 6

Hallo =)

Vielen Dank für deine ausführliche Antwort. Mit dem Shell-Skript ist leider der zweite Punkt nicht mehr erfüllt =(

  1. Musiktitel zufällig abspielen

  2. Die letzten drei Titel sollen sich unterscheiden

  3. Aktuell laufender Musiktitel in eine Textdatei schreiben

Oder sehe ich das falsch? 😮

Da ich den praktischen Weg brauche, wähle ich dann doch lieber die Muschel als Schlange verkleidet 🤣

Anpassen musste ich: Zeile 18: Hier muss "music_filename" vorher deklariert werden. Habe hier auch einfach mit "random" einen Titel aus "music_filenames" ausgewählt und damit initialisiert.

und sonst nur Kleinigkeiten, dass es sich besser in meinen Code einfindet ☺

Danke nochmal für deine Hilfe.

Viele Grüße

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4650

Wohnort: Berlin

@DrCrow: Das siehst Du richtig aber IMHO trotzdem falsch denn die Wahrscheinlichkeit ist um so kleiner je mehr Titel existieren. Und es ist letztlich genau das gleiche beim Python-Programm. Wenn Du das beim Shell-Skript nicht haben willst, dann kannst Du auch das Python-Programm so nicht verwenden. Aber der Aufwand Punkt 2 sicherzustellen ist IMHO höher als der Nutzen.

In dem Python-Programm muss vor Zeile 18 nichts ”deklariert” werden. music_filename wird durch die Schleife definiert und nur in der Schleife verwendet, das hat also da wo es verwendet wird auf jeden Fall einen Wert zugewiesen.

DrCrow

(Themenstarter)

Anmeldungsdatum:
2. November 2017

Beiträge: 6

Dann werde ich wohl was falsch gemacht haben.

Es kam ein Error beim Ausführen mit der Variable. Ich werde da aber nochmal nachforschen =)

Danke auf jeden Fall ☺

P.S. Mach dich mit " meiner bescheidenen Meinung nach" nicht kleiner als du bist. Du hast was auf dem Kasten 👍

Antworten |