finalized the support for loading .cue based media using 'files' tab or drag and drop from the system's file browser
use FILE's PERFORMER as albumartist
This commit is contained in:
parent
34d496aadc
commit
59378166b4
|
@ -20,6 +20,7 @@
|
|||
#include "library/librarybackend.h"
|
||||
#include "library/sqlrow.h"
|
||||
#include "playlistparsers/parserbase.h"
|
||||
#include "playlistparsers/cueparser.h"
|
||||
#include "playlistparsers/playlistparser.h"
|
||||
#include "radio/fixlastfm.h"
|
||||
|
||||
|
@ -39,6 +40,7 @@ SongLoader::SongLoader(LibraryBackendInterface* library, QObject *parent)
|
|||
: QObject(parent),
|
||||
timeout_timer_(new QTimer(this)),
|
||||
playlist_parser_(new PlaylistParser(library, this)),
|
||||
cue_parser_(new CueParser(library, this)),
|
||||
timeout_(kDefaultTimeout),
|
||||
state_(WaitingForType),
|
||||
success_(false),
|
||||
|
@ -130,17 +132,46 @@ SongLoader::Result SongLoader::LoadLocal(const QString& filename, bool block,
|
|||
|
||||
// Not a playlist, so just assume it's a song
|
||||
QFileInfo info(filename);
|
||||
|
||||
LibraryQuery query;
|
||||
query.SetColumnSpec("%songs_table.ROWID, " + Song::kColumnSpec);
|
||||
query.AddWhere("filename", info.canonicalFilePath());
|
||||
Song song;
|
||||
|
||||
SongList song_list;
|
||||
|
||||
if (library_->ExecQuery(&query) && query.Next()) {
|
||||
song.InitFromQuery(query);
|
||||
// we may have many results when the file has many sections
|
||||
do {
|
||||
Song song;
|
||||
song.InitFromQuery(query);
|
||||
|
||||
song_list << song;
|
||||
} while(query.Next());
|
||||
} else {
|
||||
song.InitFromFile(filename, -1);
|
||||
QString matching_cue = filename.section('.', 0, -2) + ".cue";
|
||||
|
||||
// it's a cue - create virtual tracks
|
||||
if(QFile::exists(matching_cue)) {
|
||||
QFile cue(matching_cue);
|
||||
cue.open(QIODevice::ReadOnly);
|
||||
|
||||
song_list = cue_parser_->Load(&cue, QDir(filename.section('/', 0, -2)));
|
||||
|
||||
// it's a normal media file
|
||||
} else {
|
||||
Song song;
|
||||
song.InitFromFile(filename, -1);
|
||||
|
||||
song_list << song;
|
||||
|
||||
}
|
||||
}
|
||||
if (song.is_valid())
|
||||
songs_ << song;
|
||||
|
||||
foreach(const Song& song, song_list) {
|
||||
if (song.is_valid())
|
||||
songs_ << song;
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
|
||||
class CueParser;
|
||||
class LibraryBackendInterface;
|
||||
class ParserBase;
|
||||
class PlaylistParser;
|
||||
|
@ -97,6 +98,7 @@ private:
|
|||
|
||||
QTimer* timeout_timer_;
|
||||
PlaylistParser* playlist_parser_;
|
||||
CueParser* cue_parser_;
|
||||
|
||||
// For async loads
|
||||
int timeout_;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include <QTextStream>
|
||||
#include <QtDebug>
|
||||
|
||||
const char* CueParser::kFileLineRegExp = "([^ \t\r\n]+)\\s+(?:\"([^\"]+)\"|([^ \t\r\n]+))\\s*(?:\"([^\"]+)\"|([^ \t\r\n]+))?";
|
||||
const char* CueParser::kFileLineRegExp = "(\\S+)\\s+(?:\"([^\"]+)\"|(\\S+))\\s*(?:\"([^\"]+)\"|(\\S+))?";
|
||||
const char* CueParser::kIndexRegExp = "(\\d{2}):(\\d{2}):(\\d{2})";
|
||||
|
||||
const char* CueParser::kPerformer = "performer";
|
||||
|
@ -33,9 +33,6 @@ const char* CueParser::kTrack = "track";
|
|||
const char* CueParser::kIndex = "index";
|
||||
const char* CueParser::kAudioTrackType = "audio";
|
||||
|
||||
// TODO: if some song misses it's next one (because the next one was somehow
|
||||
// broken), we need to discard the song too (can't really determine where it
|
||||
// ends
|
||||
// TODO: utf and regexps (check on Zucchero - there's something wrong)
|
||||
|
||||
CueParser::CueParser(LibraryBackendInterface* library, QObject* parent)
|
||||
|
@ -228,6 +225,7 @@ bool CueParser::UpdateSong(const CueEntry& entry, const QString& next_index, Son
|
|||
|
||||
song->Init(entry.title, entry.PrettyArtist(),
|
||||
entry.album, beginning, end);
|
||||
song->set_albumartist(entry.album_artist);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -245,6 +243,7 @@ bool CueParser::UpdateLastSong(const CueEntry& entry, Song* song) const {
|
|||
song->set_title(entry.title);
|
||||
song->set_artist(entry.PrettyArtist());
|
||||
song->set_album(entry.album);
|
||||
song->set_albumartist(entry.album_artist);
|
||||
|
||||
// we don't do anything with the end here because it's already set to
|
||||
// the end of the media file (if it exists)
|
||||
|
|
|
@ -50,6 +50,7 @@ TEST_F(CueParserTest, ParsesASong) {
|
|||
Song first_song = song_list.at(0);
|
||||
ASSERT_EQ("Un soffio caldo", first_song.title());
|
||||
ASSERT_EQ("Zucchero", first_song.artist());
|
||||
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
||||
ASSERT_EQ("", first_song.album());
|
||||
ASSERT_EQ(1, first_song.beginning());
|
||||
}
|
||||
|
@ -68,6 +69,7 @@ TEST_F(CueParserTest, ParsesTwoSongs) {
|
|||
ASSERT_EQ("Un soffio caldo", first_song.title());
|
||||
ASSERT_EQ("Chocabeck", first_song.album());
|
||||
ASSERT_EQ("Zucchero himself", first_song.artist());
|
||||
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
||||
ASSERT_EQ(1, first_song.beginning());
|
||||
ASSERT_EQ((5 * 60 + 3) - 1, first_song.length());
|
||||
|
||||
|
@ -75,5 +77,34 @@ TEST_F(CueParserTest, ParsesTwoSongs) {
|
|||
ASSERT_EQ("Somewon Else's Tears", second_song.title());
|
||||
ASSERT_EQ("Chocabeck", second_song.album());
|
||||
ASSERT_EQ("Zucchero himself", second_song.artist());
|
||||
ASSERT_EQ("Zucchero himself", second_song.albumartist());
|
||||
ASSERT_EQ(5 * 60 + 3, second_song.beginning());
|
||||
}
|
||||
|
||||
TEST_F(CueParserTest, SkipsBrokenSongs) {
|
||||
QFile file(":testdata/brokensong.cue");
|
||||
file.open(QIODevice::ReadOnly);
|
||||
|
||||
SongList song_list = parser_.Load(&file, QDir(""));
|
||||
|
||||
// two songs (the broken one is not in the list)
|
||||
ASSERT_EQ(2, song_list.size());
|
||||
|
||||
// with the specified metadata
|
||||
Song first_song = song_list.at(0);
|
||||
ASSERT_EQ("Un soffio caldo", first_song.title());
|
||||
ASSERT_EQ("Chocabeck", first_song.album());
|
||||
ASSERT_EQ("Zucchero himself", first_song.artist());
|
||||
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
||||
ASSERT_EQ(1, first_song.beginning());
|
||||
// includes the broken song too; this entry will span from it's
|
||||
// INDEX (beginning) to the end of the next correct song
|
||||
ASSERT_EQ((5 * 60) - 1, first_song.length());
|
||||
|
||||
Song second_song = song_list.at(1);
|
||||
ASSERT_EQ("Somewon Else's Tears", second_song.title());
|
||||
ASSERT_EQ("Chocabeck", second_song.album());
|
||||
ASSERT_EQ("Zucchero himself", second_song.artist());
|
||||
ASSERT_EQ("Zucchero himself", second_song.albumartist());
|
||||
ASSERT_EQ(5 * 60, second_song.beginning());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
PERFORMER "Zucchero himself"
|
||||
TITLE "Chocabeck"
|
||||
FILE files/longer.mp3 WAVE
|
||||
TRACK 01 AUDIO
|
||||
TITLE "Un soffio caldo"
|
||||
INDEX 01 00:01:00
|
||||
TRACK 02 AUDIO
|
||||
TITLE "No index - broken"
|
||||
TRACK 02 AUDIO
|
||||
TITLE "Somewon Else's Tears"
|
||||
INDEX 01 05:00:00
|
|
@ -1,4 +1,4 @@
|
|||
PERFORMER "Zucchero"
|
||||
PERFORMER "Zucchero himself"
|
||||
FILE "file.mp3" WAVE
|
||||
TRACK 01 AUDIO
|
||||
TITLE "Un soffio caldo"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<file>beep.wav</file>
|
||||
<file>beep.wma</file>
|
||||
<file>beep.m4a</file>
|
||||
<file>brokensong.cue</file>
|
||||
<file>onesong.cue</file>
|
||||
<file>twosongs.cue</file>
|
||||
<file>pls_one.pls</file>
|
||||
|
|
Loading…
Reference in New Issue