better .cue spec conformity (allow many files in one sheet, use the SONGWRITER field as song's composer, ignore data files)
This commit is contained in:
parent
bb79a68be0
commit
d4d7f19fab
|
@ -29,6 +29,7 @@ const char* CueParser::kIndexRegExp = "(\\d{2}):(\\d{2}):(\\d{2})";
|
||||||
|
|
||||||
const char* CueParser::kPerformer = "performer";
|
const char* CueParser::kPerformer = "performer";
|
||||||
const char* CueParser::kTitle = "title";
|
const char* CueParser::kTitle = "title";
|
||||||
|
const char* CueParser::kSongWriter = "songwriter";
|
||||||
const char* CueParser::kFile = "file";
|
const char* CueParser::kFile = "file";
|
||||||
const char* CueParser::kTrack = "track";
|
const char* CueParser::kTrack = "track";
|
||||||
const char* CueParser::kIndex = "index";
|
const char* CueParser::kIndex = "index";
|
||||||
|
@ -46,123 +47,155 @@ SongList CueParser::Load(QIODevice* device, const QDir& dir) const {
|
||||||
text_stream.setCodec(QTextCodec::codecForUtfText(device->peek(1024), QTextCodec::codecForName("UTF-8")));
|
text_stream.setCodec(QTextCodec::codecForUtfText(device->peek(1024), QTextCodec::codecForName("UTF-8")));
|
||||||
|
|
||||||
QString dir_path = dir.absolutePath();
|
QString dir_path = dir.absolutePath();
|
||||||
|
// read the first line already
|
||||||
QString line;
|
QString line = text_stream.readLine();
|
||||||
|
|
||||||
QString album_artist;
|
|
||||||
QString album;
|
|
||||||
QString file;
|
|
||||||
|
|
||||||
// header
|
|
||||||
while (!(line = text_stream.readLine()).isNull()) {
|
|
||||||
QStringList splitted = SplitCueLine(line);
|
|
||||||
|
|
||||||
// uninteresting or incorrect line
|
|
||||||
if(splitted.size() < 2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString line_name = splitted[0].toLower();
|
|
||||||
QString line_value = splitted[1];
|
|
||||||
|
|
||||||
// PERFORMER
|
|
||||||
if(line_name == kPerformer) {
|
|
||||||
|
|
||||||
album_artist = line_value;
|
|
||||||
|
|
||||||
// TITLE
|
|
||||||
} else if(line_name == kTitle) {
|
|
||||||
|
|
||||||
album = line_value;
|
|
||||||
|
|
||||||
// FILE
|
|
||||||
} else if(line_name == kFile) {
|
|
||||||
|
|
||||||
file = QDir::isAbsolutePath(line_value)
|
|
||||||
? line_value
|
|
||||||
: dir.absoluteFilePath(line_value);
|
|
||||||
|
|
||||||
// end of the header -> go into the track mode
|
|
||||||
} else if(line_name == kTrack) {
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// just ignore the rest of possible field types for now...
|
|
||||||
}
|
|
||||||
|
|
||||||
if(line.isNull()) {
|
|
||||||
qWarning() << "the .cue file from " << dir_path << " defines no tracks!";
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString track_type;
|
|
||||||
QString index;
|
|
||||||
QString artist;
|
|
||||||
QString title;
|
|
||||||
|
|
||||||
QList<CueEntry> entries;
|
QList<CueEntry> entries;
|
||||||
|
int files = 0;
|
||||||
|
|
||||||
// tracks
|
// -- whole file
|
||||||
do {
|
while (!text_stream.atEnd()) {
|
||||||
QStringList splitted = SplitCueLine(line);
|
|
||||||
|
|
||||||
// uninteresting or incorrect line
|
QString album_artist;
|
||||||
if(splitted.size() < 2) {
|
QString album;
|
||||||
continue;
|
QString album_composer;
|
||||||
|
QString file;
|
||||||
|
QString file_type;
|
||||||
|
|
||||||
|
// -- FILE section
|
||||||
|
do {
|
||||||
|
QStringList splitted = SplitCueLine(line);
|
||||||
|
|
||||||
|
// uninteresting or incorrect line
|
||||||
|
if(splitted.size() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString line_name = splitted[0].toLower();
|
||||||
|
QString line_value = splitted[1];
|
||||||
|
|
||||||
|
// PERFORMER
|
||||||
|
if(line_name == kPerformer) {
|
||||||
|
|
||||||
|
album_artist = line_value;
|
||||||
|
|
||||||
|
// TITLE
|
||||||
|
} else if(line_name == kTitle) {
|
||||||
|
|
||||||
|
album = line_value;
|
||||||
|
|
||||||
|
// SONGWRITER
|
||||||
|
} else if(line_name == kSongWriter) {
|
||||||
|
|
||||||
|
album_composer = line_value;
|
||||||
|
|
||||||
|
// FILE
|
||||||
|
} else if(line_name == kFile) {
|
||||||
|
|
||||||
|
file = QDir::isAbsolutePath(line_value)
|
||||||
|
? line_value
|
||||||
|
: dir.absoluteFilePath(line_value);
|
||||||
|
|
||||||
|
if(splitted.size() > 2) {
|
||||||
|
file_type = splitted[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of the header -> go into the track mode
|
||||||
|
} else if(line_name == kTrack) {
|
||||||
|
|
||||||
|
files++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// just ignore the rest of possible field types for now...
|
||||||
|
} while(!(line = text_stream.readLine()).isNull());
|
||||||
|
|
||||||
|
if(line.isNull()) {
|
||||||
|
qWarning() << "the .cue file from " << dir_path << " defines no tracks!";
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString line_name = splitted[0].toLower();
|
// if this is a data file, all of it's tracks will be ignored
|
||||||
QString line_value = splitted[1];
|
bool valid_file = file_type.compare("BINARY", Qt::CaseInsensitive) &&
|
||||||
QString line_additional = splitted.size() > 2 ? splitted[2].toLower() : "";
|
file_type.compare("MOTOROLA", Qt::CaseInsensitive);
|
||||||
|
|
||||||
if(line_name == kTrack) {
|
QString track_type;
|
||||||
|
QString index;
|
||||||
|
QString artist;
|
||||||
|
QString composer;
|
||||||
|
QString title;
|
||||||
|
|
||||||
// the beginning of another track's definition - we're saving the current one
|
// TRACK section
|
||||||
// for later (if it's valid of course)
|
do {
|
||||||
if(!index.isEmpty() && (track_type.isEmpty() || track_type == kAudioTrackType)) {
|
QStringList splitted = SplitCueLine(line);
|
||||||
entries.append(CueEntry(file, index, title, artist, album_artist, album));
|
|
||||||
|
// uninteresting or incorrect line
|
||||||
|
if(splitted.size() < 2) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the state
|
QString line_name = splitted[0].toLower();
|
||||||
track_type = index = artist = title = "";
|
QString line_value = splitted[1];
|
||||||
|
QString line_additional = splitted.size() > 2 ? splitted[2].toLower() : "";
|
||||||
|
|
||||||
if(!line_additional.isEmpty()) {
|
if(line_name == kTrack) {
|
||||||
track_type = line_additional;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if(line_name == kIndex) {
|
// the beginning of another track's definition - we're saving the current one
|
||||||
|
// for later (if it's valid of course)
|
||||||
|
// please note that the same code is repeated just after this 'do-while' loop
|
||||||
|
if(valid_file && !index.isEmpty() && (track_type.isEmpty() || track_type == kAudioTrackType)) {
|
||||||
|
entries.append(CueEntry(file, index, title, artist, album_artist, album, composer, album_composer));
|
||||||
|
}
|
||||||
|
|
||||||
// we need the index's position field
|
// clear the state
|
||||||
if(!line_additional.isEmpty()) {
|
track_type = index = artist = title = "";
|
||||||
|
|
||||||
// if there's none "01" index, we'll just take the first one
|
if(!line_additional.isEmpty()) {
|
||||||
// also, we'll take the "01" index even if it's the last one
|
track_type = line_additional;
|
||||||
if(line_value == "01" || index.isEmpty()) {
|
}
|
||||||
|
|
||||||
index = line_additional;
|
} else if(line_name == kIndex) {
|
||||||
|
|
||||||
|
// we need the index's position field
|
||||||
|
if(!line_additional.isEmpty()) {
|
||||||
|
|
||||||
|
// if there's none "01" index, we'll just take the first one
|
||||||
|
// also, we'll take the "01" index even if it's the last one
|
||||||
|
if(line_value == "01" || index.isEmpty()) {
|
||||||
|
|
||||||
|
index = line_additional;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if(line_name == kPerformer) {
|
||||||
|
|
||||||
|
artist = line_value;
|
||||||
|
|
||||||
|
} else if(line_name == kTitle) {
|
||||||
|
|
||||||
|
title = line_value;
|
||||||
|
|
||||||
|
} else if(line_name == kSongWriter) {
|
||||||
|
|
||||||
|
composer = line_value;
|
||||||
|
|
||||||
|
// end of track's for the current file -> parse next one
|
||||||
|
} else if(line_name == kFile) {
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(line_name == kPerformer) {
|
// just ignore the rest of possible field types for now...
|
||||||
|
} while(!(line = text_stream.readLine()).isNull());
|
||||||
artist = line_value;
|
|
||||||
|
|
||||||
} else if(line_name == kTitle) {
|
|
||||||
|
|
||||||
title = line_value;
|
|
||||||
|
|
||||||
|
// we didn't add the last song yet...
|
||||||
|
if(valid_file && !index.isEmpty() && (track_type.isEmpty() || track_type == kAudioTrackType)) {
|
||||||
|
entries.append(CueEntry(file, index, title, artist, album_artist, album, composer, album_composer));
|
||||||
}
|
}
|
||||||
|
|
||||||
// just ignore the rest of possible field types for now...
|
|
||||||
} while(!(line = text_stream.readLine()).isNull());
|
|
||||||
|
|
||||||
// we didn't add the last song yet...
|
|
||||||
if(!index.isEmpty() && (track_type.isEmpty() || track_type == kAudioTrackType)) {
|
|
||||||
entries.append(CueEntry(file, index, title, artist, album_artist, album));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// finalize parsing songs
|
// finalize parsing songs
|
||||||
|
@ -181,7 +214,12 @@ SongList CueParser::Load(QIODevice* device, const QDir& dir) const {
|
||||||
|
|
||||||
// overwrite the stuff, we may have read from the file or library, using
|
// overwrite the stuff, we may have read from the file or library, using
|
||||||
// the current .cue metadata
|
// the current .cue metadata
|
||||||
song.set_track(i + 1);
|
|
||||||
|
// set track number only in single-file mode
|
||||||
|
if(files == 1) {
|
||||||
|
song.set_track(i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if(i + 1 < entries.size()) {
|
if(i + 1 < entries.size()) {
|
||||||
// incorrect indices?
|
// incorrect indices?
|
||||||
if(!UpdateSong(entry, entries.at(i + 1).index, &song)) {
|
if(!UpdateSong(entry, entries.at(i + 1).index, &song)) {
|
||||||
|
@ -227,6 +265,7 @@ bool CueParser::UpdateSong(const CueEntry& entry, const QString& next_index, Son
|
||||||
song->Init(entry.title, entry.PrettyArtist(),
|
song->Init(entry.title, entry.PrettyArtist(),
|
||||||
entry.album, beginning, end);
|
entry.album, beginning, end);
|
||||||
song->set_albumartist(entry.album_artist);
|
song->set_albumartist(entry.album_artist);
|
||||||
|
song->set_composer(entry.PrettyComposer());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -245,6 +284,7 @@ bool CueParser::UpdateLastSong(const CueEntry& entry, Song* song) const {
|
||||||
song->set_artist(entry.PrettyArtist());
|
song->set_artist(entry.PrettyArtist());
|
||||||
song->set_album(entry.album);
|
song->set_album(entry.album);
|
||||||
song->set_albumartist(entry.album_artist);
|
song->set_albumartist(entry.album_artist);
|
||||||
|
song->set_composer(entry.PrettyComposer());
|
||||||
|
|
||||||
// we don't do anything with the end here because it's already set to
|
// we don't do anything with the end here because it's already set to
|
||||||
// the end of the media file (if it exists)
|
// the end of the media file (if it exists)
|
||||||
|
|
|
@ -34,6 +34,7 @@ class CueParser : public ParserBase {
|
||||||
|
|
||||||
static const char* kPerformer;
|
static const char* kPerformer;
|
||||||
static const char* kTitle;
|
static const char* kTitle;
|
||||||
|
static const char* kSongWriter;
|
||||||
static const char* kFile;
|
static const char* kFile;
|
||||||
static const char* kTrack;
|
static const char* kTrack;
|
||||||
static const char* kIndex;
|
static const char* kIndex;
|
||||||
|
@ -62,16 +63,22 @@ class CueParser : public ParserBase {
|
||||||
QString album_artist;
|
QString album_artist;
|
||||||
QString album;
|
QString album;
|
||||||
|
|
||||||
|
QString composer;
|
||||||
|
QString album_composer;
|
||||||
|
|
||||||
QString PrettyArtist() const { return artist.isEmpty() ? album_artist : artist; }
|
QString PrettyArtist() const { return artist.isEmpty() ? album_artist : artist; }
|
||||||
|
QString PrettyComposer() const { return composer.isEmpty() ? album_composer : composer; }
|
||||||
|
|
||||||
CueEntry(QString& file, QString& index, QString& title, QString& artist,
|
CueEntry(QString& file, QString& index, QString& title, QString& artist,
|
||||||
QString& album_artist, QString& album) {
|
QString& album_artist, QString& album, QString& composer, QString& album_composer) {
|
||||||
this->file = file;
|
this->file = file;
|
||||||
this->index = index;
|
this->index = index;
|
||||||
this->title = title;
|
this->title = title;
|
||||||
this->artist = artist;
|
this->artist = artist;
|
||||||
this->album_artist = album_artist;
|
this->album_artist = album_artist;
|
||||||
this->album = album;
|
this->album = album;
|
||||||
|
this->composer = composer;
|
||||||
|
this->album_composer = album_composer;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ TEST_F(CueParserTest, ParsesASong) {
|
||||||
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
||||||
ASSERT_EQ("", first_song.album());
|
ASSERT_EQ("", first_song.album());
|
||||||
ASSERT_EQ(1, first_song.beginning());
|
ASSERT_EQ(1, first_song.beginning());
|
||||||
|
ASSERT_EQ(1, first_song.track());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CueParserTest, ParsesTwoSongs) {
|
TEST_F(CueParserTest, ParsesTwoSongs) {
|
||||||
|
@ -66,19 +67,22 @@ TEST_F(CueParserTest, ParsesTwoSongs) {
|
||||||
|
|
||||||
// with the specified metadata
|
// with the specified metadata
|
||||||
Song first_song = song_list.at(0);
|
Song first_song = song_list.at(0);
|
||||||
|
Song second_song = song_list.at(1);
|
||||||
|
|
||||||
ASSERT_EQ("Un soffio caldo", first_song.title());
|
ASSERT_EQ("Un soffio caldo", first_song.title());
|
||||||
ASSERT_EQ("Chocabeck", first_song.album());
|
ASSERT_EQ("Chocabeck", first_song.album());
|
||||||
ASSERT_EQ("Zucchero himself", first_song.artist());
|
ASSERT_EQ("Zucchero himself", first_song.artist());
|
||||||
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
||||||
ASSERT_EQ(1, first_song.beginning());
|
ASSERT_EQ(1, first_song.beginning());
|
||||||
ASSERT_EQ((5 * 60 + 3) - 1, first_song.length());
|
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
|
||||||
|
ASSERT_EQ(1, first_song.track());
|
||||||
|
|
||||||
Song second_song = song_list.at(1);
|
|
||||||
ASSERT_EQ("Somewon Else's Tears", second_song.title());
|
ASSERT_EQ("Somewon Else's Tears", second_song.title());
|
||||||
ASSERT_EQ("Chocabeck", second_song.album());
|
ASSERT_EQ("Chocabeck", second_song.album());
|
||||||
ASSERT_EQ("Zucchero himself", second_song.artist());
|
ASSERT_EQ("Zucchero himself", second_song.artist());
|
||||||
ASSERT_EQ("Zucchero himself", second_song.albumartist());
|
ASSERT_EQ("Zucchero himself", second_song.albumartist());
|
||||||
ASSERT_EQ(5 * 60 + 3, second_song.beginning());
|
ASSERT_EQ(5 * 60 + 3, second_song.beginning());
|
||||||
|
ASSERT_EQ(2, second_song.track());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CueParserTest, SkipsBrokenSongs) {
|
TEST_F(CueParserTest, SkipsBrokenSongs) {
|
||||||
|
@ -92,6 +96,8 @@ TEST_F(CueParserTest, SkipsBrokenSongs) {
|
||||||
|
|
||||||
// with the specified metadata
|
// with the specified metadata
|
||||||
Song first_song = song_list.at(0);
|
Song first_song = song_list.at(0);
|
||||||
|
Song second_song = song_list.at(1);
|
||||||
|
|
||||||
ASSERT_EQ("Un soffio caldo", first_song.title());
|
ASSERT_EQ("Un soffio caldo", first_song.title());
|
||||||
ASSERT_EQ("Chocabeck", first_song.album());
|
ASSERT_EQ("Chocabeck", first_song.album());
|
||||||
ASSERT_EQ("Zucchero himself", first_song.artist());
|
ASSERT_EQ("Zucchero himself", first_song.artist());
|
||||||
|
@ -99,12 +105,183 @@ TEST_F(CueParserTest, SkipsBrokenSongs) {
|
||||||
ASSERT_EQ(1, first_song.beginning());
|
ASSERT_EQ(1, first_song.beginning());
|
||||||
// includes the broken song too; this entry will span from it's
|
// includes the broken song too; this entry will span from it's
|
||||||
// INDEX (beginning) to the end of the next correct song
|
// INDEX (beginning) to the end of the next correct song
|
||||||
ASSERT_EQ((5 * 60) - 1, first_song.length());
|
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
|
||||||
|
ASSERT_EQ(1, first_song.track());
|
||||||
|
|
||||||
Song second_song = song_list.at(1);
|
|
||||||
ASSERT_EQ("Somewon Else's Tears", second_song.title());
|
ASSERT_EQ("Somewon Else's Tears", second_song.title());
|
||||||
ASSERT_EQ("Chocabeck", second_song.album());
|
ASSERT_EQ("Chocabeck", second_song.album());
|
||||||
ASSERT_EQ("Zucchero himself", second_song.artist());
|
ASSERT_EQ("Zucchero himself", second_song.artist());
|
||||||
ASSERT_EQ("Zucchero himself", second_song.albumartist());
|
ASSERT_EQ("Zucchero himself", second_song.albumartist());
|
||||||
ASSERT_EQ(5 * 60, second_song.beginning());
|
ASSERT_EQ(5 * 60, second_song.beginning());
|
||||||
|
ASSERT_EQ(2, second_song.track());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CueParserTest, UsesAllMetadataInformation) {
|
||||||
|
QFile file(":testdata/fullmetadata.cue");
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
SongList song_list = parser_.Load(&file, QDir(""));
|
||||||
|
|
||||||
|
// two songs
|
||||||
|
ASSERT_EQ(2, song_list.size());
|
||||||
|
|
||||||
|
// with the specified metadata
|
||||||
|
Song first_song = song_list.at(0);
|
||||||
|
Song second_song = song_list.at(1);
|
||||||
|
|
||||||
|
ASSERT_TRUE(first_song.filename().endsWith("a_file.mp3"));
|
||||||
|
ASSERT_EQ("Un soffio caldo", first_song.title());
|
||||||
|
ASSERT_EQ("Album", first_song.album());
|
||||||
|
ASSERT_EQ("Zucchero", first_song.artist());
|
||||||
|
ASSERT_EQ("Zucchero himself", first_song.albumartist());
|
||||||
|
ASSERT_EQ("Some guy", first_song.composer());
|
||||||
|
ASSERT_EQ(1, first_song.beginning());
|
||||||
|
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
|
||||||
|
ASSERT_EQ(1, first_song.track());
|
||||||
|
|
||||||
|
ASSERT_TRUE(second_song.filename().endsWith("a_file.mp3"));
|
||||||
|
ASSERT_EQ("Hey you!", second_song.title());
|
||||||
|
ASSERT_EQ("Album", second_song.album());
|
||||||
|
ASSERT_EQ("Zucchero himself", second_song.artist());
|
||||||
|
ASSERT_EQ("Zucchero himself", second_song.albumartist());
|
||||||
|
ASSERT_EQ("Some other guy", second_song.composer());
|
||||||
|
ASSERT_EQ(2, second_song.beginning());
|
||||||
|
ASSERT_EQ(2, second_song.track());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CueParserTest, AcceptsMultipleFileBasedCues) {
|
||||||
|
QFile file(":testdata/manyfiles.cue");
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
SongList song_list = parser_.Load(&file, QDir(""));
|
||||||
|
|
||||||
|
// five songs
|
||||||
|
ASSERT_EQ(5, song_list.size());
|
||||||
|
|
||||||
|
// with the specified metadata
|
||||||
|
Song first_song = song_list.at(0);
|
||||||
|
Song second_song = song_list.at(1);
|
||||||
|
Song third_song = song_list.at(2);
|
||||||
|
Song fourth_song = song_list.at(3);
|
||||||
|
Song fifth_song = song_list.at(4);
|
||||||
|
|
||||||
|
ASSERT_TRUE(first_song.filename().endsWith("files/longer_one.mp3"));
|
||||||
|
ASSERT_EQ("A1Song1", first_song.title());
|
||||||
|
ASSERT_EQ("Artist One Album", first_song.album());
|
||||||
|
ASSERT_EQ("Artist One", first_song.artist());
|
||||||
|
ASSERT_EQ("Artist One", first_song.albumartist());
|
||||||
|
ASSERT_EQ(1, first_song.beginning());
|
||||||
|
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
|
||||||
|
ASSERT_EQ(-1, first_song.track());
|
||||||
|
|
||||||
|
ASSERT_TRUE(second_song.filename().endsWith("files/longer_one.mp3"));
|
||||||
|
ASSERT_EQ("A1Song2", second_song.title());
|
||||||
|
ASSERT_EQ("Artist One Album", second_song.album());
|
||||||
|
ASSERT_EQ("Artist One", second_song.artist());
|
||||||
|
ASSERT_EQ("Artist One", second_song.albumartist());
|
||||||
|
ASSERT_EQ((5 * 60 + 3), second_song.beginning());
|
||||||
|
ASSERT_EQ(-1, second_song.track());
|
||||||
|
|
||||||
|
ASSERT_TRUE(third_song.filename().endsWith("files/longer_two_p1.mp3"));
|
||||||
|
ASSERT_EQ("A2P1Song1", third_song.title());
|
||||||
|
ASSERT_EQ("Artist Two Album", third_song.album());
|
||||||
|
ASSERT_EQ("Artist X", third_song.artist());
|
||||||
|
ASSERT_EQ("Artist Two", third_song.albumartist());
|
||||||
|
ASSERT_EQ(0, third_song.beginning());
|
||||||
|
ASSERT_EQ(fourth_song.beginning() - third_song.beginning(), third_song.length());
|
||||||
|
ASSERT_EQ(-1, third_song.track());
|
||||||
|
|
||||||
|
ASSERT_TRUE(fourth_song.filename().endsWith("files/longer_two_p1.mp3"));
|
||||||
|
ASSERT_EQ("A2P1Song2", fourth_song.title());
|
||||||
|
ASSERT_EQ("Artist Two Album", fourth_song.album());
|
||||||
|
ASSERT_EQ("Artist Two", fourth_song.artist());
|
||||||
|
ASSERT_EQ("Artist Two", fourth_song.albumartist());
|
||||||
|
ASSERT_EQ(4 * 60, fourth_song.beginning());
|
||||||
|
ASSERT_EQ(-1, fourth_song.track());
|
||||||
|
|
||||||
|
ASSERT_TRUE(fifth_song.filename().endsWith("files/longer_two_p2.mp3"));
|
||||||
|
ASSERT_EQ("A2P2Song1", fifth_song.title());
|
||||||
|
ASSERT_EQ("Artist Two Album", fifth_song.album());
|
||||||
|
ASSERT_EQ("Artist Two", fifth_song.artist());
|
||||||
|
ASSERT_EQ("Artist Two", fifth_song.albumartist());
|
||||||
|
ASSERT_EQ(1, fifth_song.beginning());
|
||||||
|
ASSERT_EQ(-1, fifth_song.track());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CueParserTest, SkipsBrokenSongsInMultipleFileBasedCues) {
|
||||||
|
QFile file(":testdata/manyfilesbroken.cue");
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
SongList song_list = parser_.Load(&file, QDir(""));
|
||||||
|
|
||||||
|
// four songs
|
||||||
|
ASSERT_EQ(4, song_list.size());
|
||||||
|
|
||||||
|
// with the specified metadata
|
||||||
|
Song first_song = song_list.at(0);
|
||||||
|
Song second_song = song_list.at(1);
|
||||||
|
Song third_song = song_list.at(2);
|
||||||
|
Song fourth_song = song_list.at(3);
|
||||||
|
|
||||||
|
// A* - broken song in the middle
|
||||||
|
ASSERT_TRUE(first_song.filename().endsWith("file1.mp3"));
|
||||||
|
ASSERT_EQ("Artist One", first_song.artist());
|
||||||
|
ASSERT_EQ("Artist One Album", first_song.album());
|
||||||
|
ASSERT_EQ("A1", first_song.title());
|
||||||
|
ASSERT_EQ(1, first_song.beginning());
|
||||||
|
ASSERT_EQ(second_song.beginning() - first_song.beginning(), first_song.length());
|
||||||
|
ASSERT_EQ(-1, first_song.track());
|
||||||
|
|
||||||
|
ASSERT_TRUE(second_song.filename().endsWith("file1.mp3"));
|
||||||
|
ASSERT_EQ("Artist One", second_song.artist());
|
||||||
|
ASSERT_EQ("Artist One Album", second_song.album());
|
||||||
|
ASSERT_EQ("A3", second_song.title());
|
||||||
|
ASSERT_EQ(60, second_song.beginning());
|
||||||
|
ASSERT_EQ(-1, second_song.track());
|
||||||
|
|
||||||
|
// all B* songs are broken
|
||||||
|
|
||||||
|
// C* - broken song at the end
|
||||||
|
ASSERT_TRUE(third_song.filename().endsWith("file3.mp3"));
|
||||||
|
ASSERT_EQ("Artist Three", third_song.artist());
|
||||||
|
ASSERT_EQ("Artist Three Album", third_song.album());
|
||||||
|
ASSERT_EQ("C1", third_song.title());
|
||||||
|
ASSERT_EQ(1, third_song.beginning());
|
||||||
|
ASSERT_EQ(-1, third_song.track());
|
||||||
|
|
||||||
|
// D* - broken song at the beginning
|
||||||
|
ASSERT_TRUE(fourth_song.filename().endsWith("file4.mp3"));
|
||||||
|
ASSERT_EQ("Artist Four", fourth_song.artist());
|
||||||
|
ASSERT_EQ("Artist Four Album", fourth_song.album());
|
||||||
|
ASSERT_EQ("D2", fourth_song.title());
|
||||||
|
ASSERT_EQ(61, fourth_song.beginning());
|
||||||
|
ASSERT_EQ(-1, fourth_song.track());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CueParserTest, SkipsDataFiles) {
|
||||||
|
QFile file(":testdata/withdatafiles.cue");
|
||||||
|
file.open(QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
SongList song_list = parser_.Load(&file, QDir(""));
|
||||||
|
|
||||||
|
// two songs
|
||||||
|
ASSERT_EQ(2, song_list.size());
|
||||||
|
|
||||||
|
// with the specified metadata
|
||||||
|
Song first_song = song_list.at(0);
|
||||||
|
Song second_song = song_list.at(1);
|
||||||
|
|
||||||
|
ASSERT_TRUE(first_song.filename().endsWith("file1.mp3"));
|
||||||
|
ASSERT_EQ("Artist One", first_song.artist());
|
||||||
|
ASSERT_EQ("Artist One Album", first_song.album());
|
||||||
|
ASSERT_EQ("A1", first_song.title());
|
||||||
|
ASSERT_EQ(1, first_song.beginning());
|
||||||
|
ASSERT_EQ(-1, first_song.track());
|
||||||
|
|
||||||
|
ASSERT_TRUE(second_song.filename().endsWith("file4.mp3"));
|
||||||
|
ASSERT_EQ("Artist Four", second_song.artist());
|
||||||
|
ASSERT_EQ("Artist Four Album", second_song.album());
|
||||||
|
ASSERT_EQ("D1", second_song.title());
|
||||||
|
ASSERT_EQ(61, second_song.beginning());
|
||||||
|
ASSERT_EQ(-1, second_song.track());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
FILE a_file.mp3 WAVE
|
||||||
|
SONGWRITER "Some guy"
|
||||||
|
TITLE "Album"
|
||||||
|
PERFORMER "Zucchero himself"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "Un soffio caldo"
|
||||||
|
PERFORMER Zucchero
|
||||||
|
INDEX 00 00:01:00
|
||||||
|
INDEX 01 00:01:00
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
TITLE "Hey you!"
|
||||||
|
SONGWRITER "Some other guy"
|
||||||
|
INDEX 05 00:02:00
|
|
@ -0,0 +1,25 @@
|
||||||
|
FILE files/longer_one.mp3 WAVE
|
||||||
|
PERFORMER "Artist One"
|
||||||
|
TITLE "Artist One Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "A1Song1"
|
||||||
|
INDEX 01 00:01:00
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
TITLE "A1Song2"
|
||||||
|
INDEX 01 05:03:68
|
||||||
|
FILE files/longer_two_p1.mp3 WAVE
|
||||||
|
PERFORMER "Artist Two"
|
||||||
|
TITLE "Artist Two Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "A2P1Song1"
|
||||||
|
PERFORMER "Artist X"
|
||||||
|
INDEX 01 00:00:00
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
TITLE "A2P1Song2"
|
||||||
|
INDEX 01 04:00:00
|
||||||
|
FILE files/longer_two_p2.mp3 WAVE
|
||||||
|
PERFORMER "Artist Two"
|
||||||
|
TITLE "Artist Two Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "A2P2Song1"
|
||||||
|
INDEX 01 00:01:00
|
|
@ -0,0 +1,33 @@
|
||||||
|
FILE file1.mp3 WAVE
|
||||||
|
PERFORMER "Artist One"
|
||||||
|
TITLE "Artist One Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "A1"
|
||||||
|
INDEX 01 00:01:00
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
TITLE "A2"
|
||||||
|
TRACK 03 AUDIO
|
||||||
|
TITLE "A3"
|
||||||
|
INDEX 01 01:00:00
|
||||||
|
FILE file2.mp3 WAVE
|
||||||
|
PERFORMER "Artist Two"
|
||||||
|
TITLE "Artist Two Album"
|
||||||
|
TRACK 01 CDG
|
||||||
|
TITLE "B1"
|
||||||
|
INDEX 00 00:01:00
|
||||||
|
FILE file3.mp3 WAVE
|
||||||
|
PERFORMER "Artist Three"
|
||||||
|
TITLE "Artist Three Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "C1"
|
||||||
|
INDEX 00 00:01:00
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
TITLE "C2"
|
||||||
|
FILE file4.mp3 WAVE
|
||||||
|
PERFORMER "Artist Four"
|
||||||
|
TITLE "Artist Four Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "D1"
|
||||||
|
TRACK 02 AUDIO
|
||||||
|
TITLE "D2"
|
||||||
|
INDEX 00 01:01:00
|
|
@ -8,21 +8,25 @@
|
||||||
<file>beep.wma</file>
|
<file>beep.wma</file>
|
||||||
<file>beep.m4a</file>
|
<file>beep.m4a</file>
|
||||||
<file>brokensong.cue</file>
|
<file>brokensong.cue</file>
|
||||||
<file>onesong.cue</file>
|
|
||||||
<file>twosongs.cue</file>
|
|
||||||
<file>pls_one.pls</file>
|
|
||||||
<file>pls_somafm.pls</file>
|
|
||||||
<file>test.m3u</file>
|
|
||||||
<file>test.xspf</file>
|
|
||||||
<file>test.asx</file>
|
|
||||||
<file>secretagent.asx</file>
|
|
||||||
<file>secretagent.pls</file>
|
|
||||||
<file>test.asxini</file>
|
|
||||||
<file>fmpsplaycount.mp3</file>
|
<file>fmpsplaycount.mp3</file>
|
||||||
<file>fmpsplaycountboth.mp3</file>
|
<file>fmpsplaycountboth.mp3</file>
|
||||||
<file>fmpsplaycountuser.mp3</file>
|
<file>fmpsplaycountuser.mp3</file>
|
||||||
<file>fmpsrating.mp3</file>
|
<file>fmpsrating.mp3</file>
|
||||||
<file>fmpsratingboth.mp3</file>
|
<file>fmpsratingboth.mp3</file>
|
||||||
<file>fmpsratinguser.mp3</file>
|
<file>fmpsratinguser.mp3</file>
|
||||||
|
<file>fullmetadata.cue</file>
|
||||||
|
<file>manyfiles.cue</file>
|
||||||
|
<file>manyfilesbroken.cue</file>
|
||||||
|
<file>onesong.cue</file>
|
||||||
|
<file>pls_one.pls</file>
|
||||||
|
<file>pls_somafm.pls</file>
|
||||||
|
<file>secretagent.asx</file>
|
||||||
|
<file>secretagent.pls</file>
|
||||||
|
<file>test.m3u</file>
|
||||||
|
<file>test.xspf</file>
|
||||||
|
<file>test.asx</file>
|
||||||
|
<file>test.asxini</file>
|
||||||
|
<file>twosongs.cue</file>
|
||||||
|
<file>withdatafiles.cue</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
FILE file1.mp3
|
||||||
|
PERFORMER "Artist One"
|
||||||
|
TITLE "Artist One Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "A1"
|
||||||
|
INDEX 01 00:01:00
|
||||||
|
|
||||||
|
FILE file2.mp3 BINARY
|
||||||
|
PERFORMER "Artist Two"
|
||||||
|
TITLE "Artist Two Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "B1"
|
||||||
|
INDEX 00 00:01:00
|
||||||
|
|
||||||
|
FILE file3.mp3 MOTOROLA
|
||||||
|
PERFORMER "Artist Three"
|
||||||
|
TITLE "Artist Three Album"
|
||||||
|
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "C1"
|
||||||
|
INDEX 00 00:01:00
|
||||||
|
|
||||||
|
FILE file4.mp3 MP3
|
||||||
|
PERFORMER "Artist Four"
|
||||||
|
TITLE "Artist Four Album"
|
||||||
|
TRACK 01 AUDIO
|
||||||
|
TITLE "D1"
|
||||||
|
INDEX 00 01:01:00
|
Loading…
Reference in New Issue