xref: /MusicPlayer2/MusicPlayer2/MusicPlayerCmdHelper.cpp (revision 800a68ca4bdb8c4896c14aa157f6b72b26c482d9)
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