0 Members and 1 Guest are viewing this topic.
zldo, а код программы таки открыт или закрыт? Любопытно, как вы парсите музыку в папках. Вы вроде на делфи писали, не перебрались на что иное? Я тут на линуксе страдаю. exaile и некоторые другие умеют парсить папки и искать музыку, но вот cue и m3u не подхватывают. Я правда только то, что на питоне смотрел и ковырял.
Ну мало ли, может там другие плейлисты есть. К тому же, допустим в cue в плейлисте половина файла и т.о. у нас половина файла отражена в куе, а с остальной что делать?
Поддержка чтения и записи тегов большинства распространенных форматов файлов, расширенная поддержка cue списков, как внешних, так и «вшитых» в теги. Композиции из cue добавляются в базу данных в виде «виртуальных» файлов, таким образом работа программы с ними в дальнейшем ничем не отличается от работы с реальными файлами
Вон, какие-то вшитые куи, какие-то прям интересности, что их отдельно в описание вынесли
zldo, а код программы таки открыт или закрыт?
Ну, согласен, что ничего сложного, но прежде чем свой велик изобретать, есть же смысл в чужом харли-то поковыряться.
unit cueParser;interfaceuses Classes, Windows;type PCueItemData = ^TCueItemData; {*} TCueItemData = record {* Набор данных об элементах cue} Artist, // Исполнитель Title: string; // Название композиции Duration: double; // Продолжительность Index: integer; // Индекс элемента в списке cue end; TCueParser = class(TList) private FArtist: string; FCue: string; FAlbum: string; FSourceFileName: string; FData: string; FComment: string; FGenre: string; function GetItem(Index: integer): PCueItemData; procedure SetCue(const Value: string); procedure SetItem(Index: integer; const Value: PCueItemData); protected procedure Notify(Ptr: Pointer; Action: TListNotification); override; procedure ParseCue(const Acue: string); {* Парсинг cue. } public property SourceFileName: string read FSourceFileName; {* Имя файла к которому привязан cue список. } property Artist: string read FArtist; {* Общий для списка исполнитель (AlbumArtist)} property Album: string read FAlbum; {* Название альбома списка. } property Genre: string read FGenre; {* Жанр } property Comment: string read FComment; {* Комментарий } property Data: string read FData; {* Дата } property Cue: string read FCue write SetCue; {* Текст cue файла. } property Items[Index: integer]: PCueItemData read GetItem write SetItem; default; {* Содержимое списка cue. } function LoadFromFile(const FileName: string): boolean; {* Загрузает файл cue. } procedure Clear; override; {* Очистка. } end;implementationuses SysUtils;{ TCueParser }procedure TCueParser.Clear;begin inherited; FArtist := ''; FCue := ''; FAlbum := ''; FSourceFileName := ''; FData := ''; FComment := ''; FGenre := '';end;function TCueParser.GetItem(Index: integer): PCueItemData;begin result := PCueItemData(inherited Items[Index]);end;function TCueParser.LoadFromFile(const FileName: string): boolean;var l: TStringList;begin l := TStringList.Create; Result := true; try l.LoadFromFile(FileName); except Result := false; exit; end; ParseCue(l.Text); l.Free;end;procedure TCueParser.Notify(Ptr: Pointer; Action: TListNotification);begin case Action of lnDeleted: with PCueItemData(Ptr)^ do begin Artist := ''; Title := ''; dispose(PCueItemData(Ptr)); end; end;end;procedure TCueParser.ParseCue(const Acue: string);var l: TStringList; x: integer; CurItem, PrevItem: PCueItemData; CurTime: double; NewTime: double; CurIdx: integer; cur: string; kw: string; CheckTime: boolean; function CueStrToDuration(TimeStr: string): double; var dd: integer; m: double; s: string; begin result := 0; s := ''; TimeStr := TimeStr + '0'; m := 1; // 1000 милисекунд в секунде dd := length(TimeStr); while dd > 0 do begin case TimeStr[dd] of '0'..'9': s := TimeStr[dd] + s; ':', ' ': begin result := result + StrToIntDef(s, 0) * m; if m < 100 then m := 6000 else m := m * 60; s := ''; if TimeStr[dd] = ' ' then exit; end; else begin result := 0; exit; end; end; dec(dd); end; end; function CueKeyWord(const s: string): string; begin result := trim(Copy(s, 1, Pos(' ',s))); end; function CueValue(const s: string): string; var i: integer; begin i := Pos('"', s); result := Copy(s, i + 1, length(s) - i - 1); end;begin Clear; FCue := Acue; l := TStringList.Create; l.Text := FCue; CurItem := nil; PrevItem := nil; CurTime := 0; CurIdx := 1; CheckTime := true; for x := 0 to l.Count - 1 do begin cur := Trim(l[x]); if pos('REM GENRE ', AnsiUpperCase(cur)) = 1 then FGenre := Trim(Copy(cur, length('REM GENRE ') + 1, length(cur))); if pos('REM DATE ', AnsiUpperCase(cur)) = 1 then FData := Trim(Copy(cur, length('REM DATE ') + 1, length(cur))); if pos('REM COMMENT ', AnsiUpperCase(cur)) = 1 then FComment := Trim(Copy(cur, length('REM COMMENT ') + 1, length(cur))); kw := AnsiUpperCase(CueKeyWord(cur)); if kw = 'TITLE' then if Assigned(CurItem) then CurItem.Title := CueValue(cur) else FAlbum := CueValue(cur); if kw = 'PERFORMER' then if Assigned(CurItem) then CurItem.Artist := CueValue(cur) else FArtist := CueValue(cur); if kw = 'FILE' then FSourceFileName := Copy(CueValue(cur), 1, LastDelimiter('"', CueValue(cur)) - 1); if kw = 'TRACK' then begin if Assigned(CurItem) then Add(CurItem); PrevItem := CurItem; new(CurItem); CurItem.Index := StrToIntDef(copy(cur, length(kw), 2), CurIdx); CurItem.Artist := FArtist; inc(CurIdx); CheckTime := true; end; if kw = 'INDEX' then if Assigned(PrevItem) and CheckTime then begin NewTime := (CueStrToDuration(cur) / 100) / 60; PrevItem.Duration := NewTime - CurTime; CurTime := NewTime; CheckTime := false; end; end; if Assigned(CurItem) then begin Add(CurItem); CurItem.Duration := CurTime; end;end;procedure TCueParser.SetCue(const Value: string);begin ParseCue(Value);end;procedure TCueParser.SetItem(Index: integer; const Value: PCueItemData);begin with Items[Index]^ do begin Artist := Value.Artist; Title := Value.Title; Duration := Value.Duration; Index := Value.Index; end;end;end.
Всю сознательную жизнь использовал FOOBAR, предварительно отсмотрев и отслушав разные плееры.Во-вторых, для моего ЦАПа есть поддержка только в FOOBARе.