/* * Copyright (C) 2005-2018 Team Kodi * This file is part of Kodi - https://kodi.tv * * SPDX-License-Identifier: GPL-2.0-or-later * See LICENSES/README.md for more information. */ #include "MusicInfoTag.h" #include "ServiceBroker.h" #include "guilib/LocalizeStrings.h" #include "music/Artist.h" #include "settings/AdvancedSettings.h" #include "settings/Settings.h" #include "settings/SettingsComponent.h" #include "utils/Archive.h" #include "utils/StringUtils.h" #include "utils/Variant.h" #include using namespace MUSIC_INFO; CMusicInfoTag::CMusicInfoTag(void) { Clear(); } bool CMusicInfoTag::operator !=(const CMusicInfoTag& tag) const { if (this == &tag) return false; if (m_strURL != tag.m_strURL) return true; if (m_strTitle != tag.m_strTitle) return true; if (m_bCompilation != tag.m_bCompilation) return true; if (m_artist != tag.m_artist) return true; if (m_albumArtist != tag.m_albumArtist) return true; if (m_strAlbum != tag.m_strAlbum) return true; if (m_iDuration != tag.m_iDuration) return true; if (m_strDiscSubtitle != tag.m_strDiscSubtitle) return true; if (m_iTrack != tag.m_iTrack) return true; if (m_albumReleaseType != tag.m_albumReleaseType) return true; return false; } int CMusicInfoTag::GetTrackNumber() const { return (m_iTrack & 0xffff); } int CMusicInfoTag::GetDiscNumber() const { return (m_iTrack >> 16); } int CMusicInfoTag::GetTrackAndDiscNumber() const { return m_iTrack; } int CMusicInfoTag::GetDuration() const { return m_iDuration; } const std::string& CMusicInfoTag::GetTitle() const { return m_strTitle; } const std::string& CMusicInfoTag::GetURL() const { return m_strURL; } const std::vector& CMusicInfoTag::GetArtist() const { return m_artist; } const std::string CMusicInfoTag::GetArtistString() const { if (!m_strArtistDesc.empty()) return m_strArtistDesc; else if (!m_artist.empty()) return StringUtils::Join(m_artist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator); else return StringUtils::Empty; } const std::string& CMusicInfoTag::GetArtistSort() const { return m_strArtistSort; } const std::string& CMusicInfoTag::GetComposerSort() const { return m_strComposerSort; } const std::string& CMusicInfoTag::GetAlbum() const { return m_strAlbum; } const std::string& CMusicInfoTag::GetDiscSubtitle() const { return m_strDiscSubtitle; } const std::string& CMusicInfoTag::GetOriginalDate() const { return m_strOriginalDate; } const std::string MUSIC_INFO::CMusicInfoTag::GetOriginalYear() const { return StringUtils::Left(m_strOriginalDate, 4); } int CMusicInfoTag::GetAlbumId() const { return m_iAlbumId; } const std::vector& CMusicInfoTag::GetAlbumArtist() const { return m_albumArtist; } const std::string CMusicInfoTag::GetAlbumArtistString() const { if (!m_strAlbumArtistDesc.empty()) return m_strAlbumArtistDesc; if (!m_albumArtist.empty()) return StringUtils::Join(m_albumArtist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator); else return StringUtils::Empty; } const std::string& CMusicInfoTag::GetAlbumArtistSort() const { return m_strAlbumArtistSort; } const std::vector& CMusicInfoTag::GetGenre() const { return m_genre; } int CMusicInfoTag::GetDatabaseId() const { return m_iDbId; } const std::string &CMusicInfoTag::GetType() const { return m_type; } int CMusicInfoTag::GetYear() const { return atoi(GetYearString().c_str()); } std::string CMusicInfoTag::GetYearString() const { /* Get year as YYYY from release or original dates depending on setting This is how GUI and by year sorting swiches to using original year. For ripper and non-library items (libray entries have both values): when release date missing try to fallback to original date when original date missing use release date */ std::string value; value = GetReleaseYear(); if (CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( CSettings::SETTING_MUSICLIBRARY_USEORIGINALDATE) || value.empty()) { std::string origvalue = GetOriginalYear(); if (!origvalue.empty()) return origvalue; } return value; } const std::string &CMusicInfoTag::GetComment() const { return m_strComment; } const std::string &CMusicInfoTag::GetMood() const { return m_strMood; } const std::string &CMusicInfoTag::GetRecordLabel() const { return m_strRecordLabel; } const std::string &CMusicInfoTag::GetLyrics() const { return m_strLyrics; } const std::string &CMusicInfoTag::GetCueSheet() const { return m_cuesheet; } float CMusicInfoTag::GetRating() const { return m_Rating; } int CMusicInfoTag::GetUserrating() const { return m_Userrating; } int CMusicInfoTag::GetVotes() const { return m_Votes; } int CMusicInfoTag::GetListeners() const { return m_listeners; } int CMusicInfoTag::GetPlayCount() const { return m_iTimesPlayed; } const CDateTime &CMusicInfoTag::GetLastPlayed() const { return m_lastPlayed; } const CDateTime &CMusicInfoTag::GetDateAdded() const { return m_dateAdded; } bool CMusicInfoTag::GetCompilation() const { return m_bCompilation; } bool CMusicInfoTag::GetBoxset() const { return m_bBoxset; } int CMusicInfoTag::GetTotalDiscs() const { return m_iDiscTotal; } const EmbeddedArtInfo &CMusicInfoTag::GetCoverArtInfo() const { return m_coverArt; } const ReplayGain& CMusicInfoTag::GetReplayGain() const { return m_replayGain; } CAlbum::ReleaseType CMusicInfoTag::GetAlbumReleaseType() const { return m_albumReleaseType; } int CMusicInfoTag::GetBPM() const { return m_iBPM; } int CMusicInfoTag::GetBitRate() const { return m_bitrate; } int CMusicInfoTag::GetSampleRate() const { return m_samplerate; } int CMusicInfoTag::GetNoOfChannels() const { return m_channels; } const std::string& CMusicInfoTag::GetReleaseDate() const { return m_strReleaseDate; } const std::string MUSIC_INFO::CMusicInfoTag::GetReleaseYear() const { return StringUtils::Left(m_strReleaseDate, 4); } // This is the Musicbrainz release status tag. See https://musicbrainz.org/doc/Release#Status const std::string& CMusicInfoTag::GetAlbumReleaseStatus() const { return m_strReleaseStatus; } const std::string& CMusicInfoTag::GetStationName() const { return m_stationName; } const std::string& CMusicInfoTag::GetStationArt() const { return m_stationArt; } void CMusicInfoTag::SetURL(const std::string& strURL) { m_strURL = strURL; } void CMusicInfoTag::SetTitle(const std::string& strTitle) { m_strTitle = Trim(strTitle); } void CMusicInfoTag::SetArtist(const std::string& strArtist) { if (!strArtist.empty()) { SetArtistDesc(strArtist); SetArtist(StringUtils::Split(strArtist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator)); } else { m_strArtistDesc.clear(); m_artist.clear(); } } void CMusicInfoTag::SetArtist(const std::vector& artists, bool FillDesc /* = false*/) { m_artist = artists; if (m_strArtistDesc.empty() || FillDesc) { SetArtistDesc(StringUtils::Join(artists, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator)); } } void CMusicInfoTag::SetArtistDesc(const std::string& strArtistDesc) { m_strArtistDesc = strArtistDesc; } void CMusicInfoTag::SetArtistSort(const std::string& strArtistsort) { m_strArtistSort = strArtistsort; } void CMusicInfoTag::SetComposerSort(const std::string& strComposerSort) { m_strComposerSort = strComposerSort; } void CMusicInfoTag::SetAlbum(const std::string& strAlbum) { m_strAlbum = Trim(strAlbum); } void CMusicInfoTag::SetAlbumId(const int iAlbumId) { m_iAlbumId = iAlbumId; } void CMusicInfoTag::SetAlbumArtist(const std::string& strAlbumArtist) { if (!strAlbumArtist.empty()) { SetAlbumArtistDesc(strAlbumArtist); SetAlbumArtist(StringUtils::Split(strAlbumArtist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator)); } else { m_strAlbumArtistDesc.clear(); m_albumArtist.clear(); } } void CMusicInfoTag::SetAlbumArtist(const std::vector& albumArtists, bool FillDesc /* = false*/) { m_albumArtist = albumArtists; if (m_strAlbumArtistDesc.empty() || FillDesc) SetAlbumArtistDesc(StringUtils::Join(albumArtists, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator)); } void CMusicInfoTag::SetAlbumArtistDesc(const std::string& strAlbumArtistDesc) { m_strAlbumArtistDesc = strAlbumArtistDesc; } void CMusicInfoTag::SetAlbumArtistSort(const std::string& strAlbumArtistSort) { m_strAlbumArtistSort = strAlbumArtistSort; } void CMusicInfoTag::SetGenre(const std::string& strGenre, bool bTrim /* = false*/) { if (!strGenre.empty()) SetGenre(StringUtils::Split(strGenre, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator), bTrim); else m_genre.clear(); } void CMusicInfoTag::SetGenre(const std::vector& genres, bool bTrim /* = false*/) { m_genre = genres; if (bTrim) for (auto genre : m_genre) StringUtils::Trim(genre); } void CMusicInfoTag::SetYear(int year) { // Parse integer year value into YYYY ISO8601 format (partial) date string // Add century for to 2 digit numbers, 41 -> 1941, 40 -> 2040 if (year > 99) SetReleaseDate(StringUtils::Format("%04i", year)); else if (year > 40) SetReleaseDate(StringUtils::Format("%04i", 19 + year)); else if (year > 0) SetReleaseDate(StringUtils::Format("%04i", 20 + year)); else m_strReleaseDate.clear(); } void CMusicInfoTag::SetDatabaseId(int id, const std::string &type) { m_iDbId = id; m_type = type; } void CMusicInfoTag::SetTrackNumber(int iTrack) { m_iTrack = (m_iTrack & 0xffff0000) | (iTrack & 0xffff); } void CMusicInfoTag::SetDiscNumber(int iDiscNumber) { m_iTrack = (m_iTrack & 0xffff) | (iDiscNumber << 16); } void CMusicInfoTag::SetDiscSubtitle(const std::string& strDiscSubtitle) { m_strDiscSubtitle = strDiscSubtitle; } void CMusicInfoTag::SetTotalDiscs(int iDiscTotal) { m_iDiscTotal = iDiscTotal; } void CMusicInfoTag::SetReleaseDate(const std::string& strReleaseDate) { // Date in ISO8601 YYYY, YYYY-MM or YYYY-MM-DD m_strReleaseDate = strReleaseDate; } void CMusicInfoTag::SetOriginalDate(const std::string& strOriginalDate) { // Date in ISO8601 YYYY, YYYY-MM or YYYY-MM-DD m_strOriginalDate = strOriginalDate; } void CMusicInfoTag::AddOriginalDate(const std::string& strDateYear) { // Avoid overwriting YYYY-MM or YYYY-MM-DD (from DATE tag) with just YYYY (from YEAR tag) if (strDateYear.size() > m_strOriginalDate.size()) m_strOriginalDate = strDateYear; } void CMusicInfoTag::AddReleaseDate(const std::string& strDateYear, bool isMonth /*= false*/) { // Given MMDD (from ID3 v2.3 TDAT tag) set MM-DD part of ISO8601 string if (isMonth && !strDateYear.empty()) { std::string strYYYY = GetReleaseYear(); if (strYYYY.empty()) strYYYY = "0000"; // Fake year when TYER not read yet m_strReleaseDate = StringUtils::Format("%s-%s-%s", strYYYY, StringUtils::Left(strDateYear, 2), StringUtils::Right(strDateYear, 2)); } // Given YYYY only (from YEAR tag) and already have YYYY-MM or YYYY-MM-DD (from DATE tag) else if (strDateYear.size() == 4 && (m_strReleaseDate.size() > 4)) { // Have 0000-MM-DD where ID3 v2.3 TDAT tag read first, fill YYYY part from TYER if (GetReleaseYear() == "0000") StringUtils::Replace(m_strReleaseDate, "0000", strDateYear); } else m_strReleaseDate = strDateYear; // Could be YYYY, YYYY-MM or YYYY-MM-DD } void CMusicInfoTag::SetTrackAndDiscNumber(int iTrackAndDisc) { m_iTrack = iTrackAndDisc; } void CMusicInfoTag::SetDuration(int iSec) { m_iDuration = iSec; } void CMusicInfoTag::SetBitRate(int bitrate) { m_bitrate = bitrate; } void CMusicInfoTag::SetNoOfChannels(int channels) { m_channels = channels; } void CMusicInfoTag::SetSampleRate(int samplerate) { m_samplerate = samplerate; } void CMusicInfoTag::SetComment(const std::string& comment) { m_strComment = comment; } void CMusicInfoTag::SetMood(const std::string& mood) { m_strMood = mood; } void CMusicInfoTag::SetRecordLabel(const std::string& publisher) { m_strRecordLabel = publisher; } void CMusicInfoTag::SetCueSheet(const std::string& cueSheet) { m_cuesheet = cueSheet; } void CMusicInfoTag::SetLyrics(const std::string& lyrics) { m_strLyrics = lyrics; } void CMusicInfoTag::SetRating(float rating) { //This value needs to be between 0-10 - 0 will unset the rating rating = std::max(rating, 0.f); rating = std::min(rating, 10.f); m_Rating = rating; } void CMusicInfoTag::SetVotes(int votes) { m_Votes = votes; } void CMusicInfoTag::SetUserrating(int rating) { //This value needs to be between 0-10 - 0 will unset the userrating rating = std::max(rating, 0); rating = std::min(rating, 10); m_Userrating = rating; } void CMusicInfoTag::SetListeners(int listeners) { m_listeners = std::max(listeners, 0); } void CMusicInfoTag::SetPlayCount(int playcount) { m_iTimesPlayed = playcount; } void CMusicInfoTag::SetLastPlayed(const std::string& lastplayed) { m_lastPlayed.SetFromDBDateTime(lastplayed); } void CMusicInfoTag::SetLastPlayed(const CDateTime& lastplayed) { m_lastPlayed = lastplayed; } void CMusicInfoTag::SetDateAdded(const std::string& strDateAdded) { m_dateAdded.SetFromDBDateTime(strDateAdded); } void CMusicInfoTag::SetDateAdded(const CDateTime& dateAdded) { m_dateAdded = dateAdded; } void MUSIC_INFO::CMusicInfoTag::SetDateUpdated(const std::string& strDateUpdated) { m_dateUpdated.SetFromDBDateTime(strDateUpdated); } void MUSIC_INFO::CMusicInfoTag::SetDateUpdated(const CDateTime& dateUpdated) { m_dateUpdated = dateUpdated; } void MUSIC_INFO::CMusicInfoTag::SetDateNew(const std::string& strDateNew) { m_dateNew.SetFromDBDateTime(strDateNew); } void MUSIC_INFO::CMusicInfoTag::SetDateNew(const CDateTime& dateNew) { m_dateNew = dateNew; } void CMusicInfoTag::SetCompilation(bool compilation) { m_bCompilation = compilation; } void CMusicInfoTag::SetBoxset(bool boxset) { m_bBoxset = boxset; } void CMusicInfoTag::SetLoaded(bool bOnOff) { m_bLoaded = bOnOff; } bool CMusicInfoTag::Loaded() const { return m_bLoaded; } void CMusicInfoTag::SetBPM(int bpm) { m_iBPM = bpm; } void CMusicInfoTag::SetStationName(const std::string& strStationName) { m_stationName = strStationName; } const std::string& CMusicInfoTag::GetMusicBrainzTrackID() const { return m_strMusicBrainzTrackID; } const std::vector& CMusicInfoTag::GetMusicBrainzArtistID() const { return m_musicBrainzArtistID; } const std::vector& CMusicInfoTag::GetMusicBrainzArtistHints() const { return m_musicBrainzArtistHints; } const std::string& CMusicInfoTag::GetMusicBrainzAlbumID() const { return m_strMusicBrainzAlbumID; } const std::string & MUSIC_INFO::CMusicInfoTag::GetMusicBrainzReleaseGroupID() const { return m_strMusicBrainzReleaseGroupID; } const std::vector& CMusicInfoTag::GetMusicBrainzAlbumArtistID() const { return m_musicBrainzAlbumArtistID; } const std::vector& CMusicInfoTag::GetMusicBrainzAlbumArtistHints() const { return m_musicBrainzAlbumArtistHints; } const std::string &CMusicInfoTag::GetMusicBrainzReleaseType() const { return m_strMusicBrainzReleaseType; } void CMusicInfoTag::SetMusicBrainzTrackID(const std::string& strTrackID) { m_strMusicBrainzTrackID = strTrackID; } void CMusicInfoTag::SetMusicBrainzArtistID(const std::vector& musicBrainzArtistId) { m_musicBrainzArtistID = musicBrainzArtistId; } void CMusicInfoTag::SetMusicBrainzArtistHints(const std::vector& musicBrainzArtistHints) { m_musicBrainzArtistHints = musicBrainzArtistHints; } void CMusicInfoTag::SetMusicBrainzAlbumID(const std::string& strAlbumID) { m_strMusicBrainzAlbumID = strAlbumID; } void CMusicInfoTag::SetMusicBrainzAlbumArtistID(const std::vector& musicBrainzAlbumArtistId) { m_musicBrainzAlbumArtistID = musicBrainzAlbumArtistId; } void CMusicInfoTag::SetMusicBrainzAlbumArtistHints(const std::vector& musicBrainzAlbumArtistHints) { m_musicBrainzAlbumArtistHints = musicBrainzAlbumArtistHints; } void MUSIC_INFO::CMusicInfoTag::SetMusicBrainzReleaseGroupID(const std::string & strReleaseGroupID) { m_strMusicBrainzReleaseGroupID = strReleaseGroupID; } void CMusicInfoTag::SetMusicBrainzReleaseType(const std::string& ReleaseType) { m_strMusicBrainzReleaseType = ReleaseType; } void CMusicInfoTag::SetCoverArtInfo(size_t size, const std::string &mimeType) { m_coverArt.Set(size, mimeType); } void CMusicInfoTag::SetReplayGain(const ReplayGain& aGain) { m_replayGain = aGain; } void CMusicInfoTag::SetAlbumReleaseType(CAlbum::ReleaseType releaseType) { m_albumReleaseType = releaseType; } void CMusicInfoTag::SetType(const MediaType& mediaType) { m_type = mediaType; } // This is the Musicbrainz release status tag. See https://musicbrainz.org/doc/Release#Status void CMusicInfoTag::SetAlbumReleaseStatus(const std::string& ReleaseStatus) { m_strReleaseStatus = ReleaseStatus; } void CMusicInfoTag::SetStationArt(const std::string& strStationArt) { m_stationArt = strStationArt; } void CMusicInfoTag::SetArtist(const CArtist& artist) { SetArtist(artist.strArtist); SetArtistSort(artist.strSortName); SetAlbumArtist(artist.strArtist); SetAlbumArtistSort(artist.strSortName); SetMusicBrainzArtistID({ artist.strMusicBrainzArtistID }); SetMusicBrainzAlbumArtistID({ artist.strMusicBrainzArtistID }); SetGenre(artist.genre); SetMood(StringUtils::Join(artist.moods, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator)); SetDateAdded(artist.dateAdded); SetDateUpdated(artist.dateUpdated); SetDateNew(artist.dateNew); SetDatabaseId(artist.idArtist, MediaTypeArtist); SetLoaded(); } void CMusicInfoTag::SetAlbum(const CAlbum& album) { Clear(); //Set all artist infomation from album artist credits and artist description SetArtistDesc(album.GetAlbumArtistString()); SetArtist(album.GetAlbumArtist()); SetArtistSort(album.GetAlbumArtistSort()); SetMusicBrainzArtistID(album.GetMusicBrainzAlbumArtistID()); SetAlbumArtistDesc(album.GetAlbumArtistString()); SetAlbumArtist(album.GetAlbumArtist()); SetAlbumArtistSort(album.GetAlbumArtistSort()); SetMusicBrainzAlbumArtistID(album.GetMusicBrainzAlbumArtistID()); SetAlbumId(album.idAlbum); SetAlbum(album.strAlbum); SetTitle(album.strAlbum); SetMusicBrainzAlbumID(album.strMusicBrainzAlbumID); SetMusicBrainzReleaseGroupID(album.strReleaseGroupMBID); SetMusicBrainzReleaseType(album.strType); SetAlbumReleaseStatus(album.strReleaseStatus); SetGenre(album.genre); SetMood(StringUtils::Join(album.moods, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator)); SetRecordLabel(album.strLabel); SetRating(album.fRating); SetUserrating(album.iUserrating); SetVotes(album.iVotes); SetCompilation(album.bCompilation); SetOriginalDate(album.strOrigReleaseDate); SetReleaseDate(album.strReleaseDate); SetBoxset(album.bBoxedSet); SetAlbumReleaseType(album.releaseType); SetDateAdded(album.dateAdded); SetDateUpdated(album.dateUpdated); SetDateNew(album.dateNew); SetPlayCount(album.iTimesPlayed); SetDatabaseId(album.idAlbum, MediaTypeAlbum); SetLastPlayed(album.lastPlayed); SetTotalDiscs(album.iTotalDiscs); SetDuration(album.iAlbumDuration); SetLoaded(); } void CMusicInfoTag::SetSong(const CSong& song) { Clear(); SetTitle(song.strTitle); SetGenre(song.genre); /* Set all artist infomation from song artist credits and artist description. During processing e.g. Cue Sheets, song may only have artist description string rather than a fully populated artist credits vector. */ if (!song.HasArtistCredits()) SetArtist(song.GetArtistString()); //Sets both artist description string and artist vector from string else { SetArtistDesc(song.GetArtistString()); SetArtist(song.GetArtist()); SetMusicBrainzArtistID(song.GetMusicBrainzArtistID()); } SetArtistSort(song.GetArtistSort()); SetAlbum(song.strAlbum); SetAlbumArtist(song.GetAlbumArtist()); //Only have album artist in song as vector, no desc or MBID SetAlbumArtistSort(song.GetAlbumArtistSort()); SetMusicBrainzTrackID(song.strMusicBrainzTrackID); SetContributors(song.GetContributors()); SetComment(song.strComment); SetCueSheet(song.strCueSheet); SetPlayCount(song.iTimesPlayed); SetLastPlayed(song.lastPlayed); SetDateAdded(song.dateAdded); SetDateUpdated(song.dateUpdated); SetDateNew(song.dateNew); SetCoverArtInfo(song.embeddedArt.m_size, song.embeddedArt.m_mime); SetRating(song.rating); SetUserrating(song.userrating); SetVotes(song.votes); SetURL(song.strFileName); SetReleaseDate(song.strReleaseDate); SetOriginalDate(song.strOrigReleaseDate); SetTrackAndDiscNumber(song.iTrack); SetDiscSubtitle(song.strDiscSubtitle); SetDuration(song.iDuration); SetMood(song.strMood); SetCompilation(song.bCompilation); SetAlbumId(song.idAlbum); SetDatabaseId(song.idSong, MediaTypeSong); SetBPM(song.iBPM); SetBitRate(song.iBitRate); SetSampleRate(song.iSampleRate); SetNoOfChannels(song.iChannels); if (song.replayGain.Get(ReplayGain::TRACK).Valid()) m_replayGain.Set(ReplayGain::TRACK, song.replayGain.Get(ReplayGain::TRACK)); if (song.replayGain.Get(ReplayGain::ALBUM).Valid()) m_replayGain.Set(ReplayGain::ALBUM, song.replayGain.Get(ReplayGain::ALBUM)); SetLoaded(); } void CMusicInfoTag::Serialize(CVariant& value) const { value["url"] = m_strURL; value["title"] = m_strTitle; if (m_type.compare(MediaTypeArtist) == 0 && m_artist.size() == 1) value["artist"] = m_artist[0]; else value["artist"] = m_artist; // There are situations where the individual artist(s) are not queried from the song_artist and artist tables e.g. playlist, // only artist description from song table. Since processing of the ARTISTS tag was added the individual artists may not always // be accurately derived by simply splitting the artist desc. Hence m_artist is only populated when the individual artists are // queried, whereas GetArtistString() will always return the artist description. // To avoid empty artist array in JSON, when m_artist is empty then an attempt is made to split the artist desc into artists. // A longer term solution would be to ensure that when individual artists are to be returned then the song_artist and artist tables // are queried. if (m_artist.empty()) value["artist"] = StringUtils::Split(GetArtistString(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator); value["displayartist"] = GetArtistString(); value["displayalbumartist"] = GetAlbumArtistString(); value["sortartist"] = GetArtistSort(); value["album"] = m_strAlbum; value["albumartist"] = m_albumArtist; value["sortalbumartist"] = m_strAlbumArtistSort; value["genre"] = m_genre; value["duration"] = m_iDuration; value["track"] = GetTrackNumber(); value["disc"] = GetDiscNumber(); value["loaded"] = m_bLoaded; value["year"] = GetYear(); // Optionally from m_strOriginalDate value["musicbrainztrackid"] = m_strMusicBrainzTrackID; value["musicbrainzartistid"] = m_musicBrainzArtistID; value["musicbrainzalbumid"] = m_strMusicBrainzAlbumID; value["musicbrainzreleasegroupid"] = m_strMusicBrainzReleaseGroupID; value["musicbrainzalbumartistid"] = m_musicBrainzAlbumArtistID; value["comment"] = m_strComment; value["contributors"] = CVariant(CVariant::VariantTypeArray); for (const auto& role : m_musicRoles) { CVariant contributor; contributor["name"] = role.GetArtist(); contributor["role"] = role.GetRoleDesc(); contributor["roleid"] = role.GetRoleId(); contributor["artistid"] = (int)(role.GetArtistId()); value["contributors"].push_back(contributor); } value["displaycomposer"] = GetArtistStringForRole("composer"); //TCOM value["displayconductor"] = GetArtistStringForRole("conductor"); //TPE3 value["displayorchestra"] = GetArtistStringForRole("orchestra"); value["displaylyricist"] = GetArtistStringForRole("lyricist"); //TEXT value["mood"] = StringUtils::Split(m_strMood, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator); value["recordlabel"] = m_strRecordLabel; value["rating"] = m_Rating; value["userrating"] = m_Userrating; value["votes"] = m_Votes; value["playcount"] = m_iTimesPlayed; value["lastplayed"] = m_lastPlayed.IsValid() ? m_lastPlayed.GetAsDBDateTime() : StringUtils::Empty; value["dateadded"] = m_dateAdded.IsValid() ? m_dateAdded.GetAsDBDateTime() : StringUtils::Empty; value["datenew"] = m_dateNew.IsValid() ? m_dateNew.GetAsDBDateTime() : StringUtils::Empty; value["datemodified"] = m_dateUpdated.IsValid() ? m_dateUpdated.GetAsDBDateTime() : StringUtils::Empty; value["lyrics"] = m_strLyrics; value["albumid"] = m_iAlbumId; value["compilationartist"] = m_bCompilation; value["compilation"] = m_bCompilation; if (m_type.compare(MediaTypeAlbum) == 0) value["releasetype"] = CAlbum::ReleaseTypeToString(m_albumReleaseType); else if (m_type.compare(MediaTypeSong) == 0) value["albumreleasetype"] = CAlbum::ReleaseTypeToString(m_albumReleaseType); value["isboxset"] = m_bBoxset; value["totaldiscs"] = m_iDiscTotal; value["disctitle"] = m_strDiscSubtitle; value["releasedate"] = m_strReleaseDate; value["originaldate"] = m_strOriginalDate; value["albumstatus"] = m_strReleaseStatus; value["bpm"] = m_iBPM; value["bitrate"] = m_bitrate; value["samplerate"] = m_samplerate; value["channels"] = m_channels; } void CMusicInfoTag::ToSortable(SortItem& sortable, Field field) const { switch (field) { case FieldTitle: { // make sure not to overwrite an existing path with an empty one std::string title = m_strTitle; if (!title.empty() || sortable.find(FieldTitle) == sortable.end()) sortable[FieldTitle] = title; break; } case FieldArtist: sortable[FieldArtist] = m_strArtistDesc; break; case FieldArtistSort: sortable[FieldArtistSort] = m_strArtistSort; break; case FieldAlbum: sortable[FieldAlbum] = m_strAlbum; break; case FieldAlbumArtist: sortable[FieldAlbumArtist] = m_strAlbumArtistDesc; break; case FieldGenre: sortable[FieldGenre] = m_genre; break; case FieldTime: sortable[FieldTime] = m_iDuration; break; case FieldTrackNumber: sortable[FieldTrackNumber] = m_iTrack; break; case FieldTotalDiscs: sortable[FieldTotalDiscs] = m_iDiscTotal; break; case FieldYear: sortable[FieldYear] = GetYear(); // Optionally from m_strOriginalDate break; case FieldComment: sortable[FieldComment] = m_strComment; break; case FieldMoods: sortable[FieldMoods] = m_strMood; break; case FieldRating: sortable[FieldRating] = m_Rating; break; case FieldUserRating: sortable[FieldUserRating] = m_Userrating; break; case FieldVotes: sortable[FieldVotes] = m_Votes; break; case FieldPlaycount: sortable[FieldPlaycount] = m_iTimesPlayed; break; case FieldLastPlayed: sortable[FieldLastPlayed] = m_lastPlayed.IsValid() ? m_lastPlayed.GetAsDBDateTime() : StringUtils::Empty; break; case FieldDateAdded: sortable[FieldDateAdded] = m_dateAdded.IsValid() ? m_dateAdded.GetAsDBDateTime() : StringUtils::Empty; break; case FieldListeners: sortable[FieldListeners] = m_listeners; break; case FieldId: sortable[FieldId] = (int64_t)m_iDbId; break; case FieldOrigDate: sortable[FieldOrigDate] = m_strOriginalDate; break; case FieldBPM: sortable[FieldBPM] = m_iBPM; break; default: break; } } void CMusicInfoTag::Archive(CArchive& ar) { if (ar.IsStoring()) { ar << m_strURL; ar << m_strTitle; ar << m_artist; ar << m_strArtistSort; ar << m_strArtistDesc; ar << m_strAlbum; ar << m_albumArtist; ar << m_strAlbumArtistDesc; ar << m_genre; ar << m_iDuration; ar << m_iTrack; ar << m_bLoaded; ar << m_strReleaseDate; ar << m_strOriginalDate; ar << m_strMusicBrainzTrackID; ar << m_musicBrainzArtistID; ar << m_strMusicBrainzAlbumID; ar << m_strMusicBrainzReleaseGroupID; ar << m_musicBrainzAlbumArtistID; ar << m_strDiscSubtitle; ar << m_bBoxset; ar << m_iDiscTotal; ar << m_strMusicBrainzReleaseType; ar << m_lastPlayed; ar << m_dateAdded; ar << m_strComment; ar << (int)m_musicRoles.size(); for (const auto& credit : m_musicRoles) { ar << credit.GetRoleId(); ar << credit.GetRoleDesc(); ar << credit.GetArtist(); ar << credit.GetArtistId(); } ar << m_strMood; ar << m_strRecordLabel; ar << m_Rating; ar << m_Userrating; ar << m_Votes; ar << m_iTimesPlayed; ar << m_iAlbumId; ar << m_iDbId; ar << m_type; ar << m_strReleaseStatus; ar << m_strLyrics; ar << m_bCompilation; ar << m_listeners; ar << m_coverArt; ar << m_cuesheet; ar << static_cast(m_albumReleaseType); ar << m_iBPM; ar << m_samplerate; ar << m_bitrate; ar << m_channels; } else { ar >> m_strURL; ar >> m_strTitle; ar >> m_artist; ar >> m_strArtistSort; ar >> m_strArtistDesc; ar >> m_strAlbum; ar >> m_albumArtist; ar >> m_strAlbumArtistDesc; ar >> m_genre; ar >> m_iDuration; ar >> m_iTrack; ar >> m_bLoaded; ar >> m_strReleaseDate; ar >> m_strOriginalDate; ar >> m_strMusicBrainzTrackID; ar >> m_musicBrainzArtistID; ar >> m_strMusicBrainzAlbumID; ar >> m_strMusicBrainzReleaseGroupID; ar >> m_musicBrainzAlbumArtistID; ar >> m_strDiscSubtitle; ar >> m_bBoxset; ar >> m_iDiscTotal; ar >> m_strMusicBrainzReleaseType; ar >> m_lastPlayed; ar >> m_dateAdded; ar >> m_strComment; int iMusicRolesSize; ar >> iMusicRolesSize; m_musicRoles.reserve(iMusicRolesSize); for (int i = 0; i < iMusicRolesSize; ++i) { int idRole; int idArtist; std::string strArtist; std::string strRole; ar >> idRole; ar >> strRole; ar >> strArtist; ar >> idArtist; m_musicRoles.emplace_back(idRole, strRole, strArtist, idArtist); } ar >> m_strMood; ar >> m_strRecordLabel; ar >> m_Rating; ar >> m_Userrating; ar >> m_Votes; ar >> m_iTimesPlayed; ar >> m_iAlbumId; ar >> m_iDbId; ar >> m_type; ar >> m_strReleaseStatus; ar >> m_strLyrics; ar >> m_bCompilation; ar >> m_listeners; ar >> m_coverArt; ar >> m_cuesheet; int albumReleaseType; ar >> albumReleaseType; m_albumReleaseType = static_cast(albumReleaseType); ar >> m_iBPM; ar >> m_samplerate; ar >> m_bitrate; ar >> m_channels; } } void CMusicInfoTag::Clear() { m_strURL.clear(); m_artist.clear(); m_strArtistSort.clear(); m_strComposerSort.clear(); m_strAlbum.clear(); m_albumArtist.clear(); m_genre.clear(); m_strTitle.clear(); m_strMusicBrainzTrackID.clear(); m_musicBrainzArtistID.clear(); m_strMusicBrainzAlbumID.clear(); m_strMusicBrainzReleaseGroupID.clear(); m_musicBrainzAlbumArtistID.clear(); m_strMusicBrainzReleaseType.clear(); m_musicRoles.clear(); m_iDuration = 0; m_iTrack = 0; m_bLoaded = false; m_lastPlayed.Reset(); m_dateAdded.Reset(); m_dateNew.Reset(); m_dateUpdated.Reset(); m_bCompilation = false; m_bBoxset = false; m_strDiscSubtitle.clear(); m_strComment.clear(); m_strMood.clear(); m_strRecordLabel.clear(); m_cuesheet.clear(); m_iDbId = -1; m_type.clear(); m_strReleaseStatus.clear(); m_iTimesPlayed = 0; m_strReleaseDate.clear(); m_strOriginalDate.clear(); m_iAlbumId = -1; m_coverArt.Clear(); m_replayGain = ReplayGain(); m_albumReleaseType = CAlbum::Album; m_listeners = 0; m_Rating = 0; m_Userrating = 0; m_Votes = 0; m_iDiscTotal = 0; m_iBPM = 0; m_samplerate = 0; m_bitrate = 0; m_channels = 0; m_stationName.clear(); m_stationArt.clear(); } void CMusicInfoTag::AppendArtist(const std::string &artist) { for (unsigned int index = 0; index < m_artist.size(); index++) { if (StringUtils::EqualsNoCase(artist, m_artist.at(index))) return; } m_artist.push_back(artist); } void CMusicInfoTag::AppendAlbumArtist(const std::string &albumArtist) { for (unsigned int index = 0; index < m_albumArtist.size(); index++) { if (StringUtils::EqualsNoCase(albumArtist, m_albumArtist.at(index))) return; } m_albumArtist.push_back(albumArtist); } void CMusicInfoTag::AppendGenre(const std::string &genre) { for (unsigned int index = 0; index < m_genre.size(); index++) { if (StringUtils::EqualsNoCase(genre, m_genre.at(index))) return; } m_genre.push_back(genre); } void CMusicInfoTag::AddArtistRole(const std::string& Role, const std::string& strArtist) { if (!strArtist.empty() && !Role.empty()) AddArtistRole(Role, StringUtils::Split(strArtist, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator)); } void CMusicInfoTag::AddArtistRole(const std::string& Role, const std::vector& artists) { for (unsigned int index = 0; index < artists.size(); index++) { CMusicRole ArtistCredit(Role, Trim(artists.at(index))); //Prevent duplicate entries auto credit = find(m_musicRoles.begin(), m_musicRoles.end(), ArtistCredit); if (credit == m_musicRoles.end()) m_musicRoles.push_back(ArtistCredit); } } void CMusicInfoTag::AppendArtistRole(const CMusicRole& ArtistRole) { //Append contributor, no check for duplicates as from database m_musicRoles.push_back(ArtistRole); } const std::string CMusicInfoTag::GetArtistStringForRole(const std::string& strRole) const { std::vector artistvector; for (const auto& credit : m_musicRoles) { if (StringUtils::EqualsNoCase(credit.GetRoleDesc(), strRole)) artistvector.push_back(credit.GetArtist()); } return StringUtils::Join(artistvector, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator); } const std::string CMusicInfoTag::GetContributorsText() const { std::string strLabel; for (const auto& credit : m_musicRoles) { strLabel += StringUtils::Format("%s\n", credit.GetArtist().c_str()); } return StringUtils::TrimRight(strLabel, "\n"); } const std::string CMusicInfoTag::GetContributorsAndRolesText() const { std::string strLabel; for (const auto& credit : m_musicRoles) { strLabel += StringUtils::Format("%s - %s\n", credit.GetRoleDesc().c_str(), credit.GetArtist().c_str()); } return StringUtils::TrimRight(strLabel, "\n"); } const VECMUSICROLES &CMusicInfoTag::GetContributors() const { return m_musicRoles; } void CMusicInfoTag::SetContributors(const VECMUSICROLES& contributors) { m_musicRoles = contributors; } std::string CMusicInfoTag::Trim(const std::string &value) const { std::string trimmedValue(value); StringUtils::TrimLeft(trimmedValue, " "); StringUtils::TrimRight(trimmedValue, " \n\r"); return trimmedValue; }