xref: /MusicPlayer2/MusicPlayer2/UiMediaLibItemMgr.cpp (revision b02ea78914f3f3cea834525e3ae2052cd91d1e6d)
1 #include "stdafx.h"
2 #include "UiMediaLibItemMgr.h"
3 #include "MusicPlayer2.h"
4 #include "Playlist.h"
5 #include "SongDataManager.h"
6 #include "SongInfoHelper.h"
7 #include "CRecentList.h"
8 #include "Player.h"
9 
10 CUiMediaLibItemMgr CUiMediaLibItemMgr::m_instance;
11 
~CUiMediaLibItemMgr()12 CUiMediaLibItemMgr::~CUiMediaLibItemMgr()
13 {
14 }
15 
Instance()16 CUiMediaLibItemMgr& CUiMediaLibItemMgr::Instance()
17 {
18     return m_instance;
19 }
20 
GetClassifiedMeidaLibItemList(CMediaClassifier::ClassificationType type)21 void CUiMediaLibItemMgr::GetClassifiedMeidaLibItemList(CMediaClassifier::ClassificationType type)
22 {
23     auto& item_list{ m_item_map[type] };
24     item_list.clear();
25     CMediaClassifier classifier(type, theApp.m_media_lib_setting_data.hide_only_one_classification);
26     classifier.ClassifyMedia();
27     for (const auto& item : classifier.GetMeidaList())
28     {
29         if (item.first != STR_OTHER_CLASSIFY_TYPE)
30         {
31             ItemInfo info;
32             info.name = item.first;
33             info.count = item.second.size();
34             item_list.push_back(info);
35         }
36     }
37 }
38 
Init()39 void CUiMediaLibItemMgr::Init()
40 {
41     m_loading = true;
42     std::shared_lock<std::shared_mutex> lock(m_shared_mutex);
43 
44     GetClassifiedMeidaLibItemList(CMediaClassifier::CT_ARTIST);
45     GetClassifiedMeidaLibItemList(CMediaClassifier::CT_ALBUM);
46     GetClassifiedMeidaLibItemList(CMediaClassifier::CT_GENRE);
47     GetClassifiedMeidaLibItemList(CMediaClassifier::CT_YEAR);
48     GetClassifiedMeidaLibItemList(CMediaClassifier::CT_TYPE);
49     GetClassifiedMeidaLibItemList(CMediaClassifier::CT_BITRATE);
50     GetClassifiedMeidaLibItemList(CMediaClassifier::CT_RATING);
51 
52     m_loading = false;
53     m_inited = true;
54 }
55 
GetItemCount(CMediaClassifier::ClassificationType type) const56 int CUiMediaLibItemMgr::GetItemCount(CMediaClassifier::ClassificationType type) const
57 {
58     if (!m_loading)
59     {
60         auto iter = m_item_map.find(type);
61         if (iter != m_item_map.end())
62             return static_cast<int>(iter->second.size());
63     }
64     return 0;
65 }
66 
GetItemDisplayName(CMediaClassifier::ClassificationType type,int index) const67 std::wstring CUiMediaLibItemMgr::GetItemDisplayName(CMediaClassifier::ClassificationType type, int index) const
68 {
69     if (!m_loading)
70     {
71         const std::wstring& name{ GetItemName(type, index) };
72         ListItem list_item{ LT_MEDIA_LIB, name };
73         list_item.medialib_type = type;
74         return list_item.GetDisplayName();
75     }
76     return std::wstring();
77 }
78 
GetItemInfo(CMediaClassifier::ClassificationType type,int index) const79 const CUiMediaLibItemMgr::ItemInfo& CUiMediaLibItemMgr::GetItemInfo(CMediaClassifier::ClassificationType type, int index) const
80 {
81     if (!m_loading)
82     {
83         auto iter = m_item_map.find(type);
84         if (iter != m_item_map.end())
85         {
86             const auto& item_list{ iter->second };
87             if (index >= 0 && index < static_cast<int>(item_list.size()))
88             {
89                 return item_list[index];
90             }
91         }
92     }
93     static ItemInfo empty_info{};
94     return empty_info;
95 }
96 
GetItemName(CMediaClassifier::ClassificationType type,int index) const97 const std::wstring& CUiMediaLibItemMgr::GetItemName(CMediaClassifier::ClassificationType type, int index) const
98 {
99     return GetItemInfo(type, index).name;
100 }
101 
GetItemSongCount(CMediaClassifier::ClassificationType type,int index) const102 int CUiMediaLibItemMgr::GetItemSongCount(CMediaClassifier::ClassificationType type, int index) const
103 {
104     return GetItemInfo(type, index).count;
105 }
106 
SetCurrentName(CMediaClassifier::ClassificationType type,const std::wstring & name)107 void CUiMediaLibItemMgr::SetCurrentName(CMediaClassifier::ClassificationType type, const std::wstring& name)
108 {
109     m_current_name_map[type] = name;
110     m_current_index_map.erase(type);
111 }
112 
GetCurrentIndex(CMediaClassifier::ClassificationType type)113 int CUiMediaLibItemMgr::GetCurrentIndex(CMediaClassifier::ClassificationType type)
114 {
115     if (!m_loading)
116     {
117         auto index_iter = m_current_index_map.find(type);
118         if (index_iter == m_current_index_map.end())
119         {
120             //根据名称查找所在的序号
121             auto name_iter = m_current_name_map.find(type);
122             if (name_iter != m_current_name_map.end())
123             {
124                 const auto& name_list{ m_item_map[type] };
125                 auto iter = std::find_if(name_list.begin(), name_list.end(), [&](const ItemInfo& item) {
126                     return item.name == name_iter->second;
127                 });
128                 if (iter != name_list.end())
129                 {
130                     int index = iter - name_list.begin();
131                     //设置当前项目的序号
132                     m_current_index_map[type] = index;
133                     return index;
134                 }
135             }
136         }
137         else
138         {
139             return index_iter->second;
140         }
141     }
142 
143     return -1;
144 }
145 
CUiMediaLibItemMgr()146 CUiMediaLibItemMgr::CUiMediaLibItemMgr()
147 {
148 }
149 
150 
151 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
152 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
153 CUiMyFavouriteItemMgr CUiMyFavouriteItemMgr::m_instance;
154 
~CUiMyFavouriteItemMgr()155 CUiMyFavouriteItemMgr::~CUiMyFavouriteItemMgr()
156 {
157 }
158 
Instance()159 CUiMyFavouriteItemMgr& CUiMyFavouriteItemMgr::Instance()
160 {
161     return m_instance;
162 }
163 
GetSongCount() const164 int CUiMyFavouriteItemMgr::GetSongCount() const
165 {
166     if (!m_loading)
167         return static_cast<int>(m_may_favourite_song_list.size());
168     else
169         return 0;
170 }
171 
GetSongInfo(int index) const172 const SongInfo& CUiMyFavouriteItemMgr::GetSongInfo(int index) const
173 {
174     if (!m_loading)
175     {
176         if (index >= 0 && index < GetSongCount())
177             return m_may_favourite_song_list[index];
178     }
179     static SongInfo empty_song;
180     return empty_song;
181 }
182 
UpdateMyFavourite()183 void CUiMyFavouriteItemMgr::UpdateMyFavourite()
184 {
185     m_loading = true;
186     std::shared_lock<std::shared_mutex> lock(m_shared_mutex);
187 
188     ListItem list_item = CRecentList::Instance().GetSpecPlaylist(CRecentList::PT_FAVOURITE);
189     CPlaylistFile playlist_file;
190     playlist_file.LoadFromFile(list_item.path);
191     playlist_file.MoveToSongList(m_may_favourite_song_list);
192     CSongDataManager::GetInstance().LoadSongsInfo(m_may_favourite_song_list);  // 从媒体库加载歌曲属性
193 
194     m_loading = false;
195     m_inited = true;
196 }
197 
GetSongList(std::vector<SongInfo> & song_list) const198 void CUiMyFavouriteItemMgr::GetSongList(std::vector<SongInfo>& song_list) const
199 {
200     std::copy(m_may_favourite_song_list.begin(), m_may_favourite_song_list.end(), std::back_inserter(song_list));
201 }
202 
Contains(const SongInfo & song) const203 bool CUiMyFavouriteItemMgr::Contains(const SongInfo& song) const
204 {
205     auto iter = std::find_if(m_may_favourite_song_list.begin(), m_may_favourite_song_list.end(), [&](const SongInfo& a) {
206         return a.IsSameSong(song);
207     });
208     return iter != m_may_favourite_song_list.end();
209 }
210 
CUiMyFavouriteItemMgr()211 CUiMyFavouriteItemMgr::CUiMyFavouriteItemMgr()
212 {
213 }
214 
215 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
216 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
217 CUiAllTracksMgr CUiAllTracksMgr::m_instance;
218 
~CUiAllTracksMgr()219 CUiAllTracksMgr::~CUiAllTracksMgr()
220 {
221 }
222 
Instance()223 CUiAllTracksMgr& CUiAllTracksMgr::Instance()
224 {
225     return m_instance;
226 }
227 
GetSongCount() const228 int CUiAllTracksMgr::GetSongCount() const
229 {
230     if (!m_loading)
231         return static_cast<int>(m_all_tracks_list.size());
232     else
233         return 0;
234 }
235 
GetSongInfo(int index) const236 SongInfo CUiAllTracksMgr::GetSongInfo(int index) const
237 {
238     if (!m_loading)
239     {
240         if (index >= 0 && index < GetSongCount())
241             return CSongDataManager::GetInstance().GetSongInfo(m_all_tracks_list[index].song_key);
242     }
243     static SongInfo empty_song;
244     return empty_song;
245 }
246 
GetItem(int index) const247 const CUiAllTracksMgr::UTrackInfo& CUiAllTracksMgr::GetItem(int index) const
248 {
249     if (!m_loading)
250     {
251         if (index >= 0 && index < GetSongCount())
252             return m_all_tracks_list[index];
253     }
254     static UTrackInfo empty_item;
255     return empty_item;
256 }
257 
GetCurrentIndex() const258 int CUiAllTracksMgr::GetCurrentIndex() const
259 {
260     return m_current_index;
261 }
262 
SetCurrentSong(const SongInfo & song)263 void CUiAllTracksMgr::SetCurrentSong(const SongInfo& song)
264 {
265     if (!m_loading && m_inited && !song.IsEmpty())
266     {
267         int index{};
268         for (const auto& item : m_all_tracks_list)
269         {
270             if (std::equal_to<SongKey>()(SongKey(song), item.song_key))
271             {
272                 m_current_index = index;
273                 break;
274             }
275             index++;
276         }
277     }
278 }
279 
UpdateAllTracks()280 void CUiAllTracksMgr::UpdateAllTracks()
281 {
282     m_loading = true;
283     std::shared_lock<std::shared_mutex> lock(m_shared_mutex);
284 
285     m_all_tracks_list.clear();
286     vector<SongInfo> tmp_song_list;
287     //从song data中读取
288     CSongDataManager::GetInstance().GetSongData([&](const CSongDataManager::SongDataMap& song_data_map) {
289         tmp_song_list.reserve(song_data_map.size());
290         std::transform(song_data_map.begin(), song_data_map.end(), std::back_inserter(tmp_song_list), [](const auto& item) { return item.second; });
291     });
292 
293     //从CRecentList中查找“所有曲目”,并获取排序方式
294     ListItem list_item{ LT_MEDIA_LIB, L"" };
295     list_item.medialib_type = CMediaClassifier::CT_NONE;
296     CRecentList::Instance().LoadItem(list_item);
297     //对所有曲目排序
298     auto sort_fun = SongInfo::GetSortFunc(list_item.GetDefaultSortMode());
299     std::stable_sort(tmp_song_list.begin(), tmp_song_list.end(), sort_fun);
300     std::transform(tmp_song_list.begin(), tmp_song_list.end(), std::back_inserter(m_all_tracks_list), [](const SongInfo& song_info) {
301         UTrackInfo item;
302         item.song_key = song_info;
303         item.name = CSongInfoHelper::GetDisplayStr(song_info, theApp.m_media_lib_setting_data.display_format);
304         item.length = song_info.length();
305         item.is_favourite = CUiMyFavouriteItemMgr::Instance().Contains(song_info);
306         return item;
307         });
308     m_loading = false;
309     m_inited = true;
310 }
311 
GetSongList(std::vector<SongInfo> & song_list) const312 void CUiAllTracksMgr::GetSongList(std::vector<SongInfo>& song_list) const
313 {
314     for (const auto& item : m_all_tracks_list)
315     {
316         SongInfo song{ CSongDataManager::GetInstance().GetSongInfo(item.song_key) };
317         song_list.push_back(song);
318     }
319 }
320 
AddOrRemoveMyFavourite(int index)321 void CUiAllTracksMgr::AddOrRemoveMyFavourite(int index)
322 {
323     if (!m_loading && m_inited && index >= 0 && index < GetSongCount())
324     {
325         m_all_tracks_list[index].is_favourite = !m_all_tracks_list[index].is_favourite;
326     }
327 }
328 
CUiAllTracksMgr()329 CUiAllTracksMgr::CUiAllTracksMgr()
330 {
331 }
332 
333 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
334 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
335 CUiFolderExploreMgr CUiFolderExploreMgr::m_instance;
336 
Instance()337 CUiFolderExploreMgr& CUiFolderExploreMgr::Instance()
338 {
339     return m_instance;
340 }
341 
GetRootNodes()342 std::vector<std::shared_ptr<UiElement::TreeElement::Node>>& CUiFolderExploreMgr::GetRootNodes()
343 {
344     if (m_loading)
345     {
346         static std::vector<std::shared_ptr<UiElement::TreeElement::Node>> empty_nodes;
347         return empty_nodes;
348     }
349     else
350     {
351         return m_root_nodes;
352     }
353 }
354 
UpdateFolders()355 void CUiFolderExploreMgr::UpdateFolders()
356 {
357     m_loading = true;
358 
359     m_root_nodes.clear();
360 
361     //这里等待播放内核加载完成,否则无法判断文件夹内音频文件数量
362     while (!CPlayer::GetInstance().IsPlayerCoreInited())
363     {
364         Sleep(20);
365     }
366 
367     //获取媒体库目录
368     for (const auto& default_folder : theApp.m_media_lib_setting_data.media_folders)
369     {
370         int audo_file_count = GetAudioFilesNum(default_folder);
371         auto root_node = UiElement::FolderExploreTree::CreateNode(default_folder, audo_file_count, nullptr);
372         root_node->collapsed = false;       //默认展开顶级节点
373         m_root_nodes.push_back(root_node);
374         CreateFolderNodeByPath(default_folder, root_node);
375     }
376 
377     m_loading = false;
378 }
379 
CUiFolderExploreMgr()380 CUiFolderExploreMgr::CUiFolderExploreMgr()
381 {
382 }
383 
CreateFolderNodeByPath(std::wstring path,std::shared_ptr<UiElement::TreeElement::Node> parent)384 void CUiFolderExploreMgr::CreateFolderNodeByPath(std::wstring path, std::shared_ptr<UiElement::TreeElement::Node> parent)
385 {
386     //文件句柄
387     intptr_t hFile = 0;
388     //文件信息
389     _wfinddata_t fileinfo;
390     if (path.back() != '\\' && path.back() != '/')
391         path.push_back('\\');
392     if ((hFile = _wfindfirst((path + L"*").c_str(), &fileinfo)) != -1)
393     {
394         do
395         {
396             std::wstring file_name = fileinfo.name;
397             if (file_name == L"." || file_name == L"..")
398                 continue;
399 
400             std::wstring sub_file_path = path + file_name;
401             int audo_file_count = GetAudioFilesNum(sub_file_path);
402             if (CCommon::IsFolder(sub_file_path) && audo_file_count > 0)        //当前是文件夹且包含音频文件,则递归调用
403             {
404                 auto sub_node = UiElement::FolderExploreTree::CreateNode(file_name, audo_file_count, parent);
405                 CreateFolderNodeByPath(sub_file_path, sub_node);
406             }
407         } while (_wfindnext(hFile, &fileinfo) == 0);
408     }
409     _findclose(hFile);
410 }
411 
GetAudioFilesNum(std::wstring path)412 int CUiFolderExploreMgr::GetAudioFilesNum(std::wstring path)
413 {
414     if (path.back() != '\\' && path.back() != '/')
415         path.push_back('\\');
416 
417     auto iter = m_folder_audio_files_num.find(path);
418     if (iter != m_folder_audio_files_num.end())
419     {
420         return iter->second;
421     }
422     else
423     {
424         int audio_file_count = 0;
425         //文件句柄
426         intptr_t hFile = 0;
427         //文件信息
428         _wfinddata_t fileinfo;
429         if ((hFile = _wfindfirst((path + L"*").c_str(), &fileinfo)) != -1)
430         {
431             do
432             {
433                 wstring file_name = fileinfo.name;
434                 if (file_name == L"." || file_name == L"..")
435                     continue;
436 
437                 if (CCommon::IsFolder(path + file_name))        //是文件夹,则递归调用
438                 {
439                     audio_file_count += GetAudioFilesNum(path + file_name);
440                 }
441                 else
442                 {
443                     if (CAudioCommon::FileIsAudio(path + file_name))	//找到了音频文件
444                         audio_file_count++;
445                 }
446             } while (_wfindnext(hFile, &fileinfo) == 0);
447         }
448         _findclose(hFile);
449 
450         m_folder_audio_files_num[path] = audio_file_count;
451         return audio_file_count;
452     }
453 }
454