1 #include "stdafx.h"
2 #include "MusicPlayerCmdHelper.h"
3 #include "InternetCommon.h"
4 #include "Player.h"
5 #include "MusicPlayer2.h"
6 #include "MusicPlayerDlg.h"
7 #include "InputDlg.h"
8 #include "Playlist.h"
9 #include "AddToPlaylistDlg.h"
10 #include "AudioCommon.h"
11 #include "COSUPlayerHelper.h"
12 #include "SongDataManager.h"
13 #include "SelectItemDlg.h"
14 #include "CommonDialogMgr.h"
15 #include "FilterHelper.h"
16 #include "UiMediaLibItemMgr.h"
17 #include "SongInfoHelper.h"
18 #include "CRecentList.h"
19
CMusicPlayerCmdHelper(CWnd * pOwner)20 CMusicPlayerCmdHelper::CMusicPlayerCmdHelper(CWnd* pOwner)
21 : m_pOwner(pOwner)
22 {
23 }
24
~CMusicPlayerCmdHelper()25 CMusicPlayerCmdHelper::~CMusicPlayerCmdHelper()
26 {
27 }
28
VeiwOnline(SongInfo & song)29 void CMusicPlayerCmdHelper::VeiwOnline(SongInfo& song)
30 {
31 //查找歌曲并获取最佳匹配项的歌曲ID
32 CSongDataManager::GetInstance().GetSongID(song, song.song_id); // 从媒体库读取id
33 if (song.song_id == 0) //如果没有获取过ID,则获取一次ID
34 {
35 wstring song_id;
36 song_id = CInternetCommon::SearchSongAndGetMatched(song.title, song.artist, song.album, song.GetFileName()).id;
37 song.SetSongId(song_id);
38 CSongDataManager::GetInstance().SetSongID(song, song.song_id); // 与媒体库同步
39 }
40
41 if (song.song_id == 0)
42 return;
43 //获取网易云音乐中该歌曲的在线接听网址
44 wstring song_url{ L"http://music.163.com/#/song?id=" + song.GetSongId() };
45
46 //打开超链接
47 ShellExecute(NULL, _T("open"), song_url.c_str(), NULL, NULL, SW_SHOW);
48
49 }
50
ViewOnlineThreadFunc(LPVOID lpParam)51 UINT CMusicPlayerCmdHelper::ViewOnlineThreadFunc(LPVOID lpParam)
52 {
53 SongInfo* song = (SongInfo*)(lpParam);
54 if (song == nullptr || song->IsEmpty())
55 return 0;
56 CCommon::SetThreadLanguageList(theApp.m_str_table.GetLanguageTag());
57 CMusicPlayerCmdHelper helper;
58 helper.VeiwOnline(*song);
59 return 0;
60 }
61
FormatConvert(const std::vector<SongInfo> & songs)62 void CMusicPlayerCmdHelper::FormatConvert(const std::vector<SongInfo>& songs)
63 {
64 if (!theApp.m_format_convert_dialog_exit)
65 return;
66 CMusicPlayerDlg* pPlayerDlg = CMusicPlayerDlg::GetInstance();
67 if (pPlayerDlg == nullptr)
68 return;
69
70 CCommon::DeleteModelessDialog(pPlayerDlg->m_pFormatConvertDlg);
71
72 if (CPlayer::GetInstance().IsMciCore())
73 {
74 const wstring& info = theApp.m_str_table.LoadText(L"MSG_MCI_NO_THIS_FUNCTION_WARNING");
75 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
76 return;
77 } else if (CPlayer::GetInstance().IsFfmpegCore()) {
78 const wstring& info = theApp.m_str_table.LoadText(L"MSG_FFMPEG_NO_THIS_FUNCTION_WARNING");
79 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
80 return;
81 }
82
83 pPlayerDlg->m_pFormatConvertDlg = new CFormatConvertDlg(songs, GetOwner());
84 pPlayerDlg->m_pFormatConvertDlg->Create(IDD_FORMAT_CONVERT_DIALOG);
85 pPlayerDlg->m_pFormatConvertDlg->ShowWindow(SW_SHOW);
86 }
87
OnAddToNewPlaylist(std::function<void (std::vector<SongInfo> &)> get_song_list,std::wstring & playlist_path,const std::wstring & default_name)88 bool CMusicPlayerCmdHelper::OnAddToNewPlaylist(std::function<void(std::vector<SongInfo>&)> get_song_list, std::wstring& playlist_path, const std::wstring& default_name /*= L""*/)
89 {
90 CInputDlg imput_dlg(GetOwner());
91 imput_dlg.SetTitle(theApp.m_str_table.LoadText(L"TITLE_NEW_PLAYLIST").c_str());
92 imput_dlg.SetInfoText(theApp.m_str_table.LoadText(L"TXT_NEW_PLAYLIST_INPUT_PLAYLIST_NAME").c_str());
93 imput_dlg.SetEditText(default_name.c_str());
94 if (imput_dlg.DoModal() == IDOK)
95 {
96 wstring playlist_name = imput_dlg.GetEditText().GetString();
97 if (playlist_name.empty())
98 {
99 const wstring& info = theApp.m_str_table.LoadText(L"MSG_PLAYLIST_NAME_EMPTY_WARNING");
100 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
101 return false;
102 }
103 if (!CCommon::IsFileNameValid(playlist_name))
104 {
105 const wstring& info = theApp.m_str_table.LoadText(L"MSG_FILE_NAME_INVALID_WARNING");
106 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
107 return false;
108 }
109
110 //获取选中的曲目的路径
111 std::vector<SongInfo> selected_item_path;
112 get_song_list(selected_item_path);
113
114 playlist_path = theApp.m_playlist_dir + playlist_name + PLAYLIST_EXTENSION;
115 // 创建新的空播放列表
116 if (!CRecentList::Instance().AddNewItem(ListItem{ LT_PLAYLIST, playlist_path }))
117 {
118 //播放列表已存在,询问是否要添加到已存在的播放列表
119 wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_PLAYLIST_EXIST_INQUIRY", { playlist_name, selected_item_path.size()});
120 if (GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONQUESTION | MB_YESNO) != IDYES)
121 {
122 return false;
123 }
124 }
125
126 CMusicPlayerDlg* pPlayerDlg = CMusicPlayerDlg::GetInstance();
127
128 CPlaylistFile playlist;
129 playlist.LoadFromFile(playlist_path);
130 int rtn = playlist.AddSongsToPlaylist(selected_item_path, theApp.m_media_lib_setting_data.insert_begin_of_playlist);
131 if (rtn > 0)
132 {
133 //显示添加成功提示
134 CPlayerUIBase* ui = pPlayerDlg->GetCurrentUi();
135 if (ui != nullptr)
136 {
137 wstring playlist_display_name = ListItem(LT_PLAYLIST, playlist_path).GetDisplayName();
138 const wstring& info = theApp.m_str_table.LoadTextFormat(L"MSG_ADD_TO_PLAYLIST_SUCCEED", { rtn, playlist_display_name });
139 ui->ShowUiTipInfo(info);
140 }
141 }
142 else
143 {
144 const wstring& info = theApp.m_str_table.LoadText(L"MSG_FILE_EXIST_IN_PLAYLIST");
145 pPlayerDlg->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
146 return false;
147 }
148 playlist.SaveToFile(playlist_path);
149 // 此方法需要自行更新“添加到播放列表”菜单和媒体库标签页
150 theApp.m_pMainWnd->SendMessage(WM_INIT_ADD_TO_MENU);
151 RefreshMediaTabData(ML_PLAYLIST);
152
153 return true;
154 }
155 return false;
156 }
157
OnAddToPlaylistCommand(std::function<void (std::vector<SongInfo> &)> get_song_list,DWORD command)158 bool CMusicPlayerCmdHelper::OnAddToPlaylistCommand(std::function<void(std::vector<SongInfo>&)> get_song_list, DWORD command)
159 {
160 //响应播放列表右键菜单中的“添加到播放列表”
161 if ((command >= ID_ADD_TO_DEFAULT_PLAYLIST && command <= ID_ADD_TO_MY_FAVOURITE + ADD_TO_PLAYLIST_MAX_SIZE) || command == ID_ADD_TO_OTHER_PLAYLIST)
162 {
163 //获取选中的曲目
164 std::vector<SongInfo> selected_item_path;
165 get_song_list(selected_item_path);
166
167 if (command == ID_ADD_TO_OTHER_PLAYLIST)
168 {
169 CAddToPlaylistDlg dlg;
170 if (dlg.DoModal() == IDOK)
171 {
172 wstring playlist_path = theApp.m_playlist_dir + dlg.GetPlaylistSelected() + PLAYLIST_EXTENSION;
173 if (CCommon::FileExist(playlist_path))
174 {
175 AddToPlaylist(selected_item_path, playlist_path);
176 }
177 }
178 }
179 else if (command == ID_ADD_TO_DEFAULT_PLAYLIST) //添加到默认播放列表
180 {
181 std::wstring default_playlist_path = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_DEFAULT).path;
182 AddToPlaylist(selected_item_path, default_playlist_path);
183 }
184 else if (command == ID_ADD_TO_MY_FAVOURITE) //添加到“我喜欢”播放列表
185 {
186 std::wstring favourite_playlist_path = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE).path;
187 AddToPlaylist(selected_item_path, favourite_playlist_path);
188
189 //添加到“我喜欢”播放列表后,为添加的项目设置favourite标记
190 for (const auto& item : selected_item_path)
191 {
192 auto& cur_playlist{ CPlayer::GetInstance().GetPlayList() };
193 auto iter = std::find_if(cur_playlist.begin(), cur_playlist.end(), [&](const SongInfo& song)
194 {
195 return item.IsSameSong(song);
196 });
197 if (iter != cur_playlist.end())
198 iter->is_favourite = true;
199 }
200 //for (auto i : m_items_selected)
201 //{
202 // if (i >= 0 && i < CPlayer::GetInstance().GetSongNum())
203 // {
204 // CPlayer::GetInstance().GetPlayList()[i].is_favourite = true;
205 // }
206 //}
207
208 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
209 }
210 else //添加到选中的播放列表
211 {
212 int index = command - ID_ADD_TO_MY_FAVOURITE - 1;
213 CListCache list_cache(LT_PLAYLIST_NO_SPEC); // 应改为让theApp持有此CListCache,仅在菜单重建前reload
214 list_cache.reload();
215 ListItem list_item = list_cache.GetItem(index);
216 if (CCommon::FileExist(list_item.path))
217 {
218 AddToPlaylist(selected_item_path, list_item.path);
219 }
220 else
221 {
222 wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_PLAYLIST_ADD_SONGS_FAILED",
223 { CFilePathHelper(list_item.path).GetFileNameWithoutExtension() });
224 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
225 }
226 }
227 return true;
228 }
229 return false;
230 }
231
DeleteSongsFromDisk(const std::vector<SongInfo> & files)232 bool CMusicPlayerCmdHelper::DeleteSongsFromDisk(const std::vector<SongInfo>& files)
233 {
234 if (theApp.m_media_lib_setting_data.disable_delete_from_disk)
235 return false;
236
237 if (files.empty())
238 return false;
239
240 wstring info;
241 if (files.size() == 1)
242 info = theApp.m_str_table.LoadTextFormat(L"MSG_DELETE_SINGLE_FILE_INQUIRY", { files.front().file_path });
243 else
244 info = theApp.m_str_table.LoadTextFormat(L"MSG_DELETE_SEL_AUDIO_FILE_INQUIRY", { files.size() });
245 if (GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OKCANCEL) != IDOK)
246 return false;
247
248 vector<wstring> delected_files;
249 for (const auto& song : files)
250 {
251 if (!song.is_cue && !COSUPlayerHelper::IsOsuFile(song.file_path))
252 delected_files.push_back(song.file_path);
253
254 }
255 if (delected_files.empty())
256 return false;
257
258 wstring current_file = CPlayer::GetInstance().GetCurrentSongInfo().file_path;
259 //如何要删除的文件是正在播放的文件,则先停止播放
260 if (CCommon::IsItemInVector(delected_files, current_file))
261 {
262 CPlayer::GetInstance().GetPlayStatusMutex().lock();
263 CPlayer::GetInstance().MusicControl(Command::STOP);
264 CPlayer::GetInstance().MusicControl(Command::CLOSE);
265 CPlayer::GetInstance().GetPlayStatusMutex().unlock();
266 }
267 int rtn{};
268 rtn = CommonDialogMgr::DeleteFiles(GetOwner()->m_hWnd, delected_files);
269 if (rtn == 0)
270 {
271 //如果文件删除成功,则从歌曲数据中删除
272 for (const auto& file : delected_files)
273 {
274 CSongDataManager::GetInstance().RemoveItem(file);
275 }
276 //文件删除后同时删除和文件同名的图片文件和歌词文件
277 for (auto& file : delected_files)
278 {
279 CFilePathHelper file_path(file);
280 file = file_path.ReplaceFileExtension(L"jpg").c_str();
281 }
282 CommonDialogMgr::DeleteFiles(GetOwner()->m_hWnd, delected_files);
283 for (const wstring& ext : CLyrics::m_surpported_lyric) // 删除所有后缀的歌词
284 {
285 for (auto& file : delected_files)
286 {
287 CFilePathHelper file_path(file);
288 file = file_path.ReplaceFileExtension(ext.c_str()).c_str();
289 }
290 CommonDialogMgr::DeleteFiles(GetOwner()->m_hWnd, delected_files);
291 }
292 }
293 else if (rtn == 1223) //如果在弹出的对话框中点击“取消”则返回值为1223
294 {
295 return false;
296 }
297 else
298 {
299 GetOwner()->MessageBox(theApp.m_str_table.LoadText(L"MSG_DELETE_FILE_FAILED").c_str(), NULL, MB_ICONWARNING);
300 return false;
301 }
302 return true;
303 }
304
SearchLyricFiles(const wstring & lyric_name,const wstring & cur_dir,std::vector<std::wstring> & result,bool fuzzy_match)305 void CMusicPlayerCmdHelper::SearchLyricFiles(const wstring& lyric_name, const wstring& cur_dir, std::vector<std::wstring>& result, bool fuzzy_match)
306 {
307 result.clear();
308
309 // 查找歌词文件名和搜索关键词完全匹配的歌词
310 CFilePathHelper lyric_path{ cur_dir + lyric_name + L".lrc"}; // 得到路径+文件名的字符串,预先加扩展名防止之后ReplaceFileExtension替换误伤
311
312 // 按顺序列出所有需要查找的目录
313 vector<wstring> path_list{ cur_dir };
314 if (CCommon::FolderExist(theApp.m_lyric_setting_data.lyric_path))
315 {
316 path_list.push_back(theApp.m_lyric_setting_data.lyric_path);
317 }
318
319 // 完全匹配搜索,使用CCommon::FileExist的快速查找
320 for (const wstring& pa : path_list)
321 {
322 lyric_path.SetFilePath(pa + lyric_path.GetFileName());
323 for (const wstring& ext : CLyrics::m_surpported_lyric)
324 {
325 lyric_path.ReplaceFileExtension(ext.c_str());
326 if (CCommon::FileExist(lyric_path.GetFilePath()))
327 result.push_back(lyric_path.GetFilePath());
328 }
329 }
330
331 // 列出所有搜索路径内的歌词文件
332 vector<vector<wstring>> path_lyrics;
333 path_lyrics.resize(path_list.size());
334 for (int i{}; i < static_cast<int>(path_list.size()); ++i)
335 {
336 CAudioCommon::GetLyricFiles(path_list[i], path_lyrics[i]);
337 }
338
339 //将查找的歌词名称拆分成若干个子字符串
340 vector<wstring> key_words;
341 CCommon::StringSplit(lyric_name, L'-', key_words);
342 for (auto& key_word : key_words)
343 {
344 CCommon::StringNormalize(key_word);
345 CCommon::FileNameNormalize(key_word);
346 }
347
348 // 判断一个字符串是否匹配key_words中任意一个关键字(根据是否模糊搜索使用不同方式)
349 auto isMatched = [&](const wstring& str, const vector<wstring>& key_words)
350 {
351 if (fuzzy_match)
352 {
353 //如果是部分匹配,则只需要有一个关键字匹配,就返回true
354 for (const auto& key_word : key_words)
355 {
356 if (CCommon::StringNatchWholeWord(str, key_word) != -1)
357 return true;
358 }
359 return false;
360 }
361 else
362 {
363 //否则,需要所有关键字都匹配才返回true
364 for (const auto& key_word : key_words)
365 {
366 if (CCommon::StringNatchWholeWord(str, key_word) == -1)
367 return false;
368 }
369 return true;
370 }
371 };
372
373 for (int i{}; i < static_cast<int>(path_lyrics.size()); ++i)
374 {
375 const vector<wstring>& cur_path = path_lyrics[i];
376 for (const wstring& str : cur_path)
377 {
378 if (isMatched(str, key_words))
379 {
380 wstring matched_lyric = path_list[i] + str;
381 if (!CCommon::IsItemInVector(result, matched_lyric))
382 result.push_back(matched_lyric);
383 }
384 }
385 }
386 }
387
SearchLyricFile(const SongInfo & song,bool fuzzy_match)388 std::wstring CMusicPlayerCmdHelper::SearchLyricFile(const SongInfo& song, bool fuzzy_match)
389 {
390 if (song.GetFileName().size() < 3) return wstring();
391
392 // cue与osu文件禁止按音频文件名搜索,无视模糊搜索,优先搜索“艺术家 - 标题”
393 bool find_org_name{ !song.is_cue && !COSUPlayerHelper::IsOsuFile(song.file_path) };
394 CFilePathHelper lyric_path{ song.file_path };
395 if (!find_org_name)
396 {
397 wstring ar_ti{ song.artist + L" - " + song.title + L".lrc"}; // 预先加扩展名防止之后ReplaceFileExtension替换误伤
398 CCommon::FileNameNormalize(ar_ti);
399 lyric_path.SetFilePath(lyric_path.GetDir() + ar_ti);
400 }
401
402 // 按顺序列出所有需要查找的目录
403 vector<wstring> path_list{ lyric_path.GetDir() };
404 if (CCommon::FolderExist(theApp.m_lyric_setting_data.lyric_path))
405 {
406 path_list.push_back(theApp.m_lyric_setting_data.lyric_path);
407 }
408
409 // 完全匹配搜索,使用CCommon::FileExist的快速查找
410 for (const wstring& pa : path_list)
411 {
412 lyric_path.SetFilePath(pa + lyric_path.GetFileName());
413 for (const wstring& ext : CLyrics::m_surpported_lyric)
414 {
415 lyric_path.ReplaceFileExtension(ext.c_str());
416 if (CCommon::FileExist(lyric_path.GetFilePath()))
417 return lyric_path.GetFilePath();
418 }
419 }
420 // 进行模糊查找,由于需要列出所有歌词文件所以较慢
421 if (fuzzy_match)
422 {
423 // 列出所有搜索路径内的歌词文件
424 vector<vector<wstring>> path_lyrics;
425 path_lyrics.resize(path_list.size());
426 for (int i{}; i < static_cast<int>(path_list.size()); ++i)
427 {
428 CAudioCommon::GetLyricFiles(path_list[i], path_lyrics[i]);
429 }
430 wstring matched_lyric; // 匹配的歌词的路径
431 wstring title{ song.title }, artist{ song.artist };
432 CCommon::FileNameNormalize(title);
433 CCommon::FileNameNormalize(artist);
434 // 先寻找歌词文件中同时包含歌曲标题和艺术家的歌词文件
435 for (int i{}; i < static_cast<int>(path_lyrics.size()); ++i)
436 {
437 const vector<wstring>& cur_path = path_lyrics[i];
438 for (const wstring& str : cur_path)
439 {
440 if (CCommon::StringNatchWholeWord(str, artist) != -1 && CCommon::StringNatchWholeWord(str, title) != -1)
441 {
442 matched_lyric = path_list[i] + str;
443 return matched_lyric;
444 }
445 }
446 }
447 // 没有找到的话就寻找歌词文件中只包含歌曲标题的歌词文件
448 for (int i{}; i < static_cast<int>(path_lyrics.size()); ++i)
449 {
450 const vector<wstring>& cur_path = path_lyrics[i];
451 for (const wstring& str : cur_path)
452 {
453 if (CCommon::StringNatchWholeWord(str, title) != -1)
454 {
455 matched_lyric = path_list[i] + str;
456 return matched_lyric;
457 }
458 }
459 }
460 }
461 return wstring();
462 }
463
SearchAlbumCover(const SongInfo & song)464 std::wstring CMusicPlayerCmdHelper::SearchAlbumCover(const SongInfo& song)
465 {
466 wstring album_cover_path;
467 if (COSUPlayerHelper::IsOsuFile(song.file_path))
468 {
469 album_cover_path = COSUPlayerHelper::GetAlbumCover(song.file_path);
470 if (album_cover_path.empty())
471 album_cover_path = theApp.m_nc_setting_data.default_osu_img;
472 }
473 else
474 {
475 vector<wstring> files;
476 wstring file_name;
477 //查找文件和歌曲名一致的图片文件
478 CFilePathHelper c_file_path(song.file_path);
479 //file_name = m_path + c_file_name.GetFileNameWithoutExtension() + L".*";
480 c_file_path.ReplaceFileExtension(L"*");
481 wstring dir{ c_file_path.GetDir() };
482 CCommon::GetImageFiles(c_file_path.GetFilePath(), files);
483 if (files.empty() && !song.album.empty())
484 {
485 //没有找到和歌曲名一致的图片文件,则查找文件名为“唱片集”的文件
486 wstring album_name{ song.album };
487 CCommon::FileNameNormalize(album_name);
488 file_name = dir + album_name + L".*";
489 CCommon::GetImageFiles(file_name, files);
490 }
491 if (!files.empty())
492 album_cover_path = dir + files[0];
493 // 没有找到唱片集为文件名的文件,查找文件名为设置的专辑封面名的文件
494 else if (theApp.m_app_setting_data.use_out_image)
495 {
496 wstring absolute_dir;
497 // 按照默认封面文件名列表查找歌曲所在目录,如遇到绝对路径则存入absolute_dir
498 for (const auto& album_name : theApp.m_app_setting_data.default_album_name)
499 {
500 if (!album_name.empty())
501 {
502 if (absolute_dir.empty() && CCommon::IsPath(album_name) && CCommon::FileExist(album_name))
503 {
504 absolute_dir = album_name;
505 continue;
506 }
507 file_name = CCommon::RelativePathToAbsolutePath(album_name + L".*", dir);
508 CCommon::GetImageFiles(file_name, files);
509 }
510 if (!files.empty())
511 {
512 // 处理album_name可能含有相对路径的情况,files[0]仅有文件名
513 // 由于album_name中文件名部分可能含有通配符所以不能只替换后缀,需要替换整个文件名
514 size_t index = file_name.rfind('\\');
515 album_cover_path = file_name.substr(0, index + 1) + files[0];
516 break;
517 }
518 }
519 // 按照歌曲名、唱片名查找封面文件夹album_path
520 if (album_cover_path.empty())
521 {
522 CCommon::GetImageFiles(theApp.m_app_setting_data.album_cover_path + c_file_path.GetFileName(), files);
523 if (files.empty() && !song.album.empty())
524 {
525 // 没有找到和歌曲名一致的图片文件,则查找文件名为“唱片集”的文件
526 wstring album_name{ song.album };
527 CCommon::FileNameNormalize(album_name);
528 file_name = theApp.m_app_setting_data.album_cover_path + album_name + L".*";
529 CCommon::GetImageFiles(file_name, files);
530 }
531 if (!files.empty())
532 album_cover_path = theApp.m_app_setting_data.album_cover_path + files[0];
533 }
534 // 使用默认封面文件名列表中的绝对路径
535 if (album_cover_path.empty())
536 album_cover_path = absolute_dir;
537 }
538 }
539 return album_cover_path;
540 }
541
OnRating(const SongInfo & song,DWORD command)542 bool CMusicPlayerCmdHelper::OnRating(const SongInfo& song, DWORD command)
543 {
544 if ((command >= ID_RATING_1 && command <= ID_RATING_5) || command == ID_RATING_NONE) //如果命令是歌曲分级(应确保分级命令的ID是连续的)
545 {
546 int rating = 0;
547 if (command >= ID_RATING_1 && command <= ID_RATING_5)
548 rating = command - ID_RATING_1 + 1;
549 SongInfo song_info{ CSongDataManager::GetInstance().GetSongInfo3(song) };
550 song_info.rating = static_cast<BYTE>(rating);
551 bool succeed{};
552 // cue、osu!、不支持写入的文件分级只保存到媒体库
553 if (CAudioTag::IsFileRatingSupport(CFilePathHelper(song_info.file_path).GetFileExtension()) && !song_info.is_cue && !COSUPlayerHelper::IsOsuFile(song_info.file_path))
554 {
555 CAudioTag audio_tag(song_info);
556 succeed = audio_tag.WriteAudioRating();
557 }
558 else
559 {
560 succeed = true; //如果文件格式不支持写入分级,也返回true
561 }
562 CSongDataManager::GetInstance().AddItem(song_info);
563 return succeed;
564 }
565 return true;
566 }
567
UpdateMediaLib()568 int CMusicPlayerCmdHelper::UpdateMediaLib()
569 {
570 if (CPlayer::GetInstance().IsMciCore())
571 return 0;
572
573 vector<SongInfo> all_media_songs;
574 //获取所有音频文件的路径
575 for (const auto& item : theApp.m_media_lib_setting_data.media_folders)
576 {
577 CAudioCommon::GetAudioFiles(item, all_media_songs, MAX_SONG_NUM, true);
578 }
579
580 CAudioCommon::GetAudioInfo(all_media_songs,
581 theApp.m_media_update_para.num_added,
582 theApp.m_media_update_para.thread_exit,
583 theApp.m_media_update_para.process_percent,
584 theApp.m_media_update_para.force ? MR_FOECE_FULL : MR_FILE_MODIFICATION,
585 theApp.m_media_lib_setting_data.ignore_too_short_when_update
586 );
587
588 return theApp.m_media_update_para.num_added;
589 }
590
CleanUpSongData(std::function<bool (const SongInfo &)> fun_condition)591 int CMusicPlayerCmdHelper::CleanUpSongData(std::function<bool(const SongInfo&)> fun_condition)
592 {
593 return CSongDataManager::GetInstance().RemoveItemIf(fun_condition);
594 }
595
CleanUpRecentFolders()596 int CMusicPlayerCmdHelper::CleanUpRecentFolders()
597 {
598 int cleard_cnt = CRecentList::Instance().RemoveItemIf([](const ListItem& list_item)
599 { return list_item.type == LT_FOLDER && !CAudioCommon::IsPathContainsAudioFile(list_item.path, list_item.contain_sub_folder); });
600 CRecentList::Instance().SaveData();
601 return cleard_cnt;
602 }
603
GetMediaLibTabName(eMediaLibTab tab)604 std::wstring CMusicPlayerCmdHelper::GetMediaLibTabName(eMediaLibTab tab)
605 {
606 switch (tab)
607 {
608 case CMusicPlayerCmdHelper::ML_FOLDER: return theApp.m_str_table.LoadText(L"TXT_FOLDER");
609 case CMusicPlayerCmdHelper::ML_PLAYLIST: return theApp.m_str_table.LoadText(L"TXT_PLAYLIST");
610 case CMusicPlayerCmdHelper::ML_ARTIST: return theApp.m_str_table.LoadText(L"TXT_ARTIST");
611 case CMusicPlayerCmdHelper::ML_ALBUM: return theApp.m_str_table.LoadText(L"TXT_ALBUM");
612 case CMusicPlayerCmdHelper::ML_GENRE: return theApp.m_str_table.LoadText(L"TXT_GENRE");
613 case CMusicPlayerCmdHelper::ML_YEAR: return theApp.m_str_table.LoadText(L"TXT_YEAR");
614 case CMusicPlayerCmdHelper::ML_FILE_TYPE: return theApp.m_str_table.LoadText(L"TXT_FILE_TYPE");
615 case CMusicPlayerCmdHelper::ML_BITRATE: return theApp.m_str_table.LoadText(L"TXT_BITRATE");
616 case CMusicPlayerCmdHelper::ML_RATING: return theApp.m_str_table.LoadText(L"TXT_RATING");
617 }
618 return std::wstring();
619 }
620
ShowMediaLib(int cur_tab,int tab_force_show)621 void CMusicPlayerCmdHelper::ShowMediaLib(int cur_tab /*= -1*/, int tab_force_show)
622 {
623 CMusicPlayerDlg* pPlayerDlg = CMusicPlayerDlg::GetInstance();
624 if (pPlayerDlg == nullptr)
625 return;
626
627 bool dlg_exist = (pPlayerDlg->m_pMediaLibDlg != nullptr && IsWindow(pPlayerDlg->m_pMediaLibDlg->m_hWnd)); //媒体库对话框是否已经存在
628 bool tab_not_show = (~theApp.m_media_lib_setting_data.display_item & tab_force_show); //如果有要强制显示的标签但是媒体库设置中此标签不显示
629
630 //判断要显示的标签是否被隐藏
631 bool is_cur_tab_hide{ false };
632 if (cur_tab != ML_FOLDER && cur_tab != ML_PLAYLIST) //文件夹和播放列表标签无法被隐藏
633 {
634 int test_item_bit = 1 << (cur_tab - 2);
635 is_cur_tab_hide = !(theApp.m_media_lib_setting_data.display_item & test_item_bit);
636 }
637
638 //没有没有指定要强制显示的标签,且要显示的标签被隐藏,则将cur_tab置为-1,保持上次的标签
639 if (tab_force_show == 0 && is_cur_tab_hide)
640 {
641 cur_tab = -1;
642 }
643 else
644 {
645 //计算实际的tab序号(参数cur_tab为媒体库中标签的序号,但是如果有标签不显示,则此序号将不正确,因此这里需要根据实际显示的标签计算出真正的tab序号)
646 int shown_tab = theApp.m_media_lib_setting_data.display_item | tab_force_show; //实际要显示的标签
647 int tab_num = cur_tab - 2; //除去“文件夹”和“播放列表”两个标签(因为这两个标签总是显示,无法隐藏)
648 for (int i = 0; i < tab_num; i++) //遍历cur_tab及前面的所有标签,检查是否有未显示出来的标签
649 {
650 int tab_mask = 1 << i;
651 if ((shown_tab & tab_mask) == 0) //如果有未显示出来的标签,则当前标签序号减1
652 cur_tab--;
653 }
654 }
655
656 if (dlg_exist && !tab_not_show)
657 {
658 pPlayerDlg->m_pMediaLibDlg->SetTabForceShow(tab_force_show);
659 pPlayerDlg->m_pMediaLibDlg->ShowWindow(SW_SHOWNORMAL);
660 pPlayerDlg->m_pMediaLibDlg->SetForegroundWindow();
661 pPlayerDlg->m_pMediaLibDlg->SetCurTab(cur_tab);
662 }
663 else //如果对话框不存在,或有需要强制显示但是媒体库库中设置不显示的的标签,则需要重新打开媒体库对话框
664 {
665 CCommon::DeleteModelessDialog(pPlayerDlg->m_pMediaLibDlg);
666 pPlayerDlg->m_pMediaLibDlg = new CMediaLibDlg(cur_tab);
667 pPlayerDlg->m_pMediaLibDlg->SetTabForceShow(tab_force_show);
668 pPlayerDlg->m_pMediaLibDlg->Create(IDD_MEDIA_LIB_DIALOG/*, GetDesktopWindow()*/);
669 pPlayerDlg->m_pMediaLibDlg->ShowWindow(SW_SHOW);
670 }
671 }
672
RefreshMediaTabData(eMediaLibTab tab_index)673 void CMusicPlayerCmdHelper::RefreshMediaTabData(eMediaLibTab tab_index)
674 {
675 CMusicPlayerDlg* pPlayerDlg = CMusicPlayerDlg::GetInstance();
676 if (pPlayerDlg != nullptr && pPlayerDlg->m_pMediaLibDlg != nullptr && IsWindow(pPlayerDlg->m_pMediaLibDlg->GetSafeHwnd()))
677 {
678 if (tab_index == ML_FOLDER)
679 pPlayerDlg->m_pMediaLibDlg->m_path_dlg->RefreshTabData(); // 刷新媒体库文件夹列表
680 else if(tab_index == ML_PLAYLIST)
681 pPlayerDlg->m_pMediaLibDlg->m_playlist_dlg->RefreshTabData(); // 刷新媒体库播放列表列表
682 }
683 }
684
OnViewInMediaLib(eMediaLibTab tab,const std::wstring name)685 void CMusicPlayerCmdHelper::OnViewInMediaLib(eMediaLibTab tab, const std::wstring name)
686 {
687 int tab_force_show{};
688 switch (tab)
689 {
690 case CMusicPlayerCmdHelper::ML_ARTIST: tab_force_show = MLDI_ARTIST; break;
691 case CMusicPlayerCmdHelper::ML_ALBUM: tab_force_show = MLDI_ALBUM; break;
692 case CMusicPlayerCmdHelper::ML_GENRE: tab_force_show = MLDI_GENRE; break;
693 case CMusicPlayerCmdHelper::ML_YEAR: tab_force_show = MLDI_YEAR; break;
694 case CMusicPlayerCmdHelper::ML_FILE_TYPE: tab_force_show = MLDI_TYPE; break;
695 case CMusicPlayerCmdHelper::ML_BITRATE: tab_force_show = MLDI_BITRATE; break;
696 case CMusicPlayerCmdHelper::ML_RATING: tab_force_show = MLDI_RATING; break;
697 case CMusicPlayerCmdHelper::ML_ALL: tab_force_show = MLDI_ALL; break;
698 }
699 ShowMediaLib(tab, tab_force_show);
700 CMusicPlayerDlg* pPlayerDlg = CMusicPlayerDlg::GetInstance();
701 if (!name.empty())
702 {
703 if (!pPlayerDlg->m_pMediaLibDlg->NavigateToItem(name))
704 {
705 wstring type_name = GetMediaLibTabName(tab);
706 wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_CANNOT_FIND_IN_MEDIA_LIB_WARNING", { type_name, name });
707 pPlayerDlg->MessageBox(info.c_str(), NULL, MB_OK | MB_ICONWARNING);
708 }
709 }
710 }
711
OnViewInMediaLib(const ListItem & list_item)712 void CMusicPlayerCmdHelper::OnViewInMediaLib(const ListItem& list_item)
713 {
714 CMusicPlayerCmdHelper::eMediaLibTab tab{};
715 switch (list_item.type)
716 {
717 case LT_FOLDER: tab = CMusicPlayerCmdHelper::ML_FOLDER; break;
718 case LT_PLAYLIST: tab = CMusicPlayerCmdHelper::ML_PLAYLIST; break;
719 case LT_MEDIA_LIB:
720 switch (list_item.medialib_type)
721 {
722 case CMediaClassifier::CT_ARTIST: tab = CMusicPlayerCmdHelper::ML_ARTIST; break;
723 case CMediaClassifier::CT_ALBUM: tab = CMusicPlayerCmdHelper::ML_ALBUM; break;
724 case CMediaClassifier::CT_GENRE: tab = CMusicPlayerCmdHelper::ML_GENRE; break;
725 case CMediaClassifier::CT_YEAR: tab = CMusicPlayerCmdHelper::ML_YEAR; break;
726 case CMediaClassifier::CT_TYPE: tab = CMusicPlayerCmdHelper::ML_FILE_TYPE; break;
727 case CMediaClassifier::CT_BITRATE: tab = CMusicPlayerCmdHelper::ML_BITRATE; break;
728 case CMediaClassifier::CT_RATING: tab = CMusicPlayerCmdHelper::ML_RATING; break;
729 case CMediaClassifier::CT_NONE: tab = CMusicPlayerCmdHelper::ML_ALL; break;
730 }
731 }
732 OnViewInMediaLib(tab, list_item.path);
733 }
734
OnViewArtist(const SongInfo & song_info)735 void CMusicPlayerCmdHelper::OnViewArtist(const SongInfo& song_info)
736 {
737 vector<wstring> artist_list;
738 song_info.GetArtistList(artist_list); // 获取艺术家(可能有多个)
739 wstring artist;
740 if (artist_list.empty())
741 {
742 return;
743 }
744 else if (artist_list.size() == 1)
745 {
746 artist = artist_list.front();
747 }
748 else
749 {
750 //如果有多个艺术家,弹出“选择艺术家”对话框
751 CSelectItemDlg dlg(artist_list);
752 dlg.SetTitle(theApp.m_str_table.LoadText(L"TITLE_SELECT_ARTIST").c_str());
753 dlg.SetDlgIcon(IconMgr::IconType::IT_Artist);
754 if (dlg.DoModal() == IDOK)
755 artist = dlg.GetSelectedItem();
756 else
757 return;
758 }
759 OnViewInMediaLib(CMusicPlayerCmdHelper::ML_ARTIST, artist);
760 }
761
OnViewAlbum(const SongInfo & song_info)762 void CMusicPlayerCmdHelper::OnViewAlbum(const SongInfo& song_info)
763 {
764 wstring album = song_info.GetAlbum();
765 OnViewInMediaLib(CMusicPlayerCmdHelper::ML_ALBUM, album);
766 }
767
FixPlaylistPathError(const std::wstring & path) const768 int CMusicPlayerCmdHelper::FixPlaylistPathError(const std::wstring& path) const
769 {
770 std::unordered_map<std::wstring, std::set<std::wstring>> song_file_name_map;
771 CSongDataManager::GetInstance().GetSongData([&](const CSongDataManager::SongDataMap& song_data_map) {
772 for (const auto& song_item : song_data_map)
773 {
774 if (!song_item.second.is_cue)
775 {
776 std::wstring file_name = song_item.second.GetFileName();
777 song_file_name_map[file_name].insert(song_item.second.file_path);
778 }
779 }
780 });
781
782 vector<SongInfo> song_list;
783 CPlaylistFile playlist_file;
784 playlist_file.LoadFromFile(path);
785 playlist_file.MoveToSongList(song_list); // move后playlist_file对象不再可用
786 int fixed_count{};
787 for (auto& song : song_list)
788 {
789 if (!song.is_cue && !CCommon::FileExist(song.file_path))
790 {
791 if (FixWrongFilePath(song.file_path, song_file_name_map))
792 fixed_count++;
793 }
794 }
795 if (fixed_count > 0)
796 {
797 //保存播放列表到文件
798 CPlaylistFile::SavePlaylistToFile(song_list, path);
799
800 //如果处理的是正在播放的播放列表
801 if (CPlayer::GetInstance().IsPlaylistMode() && CPlayer::GetInstance().GetPlaylistPath() == path)
802 {
803 CPlayer::GetInstance().ReloadPlaylist(MR_MIN_REQUIRED);
804 }
805 }
806 return fixed_count;
807 }
808
809 //计算两个字符串右侧匹配的字符数量
CalcualteStringRightMatchedCharNum(const std::wstring & str1,const std::wstring & str2)810 static int CalcualteStringRightMatchedCharNum(const std::wstring& str1, const std::wstring& str2)
811 {
812 size_t index1{ str1.size() - 1 };
813 size_t index2{ str2.size() - 1 };
814 int char_matched{};
815 for (; index1 >= 0 && index2 >= 0; index1--, index2--)
816 {
817 if (str1[index1] == str2[index2])
818 char_matched++;
819 else
820 break;
821 }
822 return char_matched;
823 }
824
FixWrongFilePath(wstring & file_path,const std::unordered_map<std::wstring,std::set<std::wstring>> & song_file_name_map) const825 bool CMusicPlayerCmdHelper::FixWrongFilePath(wstring& file_path, const std::unordered_map<std::wstring, std::set<std::wstring>>& song_file_name_map) const
826 {
827 std::wstring file_name{ CFilePathHelper(file_path).GetFileName() };
828 bool fixed{ false };
829 auto iter = song_file_name_map.find(file_name);
830 if (iter != song_file_name_map.end())
831 {
832 if (iter->second.size() == 1) //媒体库中同名的文件只有一个时,直接修改为该文件的路径
833 {
834 if (CCommon::FileExist(*iter->second.begin()))
835 {
836 file_path = *iter->second.begin();
837 fixed = true;
838 }
839 }
840 else if (iter->second.size() > 1) //媒体库中同名的文件有多个时,查找两个路径末尾相同字符数量最多的那项
841 {
842 std::wstring best_match_path;
843 int max_matched_char_mun{};
844 for (const auto& path : iter->second)
845 {
846 if (!CCommon::FileExist(path))
847 continue;
848 int cur_matched_char_num = CalcualteStringRightMatchedCharNum(file_path, path);
849 if (cur_matched_char_num > max_matched_char_mun)
850 {
851 max_matched_char_mun = cur_matched_char_num;
852 best_match_path = path;
853 }
854 }
855 file_path = best_match_path;
856 fixed = true;
857 }
858 }
859 return fixed;
860 }
861
OnListItemSelected(const ListItem & list_item,bool play)862 void CMusicPlayerCmdHelper::OnListItemSelected(const ListItem& list_item, bool play)
863 {
864 if (list_item.empty())
865 return;
866 if (!CPlayer::GetInstance().SetList(list_item, play))
867 {
868 const wstring& info = theApp.m_str_table.LoadText(L"MSG_WAIT_AND_RETRY");
869 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
870 }
871 }
872
OnRenamePlaylist(const ListItem & list_item)873 bool CMusicPlayerCmdHelper::OnRenamePlaylist(const ListItem& list_item)
874 {
875 if (list_item.empty() || CRecentList::IsSpecPlaylist(list_item))
876 return false;
877
878 CInputDlg imput_dlg;
879 imput_dlg.SetTitle(theApp.m_str_table.LoadText(L"TITLE_RENAME_PLAYLIST").c_str());
880 imput_dlg.SetInfoText(theApp.m_str_table.LoadText(L"TXT_RENAME_PLAYLIST_INPUT_PLAYLIST_NAME").c_str());
881 imput_dlg.SetEditText(CFilePathHelper(list_item.path).GetFileNameWithoutExtension().c_str());
882 if (imput_dlg.DoModal() != IDOK)
883 return false;
884
885 wstring new_playlist_name{ imput_dlg.GetEditText() };
886 if (new_playlist_name.empty())
887 {
888 const wstring& info = theApp.m_str_table.LoadText(L"MSG_PLAYLIST_NAME_EMPTY_WARNING");
889 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
890 return false;
891 }
892 if (!CCommon::IsFileNameValid(new_playlist_name))
893 {
894 const wstring& info = theApp.m_str_table.LoadText(L"MSG_FILE_NAME_INVALID_WARNING");
895 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
896 return false;
897 }
898 if (CCommon::FileExist(theApp.m_playlist_dir + new_playlist_name + PLAYLIST_EXTENSION))
899 {
900 wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_PLAYLIST_EXIST_WARNING", { new_playlist_name });
901 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
902 return false;
903 }
904
905 wstring new_path = CCommon::FileRename(list_item.path, new_playlist_name); //播放列表后命名后的路径
906 if (new_path.empty())
907 {
908 const wstring& info = theApp.m_str_table.LoadText(L"MSG_PLAYLIST_RENANE_FAILED");
909 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
910 return false;
911 }
912 if (list_item.path == new_path)
913 return false;
914 // 如果重命名的播放是当前播放的播放列表,就重新设置当前播放列表的路径 (之后应该改成进入列表初始化流程)
915 if (CRecentList::Instance().IsCurrentList(list_item))
916 {
917 CPlayer::GetInstance().SetPlaylistPath(new_path); // 更新m_playlist_path变量
918 theApp.m_pMainWnd->SendMessage(WM_CUR_PLAYLIST_RENAMED); // 更新主窗口m_path_edit控件文字
919 }
920 CRecentList::Instance().RenamePlaylist(list_item, new_path);
921 CRecentList::Instance().SaveData();
922 return true;
923 }
924
925
OnNewPlaylist(const wstring & copy_from_playlist)926 wstring CMusicPlayerCmdHelper::OnNewPlaylist(const wstring& copy_from_playlist)
927 {
928 CInputDlg imput_dlg(GetOwner());
929 imput_dlg.SetTitle(theApp.m_str_table.LoadText(L"TITLE_NEW_PLAYLIST").c_str());
930 imput_dlg.SetInfoText(theApp.m_str_table.LoadText(L"TXT_NEW_PLAYLIST_INPUT_PLAYLIST_NAME").c_str());
931 if (imput_dlg.DoModal() != IDOK)
932 return wstring();
933 wstring playlist_name = imput_dlg.GetEditText().GetString();
934 if (playlist_name.empty())
935 {
936 const wstring& info = theApp.m_str_table.LoadText(L"MSG_PLAYLIST_NAME_EMPTY_WARNING");
937 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
938 return wstring();
939 }
940 if (!CCommon::IsFileNameValid(playlist_name))
941 {
942 const wstring& info = theApp.m_str_table.LoadText(L"MSG_FILE_NAME_INVALID_WARNING");
943 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
944 return wstring();
945 }
946 wstring playlist_path = theApp.m_playlist_dir + playlist_name + PLAYLIST_EXTENSION;
947 if (CCommon::FileExist(playlist_path))
948 {
949 wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_PLAYLIST_EXIST_WARNING", { playlist_name });
950 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONWARNING | MB_OK);
951 return wstring();
952 }
953 if (copy_from_playlist.empty())
954 CRecentList::Instance().AddNewItem(ListItem{ LT_PLAYLIST, playlist_path });
955 else
956 {
957 ListItem list_item{ LT_PLAYLIST, copy_from_playlist };
958 if (!CRecentList::Instance().LoadItem(list_item)) // 继承“copy_from_playlist”的 总计时长/总计曲目数
959 return wstring(); // LoadItem返回false说明copy_from_playlist不存在,不继续执行
960 CopyFile(copy_from_playlist.c_str(), playlist_path.c_str(), FALSE);
961 list_item.path = playlist_path;
962 CRecentList::Instance().AddNewItem(list_item);
963 }
964 CRecentList::Instance().SaveData();
965 return playlist_path;
966
967 }
968
OnPlaylistSaveAs(const std::wstring & playlist_path)969 void CMusicPlayerCmdHelper::OnPlaylistSaveAs(const std::wstring& playlist_path)
970 {
971 wstring filter = FilterHelper::GetPlaylistSaveAsFilter();
972 CFileDialog fileDlg(FALSE, _T("m3u"), CFilePathHelper(playlist_path).GetFileNameWithoutExtension().c_str(), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, filter.c_str(), GetOwner());
973 if (IDOK == fileDlg.DoModal())
974 {
975 CPlaylistFile playlist;
976 playlist.LoadFromFile(playlist_path);
977 //将播放列表保存到文件
978 wstring file_path{ fileDlg.GetPathName() };
979 wstring file_extension{ fileDlg.GetFileExt() };
980 file_extension = L'.' + file_extension;
981 CPlaylistFile::Type file_type{};
982 if (file_extension == PLAYLIST_EXTENSION)
983 file_type = CPlaylistFile::PL_PLAYLIST;
984 else if (file_extension == L".m3u")
985 file_type = CPlaylistFile::PL_M3U;
986 else if (file_extension == L".m3u8")
987 file_type = CPlaylistFile::PL_M3U8;
988 playlist.SaveToFile(file_path, file_type);
989 }
990 }
991
OnPlaylistFixPathError(const std::wstring & playlist_path)992 bool CMusicPlayerCmdHelper::OnPlaylistFixPathError(const std::wstring& playlist_path)
993 {
994 if (!playlist_path.empty())
995 {
996 const wstring& inquiry_info = theApp.m_str_table.LoadText(L"MSG_PLAYLIST_FIX_ERROR_PATH_INQUIRY");
997 if (GetOwner()->MessageBox(inquiry_info.c_str(), NULL, MB_ICONQUESTION | MB_YESNO) == IDYES)
998 {
999 int fixed_count = FixPlaylistPathError(playlist_path);
1000 wstring complete_info = theApp.m_str_table.LoadTextFormat(L"MSG_PLAYLIST_FIX_ERROR_PATH_COMPLETE", { fixed_count });
1001 GetOwner()->MessageBox(complete_info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1002 return true;
1003 }
1004 }
1005 return false;
1006 }
1007
OnDeleteRecentListItem(const ListItem & list_item)1008 bool CMusicPlayerCmdHelper::OnDeleteRecentListItem(const ListItem& list_item)
1009 {
1010 wstring inquiry_info;
1011 if (list_item.type == LT_FOLDER)
1012 inquiry_info = theApp.m_str_table.LoadTextFormat(L"MSG_DELETE_FOLDER_INQUIRY", { list_item.path });
1013 else if (list_item.type == LT_PLAYLIST && !CRecentList::IsSpecPlaylist(list_item, CRecentList::PT_DEFAULT) && !CRecentList::IsSpecPlaylist(list_item, CRecentList::PT_FAVOURITE))
1014 inquiry_info = theApp.m_str_table.LoadTextFormat(L"MSG_DELETE_PLAYLIST_INQUIRY", { list_item.GetDisplayName() });
1015 else
1016 return false;
1017 if (GetOwner()->MessageBox(inquiry_info.c_str(), NULL, MB_ICONQUESTION | MB_YESNO) == IDYES)
1018 {
1019 // 如果是当前播放则使用CPlayer成员方法处理
1020 if (CRecentList::Instance().IsCurrentList(list_item))
1021 {
1022 if (!CPlayer::GetInstance().RemoveCurPlaylistOrFolder())
1023 {
1024 const wstring& info = theApp.m_str_table.LoadText(L"MSG_WAIT_AND_RETRY");
1025 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1026 }
1027 }
1028 else
1029 {
1030 if (list_item.type == LT_PLAYLIST)
1031 CommonDialogMgr::DeleteAFile(GetOwner()->GetSafeHwnd(), list_item.path);
1032 if (CRecentList::Instance().RemoveItem(list_item))
1033 {
1034 CRecentList::Instance().SaveData();
1035 return true;
1036 }
1037 }
1038 }
1039 return false;
1040 }
1041
OnOpenFolder()1042 bool CMusicPlayerCmdHelper::OnOpenFolder()
1043 {
1044 static bool include_sub_dir{ false };
1045 static CString include_sub_dir_str{ theApp.m_str_table.LoadText(L"TXT_FOLDER_BROWSER_INCLUDE_SUB_DIR").c_str() };
1046 const wstring& title = theApp.m_str_table.LoadText(L"TITLE_FOLDER_BROWSER_SONG_SOURCE");
1047 #ifdef COMPILE_IN_WIN_XP
1048 CFolderBrowserDlg folderPickerDlg(this->GetSafeHwnd());
1049 folderPickerDlg.SetInfo(title.c_str());
1050 #else
1051 CFilePathHelper current_path(CPlayer::GetInstance().GetCurrentDir());
1052 CFolderPickerDialog folderPickerDlg(current_path.GetParentDir().c_str());
1053 folderPickerDlg.m_ofn.lpstrTitle = title.c_str();
1054 folderPickerDlg.AddCheckButton(IDC_OPEN_CHECKBOX, include_sub_dir_str, include_sub_dir); //在打开对话框中添加一个复选框
1055 #endif
1056 if (folderPickerDlg.DoModal() == IDOK)
1057 {
1058 #ifndef COMPILE_IN_WIN_XP
1059 BOOL checked;
1060 folderPickerDlg.GetCheckButtonState(IDC_OPEN_CHECKBOX, checked);
1061 include_sub_dir = (checked != FALSE);
1062 #endif
1063 return OnOpenFolder(wstring(folderPickerDlg.GetPathName()), include_sub_dir, false);
1064 }
1065 return false;
1066 }
1067
OnOpenFolder(std::wstring folder_path,bool include_sub_dir,bool play)1068 bool CMusicPlayerCmdHelper::OnOpenFolder(std::wstring folder_path, bool include_sub_dir, bool play)
1069 {
1070 if (!folder_path.empty() && folder_path.back() != L'\\' && folder_path.back() != L'/')
1071 folder_path.push_back(L'\\');
1072 ListItem list_item{ LT_FOLDER, folder_path };
1073 if (CRecentList::Instance().LoadItem(list_item))
1074 {
1075 list_item.contain_sub_folder = include_sub_dir;
1076 OnListItemSelected(list_item, play);
1077 return true;
1078 }
1079 else
1080 {
1081 if (!CPlayer::GetInstance().OpenFolder(folder_path, include_sub_dir, play))
1082 {
1083 const wstring& info = theApp.m_str_table.LoadText(L"MSG_WAIT_AND_RETRY");
1084 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1085 return false;
1086 }
1087 else
1088 {
1089 return true;
1090 }
1091 }
1092 }
1093
OnRemoveFromPlaylist(const ListItem & list_item,const std::vector<SongInfo> & songs)1094 bool CMusicPlayerCmdHelper::OnRemoveFromPlaylist(const ListItem& list_item, const std::vector<SongInfo>& songs)
1095 {
1096 if (songs.empty())
1097 return false;
1098 ASSERT(list_item.type == LT_PLAYLIST);
1099 wstring playlist_display_name = list_item.GetDisplayName();
1100 wstring info;
1101 if (songs.size() == 1)
1102 {
1103 std::wstring song_display_name = CSongInfoHelper::GetDisplayStr(songs.front(), theApp.m_media_lib_setting_data.display_format);
1104 info = theApp.m_str_table.LoadTextFormat(L"MSG_REMOVE_SINGLE_ITEM_FROM_PLAYLIST_INQUIRY", { playlist_display_name, song_display_name });
1105 }
1106 else
1107 {
1108 info = theApp.m_str_table.LoadTextFormat(L"MSG_REMOVE_FROM_PLAYLIST_INQUIRY", { playlist_display_name, songs.size() });
1109 }
1110 if (GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONQUESTION | MB_YESNO) != IDYES)
1111 return false;
1112 //如果当前列表正在播放
1113 if (CRecentList::Instance().IsCurrentList(list_item))
1114 {
1115 std::vector<int> indexs; // 这里问题很大,之后要重新设计
1116 for (const auto& song : songs)
1117 {
1118 auto iter = std::find_if(CPlayer::GetInstance().GetPlayList().begin(), CPlayer::GetInstance().GetPlayList().end(), [&](const SongInfo& a) {
1119 return a.IsSameSong(song);
1120 });
1121 if (iter != CPlayer::GetInstance().GetPlayList().end())
1122 indexs.push_back(iter - CPlayer::GetInstance().GetPlayList().begin());
1123 }
1124 CPlayer::GetInstance().RemoveSongs(indexs);
1125 }
1126 else
1127 {
1128 CPlaylistFile playlist_file;
1129 playlist_file.LoadFromFile(list_item.path);
1130 for (const auto& song : songs)
1131 {
1132 playlist_file.RemoveSong(song);
1133 }
1134 playlist_file.SaveToFile(list_item.path);
1135 }
1136
1137 //如果是我喜欢的曲目,则需要更新UI中的显示
1138 if (CRecentList::IsSpecPlaylist(list_item, CRecentList::PT_FAVOURITE))
1139 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
1140
1141 return true;
1142 }
1143
OnRemoveFromCurrentPlaylist(const std::vector<int> & indexs)1144 bool CMusicPlayerCmdHelper::OnRemoveFromCurrentPlaylist(const std::vector<int>& indexs)
1145 {
1146 ListItem cur_list = CRecentList::Instance().GetCurrentList();
1147 if (!indexs.empty() && cur_list.type == LT_PLAYLIST)
1148 {
1149 std::wstring playlist_name = cur_list.GetDisplayName();
1150 std::wstring info;
1151 if (indexs.size() == 1)
1152 {
1153 std::wstring song_display_name;
1154 int index = indexs.front();
1155 if (index >= 0 && index < CPlayer::GetInstance().GetSongNum())
1156 {
1157 SongInfo song = CPlayer::GetInstance().GetPlayList()[index];
1158 song_display_name = CSongInfoHelper::GetDisplayStr(song, theApp.m_media_lib_setting_data.display_format);
1159 }
1160 info = theApp.m_str_table.LoadTextFormat(L"MSG_REMOVE_SINGLE_ITEM_FROM_PLAYLIST_INQUIRY", { playlist_name, song_display_name });
1161 }
1162 else
1163 {
1164 info = theApp.m_str_table.LoadTextFormat(L"MSG_REMOVE_FROM_PLAYLIST_INQUIRY", { playlist_name, indexs.size() });
1165 }
1166 if (GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONQUESTION | MB_YESNO) == IDYES)
1167 {
1168 CPlayer::GetInstance().RemoveSongs(indexs);
1169
1170 //如果是我喜欢的曲目,则需要更新UI中的显示
1171 if (CRecentList::Instance().IsCurrentList(CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE)))
1172 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
1173
1174 return true;
1175 }
1176 }
1177 return false;
1178 }
1179
OnPlayMyFavourite(const SongKey & song_key)1180 void CMusicPlayerCmdHelper::OnPlayMyFavourite(const SongKey& song_key)
1181 {
1182 ListItem list_item = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE);
1183 list_item.SetPlayTrack(song_key);
1184 bool ok = CPlayer::GetInstance().SetList(list_item, true, true);
1185 if (!ok)
1186 {
1187 const wstring& info = theApp.m_str_table.LoadText(L"MSG_WAIT_AND_RETRY");
1188 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1189 }
1190 }
1191
OnPlayMyFavourite()1192 void CMusicPlayerCmdHelper::OnPlayMyFavourite()
1193 {
1194 //已经在播放“我喜欢的音乐”
1195 if (CRecentList::Instance().IsCurrentList(CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE)))
1196 {
1197 //不在播放状态时执行播放命令
1198 if (!CPlayer::GetInstance().IsPlaying())
1199 theApp.m_pMainWnd->SendMessage(WM_COMMAND, ID_PLAY);
1200 }
1201 //没有播放“我喜欢的音乐”的情况下,播放“我喜欢的音乐”
1202 else
1203 {
1204 OnListItemSelected(CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE), true);
1205 }
1206 }
1207
OnPlayAllTrack(const SongInfo & song)1208 void CMusicPlayerCmdHelper::OnPlayAllTrack(const SongInfo& song)
1209 {
1210 ListItem list_item{ LT_MEDIA_LIB, L"", CMediaClassifier::CT_NONE };
1211 list_item.SetPlayTrack(song);
1212 bool ok = CPlayer::GetInstance().SetList(list_item, true, true);
1213 if (!ok)
1214 {
1215 const wstring& info = theApp.m_str_table.LoadText(L"MSG_WAIT_AND_RETRY");
1216 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1217 }
1218 }
1219
OnPlayTrack(int track)1220 void CMusicPlayerCmdHelper::OnPlayTrack(int track)
1221 {
1222 if (!CPlayer::GetInstance().PlayTrack(track))
1223 {
1224 const wstring& info = theApp.m_str_table.LoadText(L"MSG_WAIT_AND_RETRY");
1225 GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1226 }
1227 }
1228
1229
OnAddRemoveFromFavourite(int track)1230 bool CMusicPlayerCmdHelper::OnAddRemoveFromFavourite(int track)
1231 {
1232 if (track < 0 || track >= CPlayer::GetInstance().GetSongNum())
1233 return false;
1234
1235 if (CRecentList::Instance().IsPlayingSpecPlaylist(CRecentList::PT_FAVOURITE))
1236 {
1237 //如果当前播放列表就是“我喜欢”播放列表,则直接将歌曲从列表中移除
1238 const wstring& info = theApp.m_str_table.LoadText(L"MSG_REMOVE_FAVOURITE_WARNING");
1239 if (GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OKCANCEL) == IDOK)
1240 {
1241 bool removed = CPlayer::GetInstance().RemoveSong(track);
1242 if (removed)
1243 {
1244 CMusicPlayerDlg* pDlg = dynamic_cast<CMusicPlayerDlg*>(theApp.m_pMainWnd);
1245 if (pDlg != nullptr)
1246 pDlg->ShowPlayList();
1247 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
1248 }
1249 return removed;
1250 }
1251 }
1252 else
1253 {
1254 SongInfo song = CPlayer::GetInstance().GetPlayList()[track];
1255 std::wstring favourite_playlist_path = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE).path;
1256 CPlaylistFile playlist;
1257 playlist.LoadFromFile(favourite_playlist_path);
1258 if (!CPlayer::GetInstance().IsFavourite(track))
1259 {
1260 //添加到“我喜欢”播放列表
1261 if (!playlist.IsSongInPlaylist(song))
1262 {
1263 playlist.AddSongsToPlaylist(std::vector<SongInfo> {song}, theApp.m_media_lib_setting_data.insert_begin_of_playlist);
1264 playlist.SaveToFile(favourite_playlist_path);
1265 }
1266 CPlayer::GetInstance().SetFavourite(track, true);
1267 }
1268 else
1269 {
1270 //从“我喜欢”播放列表移除
1271 playlist.RemoveSong(song);
1272 playlist.SaveToFile(favourite_playlist_path);
1273 CPlayer::GetInstance().SetFavourite(track, false);
1274 }
1275 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
1276 return true;
1277 }
1278 return false;
1279 }
1280
OnAddRemoveFromFavourite(const SongInfo & song)1281 bool CMusicPlayerCmdHelper::OnAddRemoveFromFavourite(const SongInfo& song)
1282 {
1283 auto& playlist{ CPlayer::GetInstance().GetPlayList() };
1284 auto iter = std::find_if(playlist.begin(), playlist.end(), [&](const SongInfo& a) {
1285 return a.IsSameSong(song);
1286 });
1287 if (iter != playlist.end() && CRecentList::Instance().IsPlayingSpecPlaylist(CRecentList::PT_FAVOURITE))
1288 {
1289 //如果当前播放列表就是“我喜欢”播放列表,则直接将歌曲从列表中移除
1290 const wstring& info = theApp.m_str_table.LoadText(L"MSG_REMOVE_FAVOURITE_WARNING");
1291 if (GetOwner()->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OKCANCEL) == IDOK)
1292 {
1293 int track = iter - playlist.begin();
1294 bool removed = CPlayer::GetInstance().RemoveSong(track);
1295 if (removed)
1296 {
1297 CMusicPlayerDlg* pDlg = dynamic_cast<CMusicPlayerDlg*>(theApp.m_pMainWnd);
1298 if (pDlg != nullptr)
1299 pDlg->ShowPlayList();
1300 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
1301 }
1302 return removed;
1303 }
1304 }
1305 else
1306 {
1307 std::wstring favourite_playlist_path = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE).path;
1308 CPlaylistFile favourite_playlist;
1309 favourite_playlist.LoadFromFile(favourite_playlist_path);
1310 //添加到“我喜欢”播放列表
1311 if (!favourite_playlist.IsSongInPlaylist(song))
1312 {
1313 favourite_playlist.AddSongsToPlaylist(std::vector<SongInfo> {song}, theApp.m_media_lib_setting_data.insert_begin_of_playlist);
1314 favourite_playlist.SaveToFile(favourite_playlist_path);
1315
1316 //如果正在播放“我喜欢的音乐”
1317 if (CRecentList::Instance().IsPlayingSpecPlaylist(CRecentList::PT_FAVOURITE))
1318 {
1319 CPlayer::GetInstance().AddSongsToPlaylist(std::vector<SongInfo> {song});
1320 }
1321 }
1322 else
1323 {
1324 //从“我喜欢”播放列表移除
1325 favourite_playlist.RemoveSong(song);
1326 favourite_playlist.SaveToFile(favourite_playlist_path);
1327 }
1328 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
1329 return true;
1330
1331 }
1332
1333 return false;
1334 }
1335
OnAddToFavourite()1336 bool CMusicPlayerCmdHelper::OnAddToFavourite()
1337 {
1338 if (CRecentList::Instance().IsPlayingSpecPlaylist(CRecentList::PT_FAVOURITE))
1339 return false;
1340
1341 SongInfo song = CPlayer::GetInstance().GetCurrentSongInfo();
1342 std::wstring favourite_playlist_path = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE).path;
1343 CPlaylistFile playlist;
1344 playlist.LoadFromFile(favourite_playlist_path);
1345 if (!CPlayer::GetInstance().IsFavourite())
1346 {
1347 //添加到“我喜欢”播放列表
1348 if (!playlist.IsSongInPlaylist(song))
1349 {
1350 playlist.AddSongsToPlaylist(std::vector<SongInfo> {song}, theApp.m_media_lib_setting_data.insert_begin_of_playlist);
1351 playlist.SaveToFile(favourite_playlist_path);
1352 }
1353 CPlayer::GetInstance().SetFavourite(true);
1354 CUiMyFavouriteItemMgr::Instance().UpdateMyFavourite();
1355 return true;
1356 }
1357
1358 return false;
1359 }
1360
AddToPlaylist(const std::vector<SongInfo> & songs,const std::wstring & playlist_path)1361 void CMusicPlayerCmdHelper::AddToPlaylist(const std::vector<SongInfo>& songs, const std::wstring& playlist_path)
1362 {
1363 CMusicPlayerDlg* pPlayerDlg = CMusicPlayerDlg::GetInstance();
1364 if (CPlayer::GetInstance().IsPlaylistMode() && playlist_path == CPlayer::GetInstance().GetPlaylistPath())
1365 {
1366 int rtn = CPlayer::GetInstance().AddSongsToPlaylist(songs);
1367 if (rtn == 0)
1368 {
1369 const wstring& info = theApp.m_str_table.LoadText(L"MSG_FILE_EXIST_IN_PLAYLIST");
1370 pPlayerDlg->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1371 }
1372 else if (rtn == -1)
1373 {
1374 const wstring& info = theApp.m_str_table.LoadText(L"MSG_WAIT_AND_RETRY");
1375 pPlayerDlg->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1376 }
1377 else
1378 {
1379 //显示添加成功提示
1380 CPlayerUIBase* ui = pPlayerDlg->GetCurrentUi();
1381 if (ui != nullptr)
1382 {
1383 wstring playlist_display_name = ListItem(LT_PLAYLIST, playlist_path).GetDisplayName();
1384 const wstring& info = theApp.m_str_table.LoadTextFormat(L"MSG_ADD_TO_PLAYLIST_SUCCEED", { rtn, playlist_display_name });
1385 ui->ShowUiTipInfo(info);
1386 }
1387 }
1388 }
1389 else
1390 {
1391 CPlaylistFile playlist;
1392 playlist.LoadFromFile(playlist_path);
1393 int rtn = playlist.AddSongsToPlaylist(songs, theApp.m_media_lib_setting_data.insert_begin_of_playlist);
1394 if (rtn)
1395 {
1396 playlist.SaveToFile(playlist_path);
1397 //显示添加成功提示
1398 CPlayerUIBase* ui = pPlayerDlg->GetCurrentUi();
1399 if (ui != nullptr)
1400 {
1401 wstring playlist_display_name = ListItem(LT_PLAYLIST, playlist_path).GetDisplayName();
1402 const wstring& info = theApp.m_str_table.LoadTextFormat(L"MSG_ADD_TO_PLAYLIST_SUCCEED", { rtn, playlist_display_name });
1403 ui->ShowUiTipInfo(info);
1404 }
1405 }
1406 else
1407 {
1408 const wstring& info = theApp.m_str_table.LoadText(L"MSG_FILE_EXIST_IN_PLAYLIST");
1409 pPlayerDlg->MessageBox(info.c_str(), NULL, MB_ICONINFORMATION | MB_OK);
1410 }
1411 }
1412 }
1413
GetOwner()1414 CWnd* CMusicPlayerCmdHelper::GetOwner()
1415 {
1416 if (m_pOwner != nullptr)
1417 {
1418 return m_pOwner;
1419 }
1420 else
1421 {
1422 CMusicPlayerDlg* dlg = CMusicPlayerDlg::GetInstance();
1423 if (dlg != nullptr && dlg->IsMiniMode())
1424 return dlg->GetMinimodeDlg();
1425 return theApp.m_pMainWnd;
1426 }
1427 }
1428