![]() |
M3U
Hi,
ich bin - wegen einigen nervigen Problemen - erst jetzt bei den Playlisten-Ladeprozeduren meines neuen Players angekommen. Der alte Player konnte mit einigen Abwandlungen von M3U nicht umgehen. Das liegt aber auch daran, dass M3U nicht wirklich festgelegt ist. Es gibt das simple und das erweiterte Format, welches total einfach auseinanderzuhalten ist, ansonsten gibt es jedoch üble Unterschiede in den Playlisten. Kann mir jemand sagen, welche Dialkete es gibt und was ich zu beachten habe ? Denn in vielen Fällen wird einfach mal etwas weggelassen, zum Beispiel das #EXTINF:. Wenn man nun das #EXTINF: weglässt, stellt sich die Frage, ob dann jede zweite Zeile eine #EXTINF:-ohne-#EXTINF:-Zeile wäre, oder ob es dann noch Leerzeilen dazwischen geben darf. Wie könnte man überhaupt Exceptions usw. vermeiden oder falsches laden, weil was in der Datei nicht stimmt ? Der folgende Code funktioniert gar nicht mal schlecht, aber nur unvollständig. Abgesehen davon bleibt die Frage mit dem #EXTINF: noch offen. Hier eine Playlist (von Wikipedia kopiert, ich benutze selbst keine M3U-Playlisten): Zitat:
Hier der bisherige Code, ich denke er muss noch verbessert werden, hat aber schon einen halbwegs brauchbaren Ansatz:
Delphi-Quellcode:
Das Array (Arr) wird später nochmal auseinandergenommen. Es wird bevor es in meine eigene Listbox kommt nochmal geschaut, ob Artist und Titel zugewiesen, ob Tags vorhanden usw. sind. Das sieht so aus:
for i := 1 to Pred(sl.Count) do // in der StringList befindet sich die rohe Datei.
begin SetLength(Arr, Succ(Length(Arr))); // Arr ist ein Array of TTagInfo. Dort werden alle Tags reingespeichert. p1 := Pos('#EXTINF:', sl[i]); // Die Position von #EXTINF: wird später noch gebraucht, daher speicher ich sie in p1. if (sl[i] <> '') and (p1 < 1) then // Wenn kein #EXTINF: vorhanden ist, jedoch die Zeile nicht leer ist, gehe ich davon aus, dass es sich um die Zeile mit dem Dateinamen handelt. begin Arr[High(Arr)].Dateiname := sl[i]; // Dateiname in langer Form zuweisen. Arr[High(Arr)].kDateiname := ExtractFileName(sl[i]); // Und noch in kurzer Form. end else begin p2 := Pos(',', sl[i]); // Da später noch Position von , benötigt, speichere ich sie in p2. p3 := Pos('-', sl[i]); // Da später noch Position von - benötigt, speichere ich sie in p3. if (p1 > 0) and (p2 > p1) then // p1 muss vorhanden sein und das , (p2) muss sich hinter p1 befinden. Arr[High(Arr)].Dauer := SecToOut(StrToInt(Copy(sl[i], p1+8, p2-(p1+8)))); // So lässt sich die Dauer bestimmen. Was die 8 betrifft, muss man einfach nachrechnen, es geht auf. SecOut konvertiert Sekunden in das [hh:mm:ss]-Format. if p3 > p2 then // Der - (p3) muss hinter dem , (p2) sein. begin Arr[High(Arr)].Artist := Copy(sl[i], Succ(p2), Pred(p3)-Succ(p2)); // Copyrei. Arr[High(Arr)].Titel := Copy(sl[i], Succ(p3), Length(sl[i])); // Hier ebenfalls. end else Arr[High(Arr)].Artist := Copy(sl[i], Succ(p2), Length(sl[i])); // Falls es kein - (p3) gibt, wird einfach alles hinter dem , (p2) in Artist geschrieben. end; end;
Delphi-Quellcode:
lb.Clear;
lb.BeginUpdate; for i := 0 to Pred(Length(Arr)) do if (Trim(Arr[i].Artist) = '') and (Trim(Arr[i].Titel) = '') then // Da Artist und Titel nicht vorhanden, wird der Dateiname und die Dauer angegeben. lb.Add(Arr[i].kDateiname + ' [' + Arr[i].Dauer + ']') else if (Trim(Arr[i].Artist) <> '') and (Trim(Arr[i].Titel) = '') then // Da der Titel nicht vorhanden ist, wurde alles ab dem , (p2) übernommen, Arr[i].Titel muss logischerweise nicht ausgegeben werden. lb.Add(Arr[i].Artist + ' [' + Arr[i].Dauer + ']') else // Wenn alles in Ordnung ist, wie gewöhnlich ausgeben. lb.Add(Arr[i].Artist + ' - ' + Arr[i].Titel + ' [' + Arr[i].Dauer + ']'); lb.EndUpdate; lb.Draw; |
Re: M3U
Liste der Anhänge anzeigen (Anzahl: 1)
...
|
Re: M3U
Ich weiß nicht genau, um was es geht
aaabeerrr Wenn du willst, kannst du dir die "Playlistread.pas" Unit von meinem iBan anschauen ! |
Re: M3U
omata: Dein Code ist sehr hilfreich. Ich habe ihn in meinen Code integriert. Dies tue ich generell nicht ohne ihn zu verstehen. Ich habe noch eine Frage zum Code:
Delphi-Quellcode:
Warum genügt nicht folgender Code ?
if ExtractFilePath(Filename) = '' then
Dateiname := ExtractFilePath(Application.ExeName)+Zeile else Dateiname := ExtractFilePath(Filename)+Zeile;
Delphi-Quellcode:
Abgesehen davon: Bei meiner an sich identischen Version im Code liest mir der Code aus irgendeinem Grund ??? – Boléro nicht aus. Ich erhalte wie bei meinem alten Code nichts weiter als eine komplett leere Ausgabe. Ich habe nicht viel geändert im Vergleich zu deinem Code. Abgesehen von der Ersetzung von Textfile durch StringList habe ich nichts geändert und die eine Stelle mit dem Dateiname (siehe oben) habe ich wie oben gezeigt verändert. Also hier nochmal der ganze Code, sieht jemand den Fehler ? Ich habe extra dein Projekt mal kompiliert und es ging alles sehr gut. Woran könnte das liegen ? Ist da eventuell ein verstecktes Zeichen in der Datei welches wegen anderem Auslesen deines Codes keine Rolle spielt ? Alle anderen Lieder liest auch mein Code einwandfrei aus.
Dateiname := ExtractFilePath(Filename)+Zeile;
Delphi-Quellcode:
var sl : TStrings;
Zeile, Titel, Dateiname : String; // Titel=Artist+Titel p, Sekunden : Integer; begin sl := TStringList.Create; sl.LoadFromFile(f); if sl.Count > 1 then begin if sl[0] = '#EXTM3U' then begin Sekunden := -1; Titel := ''; for i := 1 to Pred(sl.Count) do // 1, weil erste Zeile #EXTM3U begin Zeile := Trim(sl[i]); Dateiname := ''; if Pos('#EXTINF', Zeile) = 1 then begin Delete(Zeile, 1, 8); p := Pos(',', Zeile); if p > 0 then begin if not TryStrToInt(Copy(Zeile, 1, Pred(p)), Sekunden) then Sekunden := -1; Delete(Zeile, 1, p); Titel := Zeile; end; end else begin Dateiname := Zeile; {$IFDEF WIN} if Pos(':', Zeile) > 0 then Dateiname := Zeile else {$ENDIF} {$IFDEF UNIX} if (Length(Zeile) > 0) and (s[1] = '/') then Dateiname := Zeile else {$ENDIF} Dateiname := ExtractFilePath(f)+Zeile; end; if Dateiname <> '' then begin SetLength(Arr, Succ(Length(Arr))); Arr[High(Arr)].Dauer := SecToOut(Sekunden); Arr[High(Arr)].Artist := Titel; Arr[High(Arr)].Dateiname := Dateiname; Arr[High(Arr)].kDateiname := ExtractFileName(Dateiname); ShowMessage(Arr[High(Arr)].Artist); Sekunden := -1; Titel := ''; end; end; end; end; sl.Free; end; |
Re: M3U
Zitat:
Warum liest du deine m3u-Datei in eine Liste ein? Stell dir vor, die Datei ist 100MB groß. Dein Quellcode würde diese Datei vollständig in den Arbeitsspeicher laden. Die Variante mit assignfile, in meinem Beispiel, liest immer nur eine Zeile aus und verarbeitet diese. Das funktioniert auch mit einer 100MB Datei. Wieso soll ich also einen Fehler in deinem Quellcode suchen? Ich habe dir doch einen sinnvollen Weg gezeigt? Vermeide einfach die StringList. |
Re: M3U
Mit dem AssignFile hast du wirklich recht. Keine Ahnung warum ich das überhaupt durch eine StringList ersetzt habe, war definitiv ein Fehler. Nun aber eine Frage dazu: Spielt das Clear eine Rolle ? Denn Lazarus kennt das nicht. Ich habe es daher einfach mal weggelassen, in Beispielen zu AssignFile in Lazarus taucht das Clear auch nicht auf.
Bei "??? – Boléro" erscheint weiterhin nur eine leere Meldung (=leerer Listboxeintrag). Hier die aktuelle Version, sie entspricht deinem zurecht bevorzugtem Stil mit AssignFile. In meinen Augen ist es identisch zu deinem Code, bloß dass eben die ein oder andere Variable anders heißt, aber mehr auch wirklich nicht.
Delphi-Quellcode:
var Datei : TextFile;
Zeile, Titel, Dateiname : String; // Titel=Artist+Titel p, Sekunden : Integer; begin AssignFile(Datei, f); try Reset(Datei); Sekunden := -1; Titel := ''; while not EOF(Datei) do begin ReadLn(Datei, Zeile); Zeile := Trim(Zeile); Dateiname := ''; if Pos('#EXTM3U', Zeile) = 1 then begin end else if Pos('#EXTINF:', Zeile) = 1 then begin Delete(Zeile, 1, 8); p := Pos(',', Zeile); if p > 0 then begin if not TryStrToInt(Copy(Zeile, 1, Pred(p)), Sekunden) then Sekunden := -1; Delete(Zeile, 1, p); Titel := Zeile; end; end else begin Dateiname := Zeile; {$IFDEF Win32} if Pos(':', Zeile) > 0 then Dateiname := Zeile else {$ENDIF} {$IFDEF UNIX} if (Length(Zeile) > 0) and (s[1] = '/') then Dateiname := Zeile else {$ENDIF} Dateiname := ExtractFilePath(f)+Zeile; end; if Dateiname <> '' then begin SetLength(Arr, Succ(Length(Arr))); Arr[High(Arr)].Dauer := SecToOut(Sekunden); Arr[High(Arr)].Artist := Titel; Arr[High(Arr)].Dateiname := Dateiname; Arr[High(Arr)].kDateiname := ExtractFileName(Dateiname); ShowMessage(Arr[High(Arr)].Artist); Sekunden := -1; Titel := ''; end; end; finally CloseFile(Datei); end; end; |
Re: M3U
Welches Clear meinst du jetzt? Das Clear der StringList löscht diese. Lazarus hat diese Möglichkeit nicht? Das kann ich gar nicht glauben. Wenn es dort eine StringList gibt, dann kann die bestimmt auch geleert werden.
Das Clear beim ersten Ausführen der Routine natürlich unwichtig, weil die Liste dann ja leer ist. Bei einem dann folgenden Aufruf ist das Clear dann wichtig, um eben alle vorherigen Einträge zu löschen. Aber das Clear ist doch bei der AssignFile-Variante gar nicht vorhanden. Also ich weiss nicht wirklich, was gerade dein Problem ist. |
Re: M3U
Das ist ein Codeausschnitt aus der TM3UList.LoadFromFile:
Delphi-Quellcode:
Wofür steht dort das Clear ?
Clear;
assignfile(Datei, Filename); try reset(Datei); Sekunden:=-1; ... |
Re: M3U
Bei so etwas musst du den Zusammenhang sehen. Drück z.B. mal Strg + Maustaste auf dem Methodenaufruf, dann springt Delphi genau zu der Routine die dort aufgerufen wird.
In diesem Fall wird einfach das Clear der Klasse TM3UList aufgerufen. Diese Methode löscht alle Einträge der Liste und gibt den Speicher wieder frei. Bei einem Neuladen wird eben erstmal der eventuell verwendente Speicher freigegeben. Ein Benutzer der Klasse kann diese also auch falsch einsetzen (eben nach einem Laden kein Clear aufrufen) trotzdem entsteht kein Speicherleck, die Klasse korrigiert diesen Programmiererfehler. |
Re: M3U
Oh, Entschuldigung, das hätte ich eigentlich sehen müssen. :oops:
Aber nochmal zu der Sache mit ??? - Bolero: Siehst du da irgendeinen Grund für ? |
Re: M3U
Mein Beispiel liesst die Datei aber richtig ein?
Setz doch mal einen Breakpoint und werte deine Programmzeilen Zeile für Zeile aus. Dann wirst du irgendwo erkennen, das die Abarbeitung nicht genau das macht was du dir überlegt hast. Diese Stelle must du dann verstehen und ändern. |
Re: M3U
Unser Code ist identisch. Bloß handhabt Lazarus die Stringverarbeitung etwas anders: Man muss aufpassen, dass man WideStrings benutzt. Am Ende schadet ein AnsiToUTF8 nicht gerade und wenn man genau das getan hat, funktioniert alles.
Was sonst noch zu sagen ist: Danke für deine Hilfe! |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz