xref: /MusicPlayer2/MusicPlayer2/MediaLibHelper.cpp (revision 965ce478a79b0d21e8a6e2ade0490efa175855dd)
1 #include "stdafx.h"
2 #include "MediaLibHelper.h"
3 #include "MusicPlayer2.h"
4 #include "SongDataManager.h"
5 #include "FilePathHelper.h"
6 
7 
operator ()(const std::wstring & a,const std::wstring & b) const8 bool StringComparerNoCase::operator()(const std::wstring& a, const std::wstring& b) const
9 {
10     return CCommon::StringCompareInLocalLanguage(a, b, true) < 0;
11 }
12 
CMediaClassifier(ClassificationType type,bool hide_only_one_classification)13 CMediaClassifier::CMediaClassifier(ClassificationType type, bool hide_only_one_classification)
14     : m_type(type), m_hide_only_one_classification(hide_only_one_classification)
15 {
16 }
17 
18 
~CMediaClassifier()19 CMediaClassifier::~CMediaClassifier()
20 {
21 }
22 
GetMeidaList() const23 const CMediaClassifier::MediaList& CMediaClassifier::GetMeidaList() const
24 {
25     return m_media_list;
26 }
27 
GetMeidaList()28 CMediaClassifier::MediaList& CMediaClassifier::GetMeidaList()
29 {
30     return m_media_list;
31 }
32 
ClassifyMedia()33 void CMediaClassifier::ClassifyMedia()
34 {
35     m_media_list.clear();
36     CSongDataManager::GetInstance().GetSongData([&](const CSongDataManager::SongDataMap& song_data_map)
37         {
38             for (const auto& song_info : song_data_map)
39             {
40                 std::vector<std::wstring> item_names;
41                 switch (m_type)
42                 {
43                 case CMediaClassifier::CT_ARTIST:
44                 {
45                     static const wstring& default_artist = theApp.m_str_table.LoadText(L"TXT_EMPTY_ARTIST");
46                     song_info.second.GetArtistList(item_names);   // 有的歌曲可能有多个艺术家,将解析到的艺术家保存到vector里
47                     for (auto& item_name : item_names)
48                         CCommon::StringNormalize(item_name);
49                     if (item_names.empty() || (item_names.size() == 1 && default_artist == item_names[0]))
50                     {
51                         item_names.clear();
52                         item_names.push_back(std::wstring());
53                     }
54                 }
55                 break;
56                 case CMediaClassifier::CT_ALBUM:
57                 {
58                     static const wstring& default_album = theApp.m_str_table.LoadText(L"TXT_EMPTY_ALBUM");
59                     wstring str_album = song_info.second.album;
60                     if (default_album == str_album)
61                         str_album.clear();
62                     item_names.push_back(str_album);
63                 }
64                 break;
65                 case CMediaClassifier::CT_GENRE:
66                 {
67                     static const wstring& default_genre = theApp.m_str_table.LoadText(L"TXT_EMPTY_GENRE");
68                     wstring str_genre = song_info.second.genre;
69                     if (default_genre == str_genre)
70                         str_genre.clear();
71                     item_names.push_back(str_genre);
72                 }
73                 break;
74                 case CMediaClassifier::CT_YEAR:
75                 {
76                     static const wstring& default_year = theApp.m_str_table.LoadText(L"TXT_EMPTY_YEAR");
77                     wstring str_year = song_info.second.get_year();
78                     if (default_year == str_year)
79                         str_year.clear();
80                     if (str_year.size() > 4)
81                         str_year.resize(4);
82                     item_names.push_back(str_year);
83                 }
84                 break;
85                 case CMediaClassifier::CT_TYPE:
86                 {
87                     wstring str_type = CFilePathHelper(song_info.first.path).GetFileExtension();
88                     item_names.push_back(str_type);
89                 }
90                 break;
91                 case CMediaClassifier::CT_BITRATE:
92                 {
93                     wstring str_type;
94                     if (song_info.second.bitrate == 0)
95                         str_type = L"-";
96                     else if (song_info.second.bitrate < 32)
97                         str_type = L"<32";
98                     else if (song_info.second.bitrate < 64)
99                         str_type = L"32+";
100                     else if (song_info.second.bitrate < 128)
101                         str_type = L"64+";
102                     else if (song_info.second.bitrate < 192)
103                         str_type = L"128+";
104                     else if (song_info.second.bitrate < 300)
105                         str_type = L"192+";
106                     else if (song_info.second.bitrate < 512)
107                         str_type = L"300+";
108                     else if (song_info.second.bitrate < 1024)
109                         str_type = L"512+";
110                     else
111                         str_type = L"1024+";
112                     item_names.push_back(str_type);
113                 }
114                 break;
115                 case CT_RATING:
116                 {
117                     wstring str_type;
118                     if (song_info.second.rating >= 1 && song_info.second.rating <= 5)
119                         str_type = std::to_wstring(song_info.second.rating);
120                     else
121                         str_type = theApp.m_str_table.LoadText(L"TXT_EMPTY_RATED");
122                     item_names.push_back(str_type);
123                     break;
124                 }
125                 default:
126                     break;
127                 }
128 
129                 for (const auto& item_name : item_names)
130                 {
131                     auto iter = m_media_list.find(item_name);
132                     if (iter != m_media_list.end())
133                         iter->second.push_back(song_info.second);
134                     else
135                         m_media_list[item_name].push_back(song_info.second);
136                 }
137             }
138         });
139 
140     std::vector<SongInfo> other_list;
141 
142     //查找只有一个项目的分类,将其归到“其他”类里
143     if (m_hide_only_one_classification && (m_type == CT_ARTIST || m_type == CT_ALBUM || m_type == CT_GENRE))
144     {
145         for (auto iter{ m_media_list.begin() }; iter != m_media_list.end();)
146         {
147             if (iter->second.size() == 1)
148             {
149                 //确保其他类列表里的项目不会重复
150                 if (!CCommon::IsItemInVector(other_list, [&](const SongInfo& item) {
151                     return item.file_path == iter->second[0].file_path;
152                     }))
153                 {
154                     other_list.push_back(iter->second[0]);
155                 }
156                     iter = m_media_list.erase(iter);
157             }
158             else
159             {
160                 ++iter;
161             }
162         }
163         if (m_type == CT_ARTIST)
164             std::sort(other_list.begin(), other_list.end(), SongInfo::GetSortFunc(SM_U_ARTIST));
165         else if (m_type == CT_ALBUM)
166             std::sort(other_list.begin(), other_list.end(), SongInfo::GetSortFunc(SM_U_ALBUM));
167         else if (m_type == CT_GENRE)
168             std::sort(other_list.begin(), other_list.end(), SongInfo::GetSortFunc(SM_U_GENRE));
169         //else if (m_type == CT_YEAR)
170         //    std::sort(other_list.begin(), other_list.end(), SongInfo::GetSortFunc(SM_U_YEAR));
171         if (!other_list.empty())
172             m_media_list[STR_OTHER_CLASSIFY_TYPE] = other_list;
173     }
174 
175     //将年份不是4位数字的归到“其他”类里
176     if (m_type == CT_YEAR)
177     {
178         for (auto iter{ m_media_list.begin() }; iter != m_media_list.end();)
179         {
180             if (!iter->first.empty() && !IsStringYear(iter->first))     //如果年份不是4位数字,则添加到其他列表里
181             {
182                 other_list.insert(other_list.end(), iter->second.begin(), iter->second.end());
183                 iter = m_media_list.erase(iter);
184             }
185             else
186             {
187                 ++iter;
188             }
189         }
190         if (!other_list.empty())
191             m_media_list[STR_OTHER_CLASSIFY_TYPE] = other_list;
192     }
193 
194     for (auto& item : m_media_list)
195     {
196         if (item.first != STR_OTHER_CLASSIFY_TYPE)
197         {
198             if (m_type == CT_ALBUM)    //“唱片集”类别中,默认按音轨序号排序
199                 std::sort(item.second.begin(), item.second.end(), SongInfo::GetSortFunc(SM_U_TRACK));
200             else    //其他类别默认按文件路径排序
201                 std::sort(item.second.begin(), item.second.end(), SongInfo::GetSortFunc(SM_U_PATH));
202         }
203     }
204 }
205 
IsStringYear(std::wstring str)206 bool CMediaClassifier::IsStringYear(std::wstring str)
207 {
208     if (str.size() < 4)
209         return false;
210     str.resize(4);
211 
212     for (size_t i = 0; i < 4; i++)
213     {
214         if (str[i] < L'0' || str[i] > L'9')
215             return false;
216     }
217 
218     return str > L"1000" && str < L"3000";
219 }
220 
ClearResult()221 void CMediaClassifier::ClearResult()
222 {
223     m_media_list.clear();
224 }
225 
RemoveFiles(std::vector<SongInfo> songs)226 void CMediaClassifier::RemoveFiles(std::vector<SongInfo> songs)
227 {
228     auto isRemoved = [&](const SongInfo& song)
229     {
230         for (const auto& item : songs)
231         {
232             if (item.IsSameSong(song))
233                 return true;
234         }
235         return false;
236     };
237     for (auto& item : m_media_list)
238     {
239         auto iter_removed = std::remove_if(item.second.begin(), item.second.end(), isRemoved);
240         item.second.erase(iter_removed, item.second.end());
241     }
242 }
243 
SetHideOnlyOneClassification(bool hide_only_one_classification)244 void CMediaClassifier::SetHideOnlyOneClassification(bool hide_only_one_classification)
245 {
246     m_hide_only_one_classification = hide_only_one_classification;
247 }
248