- Fixed decoding of non-ASCII lyric texts

- Lyrics can now be viewed/edited in the metadata-editor

Squashed commit of the following:

commit 0851f619c27348e3ceeaf31a8edc3a567ccee99c
Author: Martin Babutzka <martin.babutzka@online.de>
Date:   Wed Jun 10 21:21:50 2015 +0200

    'make format' and brackets in a condition clause.

commit bab7a1d07af3bc53034e3883d352ae6d4dd33e2a
Author: Martin Babutzka <martin.babutzka@online.de>
Date:   Sun Jun 7 01:51:31 2015 +0200

    Added capability to SAVE lyrics frames to mp3 files in tagreader.
    Improved scaling properties of edittags dialog.

commit 4bd71a2d6a4479a664bf8b5b3ead05c23c86e15d
Author: Martin Babutzka <martin.babutzka@online.de>
Date:   Sat Jun 6 23:33:22 2015 +0200

    Updated lyrics tag buddy to lyrics

commit 2ceb8967f67e76a0f78b25a7a128c4429a93bcd9
Author: Martin Babutzka <martin.babutzka@online.de>
Date:   Sun May 17 18:52:33 2015 +0200

    Add lyrics field to tag editor

commit 04b65e33a83e449055659a72a283954311a12fb7
Author: Martin Babutzka <martin.babutzka@online.de>
Date:   Fri May 8 23:24:02 2015 +0200

    Using decode method to fix non-ASCII letters.
This commit is contained in:
Martin Babutzka 2015-06-10 21:23:40 +02:00
parent 88bce5115f
commit 0b16dad50f
5 changed files with 381 additions and 289 deletions

View File

@ -48,6 +48,7 @@
#include <textidentificationframe.h> #include <textidentificationframe.h>
#include <trueaudiofile.h> #include <trueaudiofile.h>
#include <tstring.h> #include <tstring.h>
#include <unsynchronizedlyricsframe.h>
#include <vorbisfile.h> #include <vorbisfile.h>
#include <wavfile.h> #include <wavfile.h>
@ -190,10 +191,12 @@ void TagReader::ReadFile(const QString& filename,
TStringToQString(map["TCMP"].front()->toString()).trimmed(); TStringToQString(map["TCMP"].front()->toString()).trimmed();
if (!map["USLT"].isEmpty()) { if (!map["USLT"].isEmpty()) {
lyrics = TStringToQString((map["USLT"].front())->toString()).trimmed(); Decode(map["USLT"].front()->toString(), nullptr,
qLog(Debug) << "Read ULST lyrics " << lyrics; song->mutable_lyrics());
} else if (!map["SYLT"].isEmpty()) } else if (!map["SYLT"].isEmpty()) {
lyrics = TStringToQString((map["SYLT"].front())->toString()).trimmed(); Decode(map["SYLT"].front()->toString(), nullptr,
song->mutable_lyrics());
}
if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover); if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover);
@ -628,7 +631,7 @@ bool TagReader::SaveFile(const QString& filename,
SetTextFrame("TCOM", song.composer(), tag); SetTextFrame("TCOM", song.composer(), tag);
SetTextFrame("TIT1", song.grouping(), tag); SetTextFrame("TIT1", song.grouping(), tag);
SetTextFrame("TOPE", song.performer(), tag); SetTextFrame("TOPE", song.performer(), tag);
SetTextFrame("USLT", song.lyrics(), tag); SetUnsyncLyricsFrame(song.lyrics(), tag);
// Skip TPE1 (which is the artist) here because we already set it // Skip TPE1 (which is the artist) here because we already set it
SetTextFrame("TPE2", song.albumartist(), tag); SetTextFrame("TPE2", song.albumartist(), tag);
SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag); SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag);
@ -857,6 +860,23 @@ void TagReader::SetTextFrame(const char* id, const std::string& value,
tag->addFrame(frame); tag->addFrame(frame);
} }
void TagReader::SetUnsyncLyricsFrame(const std::string& value,
TagLib::ID3v2::Tag* tag) const {
TagLib::ByteVector id_vector("USLT");
// Remove the frame if it already exists
while (tag->frameListMap().contains(id_vector) &&
tag->frameListMap()[id_vector].size() != 0) {
tag->removeFrame(tag->frameListMap()[id_vector].front());
}
// Create and add a new frame
TagLib::ID3v2::UnsynchronizedLyricsFrame* frame =
new TagLib::ID3v2::UnsynchronizedLyricsFrame(TagLib::String::UTF8);
frame->setText(StdStringToTaglibString(value));
tag->addFrame(frame);
}
bool TagReader::IsMediaFile(const QString& filename) const { bool TagReader::IsMediaFile(const QString& filename) const {
qLog(Debug) << "Checking for valid file" << filename; qLog(Debug) << "Checking for valid file" << filename;

View File

@ -87,12 +87,12 @@ class TagReader {
void SetFMPSStatisticsVorbisComments( void SetFMPSStatisticsVorbisComments(
TagLib::Ogg::XiphComment* vorbis_comments, TagLib::Ogg::XiphComment* vorbis_comments,
const pb::tagreader::SongMetadata& song) const; const pb::tagreader::SongMetadata& song) const;
void SetFMPSRatingVorbisComments(TagLib::Ogg::XiphComment* vorbis_comments, void SetFMPSRatingVorbisComments(
const pb::tagreader::SongMetadata& song) TagLib::Ogg::XiphComment* vorbis_comments,
const; const pb::tagreader::SongMetadata& song) const;
pb::tagreader::SongMetadata_Type GuessFileType(TagLib::FileRef* fileref) pb::tagreader::SongMetadata_Type GuessFileType(
const; TagLib::FileRef* fileref) const;
void SetUserTextFrame(const QString& description, const QString& value, void SetUserTextFrame(const QString& description, const QString& value,
TagLib::ID3v2::Tag* tag) const; TagLib::ID3v2::Tag* tag) const;
@ -104,6 +104,8 @@ class TagReader {
TagLib::ID3v2::Tag* tag) const; TagLib::ID3v2::Tag* tag) const;
void SetTextFrame(const char* id, const std::string& value, void SetTextFrame(const char* id, const std::string& value,
TagLib::ID3v2::Tag* tag) const; TagLib::ID3v2::Tag* tag) const;
void SetUnsyncLyricsFrame(const std::string& value,
TagLib::ID3v2::Tag* tag) const;
private: private:
static const char* kMP4_FMPS_Rating_ID; static const char* kMP4_FMPS_Rating_ID;

View File

@ -304,6 +304,7 @@ QVariant EditTagDialog::Data::value(const Song& song, const QString& id) {
if (id == "grouping") return song.grouping(); if (id == "grouping") return song.grouping();
if (id == "genre") return song.genre(); if (id == "genre") return song.genre();
if (id == "comment") return song.comment(); if (id == "comment") return song.comment();
if (id == "lyrics") return song.lyrics();
if (id == "track") return song.track(); if (id == "track") return song.track();
if (id == "disc") return song.disc(); if (id == "disc") return song.disc();
if (id == "year") return song.year(); if (id == "year") return song.year();
@ -330,6 +331,8 @@ void EditTagDialog::Data::set_value(const QString& id, const QVariant& value) {
current_.set_genre(value.toString()); current_.set_genre(value.toString());
else if (id == "comment") else if (id == "comment")
current_.set_comment(value.toString()); current_.set_comment(value.toString());
else if (id == "lyrics")
current_.set_lyrics(value.toString());
else if (id == "track") else if (id == "track")
current_.set_track(value.toInt()); current_.set_track(value.toInt());
else if (id == "disc") else if (id == "disc")

View File

@ -30,7 +30,7 @@
</widget> </widget>
<widget class="QTabWidget" name="tab_widget"> <widget class="QTabWidget" name="tab_widget">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="summary_tab"> <widget class="QWidget" name="summary_tab">
<attribute name="title"> <attribute name="title">
@ -605,284 +605,350 @@
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tags_tab"> <widget class="QWidget" name="tags_tab">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>528</width>
<height>514</height>
</size>
</property>
<attribute name="title"> <attribute name="title">
<string>Edit tags</string> <string>Edit tags</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="title_label"> <layout class="QVBoxLayout" name="verticalLayout_4">
<property name="text"> <item>
<string>Title</string> <layout class="QGridLayout" name="gridLayout">
</property> <item row="0" column="0">
<property name="buddy"> <widget class="QLabel" name="title_label">
<cstring>title</cstring> <property name="text">
</property> <string>Title</string>
</widget> </property>
</item> <property name="buddy">
<item row="0" column="1"> <cstring>title</cstring>
<widget class="LineEdit" name="title"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="0" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="title">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="0" column="2"> <bool>false</bool>
<widget class="QLabel" name="track_label"> </property>
<property name="text"> </widget>
<string>Track</string> </item>
</property> <item row="0" column="2">
<property name="buddy"> <widget class="QLabel" name="track_label">
<cstring>track</cstring> <property name="text">
</property> <string>Track</string>
</widget> </property>
</item> <property name="buddy">
<item row="0" column="3"> <cstring>track</cstring>
<widget class="SpinBox" name="track"> </property>
<property name="correctionMode"> </widget>
<enum>QAbstractSpinBox::CorrectToNearestValue</enum> </item>
</property> <item row="0" column="3">
<property name="maximum"> <widget class="SpinBox" name="track">
<number>9999</number> <property name="correctionMode">
</property> <enum>QAbstractSpinBox::CorrectToNearestValue</enum>
<property name="has_clear_button" stdset="0"> </property>
<bool>false</bool> <property name="maximum">
</property> <number>9999</number>
<property name="has_reset_button" stdset="0"> </property>
<bool>true</bool> <property name="has_clear_button" stdset="0">
</property> <bool>false</bool>
</widget> </property>
</item> <property name="has_reset_button" stdset="0">
<item row="1" column="0"> <bool>true</bool>
<widget class="QLabel" name="artist_label"> </property>
<property name="text"> </widget>
<string>Artist</string> </item>
</property> <item row="1" column="0">
<property name="buddy"> <widget class="QLabel" name="artist_label">
<cstring>artist</cstring> <property name="text">
</property> <string>Artist</string>
</widget> </property>
</item> <property name="buddy">
<item row="1" column="1"> <cstring>artist</cstring>
<widget class="LineEdit" name="artist"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="1" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="artist">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="1" column="2"> <bool>false</bool>
<widget class="QLabel" name="disc_label"> </property>
<property name="text"> </widget>
<string>Disc</string> </item>
</property> <item row="1" column="2">
<property name="buddy"> <widget class="QLabel" name="disc_label">
<cstring>disc</cstring> <property name="text">
</property> <string>Disc</string>
</widget> </property>
</item> <property name="buddy">
<item row="1" column="3"> <cstring>disc</cstring>
<widget class="SpinBox" name="disc"> </property>
<property name="correctionMode"> </widget>
<enum>QAbstractSpinBox::CorrectToNearestValue</enum> </item>
</property> <item row="1" column="3">
<property name="maximum"> <widget class="SpinBox" name="disc">
<number>9999</number> <property name="correctionMode">
</property> <enum>QAbstractSpinBox::CorrectToNearestValue</enum>
<property name="has_clear_button" stdset="0"> </property>
<bool>false</bool> <property name="maximum">
</property> <number>9999</number>
<property name="has_reset_button" stdset="0"> </property>
<bool>true</bool> <property name="has_clear_button" stdset="0">
</property> <bool>false</bool>
</widget> </property>
</item> <property name="has_reset_button" stdset="0">
<item row="2" column="0"> <bool>true</bool>
<widget class="QLabel" name="album_label"> </property>
<property name="text"> </widget>
<string>Album</string> </item>
</property> <item row="2" column="0">
<property name="buddy"> <widget class="QLabel" name="album_label">
<cstring>album</cstring> <property name="text">
</property> <string>Album</string>
</widget> </property>
</item> <property name="buddy">
<item row="2" column="1"> <cstring>album</cstring>
<widget class="LineEdit" name="album"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="2" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="album">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="2" column="2"> <bool>false</bool>
<widget class="QLabel" name="year_label"> </property>
<property name="text"> </widget>
<string>Year</string> </item>
</property> <item row="2" column="2">
<property name="buddy"> <widget class="QLabel" name="year_label">
<cstring>year</cstring> <property name="text">
</property> <string>Year</string>
</widget> </property>
</item> <property name="buddy">
<item row="2" column="3"> <cstring>year</cstring>
<widget class="SpinBox" name="year"> </property>
<property name="correctionMode"> </widget>
<enum>QAbstractSpinBox::CorrectToNearestValue</enum> </item>
</property> <item row="2" column="3">
<property name="maximum"> <widget class="SpinBox" name="year">
<number>9999</number> <property name="correctionMode">
</property> <enum>QAbstractSpinBox::CorrectToNearestValue</enum>
<property name="has_clear_button" stdset="0"> </property>
<bool>false</bool> <property name="maximum">
</property> <number>9999</number>
<property name="has_reset_button" stdset="0"> </property>
<bool>true</bool> <property name="has_clear_button" stdset="0">
</property> <bool>false</bool>
</widget> </property>
</item> <property name="has_reset_button" stdset="0">
<item row="3" column="0"> <bool>true</bool>
<widget class="QLabel" name="albumartist_label"> </property>
<property name="text"> </widget>
<string>Album artist</string> </item>
</property> <item row="3" column="0">
<property name="buddy"> <widget class="QLabel" name="albumartist_label">
<cstring>albumartist</cstring> <property name="text">
</property> <string>Album artist</string>
</widget> </property>
</item> <property name="buddy">
<item row="3" column="1"> <cstring>albumartist</cstring>
<widget class="LineEdit" name="albumartist"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="3" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="albumartist">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="4" column="0"> <bool>false</bool>
<widget class="QLabel" name="composer_label"> </property>
<property name="text"> </widget>
<string>Composer</string> </item>
</property> <item row="4" column="0">
<property name="buddy"> <widget class="QLabel" name="composer_label">
<cstring>composer</cstring> <property name="text">
</property> <string>Composer</string>
</widget> </property>
</item> <property name="buddy">
<item row="4" column="1"> <cstring>composer</cstring>
<widget class="LineEdit" name="composer"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="4" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="composer">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="5" column="0"> <bool>false</bool>
<widget class="QLabel" name="performer_label"> </property>
<property name="text"> </widget>
<string>Performer</string> </item>
</property> <item row="5" column="0">
<property name="buddy"> <widget class="QLabel" name="performer_label">
<cstring>performer</cstring> <property name="text">
</property> <string>Performer</string>
</widget> </property>
</item> <property name="buddy">
<item row="5" column="1"> <cstring>performer</cstring>
<widget class="LineEdit" name="performer"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="5" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="performer">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="6" column="0"> <bool>false</bool>
<widget class="QLabel" name="grouping_label"> </property>
<property name="text"> </widget>
<string>Grouping</string> </item>
</property> <item row="6" column="0">
<property name="buddy"> <widget class="QLabel" name="grouping_label">
<cstring>grouping</cstring> <property name="text">
</property> <string>Grouping</string>
</widget> </property>
</item> <property name="buddy">
<item row="6" column="1"> <cstring>grouping</cstring>
<widget class="LineEdit" name="grouping"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="6" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="grouping">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="7" column="0"> <bool>false</bool>
<widget class="QLabel" name="genre_label"> </property>
<property name="text"> </widget>
<string>Genre</string> </item>
</property> <item row="7" column="0">
<property name="buddy"> <widget class="QLabel" name="genre_label">
<cstring>genre</cstring> <property name="text">
</property> <string>Genre</string>
</widget> </property>
</item> <property name="buddy">
<item row="7" column="1"> <cstring>genre</cstring>
<widget class="LineEdit" name="genre"> </property>
<property name="has_reset_button" stdset="0"> </widget>
<bool>true</bool> </item>
</property> <item row="7" column="1">
<property name="has_clear_button" stdset="0"> <widget class="LineEdit" name="genre">
<bool>false</bool> <property name="has_reset_button" stdset="0">
</property> <bool>true</bool>
</widget> </property>
</item> <property name="has_clear_button" stdset="0">
<item row="9" column="1"> <bool>false</bool>
<widget class="QPushButton" name="fetch_tag"> </property>
<property name="text"> </widget>
<string>Complete tags automatically</string> </item>
</property> <item row="8" column="1">
<property name="icon"> <widget class="QPushButton" name="fetch_tag">
<iconset resource="../../data/data.qrc"> <property name="text">
<normaloff>:/providers/musicbrainz.png</normaloff>:/providers/musicbrainz.png</iconset> <string>Complete tags automatically</string>
</property> </property>
<property name="iconSize"> <property name="icon">
<size> <iconset resource="../../data/data.qrc">
<width>38</width> <normaloff>:/providers/musicbrainz.png</normaloff>:/providers/musicbrainz.png</iconset>
<height>22</height> </property>
</size> <property name="iconSize">
</property> <size>
</widget> <width>38</width>
</item> <height>22</height>
<item row="11" column="0"> </size>
<widget class="QLabel" name="comment_label"> </property>
<property name="text"> </widget>
<string>Comment</string> </item>
</property> </layout>
<property name="buddy"> </item>
<cstring>comment</cstring> <item>
</property> <layout class="QHBoxLayout" name="horizontalLayout_3">
</widget> <item>
</item> <widget class="QLabel" name="lyrics_label">
<item row="11" column="1" colspan="3"> <property name="sizePolicy">
<widget class="TextEdit" name="comment"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<property name="has_reset_button" stdset="0"> <horstretch>0</horstretch>
<bool>true</bool> <verstretch>0</verstretch>
</property> </sizepolicy>
<property name="has_clear_button" stdset="0"> </property>
<bool>false</bool> <property name="minimumSize">
</property> <size>
</widget> <width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Lyrics</string>
</property>
<property name="buddy">
<cstring>lyrics</cstring>
</property>
</widget>
</item>
<item>
<widget class="TextEdit" name="lyrics">
<property name="has_reset_button" stdset="0">
<bool>true</bool>
</property>
<property name="has_clear_button" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="comment_label">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Comment</string>
</property>
<property name="buddy">
<cstring>comment</cstring>
</property>
</widget>
</item>
<item>
<widget class="TextEdit" name="comment">
<property name="has_reset_button" stdset="0">
<bool>true</bool>
</property>
<property name="has_clear_button" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -890,7 +956,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="BusyIndicator" name="loading_label"/> <widget class="BusyIndicator" name="loading_label" native="true"/>
</item> </item>
<item> <item>
<widget class="QDialogButtonBox" name="button_box"> <widget class="QDialogButtonBox" name="button_box">

View File

@ -99,8 +99,8 @@ NowPlayingWidget::NowPlayingWidget(QWidget* parent)
CreateModeAction(LargeSongDetailsBelow, CreateModeAction(LargeSongDetailsBelow,
tr("Large album cover (details below)"), mode_group, tr("Large album cover (details below)"), mode_group,
mode_mapper); mode_mapper);
CreateModeAction(LargeNoSongDetails, tr("Large album cover (no details)"), mode_group, CreateModeAction(LargeNoSongDetails, tr("Large album cover (no details)"),
mode_mapper); mode_group, mode_mapper);
menu_->addActions(mode_group->actions()); menu_->addActions(mode_group->actions());
@ -528,7 +528,8 @@ void NowPlayingWidget::SetMode(int mode) {
void NowPlayingWidget::resizeEvent(QResizeEvent* e) { void NowPlayingWidget::resizeEvent(QResizeEvent* e) {
if (visible_ && e->oldSize() != e->size()) { if (visible_ && e->oldSize() != e->size()) {
if (mode_ == LargeSongDetails || mode_ == LargeNoSongDetails || mode_ == LargeSongDetailsBelow) { if (mode_ == LargeSongDetails || mode_ == LargeNoSongDetails ||
mode_ == LargeSongDetailsBelow) {
UpdateHeight(); UpdateHeight();
UpdateDetailsText(); UpdateDetailsText();
} }