AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

M3U

Ein Thema von Nils_13 · begonnen am 25. Sep 2008 · letzter Beitrag vom 28. Sep 2008
Antwort Antwort
Seite 1 von 2  1 2      
Nils_13

Registriert seit: 15. Nov 2004
2.647 Beiträge
 
#1

M3U

  Alt 25. Sep 2008, 21:20
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 #EXTINFhne-#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:
#EXTM3U
#EXTINF:221,Queen - Bohemian Rhapsody
Titel 1.mp3
#EXTINF:473,Dire Straits - Walk Of Life
Pop\Meine Auswahl\Titel 2.mp3
#EXTINF:264,asd – Bolero
C:\Dokumente und Einstellungen\All Users\Dokumente\Eigene Musik\Titel irgendeinenummer.mp3
Queen - Bohemian Rhapsody und Dire Straits - Walk Of Life werden korrekt ausgelesen. Beim letzten ist es seltsam: Ich gebe einfach mal nach jedem Schleifendurchlauf eine Nachricht wie folgt aus: ShowMessage('||'+Arr[High(Arr)].Artist+'||'+Arr[High(Arr)].Titel+'||'+Arr[High(Arr)].Dauer+'||'); Überall kommt was, nur beim asd - Bolero erscheint eine komplett leere Nachricht. Habt ihr eine Idee warum ?

Hier der bisherige Code, ich denke er muss noch verbessert werden, hat aber schon einen halbwegs brauchbaren Ansatz:
Delphi-Quellcode:
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;
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:
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;
  Mit Zitat antworten Zitat
omata

Registriert seit: 26. Aug 2004
Ort: Nebel auf Amrum
3.154 Beiträge
 
Delphi 7 Enterprise
 
#2

Re: M3U

  Alt 25. Sep 2008, 22:53
...
Angehängte Dateien
Dateityp: zip m3uladen_203.zip (2,9 KB, 57x aufgerufen)
  Mit Zitat antworten Zitat
mr_emre_d
(Gast)

n/a Beiträge
 
#3

Re: M3U

  Alt 26. Sep 2008, 00:11
Ich weiß nicht genau, um was es geht

aaabeerrr

Wenn du willst, kannst du dir die "Playlistread.pas" Unit von meinem iBan anschauen !
  Mit Zitat antworten Zitat
Nils_13

Registriert seit: 15. Nov 2004
2.647 Beiträge
 
#4

Re: M3U

  Alt 26. Sep 2008, 22:31
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:
if ExtractFilePath(Filename) = 'then
  Dateiname := ExtractFilePath(Application.ExeName)+Zeile
else
  Dateiname := ExtractFilePath(Filename)+Zeile;
Warum genügt nicht folgender Code ?
Dateiname := ExtractFilePath(Filename)+Zeile; 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.
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] = '#EXTM3Uthen
    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;
  Mit Zitat antworten Zitat
omata

Registriert seit: 26. Aug 2004
Ort: Nebel auf Amrum
3.154 Beiträge
 
Delphi 7 Enterprise
 
#5

Re: M3U

  Alt 27. Sep 2008, 00:01
Zitat von Nils_13:
Warum genügt nicht folgender Code?
Stell dir vor, du öffnest die m3u-Datei ohne Pfadangabe. Normalerweise ist das dann der Programmpfad. Deshalb der aufwendigere Quellcode.

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.
  Mit Zitat antworten Zitat
Nils_13

Registriert seit: 15. Nov 2004
2.647 Beiträge
 
#6

Re: M3U

  Alt 27. Sep 2008, 22:22
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;
  Mit Zitat antworten Zitat
omata

Registriert seit: 26. Aug 2004
Ort: Nebel auf Amrum
3.154 Beiträge
 
Delphi 7 Enterprise
 
#7

Re: M3U

  Alt 27. Sep 2008, 22:27
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.
  Mit Zitat antworten Zitat
Nils_13

Registriert seit: 15. Nov 2004
2.647 Beiträge
 
#8

Re: M3U

  Alt 27. Sep 2008, 22:31
Das ist ein Codeausschnitt aus der TM3UList.LoadFromFile:
Delphi-Quellcode:
Clear;
assignfile(Datei, Filename);
try
  reset(Datei);
  Sekunden:=-1;
...
Wofür steht dort das Clear ?
  Mit Zitat antworten Zitat
omata

Registriert seit: 26. Aug 2004
Ort: Nebel auf Amrum
3.154 Beiträge
 
Delphi 7 Enterprise
 
#9

Re: M3U

  Alt 27. Sep 2008, 22:41
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.
  Mit Zitat antworten Zitat
Nils_13

Registriert seit: 15. Nov 2004
2.647 Beiträge
 
#10

Re: M3U

  Alt 27. Sep 2008, 22:44
Oh, Entschuldigung, das hätte ich eigentlich sehen müssen.

Aber nochmal zu der Sache mit ??? - Bolero: Siehst du da irgendeinen Grund für ?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:24 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz