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