Работа с форматом M3U

Интро.

Поводом для написания этой статьи послужило то, что я в Интернете не нашёл ни одной подобной статьи, описывающей такой формат. Начнём с назначения m3u файлов. Не для кого, думаю, не секрет, что этот тип файлов используется в WinAmp 'е для (со)хранения «плей листа». В этой статье мы рассмотрим запись и чтение m3u файлов.

Ближе к делу. Теория.

Формат этого файла таков: в начале файла есть служебное слово [#EXTM3U], означающее, что выбранный нами файл действительно m3u. Далее идут строки вида:

#EXTINF:120,Вася барабанщик – Kill My
My Music\Kill_My.mp3


Где [#EXTINF:] служебное слово, [120] – длина трека в секундах, [Вася барабанщик – Kill My ] – тэг, а [ My Music\Kill_My.mp3] – путь к файлу. Причём путь к файлу не полный и зависит от места расположения m3u файла. Пример: m3u файл находится в папке X:\ Music, а муз. файлы в X:\Music\My Music\Kill_My.mp3, тогда путь к файлу в плей листе будет My Music\Kill_My.mp3. А если файл музыки и файл плей листа будут на разных дисках, то путь будет полным. К чему такие сложности я не знаю, ведь можно просто писать полный путь и никаких проблем не будет. И ещё, если переместить файл плей листа, то WinAmp (и др. программы) не смогут воспроизвести файл, так как не найдут путь к нему. (При условии, что путь неполный).

Ближе к делу. Практика.

Казалось бы неполный путь к файлу создаёт нам дополнительные проблемы. Это так. Но я написал функцию, которая восстанавливает этот путь. Итак, рассмотрим на примере, как можно загрузить в ListView данные из m3u файла. На форму помещаем ListView с тремя колонками. 1-я колонка – тэг, 2-я – длина трека, 3-я – путь. И добавим OpenDialog, для открытия файла, и кнопочку.


function NotFullPathToFullPath(FM3U, FM: string): string;  
(*Из неполного пути -> полный*)  
var  
  Ress: string;  
begin  
  Ress := '';  
  Result := '';  
(*Если 1-й символ ‘\’, то просто добавляем букву диска*)  
  if FM[1] = '\' then  
  begin  
    Result := ExtractFileDrive(FM3U) + FM;  
    exit;  
  end else  
  begin  
(*Путь к m3u + неполный путь к файлу*)  
    if FileExists(ExtractFilePath(FM3U) + FM) then  
    begin  
      Result := ExtractFilePath(FM3U) + FM;  
      exit;  
    end;  
(*А вдруг путь уже полный?*)  
    if FileExists(FM) then  
    begin  
      Result := FM;  
      exit;  
    end;  
  end;  
end;  
  
procedure ReadM3U(files: string);  
(*Чтение m3u*)  
(*Думаю всё и так понятно без комментариев ;)*)  
var List: TStringList;  
  i, n: integer;  
  s, a: string;  
  ListItem: TListItem;  
begin  
(*Очищаем ЛистВив*)  
  Form1.ListView1.Clear;  
  List := TStringList.Create;  
  try  
    List.LoadFromFile(files);  
    for i := 0 to List.Count - 1 do  
    begin  
(*Первая строка – «#EXTM3U»? Если да, то это файл m3u*)  
      if List.Strings[0] = '#EXTM3U' then  
      begin  
        s := List.Strings[i];  
        if s[1] <> '#' then  
        begin  
          ListItem.SubItems.Add('');  
          s := NotFullPathToFullPath(Files, s);  
          ListItem.SubItems[1] := s;  
        end else  
        begin  
          if s <> '#EXTM3U' then  
          begin  
            Delete(S, 1, 8);  
            a := '';  
            n := 1;  
            repeat  
              a := a + s[n];  
              Inc(n);  
            until s[n] = ',';  
            Delete(S, 1, Length(a) + 1);  
            ListItem := Form1.ListView1.Items.Add;  
            ListItem.Caption := s;  
            ListItem.SubItems.Add(Format('%d:%.2d', [StrToInt(a) div 60, StrToInt(a) mod 60]));  
          end;  
        end;  
      end;  
    end;  
  finally  
    List.Free;  
  end;  
end;  

А вызывать будем по кнопке:


procedure TForm1.Button1Click(Sender: TObject);  
begin  
  if OpenDialog1.Execute then  
    ReadM3U(OpenDialog1.FileName) else exit;  
end;  

Так. Открытие мы сделали. Можете открыть свой плей лист, сохраненный в WinAmp'е и вглянуть на то, что получилось. Перейдём к сохранению. Положите на форму ещё одну кнопку и в путь. Не забудьте подключить модуль StrUtils.


function ExtNotFullPath(FM3U, FM: string): string;  
(*Из полного пути в неполный*)  
var  
  i: integer;  
  Ress: string;  
begin  
  Ress := '';  
  Result := '';  
  for i := 1 to Length(FM3U) do  
  begin  
    if FM3U[i] = FM[i] then  
    begin  
      Ress := Ress + FM3U[i];  
      if FM3U[i] = '\' then Result := Ress;  
    end else exit;  
  end;  
end;  
  
function MinToSec(tim: string): string;  
(*Это такой компьютерный юмор, функция из минут в секунды, результат String ;)*)  
(*Помнишь мы секунды преобразовывали в минуты? Вот теперь всё наоборот*)  
var n: integer;  
  a: string;  
begin  
  n := 1;  
  a := '';  
  repeat  
    a := a + tim[n];  
    Inc(n);  
  until tim[n] = ':';  
  Delete(tim, 1, Length(a) + 1);  
  result := IntToStr((StrToInt(a) * 60) + StrToInt(tim));  
end;  
  
procedure SaveList(SaveFile: string);  
(*Сохранение...*)  
var List: TStringList;  
  i: integer;  
  b, s: string;  
begin  
  List := TStringList.Create;  
  List.Add('#EXTM3U');  
  for i := 0 to Form1.ListView1.Items.Count - 1 do  
  begin  
    s := '';  
    List.Add('#EXTINF:' + MinToSec(Form1.ListView1.Items.Item[i].SubItems.Strings[0]) + ',' + Form1.ListView1.Items.Item[i].Caption);  
    b := ExtNotFullPath(SaveFile, Form1.ListView1.Items.Item[i].SubItems.Strings[1]);  
    if Length(b) < Length(ExtractFilePath(SaveFile)) then  
    begin  
      s := Form1.ListView1.Items.Item[i].SubItems.Strings[1];  
      if b<>`` then //проверка, на одинаковых ли дисках?  
        Delete(s, 1, 2);  
    end else  
      s := AnsiReplaceText(Form1.ListView1.Items.Item[i].SubItems.Strings[1], b, '');  
    List.Add(s);  
  end;  
(*Сохраняем в файл*)  
  List.SaveToFile(SaveFile);  
  List.Free;  
end;  

А вот и кнопочка пригодилась :-)


procedure TForm1.Button2Click(Sender: TObject);  
begin  
  if SaveDialog1.Execute then  
  begin  
    if ExtractFileExt(SaveDialog1.FileName) = '.m3u' then  
      SaveList(SaveDialog1.FileName) else SaveList(SaveDialog1.FileName + '.m3u');  
  end;  
end;  

The End.
Теги:
M3U
Добавлено: 07 Августа 2018 21:29:11 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...