diff --git a/MusicPlayer2/FindDlg.cpp b/MusicPlayer2/FindDlg.cpp index d6365dd06..c8669b85d 100644 --- a/MusicPlayer2/FindDlg.cpp +++ b/MusicPlayer2/FindDlg.cpp @@ -581,8 +581,7 @@ void CFindDlg::OnAddToNewPalylistAndPlay() wstring playlist_path; if (_OnAddToNewPlaylist(playlist_path)) { - CPlayer::GetInstance().SetPlaylist(playlist_path, 0, 0, false, true); - CPlayer::GetInstance().SaveRecentPath(); + CPlayer::GetInstance().SetPlaylist(playlist_path, 0, 0, true); OnCancel(); } } diff --git a/MusicPlayer2/MediaLibTabDlg.cpp b/MusicPlayer2/MediaLibTabDlg.cpp index 68c91b0e5..a58edc9ad 100644 --- a/MusicPlayer2/MediaLibTabDlg.cpp +++ b/MusicPlayer2/MediaLibTabDlg.cpp @@ -186,8 +186,7 @@ void CMediaLibTabDlg::OnAddToNewPalylistAndPlay() wstring playlist_path; if (_OnAddToNewPlaylist(playlist_path)) { - CPlayer::GetInstance().SetPlaylist(playlist_path, 0, 0, false, true); - CPlayer::GetInstance().SaveRecentPath(); + CPlayer::GetInstance().SetPlaylist(playlist_path, 0, 0, true); OnCancel(); } } diff --git a/MusicPlayer2/MusicPlayerDlg.cpp b/MusicPlayer2/MusicPlayerDlg.cpp index b2abb0b4c..28f821ae7 100644 --- a/MusicPlayer2/MusicPlayerDlg.cpp +++ b/MusicPlayer2/MusicPlayerDlg.cpp @@ -2911,7 +2911,6 @@ afx_msg LRESULT CMusicPlayerDlg::OnPathSelected(WPARAM wParam, LPARAM lParam) //ShowTime(); DrawInfo(true); //m_findDlg.ClearFindResult(); //更换路径后清除查找结果 - CPlayer::GetInstance().SaveRecentPath(); m_play_error_cnt = 0; SetTimer(DELAY_TIMER_ID, 500, NULL); //在媒体库对话框中选择了一个文件夹播放后,500毫秒内不响应WM_LBUTTONUP消息 m_no_lbtnup = true; @@ -3496,10 +3495,9 @@ BOOL CMusicPlayerDlg::OnCommand(WPARAM wParam, LPARAM lParam) { if (item.playlist_info != nullptr) { - CPlayer::GetInstance().SetPlaylist(item.playlist_info->path, item.playlist_info->track, item.playlist_info->position, false, false); + CPlayer::GetInstance().SetPlaylist(item.playlist_info->path, item.playlist_info->track, item.playlist_info->position); UpdatePlayPauseButton(); DrawInfo(true); - CPlayer::GetInstance().SaveRecentPath(); IniPlaylistPopupMenu(); m_play_error_cnt = 0; } @@ -3512,7 +3510,6 @@ BOOL CMusicPlayerDlg::OnCommand(WPARAM wParam, LPARAM lParam) CPlayer::GetInstance().SetPath(*item.folder_info); UpdatePlayPauseButton(); DrawInfo(true); - CPlayer::GetInstance().SaveRecentPath(); m_play_error_cnt = 0; } } @@ -5420,14 +5417,13 @@ afx_msg LRESULT CMusicPlayerDlg::OnPlaylistSelected(WPARAM wParam, LPARAM lParam } } // index大于等于0时即此次播放为从右侧列表指定歌曲,设置force为true以忽略continue_when_switch_playlist设置 - CPlayer::GetInstance().SetPlaylist(pPathDlg->GetSelPlaylistPath(), track_played, position, false, continue_play, index >= 0); + CPlayer::GetInstance().SetPlaylist(pPathDlg->GetSelPlaylistPath(), track_played, position, continue_play, index >= 0); } UpdatePlayPauseButton(); //SetPorgressBarSize(); //ShowTime(); DrawInfo(true); //m_findDlg.ClearFindResult(); //更换路径后清除查找结果 - CPlayer::GetInstance().SaveRecentPath(); IniPlaylistPopupMenu(); m_play_error_cnt = 0; SetTimer(DELAY_TIMER_ID, 500, NULL); //在媒体库对话框中选择了一个播放列表播放后,500毫秒内不响应WM_LBUTTONUP消息 diff --git a/MusicPlayer2/Player.cpp b/MusicPlayer2/Player.cpp index 9fd08de45..acfe3cd89 100644 --- a/MusicPlayer2/Player.cpp +++ b/MusicPlayer2/Player.cpp @@ -101,45 +101,31 @@ void CPlayer::Create() LoadConfig(); LoadRecentPath(); LoadRecentPlaylist(); - bool change_to_default_playlist{}; + m_controls.Init(); + bool change_to_default_playlist{ !m_playlist_mode && m_recent_path.empty() }; for (size_t i{}; i < m_recent_path.size(); ++i) // 清除最近播放文件夹列表中的无效项 { if (!CAudioCommon::IsPathContainsAudioFile(m_recent_path[i].path, m_recent_path[i].contain_sub_folder) && !COSUPlayerHelper::IsOsuFolder(m_recent_path[i].path)) { m_recent_path.erase(m_recent_path.begin() + i); - change_to_default_playlist = (i == 0); + change_to_default_playlist |= (i == 0); i--; } } if (change_to_default_playlist) { - PlaylistInfo playlist_info; - playlist_info = CPlaylistMgr::Instance().m_default_playlist; - SetPlaylist(playlist_info.path, playlist_info.track, playlist_info.position, true); + const PlaylistInfo& playlist_info = CPlaylistMgr::Instance().m_default_playlist; + SetPlaylist(playlist_info.path, playlist_info.track, playlist_info.position); } else if (!m_playlist_mode) { - GetPlayStatusMutex().lock(); - m_loading = true; - IniPlayList(); //初始化播放列表 + SetPath(m_recent_path.front()); } else { - PlaylistInfo playlist_info; - if (CPlaylistMgr::Instance().m_cur_playlist_type == PT_USER && CPlaylistMgr::Instance().m_recent_playlists.empty()) - CPlaylistMgr::Instance().m_cur_playlist_type = PT_DEFAULT; - if (CPlaylistMgr::Instance().m_cur_playlist_type == PT_DEFAULT) - playlist_info = CPlaylistMgr::Instance().m_default_playlist; - else if (CPlaylistMgr::Instance().m_cur_playlist_type == PT_FAVOURITE) - playlist_info = CPlaylistMgr::Instance().m_favourite_playlist; - else if (CPlaylistMgr::Instance().m_cur_playlist_type == PT_TEMP) - playlist_info = CPlaylistMgr::Instance().m_temp_playlist; - else - playlist_info = CPlaylistMgr::Instance().m_recent_playlists.front(); - SetPlaylist(playlist_info.path, playlist_info.track, playlist_info.position, true); + const PlaylistInfo& playlist_info = CPlaylistMgr::Instance().GetCurrentPlaylistInfo(); + SetPlaylist(playlist_info.path, playlist_info.track, playlist_info.position); } - SetTitle(); //用当前正在播放的歌曲名作为窗口标题 - m_controls.Init(); } void CPlayer::CreateWithFiles(const vector& files) @@ -148,8 +134,8 @@ void CPlayer::CreateWithFiles(const vector& files) LoadConfig(); LoadRecentPath(); LoadRecentPlaylist(); - OpenFilesInDefaultPlaylist(files); m_controls.Init(); + OpenFilesInDefaultPlaylist(files); } void CPlayer::CreateWithPath(const wstring& path) @@ -158,9 +144,8 @@ void CPlayer::CreateWithPath(const wstring& path) LoadConfig(); LoadRecentPath(); LoadRecentPlaylist(); - OpenFolder(path); - SetTitle(); //用当前正在播放的歌曲名作为窗口标题 m_controls.Init(); + OpenFolder(path); } void CPlayer::CreateWithPlaylist(const wstring& playlist_path) @@ -169,40 +154,40 @@ void CPlayer::CreateWithPlaylist(const wstring& playlist_path) LoadConfig(); LoadRecentPath(); LoadRecentPlaylist(); - wstring tmp{ playlist_path }; - OpenPlaylistFile(tmp); - SetTitle(); m_controls.Init(); + wstring playlist_path_{ playlist_path }; + OpenPlaylistFile(playlist_path_); } -void CPlayer::IniPlayList(bool playlist_mode, bool refresh_info, bool play) +void CPlayer::IniPlayList(bool play, bool refresh_info) { - // 这里不再判断m_loading,因为调用此方法前一定加锁了,需要初始化线程发出消息触发IniPlaylistComplate解锁 - m_playlist_mode = playlist_mode; - if (!playlist_mode) //非播放列表模式下,从当前目录m_path下搜索文件 + m_playlist.clear(); + if (m_playlist_mode) + { + CPlaylistMgr::Instance().UpdateCurrentPlaylistType(m_playlist_path); + CPlaylistFile playlist; + playlist.LoadFromFile(m_playlist_path); + playlist.ToSongList(m_playlist); + } + else { + if (m_path.empty() || (m_path.back() != L'/' && m_path.back() != L'\\')) //如果输入的新路径为空或末尾没有斜杠,则在末尾加上一个 + m_path.append(1, L'\\'); if (COSUPlayerHelper::IsOsuFolder(m_path)) COSUPlayerHelper::GetOSUAudioFiles(m_path, m_playlist); else CAudioCommon::GetAudioFiles(m_path, m_playlist, MAX_SONG_NUM, m_contain_sub_folder); } - //m_index = 0; - //m_song_num = m_playlist.size(); - m_index_tmp = m_index; //保存歌曲序号,cue未解析情况下当前的m_index有可能超过当前歌曲数目,临时存储待cue解析后恢复 - if (m_index < 0 || m_index >= GetSongNum()) m_index = 0; //确保当前歌曲序号不会超过歌曲总数 - //m_song_length = { 0, 0, 0 }; - if (GetSongNum() == 0) - { - m_playlist.push_back(SongInfo{}); //没有歌曲时向播放列表插入一个空的SongInfo对象 - } + m_index_tmp = m_index; // 保存歌曲序号,cue未解析情况下当前的m_index有可能超过当前歌曲数目,临时存储待cue解析后恢复 + m_index = 0; // 在初始化期间为维持程序其他部分不报错(可能需要(但不应该需要))保持m_playlist[m_index]有效 + if (m_playlist.empty()) + m_playlist.push_back(SongInfo{}); // 没有歌曲时向播放列表插入一个空的SongInfo对象 - //m_thread_info.playlist = &m_playlist; m_thread_info.refresh_info = refresh_info; - m_thread_info.is_playlist_mode = playlist_mode; m_thread_info.play = play; m_thread_info.play_index = m_index_tmp; - //m_thread_info.path = m_path; + //创建初始化播放列表的工作线程 m_pThread = AfxBeginThread(IniPlaylistThreadFunc, &m_thread_info); } @@ -312,16 +297,14 @@ void CPlayer::IniPlaylistComplate() ASSERT(m_playing == 0); // 这里应该一定是停止状态,我将之前的旧代码换成了这个断言,有问题的话再改回去 // 对播放列表排序 - if (!m_thread_info.is_playlist_mode && m_playlist.size() > 1) + if (!m_playlist_mode && m_playlist.size() > 1) SortPlaylist(true); // 清除歌词和专辑封面 m_album_cover.Destroy(); m_album_cover_blur.Destroy(); m_Lyrics = CLyrics(); - // 修正程序启动时系统播放控件的播放状态不正确的问题(改在这里,可被下面的初始化后继续播放重新设置为playing状态) - MusicControl(Command::CLOSE); // 这里设置GetSongNum()返回0时的默认SMTC状态 - if (GetSongNum() > 0) // 播放列表初始化完成,根据m_index,m_current_position,m_thread_info.play还原播放状态 + if (!IsPlaylistEmpty()) // 播放列表初始化完成,根据m_index,m_current_position,m_thread_info.play还原播放状态 { bool tmp_find{ false }; if (!m_current_song_tmp.IsEmpty()) // m_current_song_tmp不为空则改为查找播放此歌曲,同时定位到m_current_song_position_tmp @@ -347,9 +330,7 @@ void CPlayer::IniPlaylistComplate() MusicControl(Command::PLAY); } - SaveCurrentPlaylist(); - EmplaceCurrentPathToRecent(); - EmplaceCurrentPlaylistToRecent(); + SaveRecentInfoToFiles(); SetTitle(); OnPlaylistChange(); @@ -966,18 +947,25 @@ void CPlayer::LoopPlaylist(int& song_track) } } -void CPlayer::ChangePath(const wstring& path, int track, bool play, int position) +void CPlayer::SaveRecentInfoToFiles() { - m_path = path; - if (m_path.empty() || (m_path.back() != L'/' && m_path.back() != L'\\')) //如果输入的新路径为空或末尾没有斜杠,则在末尾加上一个 - m_path.append(1, L'\\'); - m_playlist.clear(); //清空播放列表 - m_index = track; - //初始化播放列表 - IniPlayList(false, false, play); //根据新路径重新初始化播放列表 - m_current_position.fromInt(position); - SaveConfig(); - SetTitle(); + static bool initailzed{ false }; + // 程序启动后第一次调用时不需要保存(m_playlist为空时进行播放列表保存会导致清空列表) + if (initailzed) + { + if (m_playlist_mode) + { + SaveCurrentPlaylist(); + EmplaceCurrentPlaylistToRecent(); + CPlaylistMgr::Instance().SavePlaylistData(); + } + else + { + EmplaceCurrentPathToRecent(); + SaveRecentPath(); + } + } + initailzed = true; } void CPlayer::SetPath(const PathInfo& path_info) @@ -987,14 +975,8 @@ void CPlayer::SetPath(const PathInfo& path_info) m_loading = true; IniPlayerCore(); - MusicControl(Command::CLOSE); + SaveRecentInfoToFiles(); - if (GetSongNum() > 0) - { - SaveCurrentPlaylist(); - EmplaceCurrentPlaylistToRecent(); - EmplaceCurrentPathToRecent(); - } // 实现切换到文件夹模式时的同曲目播放保持 if (theApp.m_play_setting_data.continue_when_switch_playlist) { @@ -1003,117 +985,109 @@ void CPlayer::SetPath(const PathInfo& path_info) m_current_song_playing_tmp = (m_playing == PlayingState::PS_PLAYING); } + MusicControl(Command::CLOSE); + + m_path = path_info.path; + m_playlist_path.clear(); + m_playlist_mode = false; m_sort_mode = path_info.sort_mode; m_descending = path_info.descending; m_contain_sub_folder = path_info.contain_sub_folder; - ChangePath(path_info.path, path_info.track, path_info.position); - EmplaceCurrentPathToRecent(); //保存新的路径到最近路径 + m_index = path_info.track; + m_current_position.fromInt(path_info.position); + IniPlayList(); } -bool CPlayer::SetPlaylist(const wstring& playlist_path, int track, int position, bool init, bool play, bool force) +bool CPlayer::OpenFolder(wstring path, bool contain_sub_folder, bool play) { if (m_loading) return false; if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false; m_loading = true; IniPlayerCore(); - if (!init) - { - // 实现切换到播放列表模式时的同曲目播放保持 - if (theApp.m_play_setting_data.continue_when_switch_playlist && !force) - { - m_current_song_tmp = GetCurrentSongInfo(); - m_current_song_position_tmp = GetCurrentPosition(); - m_current_song_playing_tmp = (m_playing == PlayingState::PS_PLAYING); - } - - if (!CCommon::StringCompareNoCase(playlist_path, m_playlist_path)) - SaveCurrentPlaylist(); - if (m_playlist_mode) - EmplaceCurrentPlaylistToRecent(); - else - EmplaceCurrentPathToRecent(); - MusicControl(Command::STOP); - MusicControl(Command::CLOSE); - } + SaveRecentInfoToFiles(); - if (playlist_path == CPlaylistMgr::Instance().m_default_playlist.path) - CPlaylistMgr::Instance().m_cur_playlist_type = PT_DEFAULT; - else if (playlist_path == CPlaylistMgr::Instance().m_favourite_playlist.path) - CPlaylistMgr::Instance().m_cur_playlist_type = PT_FAVOURITE; - else if (playlist_path == CPlaylistMgr::Instance().m_temp_playlist.path) - CPlaylistMgr::Instance().m_cur_playlist_type = PT_TEMP; - else - CPlaylistMgr::Instance().m_cur_playlist_type = PT_USER; + MusicControl(Command::CLOSE); - m_playlist.clear(); - CPlaylistFile playlist; - playlist.LoadFromFile(playlist_path); + // 按照新文件夹设置 + m_path = path; + m_sort_mode = SM_FILE; + m_descending = false; + m_contain_sub_folder = contain_sub_folder; + m_index = 0; + m_current_position.fromInt(0); - auto playlist_files{ playlist.GetPlaylist() }; - for (const auto& file : playlist_files) + // 如果是打开过的文件夹那么用保存的设置覆盖默认值 + auto iter = std::find_if(m_recent_path.begin(), m_recent_path.end(), + [&](const PathInfo& path_info) { return path_info.path == m_path; }); + if (iter != m_recent_path.end()) { - m_playlist.push_back(file); + const PathInfo& path_info = *iter; + m_sort_mode = path_info.sort_mode; + m_descending = path_info.descending; + m_index = path_info.track; + m_current_position.fromInt(path_info.position); } - m_index = track; - m_current_position.fromInt(position); - SetTitle(); - m_playlist_path = playlist_path; - EmplaceCurrentPlaylistToRecent(); - - IniPlayList(true, false, play); + IniPlayList(play); return true; } -bool CPlayer::OpenFolder(wstring path, bool contain_sub_folder, bool play) +bool CPlayer::SetPlaylist(const wstring& playlist_path, int track, int position, bool play, bool force) { if (m_loading) return false; if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return false; m_loading = true; IniPlayerCore(); - MusicControl(Command::CLOSE); + SaveRecentInfoToFiles(); - if (path.empty() || (path.back() != L'/' && path.back() != L'\\')) //如果打开的新路径为空或末尾没有斜杠,则在末尾加上一个 - path.append(1, L'\\'); - bool path_exist{ false }; - int track{}; - int position{}; - if (GetSongNum() > 0) - { - SaveCurrentPlaylist(); - EmplaceCurrentPlaylistToRecent(); - EmplaceCurrentPathToRecent(); - } - m_contain_sub_folder = contain_sub_folder; - //检查打开的路径是否已经存在于最近路径中 - for (const auto& a_path_info : m_recent_path) + // 实现切换到播放列表模式时的同曲目播放保持 + if (theApp.m_play_setting_data.continue_when_switch_playlist && !force) { - if (path == a_path_info.path) - { - path_exist = true; - track = a_path_info.track; - position = a_path_info.position; - m_sort_mode = a_path_info.sort_mode; - m_descending = a_path_info.descending; - break; - } + m_current_song_tmp = GetCurrentSongInfo(); + m_current_song_position_tmp = GetCurrentPosition(); + m_current_song_playing_tmp = (m_playing == PlayingState::PS_PLAYING); } - if (path_exist) //如果打开的路径已经存在于最近路径中 + + MusicControl(Command::CLOSE); + + m_path.clear(); + m_playlist_path = playlist_path; + m_playlist_mode = true; + m_sort_mode = SM_FILE; + m_descending = false; + m_contain_sub_folder = false; + m_index = track; + m_current_position.fromInt(position); + + IniPlayList(play); + return true; +} + +bool CPlayer::OpenPlaylistFile(wstring& file_path) +{ + CFilePathHelper helper(file_path); + if (!CCommon::StringCompareNoCase(helper.GetDir(), theApp.m_playlist_dir)) //如果打开的播放列表文件不是程序默认的播放列表目录,则将其转换为*.playlist格式并复制到默认的播放列表目录 { - ChangePath(path, track, play, position); + //设置新的路径 + wstring playlist_name = helper.GetFileNameWithoutExtension(); + wstring new_path = theApp.m_playlist_dir + playlist_name + PLAYLIST_EXTENSION; + CCommon::FileAutoRename(new_path); + + CPlaylistFile playlist; + playlist.LoadFromFile(file_path); + playlist.SaveToFile(new_path); + file_path = new_path; + + return SetPlaylist(new_path, 0, 0); } - else //如果打开的路径是新的路径 + else //如果打开的播放文件就在默认播放列表目录下,则直接打开 { - m_sort_mode = SM_FILE; - m_descending = false; - ChangePath(path, 0, play); + const PlaylistInfo& path_info = CPlaylistMgr::Instance().FindPlaylistInfo(file_path); + return SetPlaylist(file_path, path_info.track, path_info.position); } - EmplaceCurrentPathToRecent(); //保存打开的路径到最近路径 - SaveRecentPath(); - return true; } bool CPlayer::OpenFilesInDefaultPlaylist(const vector& files, bool play) @@ -1132,45 +1106,28 @@ bool CPlayer::OpenSongsInDefaultPlaylist(const vector& songs, bool pla m_loading = true; IniPlayerCore(); + SaveRecentInfoToFiles(); + MusicControl(Command::CLOSE); - if (GetSongNum() > 0) - { - SaveCurrentPlaylist(); - EmplaceCurrentPlaylistToRecent(); - EmplaceCurrentPathToRecent(); - } - CPlaylistMgr::Instance().m_cur_playlist_type = PT_DEFAULT; - m_playlist_mode = true; + m_path.clear(); m_playlist_path = CPlaylistMgr::Instance().m_default_playlist.path; + m_playlist_mode = true; + m_sort_mode = SM_FILE; + m_descending = false; + m_contain_sub_folder = false; + m_index = 0; + m_current_position.fromInt(0); - //加载默认播放列表 - m_playlist.clear(); + // 向播放列表文件追加songs CPlaylistFile playlist; - playlist.LoadFromFile(CPlaylistMgr::Instance().m_default_playlist.path); - playlist.ToSongList(m_playlist); - - //将播放的文件添加到默认播放列表 - int play_index = GetSongNum(); //播放的序号 - for (const auto& song : songs) - { - auto iter = std::find_if(m_playlist.begin(), m_playlist.end(), [&](const SongInfo& tmp) - { - return song.IsSameSong(tmp); - }); - - if (iter == m_playlist.end()) //如果要打开的文件不在播放列表里才添加 - m_playlist.push_back(song); - else - play_index = iter - m_playlist.begin(); - } - m_index = play_index; - m_current_position = Time(); - - SaveCurrentPlaylist(); - SetTitle(); //用当前正在播放的歌曲名作为窗口标题 + playlist.LoadFromFile(m_playlist_path); + playlist.AddSongsToPlaylist(songs, true); + // 设置播放songs的第一个文件 + m_index = playlist.GetSongIndexInPlaylist(songs.front()); + playlist.SaveToFile(m_playlist_path); - IniPlayList(true, false, play); + IniPlayList(play); return true; } @@ -1182,33 +1139,25 @@ void CPlayer::OpenSongsInTempPlaylist(const vector& songs, int play_in m_loading = true; IniPlayerCore(); + SaveRecentInfoToFiles(); + MusicControl(Command::CLOSE); - if (GetSongNum() > 0) - { - if (!(CPlaylistMgr::Instance().m_cur_playlist_type == PT_TEMP)) - SaveCurrentPlaylist(); - EmplaceCurrentPlaylistToRecent(); - EmplaceCurrentPathToRecent(); - } - CPlaylistMgr::Instance().m_cur_playlist_type = PT_TEMP; - m_playlist_mode = true; + m_path.clear(); m_playlist_path = CPlaylistMgr::Instance().m_temp_playlist.path; - m_playlist.clear(); - m_playlist = songs; - if (play_index >= 0 && play_index < static_cast(m_playlist.size())) - { - m_current_song_tmp = m_playlist[play_index]; - m_current_song_playing_tmp = play; - } - // 若m_current_song_tmp不存在于初始化后的播放列表则这里设置的0值作为默认值被使用 - m_index = 0; - m_current_position = Time(); + m_playlist_mode = true; + m_sort_mode = SM_FILE; + m_descending = false; + m_contain_sub_folder = false; + m_index = play_index; + m_current_position.fromInt(0); - SaveCurrentPlaylist(); - SetTitle(); + // 向播放列表文件覆写songs + CPlaylistFile playlist; + playlist.FromSongList(songs); + playlist.SaveToFile(m_playlist_path); - IniPlayList(true, false, play); + IniPlayList(play); } void CPlayer::OpenASongInFolderMode(const SongInfo& song, bool play) @@ -1219,61 +1168,38 @@ void CPlayer::OpenASongInFolderMode(const SongInfo& song, bool play) m_loading = true; IniPlayerCore(); + SaveRecentInfoToFiles(); + MusicControl(Command::CLOSE); - if (GetSongNum() > 0) - { - SaveCurrentPlaylist(); - EmplaceCurrentPlaylistToRecent(); - EmplaceCurrentPathToRecent(); - } + CFilePathHelper file_path(song.file_path); m_path = file_path.GetDir(); - m_playlist.clear(); - m_current_position = { 0, 0, 0 }; + m_playlist_path.clear(); + m_playlist_mode = false; + m_sort_mode = SM_FILE; + m_descending = false; + m_contain_sub_folder = false; m_index = 0; + m_current_position.fromInt(0); - //获取打开路径的排序方式 - m_sort_mode = SortMode::SM_FILE; - m_descending = false; - for (const auto& path_info : m_recent_path) + // 如果是打开过的文件夹那么用保存的设置覆盖默认值 + auto iter = std::find_if(m_recent_path.begin(), m_recent_path.end(), + [&](const PathInfo& path_info) { return path_info.path == m_path; }); + if (iter != m_recent_path.end()) { - if (m_path == path_info.path) - { - m_sort_mode = path_info.sort_mode; - m_descending = path_info.descending; - } + const PathInfo& path_info = *iter; + m_sort_mode = path_info.sort_mode; + m_descending = path_info.descending; + m_contain_sub_folder = path_info.contain_sub_folder; + m_index = path_info.track; + m_current_position.fromInt(path_info.position); } // 使用切换播放列表继续播放实现初始化线程后的指定歌曲播放 m_current_song_tmp = song; m_current_song_position_tmp = 0; m_current_song_playing_tmp = play; - //初始化播放列表 - IniPlayList(false, false, play); //根据新路径重新初始化播放列表 -} - -bool CPlayer::OpenPlaylistFile(wstring& file_path) -{ - CFilePathHelper helper(file_path); - if (!CCommon::StringCompareNoCase(helper.GetDir(), theApp.m_playlist_dir)) //如果打开的播放列表文件不是程序默认的播放列表目录,则将其转换为*.playlist格式并复制到默认的播放列表目录 - { - //设置新的路径 - wstring playlist_name = helper.GetFileNameWithoutExtension(); - wstring new_path = theApp.m_playlist_dir + playlist_name + PLAYLIST_EXTENSION; - CCommon::FileAutoRename(new_path); - - CPlaylistFile playlist; - playlist.LoadFromFile(file_path); - playlist.SaveToFile(new_path); - file_path = new_path; - - return SetPlaylist(new_path, 0, 0); - } - else //如果打开的播放文件就在默认播放列表目录下,则直接打开 - { - auto path_info = CPlaylistMgr::Instance().FindPlaylistInfo(file_path); - return SetPlaylist(file_path, path_info.track, path_info.position); - } + IniPlayList(play); } bool CPlayer::AddFilesToPlaylist(const vector& files, bool ignore_if_exist) @@ -1286,7 +1212,7 @@ bool CPlayer::AddFilesToPlaylist(const vector& files, bool ignore_if_ex bool CPlayer::AddSongsToPlaylist(const vector& songs, bool ignore_if_exist) { - ASSERT(m_playlist_mode); //此方法仅限播放列表模式使用 + ASSERT(m_playlist_mode && !m_playlist_path.empty()); // 此方法仅限已处于播放列表模式时使用 if (songs.empty()) return false; if (m_loading) return false; @@ -1294,26 +1220,22 @@ bool CPlayer::AddSongsToPlaylist(const vector& songs, bool ignore_if_e m_loading = true; IniPlayerCore(); - if (m_playlist.size() == 1 && m_playlist[0].file_path.empty()/* && m_playlist[0].file_name.empty()*/) - m_playlist.clear(); //删除播放列表中的占位项 + // 这里有必要暂时关闭,故保存播放状态,AddSongsToPlaylist可能将歌曲插入到开头导致index不再准确 + m_current_song_tmp = GetCurrentSongInfo(); + m_current_song_position_tmp = GetCurrentPosition(); + m_current_song_playing_tmp = (m_playing == PlayingState::PS_PLAYING); - bool added{ false }; - SongInfo song_info; - for (const SongInfo& song : songs) - { - if (song.file_path.empty()) - continue; + MusicControl(Command::CLOSE); - if (ignore_if_exist && CCommon::IsItemInVector(m_playlist, [&](const SongInfo& tmp) { - return song.IsSameSong(tmp); - })) - continue; + // 向当前播放列表文件追加songs + CPlaylistFile playlist; + playlist.LoadFromFile(m_playlist_path); + bool added = playlist.AddSongsToPlaylist(songs, true); + playlist.SaveToFile(m_playlist_path); - m_playlist.push_back(song); - added = true; - } - SaveCurrentPlaylist(); - IniPlayList(true); + m_index = 0; + + IniPlayList(); return added; } @@ -1686,24 +1608,20 @@ void CPlayer::ReloadPlaylist(bool refresh_info) if (m_loading) return; if (!GetPlayStatusMutex().try_lock_for(std::chrono::milliseconds(1000))) return; m_loading = true; + IniPlayerCore(); - MusicControl(Command::CLOSE); - m_current_song_tmp = GetCurrentSongInfo(); // 保存当前播放的曲目,用于在播放列表初始化结束时确保播放的还是之前播放的曲目 + SaveRecentInfoToFiles(); + + // 保存当前播放状态,reload后如果当前歌曲还存在则恢复播放状态 + m_current_song_tmp = GetCurrentSongInfo(); m_current_song_position_tmp = GetCurrentPosition(); - if (!m_playlist_mode) - { - m_playlist.clear(); //清空播放列表 - IniPlayList(false, refresh_info); //根据新路径重新初始化播放列表 - } - else - { - m_playlist.clear(); - CPlaylistFile playlist; - playlist.LoadFromFile(m_playlist_path); - playlist.ToSongList(m_playlist); + m_current_song_playing_tmp = (m_playing == PlayingState::PS_PLAYING); - IniPlayList(true, refresh_info); - } + MusicControl(Command::CLOSE); + + m_index = 0; + + IniPlayList(false, true); } bool CPlayer::RemoveSong(int index, bool skip_locking) @@ -2342,10 +2260,7 @@ void CPlayer::OnExit() m_recent_path[0].track = m_index; m_recent_path[0].position = m_current_position.toInt(); } - SaveRecentPath(); - EmplaceCurrentPlaylistToRecent(); - CPlaylistMgr::Instance().SavePlaylistData(); - SaveCurrentPlaylist(); + SaveRecentInfoToFiles(); } void CPlayer::LoadRecentPath() @@ -2479,15 +2394,6 @@ void CPlayer::SaveCurrentPlaylist() { if (m_playlist_mode) { - //wstring current_playlist; - //if (CPlaylistMgr::Instance().m_cur_playlist_type == PT_DEFAULT || CPlaylistMgr::Instance().m_recent_playlists.empty()) - // current_playlist = CPlaylistMgr::Instance().m_default_playlist.path; - //else if (CPlaylistMgr::Instance().m_cur_playlist_type == PT_FAVOURITE) - // current_playlist = CPlaylistMgr::Instance().m_favourite_playlist.path; - //else if (CPlaylistMgr::Instance().m_cur_playlist_type == PT_TEMP) - // current_playlist = CPlaylistMgr::Instance().m_temp_playlist.path; - //else - // current_playlist = CPlaylistMgr::Instance().m_recent_playlists.front().path; CPlaylistFile playlist; playlist.FromSongList(m_playlist); playlist.SaveToFile(m_playlist_path); @@ -2504,7 +2410,7 @@ void CPlayer::EmplaceCurrentPathToRecent() if (m_path == m_recent_path[i].path) m_recent_path.erase(m_recent_path.begin() + i); //如果当前路径已经在最近路径中,就把它最近路径中删除 } - if (IsPlaylistEmpty()) return; //如果当前路径中没有文件,就不保存 + if (IsPlaylistEmpty()) return; // 如果当前路径中没有文件,就不保存 PathInfo path_info; path_info.path = m_path; path_info.track = m_index; @@ -2514,12 +2420,9 @@ void CPlayer::EmplaceCurrentPathToRecent() path_info.track_num = GetSongNum(); path_info.total_time = m_total_time; path_info.contain_sub_folder = m_contain_sub_folder; - if (GetSongNum() > 0) - { - path_info.last_played_time = CCommon::GetCurTimeElapse(); - m_recent_path.push_front(path_info); //当前路径插入到m_recent_path的前面 - CRecentFolderAndPlaylist::Instance().Init(); - } + path_info.last_played_time = CCommon::GetCurTimeElapse(); + m_recent_path.push_front(path_info); // 当前路径插入到m_recent_path的前面 + CRecentFolderAndPlaylist::Instance().Init(); } @@ -2891,7 +2794,6 @@ void CPlayer::SetContainSubFolder(bool contain_sub_folder) m_contain_sub_folder = contain_sub_folder; if (!IsPlaylistMode()) { - EmplaceCurrentPathToRecent(); ReloadPlaylist(false); } } diff --git a/MusicPlayer2/Player.h b/MusicPlayer2/Player.h index 968628cc3..d740aaaa5 100644 --- a/MusicPlayer2/Player.h +++ b/MusicPlayer2/Player.h @@ -53,7 +53,6 @@ class CPlayer struct ThreadInfo { bool refresh_info{}; - bool is_playlist_mode{}; // 指示是否为播放列表模式,文件夹模式加载完播放列表后需要排序 bool play{}; // 加载完播放列表后是否立即播放 int play_index{}; // 播放索引,播放列表模式下需要在cue解析时维持其指向 int process_percent{}; @@ -168,12 +167,12 @@ class CPlayer //初始化播放内核 void IniPlayerCore(); void UnInitPlayerCore(); - //初始化播放列表(如果参数playlist_mode为true,则为播放列表模式,否则从指定目录下搜索文件; - //如果refresh_info为true,则不管媒体库里是否有当前歌曲的信息,都从文件重新获取信息) - void IniPlayList(bool playlist_mode = false, bool refresh_info = false, bool play = false); - //改变当前路径 - void ChangePath(const wstring& path, int track = 0, bool play = false, int position = 0); + // 此方法进行重新填充m_playlist以及一些共有操作,最后会启动初始化播放列表线程函数,调用前必须停止播放 + // 调用完此方法后请尽快返回并且尽量不要执行任何操作,应当提前进行或安排在IniPlaylistComplate中进行 + // 此方法返回后的任何修改数据的操作都应视为(实际上也是如此)与IniPlaylistThreadFunc及IniPlaylistComplate处于竞争状态 + // play参数会传递到IniPlaylistComplate指示是否播放,refresh_info指示初始化线程总是重新从文件读取信息 + void IniPlayList(bool play = false, bool refresh_info = false); //应用一个均衡器通道的增益 void ApplyEqualizer(int channel, int gain); @@ -262,8 +261,10 @@ class CPlayer void MusicControl(Command command, int volume_step = 2); //判断当前音乐是否播放完毕 bool SongIsOver() const; - //从播放内核获取当前播放到的位置(更新m_current_position) + //从播放内核获取当前播放到的位置(更新m_current_position),仅限UI线程主动调用 void GetPlayerCoreCurrentPosition(); + //用m_volume的值设置音量 + void SetVolume(); //计算频谱分析 void CalculateSpectralData(); @@ -281,19 +282,26 @@ class CPlayer private: void LoopPlaylist(int& song_track); + void SaveRecentInfoToFiles(); + public: - //用m_volume的值设置音量 - void SetVolume(); + // 以下十个方法调用后时间上直到IniPlaylistComplate的最后unlock为止 + // 都是处于与IniPlaylistThreadFunc/IniPlaylistComplate/CMusicPlayerDlg::OnPlaylistIniComplate的数据竞争状态 + // 建议改在调用以下方法之前或IniPlaylistComplate中进行需要的操作,代替紧接着调用与上述方法竞争数据的方法 // 切换到指定路径的文件夹模式,没有PathInfo时应使用CPlayer::OpenFolder void SetPath(const PathInfo& path_info); - // 切换到指定播放列表模式 - // force为true时忽略continue_when_switch_playlist设置播放track指定歌曲(没能取得播放状态锁返回false) - bool SetPlaylist(const wstring& playlist_path, int track, int position, bool init = false, bool play = false, bool force = false); // 切换到指定路径的播放列表模式/通过“打开文件夹”来设置路径的处理 // (不进行“切换播放列表时继续播放”)(没能取得播放状态锁返回false) bool OpenFolder(wstring path, bool contain_sub_folder = false, bool play = false); + // 切换到指定播放列表模式(没能取得播放状态锁返回false) + // force为true时忽略continue_when_switch_playlist设置播放track指定歌曲 + bool SetPlaylist(const wstring& playlist_path, int track, int position, bool play = false, bool force = false); + // 打开一个播放列表文件(没能取得播放状态锁返回false) + // 支持所有支持的播放列表格式,不在默认播放列表目录则以.playlist格式复制到默认播放列表目录,会修改参数file_path为复制后的路径 + bool OpenPlaylistFile(wstring& file_path); + // 向默认播放列表添加并打开多个文件,play用来设置是否立即播放(没能取得播放状态锁返回false) // 由于cue解析问题,请在判断需要“添加歌曲”而不是“添加文件”时尽量使用CPlayer::OpenSongsInDefaultPlaylist代替此方法而不是使用path构建SongInfo bool OpenFilesInDefaultPlaylist(const vector& files, bool play = true); @@ -304,12 +312,9 @@ class CPlayer // 切换到此歌曲音频文件目录的文件夹模式并播放此歌曲 void OpenASongInFolderMode(const SongInfo& song, bool play = false); - // 打开一个播放列表文件(没能取得播放状态锁返回false) - // 支持所有支持的播放列表格式,不在默认播放列表目录则以.playlist格式复制到默认播放列表目录,会修改参数file_path为复制后的路径 - bool OpenPlaylistFile(wstring& file_path); // 向当前播放列表添加文件,仅在播放列表模式可用,如果一个都没有添加,则返回false,否则返回true // 由于cue解析问题,请在判断需要“添加歌曲”而不是“添加文件”时尽量使用CPlayer::AddSongs代替此方法而不是使用path构建SongInfo - // files内含有cue原始文件时返回值可能不正确(处理在线程函数,无法及时返回是否添加,初始化线程结束后有保存操作,不必另外执行保存) + // files内含有cue原始文件时返回值可能不正确(处理在线程函数,无法及时返回是否添加,初始化线程结束后有保存操作,不要另外执行保存) bool AddFilesToPlaylist(const vector& files, bool ignore_if_exist = false); // 向当前播放列表添加歌曲,仅在播放列表模式可用,如果一个都没有添加,则返回false,否则返回true bool AddSongsToPlaylist(const vector& songs, bool ignore_if_exist = false); diff --git a/MusicPlayer2/Playlist.cpp b/MusicPlayer2/Playlist.cpp index 245964bf5..0efa503ab 100644 --- a/MusicPlayer2/Playlist.cpp +++ b/MusicPlayer2/Playlist.cpp @@ -48,7 +48,7 @@ void CPlaylistFile::LoadFromFile(const wstring & file_path) std::getline(stream, current_line); DisposePlaylistFileLine(current_line, utf8); } - + stream.close(); } void CPlaylistFile::SaveToFile(const wstring & file_path, Type type) const @@ -101,6 +101,7 @@ void CPlaylistFile::SaveToFile(const wstring & file_path, Type type) const } } } + stream.close(); } const vector& CPlaylistFile::GetPlaylist() const @@ -132,10 +133,7 @@ void CPlaylistFile::FromSongList(const vector& song_list) void CPlaylistFile::ToSongList(vector& song_list) { - for (const auto& item : m_playlist) - { - song_list.push_back(item); - } + song_list.insert(song_list.end(), m_playlist.begin(), m_playlist.end()); } bool CPlaylistFile::IsSongInPlaylist(const SongInfo& song) diff --git a/MusicPlayer2/PlaylistMgr.cpp b/MusicPlayer2/PlaylistMgr.cpp index 09aff0060..96d99b072 100644 --- a/MusicPlayer2/PlaylistMgr.cpp +++ b/MusicPlayer2/PlaylistMgr.cpp @@ -114,6 +114,12 @@ void CPlaylistMgr::UpdateCurrentPlaylist(int track, int pos, int track_num, int } } +void CPlaylistMgr::UpdateCurrentPlaylistType(const wstring& path) +{ + if (path.empty()) return; + m_cur_playlist_type = GetPlaylistType(path); +} + void CPlaylistMgr::UpdatePlaylistInfo(PlaylistInfo playlist_info) { PlaylistType type = GetPlaylistType(playlist_info.path); @@ -342,6 +348,18 @@ PlaylistInfo CPlaylistMgr::FindPlaylistInfo(const wstring& str) const } } +PlaylistInfo CPlaylistMgr::GetCurrentPlaylistInfo() const +{ + if (m_cur_playlist_type == PT_DEFAULT || m_recent_playlists.empty()) // m_recent_playlists为空时返回默认播放列表 + return m_default_playlist; + else if (m_cur_playlist_type == PT_FAVOURITE) + return m_favourite_playlist; + else if (m_cur_playlist_type == PT_TEMP) + return m_temp_playlist; + else + return m_recent_playlists.front(); +} + PlaylistType CPlaylistMgr::GetPlaylistType(const wstring& path) const { if (path == m_default_playlist.path) diff --git a/MusicPlayer2/PlaylistMgr.h b/MusicPlayer2/PlaylistMgr.h index 4def6b891..b77951ef4 100644 --- a/MusicPlayer2/PlaylistMgr.h +++ b/MusicPlayer2/PlaylistMgr.h @@ -31,12 +31,14 @@ class CPlaylistMgr void AddNewPlaylist(const wstring& path); bool DeletePlaylist(const wstring& path); void UpdateCurrentPlaylist(int track, int pos, int track_num, int total_time); + void UpdateCurrentPlaylistType(const wstring& path); void UpdatePlaylistInfo(PlaylistInfo playlist_info); void SavePlaylistData(); void LoadPlaylistData(); PlaylistInfo FindPlaylistInfo(const wstring& str) const; + PlaylistInfo GetCurrentPlaylistInfo() const; PlaylistType GetPlaylistType(const wstring& path) const; private: