xref: /MusicPlayer2/MusicPlayer2/SongInfo.cpp (revision 965ce478a79b0d21e8a6e2ade0490efa175855dd)
1 #include "stdafx.h"
2 #include "SongInfo.h"
3 #include "MusicPlayer2.h"
4 
5 
NoOnlineLyric() const6 bool SongInfo::NoOnlineLyric() const
7 {
8     return CCommon::GetNumberBit(flags, 0);
9 }
10 
SetNoOnlineLyric(bool val)11 void SongInfo::SetNoOnlineLyric(bool val)
12 {
13     CCommon::SetNumberBit(flags, 0, val);
14 }
15 
NoOnlineAlbumCover() const16 bool SongInfo::NoOnlineAlbumCover() const
17 {
18     return CCommon::GetNumberBit(flags, 1);
19 }
20 
SetNoOnlineAlbumCover(bool val)21 void SongInfo::SetNoOnlineAlbumCover(bool val)
22 {
23     CCommon::SetNumberBit(flags, 1, val);
24 }
25 
AlwaysUseExternalAlbumCover() const26 bool SongInfo::AlwaysUseExternalAlbumCover() const
27 {
28     return CCommon::GetNumberBit(flags, 2);
29 }
30 
SetAlwaysUseExternalAlbumCover(bool val)31 void SongInfo::SetAlwaysUseExternalAlbumCover(bool val)
32 {
33     CCommon::SetNumberBit(flags, 2, val);
34 }
35 
ChannelInfoAcquired() const36 bool SongInfo::ChannelInfoAcquired() const
37 {
38     return CCommon::GetNumberBit(flags, 3);
39 }
40 
SetChannelInfoAcquired(bool val)41 void SongInfo::SetChannelInfoAcquired(bool val)
42 {
43     CCommon::SetNumberBit(flags, 3, val);
44 }
45 
CopyAudioTag(const SongInfo & song_info)46 void SongInfo::CopyAudioTag(const SongInfo& song_info)
47 {
48     title = song_info.title;
49     artist = song_info.artist;
50     album = song_info.album;
51     year = song_info.year;
52     comment = song_info.comment;
53     genre = song_info.genre;
54     genre_idx = song_info.genre_idx;
55     track = song_info.track;
56     album_artist = song_info.album_artist;
57     total_tracks = song_info.total_tracks;
58     disc_num = song_info.disc_num;
59     total_discs = song_info.total_discs;
60     tag_type = song_info.tag_type;
61 }
62 
IsTitleEmpty() const63 bool SongInfo::IsTitleEmpty() const
64 {
65     static const wstring& default_title = theApp.m_str_table.LoadText(L"TXT_EMPTY_TITLE");
66     return title.empty() || title == default_title;
67 }
68 
IsArtistEmpty() const69 bool SongInfo::IsArtistEmpty() const
70 {
71     static const wstring& default_artist = theApp.m_str_table.LoadText(L"TXT_EMPTY_ARTIST");
72     return artist.empty() || artist == default_artist;
73 }
74 
IsAlbumEmpty() const75 bool SongInfo::IsAlbumEmpty() const
76 {
77     static const wstring& default_album = theApp.m_str_table.LoadText(L"TXT_EMPTY_ALBUM");
78     return album.empty() || album == default_album;
79 }
80 
IsYearEmpty() const81 bool SongInfo::IsYearEmpty() const
82 {
83     return year == 0;
84 }
85 
IsGenreEmpty() const86 bool SongInfo::IsGenreEmpty() const
87 {
88     static const wstring& default_genre = theApp.m_str_table.LoadText(L"TXT_EMPTY_GENRE");
89     return genre.empty() || genre == default_genre;
90 }
91 
GetArtistList(vector<wstring> & artist_list) const92 void SongInfo::GetArtistList(vector<wstring>& artist_list) const
93 {
94     artist_list.clear();
95     if (artist.empty())
96         return;
97     static const wstring split_char = L"/;&、";
98     if (artist.find_first_of(split_char) == wstring::npos)  // 不含分割字符的字符串不需要处理,直接返回
99     {
100         artist_list.push_back(artist);
101         return;
102     }
103     // 现在是保守分割方案,理论上有可能少切分但不会多,处理后艺术家仍然按照原顺序排列
104     vector<bool> char_flag(artist.size(), false);
105     for (size_t i{}; i < artist.size(); ++i)
106     {
107         if (split_char.find(artist[i]) == wstring::npos)
108             char_flag[i] = true;
109     }
110     const vector<wstring>& split_ext = theApp.m_media_lib_setting_data.artist_split_ext;
111     for (const wstring& str : split_ext)
112     {
113         size_t index{ artist.find(str) };
114         while (index != wstring::npos)
115         {
116             for (size_t i{}; i < str.size(); ++i)
117                 char_flag[index + i] = true;
118             index = artist.find(str, index + 1);
119         }
120     }
121     auto push_back_artist = [&](size_t _Off, size_t _Count = std::wstring::npos)
122     {
123         wstring temp = artist.substr(_Off, _Count);
124         CCommon::StringNormalize(temp);
125         if (!temp.empty())
126             artist_list.push_back(temp);
127     };
128     size_t start_pos{};
129     for (size_t i{}; i < artist.size(); ++i)
130     {
131         if (char_flag[i])
132             continue;
133         push_back_artist(start_pos, i - start_pos);
134         start_pos = i + 1;
135     }
136     push_back_artist(start_pos); // 处理最后一项艺术家
137 }
138 
GetFirstArtist() const139 wstring SongInfo::GetFirstArtist() const
140 {
141     vector<wstring> artist_list;
142     GetArtistList(artist_list);
143     if (artist_list.empty())
144         return GetArtist();
145     return artist_list.at(0);
146 }
147 
GetTitle() const148 wstring SongInfo::GetTitle() const
149 {
150     static const wstring& default_title = theApp.m_str_table.LoadText(L"TXT_EMPTY_TITLE");
151     return title.empty() ? default_title : title;
152 }
153 
GetArtist() const154 wstring SongInfo::GetArtist() const
155 {
156     static const wstring& default_artist = theApp.m_str_table.LoadText(L"TXT_EMPTY_ARTIST");
157     return artist.empty() ? default_artist : artist;
158 }
159 
GetAlbum() const160 wstring SongInfo::GetAlbum() const
161 {
162     static const wstring& default_album = theApp.m_str_table.LoadText(L"TXT_EMPTY_ALBUM");
163     return album.empty() ? default_album : album;
164 }
165 
GetYear() const166 wstring SongInfo::GetYear() const
167 {
168     static const wstring& default_year = theApp.m_str_table.LoadText(L"TXT_EMPTY_YEAR");
169     if (year == 0)
170         return default_year;
171     else
172         return std::to_wstring(year);
173 }
174 
get_year() const175 wstring SongInfo::get_year() const
176 {
177     if (year == 0)
178         return wstring();
179     else
180         return std::to_wstring(year);
181 }
182 
GetGenre() const183 wstring SongInfo::GetGenre() const
184 {
185     static const wstring& default_genre = theApp.m_str_table.LoadText(L"TXT_EMPTY_GENRE");
186     return genre.empty() ? default_genre : genre;
187 }
188 
GetFileName() const189 wstring SongInfo::GetFileName() const
190 {
191     wstring file_name;
192     size_t index = file_path.rfind(L'\\');
193     if (index == wstring::npos)
194         index = file_path.rfind(L'/');
195     if (index == wstring::npos)
196         return file_path;
197 
198     file_name = file_path.substr(index + 1);
199     return file_name;
200 }
201 
GetSongId() const202 wstring SongInfo::GetSongId() const
203 {
204     return std::to_wstring(song_id);
205 }
206 
SetYear(const wchar_t * str_year)207 void SongInfo::SetYear(const wchar_t* str_year)
208 {
209     year = static_cast<unsigned short>(_wtoi(str_year));
210 }
211 
SetSongId(const wstring & id)212 void SongInfo::SetSongId(const wstring& id)
213 {
214     song_id = _wtoi64(id.c_str());
215 }
216 
IsEmpty() const217 bool SongInfo::IsEmpty() const
218 {
219     return file_path.empty() && title.empty() && artist.empty() && album.empty() && comment.empty() && genre.empty() && year == 0 && length().isZero();
220 }
221 
length() const222 Time SongInfo::length() const
223 {
224     return Time(end_pos - start_pos);
225 }
226 
IsSameSong(const SongInfo & song) const227 bool SongInfo::IsSameSong(const SongInfo& song) const
228 {   // 存在file_path和track相同但is_cue不同的情况(分立曲目被播放后又打开一个描述这些歌曲的cue),此时应返回false
229     if (is_cue != song.is_cue)
230         return false;
231     if (file_path != song.file_path)
232         return false;
233     if (is_cue && track != song.track)
234         return false;
235     return true;
236 }
237 
Normalize()238 void SongInfo::Normalize()
239 {
240     if (theApp.m_str_table.LoadText(L"TXT_EMPTY_TITLE") == title)
241         title.clear();
242     if (theApp.m_str_table.LoadText(L"TXT_EMPTY_ARTIST") == artist)
243         artist.clear();
244     if (theApp.m_str_table.LoadText(L"TXT_EMPTY_ALBUM") == album)
245         album.clear();
246     if (theApp.m_str_table.LoadText(L"TXT_EMPTY_GENRE") == genre)
247         genre.clear();
248 }
249 
250 
ByFileName(const SongInfo & a,const SongInfo & b)251 static bool ByFileName(const SongInfo& a, const SongInfo& b)
252 {
253     return CCommon::StringCompareInLocalLanguage(a.GetFileName(), b.GetFileName()) < 0;
254 }
255 
ByFileNameDecending(const SongInfo & a,const SongInfo & b)256 static bool ByFileNameDecending(const SongInfo& a, const SongInfo& b)
257 {
258     return CCommon::StringCompareInLocalLanguage(a.GetFileName(), b.GetFileName()) > 0;
259 }
260 
ByPath(const SongInfo & a,const SongInfo & b)261 static bool ByPath(const SongInfo& a, const SongInfo& b)
262 {
263     return CCommon::StringCompareInLocalLanguage(a.file_path, b.file_path) < 0;
264 }
265 
ByPathDecending(const SongInfo & a,const SongInfo & b)266 static bool ByPathDecending(const SongInfo& a, const SongInfo& b)
267 {
268     return CCommon::StringCompareInLocalLanguage(a.file_path, b.file_path) > 0;
269 }
270 
ByTitle(const SongInfo & a,const SongInfo & b)271 static bool ByTitle(const SongInfo& a, const SongInfo& b)
272 {
273     return CCommon::StringCompareInLocalLanguage(a.title, b.title) < 0;
274 }
275 
ByTitleDecending(const SongInfo & a,const SongInfo & b)276 static bool ByTitleDecending(const SongInfo& a, const SongInfo& b)
277 {
278     return CCommon::StringCompareInLocalLanguage(a.title, b.title) > 0;
279 }
280 
ByTrack(const SongInfo & a,const SongInfo & b)281 static bool ByTrack(const SongInfo& a, const SongInfo& b)
282 {
283     if (a.disc_num != b.disc_num)
284         return a.disc_num < b.disc_num;
285     else
286         return a.track < b.track;
287 }
288 
ByTrackDecending(const SongInfo & a,const SongInfo & b)289 static bool ByTrackDecending(const SongInfo& a, const SongInfo& b)
290 {
291     return ByTrack(b, a);
292 }
293 
ByArtist(const SongInfo & a,const SongInfo & b)294 static bool ByArtist(const SongInfo& a, const SongInfo& b)
295 {
296     int compare_album = CCommon::StringCompareInLocalLanguage(a.album, b.album);
297     int compare_artist = CCommon::StringCompareInLocalLanguage(a.artist, b.artist);
298     if (compare_artist != 0)
299         return compare_artist < 0;
300     else if (compare_album != 0)
301         return compare_album < 0;
302     else return ByTrack(a, b);
303 }
304 
ByArtistDecending(const SongInfo & a,const SongInfo & b)305 static bool ByArtistDecending(const SongInfo& a, const SongInfo& b)
306 {
307     return ByArtist(b, a);
308 }
309 
ByAlbum(const SongInfo & a,const SongInfo & b)310 static bool ByAlbum(const SongInfo& a, const SongInfo& b)
311 {
312     int compare_album = CCommon::StringCompareInLocalLanguage(a.album, b.album);
313     int compare_artist = CCommon::StringCompareInLocalLanguage(a.artist, b.artist);
314     if (compare_album != 0)
315         return compare_album < 0;
316     else if (a.track != b.track || a.disc_num != b.disc_num)        //唱片集相同的情况下比较音轨号
317         return ByTrack(a, b);
318     else                                //音轨号仍然相同,比较艺术家
319         return compare_artist < 0;
320 }
321 
ByAlbumDecending(const SongInfo & a,const SongInfo & b)322 static bool ByAlbumDecending(const SongInfo& a, const SongInfo& b)
323 {
324     return ByAlbum(b, a);
325 }
326 
ByListenTime(const SongInfo & a,const SongInfo & b)327 static bool ByListenTime(const SongInfo& a, const SongInfo& b)
328 {
329     return a.listen_time < b.listen_time;
330 }
331 
ByListenTimeDecending(const SongInfo & a,const SongInfo & b)332 static bool ByListenTimeDecending(const SongInfo& a, const SongInfo& b)
333 {
334     return a.listen_time > b.listen_time;
335 }
336 
ByModifiedTime(const SongInfo & a,const SongInfo & b)337 static bool ByModifiedTime(const SongInfo& a, const SongInfo& b)
338 {
339     return a.modified_time < b.modified_time;
340 }
341 
ByModifiedTimeDecending(const SongInfo & a,const SongInfo & b)342 static bool ByModifiedTimeDecending(const SongInfo& a, const SongInfo& b)
343 {
344     return a.modified_time > b.modified_time;
345 }
346 
ByGenre(const SongInfo & a,const SongInfo & b)347 static bool ByGenre(const SongInfo& a, const SongInfo& b)
348 {
349     return CCommon::StringCompareInLocalLanguage(a.genre, b.genre) < 0;
350 }
351 
ByGenreDecending(const SongInfo & a,const SongInfo & b)352 static bool ByGenreDecending(const SongInfo& a, const SongInfo& b)
353 {
354     return CCommon::StringCompareInLocalLanguage(a.genre, b.genre) > 0;
355 }
356 
ByYear(const SongInfo & a,const SongInfo & b)357 static bool ByYear(const SongInfo& a, const SongInfo& b)
358 {
359     return a.year < b.year;
360 }
361 
ByYearDecending(const SongInfo & a,const SongInfo & b)362 static bool ByYearDecending(const SongInfo& a, const SongInfo& b)
363 {
364     return a.year > b.year;
365 }
366 
ByBitrate(const SongInfo & a,const SongInfo & b)367 static bool ByBitrate(const SongInfo& a, const SongInfo& b)
368 {
369     return a.bitrate < b.bitrate;
370 }
371 
ByBitrateDecending(const SongInfo & a,const SongInfo & b)372 static bool ByBitrateDecending(const SongInfo& a, const SongInfo& b)
373 {
374     return a.bitrate > b.bitrate;
375 }
376 
GetSortFunc(SortMode sort_mode)377 std::function<bool(const SongInfo& a, const SongInfo& b)> SongInfo::GetSortFunc(SortMode sort_mode)
378 {
379     switch (sort_mode)
380     {
381     case SM_U_FILE: return ByFileName;
382     case SM_D_FILE: return ByFileNameDecending;
383     case SM_U_PATH: return ByPath;
384     case SM_D_PATH: return ByPathDecending;
385     case SM_U_TITLE: return ByTitle;
386     case SM_D_TITLE: return ByTitleDecending;
387     case SM_U_ARTIST: return ByArtist;
388     case SM_D_ARTIST: return ByArtistDecending;
389     case SM_U_ALBUM: return ByAlbum;
390     case SM_D_ALBUM: return ByAlbumDecending;
391     case SM_U_TRACK: return ByTrack;
392     case SM_D_TRACK: return ByTrackDecending;
393     case SM_U_LISTEN: return ByListenTime;
394     case SM_D_LISTEN: return ByListenTimeDecending;
395     case SM_U_TIME: return ByModifiedTime;
396     case SM_D_TIME: return ByModifiedTimeDecending;
397     case SM_U_GENRE: return ByGenre;
398     case SM_D_GENRE: return ByGenreDecending;
399     case SM_U_YEAR: return ByYear;
400     case SM_D_YEAR: return ByYearDecending;
401     case SM_U_BITRATE: return ByBitrate;
402     case SM_D_BITRATE: return ByBitrateDecending;
403     default: return [](const SongInfo& a, const SongInfo& b) { return true; };
404     }
405 }
406 
GetSortModeDisplayName(SortMode sort_mode)407 wstring SongInfo::GetSortModeDisplayName(SortMode sort_mode)
408 {
409     std::wstring str_sort_mode;
410     switch (sort_mode)
411     {
412     case SM_U_FILE: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_FILE"); break;
413     case SM_D_FILE: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_FILE"); break;
414     case SM_U_PATH: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_PATH"); break;
415     case SM_D_PATH: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_PATH"); break;
416     case SM_U_TITLE: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_TITLE"); break;
417     case SM_D_TITLE: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_TITLE"); break;
418     case SM_U_ARTIST: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_ARTIST"); break;
419     case SM_D_ARTIST: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_ARTIST"); break;
420     case SM_U_ALBUM: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_ALBUM"); break;
421     case SM_D_ALBUM: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_ALBUM"); break;
422     case SM_U_TRACK: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_TRACK"); break;
423     case SM_D_TRACK: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_TRACK"); break;
424     case SM_U_LISTEN: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_LISTEN"); break;
425     case SM_D_LISTEN: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_LISTEN"); break;
426     case SM_U_TIME: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_U_TIME"); break;
427     case SM_D_TIME: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_D_TIME"); break;
428     case SM_UNSORT: str_sort_mode = theApp.m_str_table.LoadText(L"TXT_SM_UNSORT"); break;
429     }
430     return str_sort_mode;
431 }
432