1 #include "stdafx.h"
2 #include "COSUPlayerHelper.h"
3 #include "FilePathHelper.h"
4 #include "AudioCommon.h"
5 #include "Common.h"
6
7
COSUPlayerHelper()8 COSUPlayerHelper::COSUPlayerHelper()
9 {
10 }
11
12
~COSUPlayerHelper()13 COSUPlayerHelper::~COSUPlayerHelper()
14 {
15 }
16
IsOsuFolder(const std::wstring & strPath)17 bool COSUPlayerHelper::IsOsuFolder(const std::wstring & strPath)
18 {
19 if (strPath.empty())
20 return false;
21
22 wstring folder_path{ strPath };
23 if (folder_path.back() != L'\\' && folder_path.back() != L'/')
24 folder_path.push_back(L'\\');
25
26 CFilePathHelper path_helper(folder_path);
27 wstring parent_dir = path_helper.GetParentDir();
28
29 //判断一个文件是否为osu的Songs目录:它的父级目录有osu!.exe文件且文件夹是Songs
30 return folder_path.size() > 7 && folder_path.substr(folder_path.size() - 6, 5) == L"Songs" && CCommon::FileExist(parent_dir + L"osu!.exe");
31 }
32
IsOsuFile(const std::wstring & strPath)33 bool COSUPlayerHelper::IsOsuFile(const std::wstring& strPath)
34 {
35 if (strPath.empty())
36 return false;
37
38 CFilePathHelper path_helper(strPath);
39 return IsOsuFolder(path_helper.GetParentDir());
40 }
41
GetOSUAudioFiles(wstring path,vector<SongInfo> & song_list)42 void COSUPlayerHelper::GetOSUAudioFiles(wstring path, vector<SongInfo>& song_list)
43 {
44 vector<wstring> files;
45 GetOSUAudioFiles(path, files);
46 for (const auto& file : files)
47 {
48 SongInfo song_info;
49 song_info.file_path = file;
50 song_list.push_back(song_info);
51 }
52 }
53
GetOSUAudioFiles(wstring path,vector<wstring> & files)54 void COSUPlayerHelper::GetOSUAudioFiles(wstring path, vector<wstring>& files)
55 {
56 if (path.back() != L'\\' && path.back() != L'/')
57 path.push_back(L'\\');
58
59 vector<wstring> folder_list;
60 CCommon::GetFiles(path + L"*", folder_list);
61 for (const auto& folder_name : folder_list)
62 {
63 if(folder_name == L"." || folder_name == L"..")
64 continue;
65
66 std::vector<wstring> osu_list;
67 CCommon::GetFiles(path + folder_name + L"\\*.osu", osu_list);
68 if(!osu_list.empty())
69 {
70 COSUFile osu_file{ (path + folder_name + L'\\' + osu_list.front()).c_str() };
71 wstring file_name = path + folder_name + L'\\' + osu_file.GetAudioFileName();
72 // 这里的file_name大小写可能与实际文件不同会导致自动更新/播放时媒体库出现大小写各一份,这里统一以音频文件为准
73 if (CCommon::CheckAndFixFile(file_name))
74 files.push_back(file_name);
75 }
76 }
77 }
78
GetOSUAudioTitleArtist(SongInfo & song_info)79 void COSUPlayerHelper::GetOSUAudioTitleArtist(SongInfo & song_info)
80 {
81 CFilePathHelper file_path{ song_info.file_path };
82 wstring song_folder = file_path.GetDir();
83
84 std::vector<wstring> osu_list;
85 CCommon::GetFiles(song_folder + L"*.osu", osu_list);
86 if (!osu_list.empty())
87 {
88 COSUFile osu_file{ (song_folder + osu_list.front()).c_str() };
89 song_info.artist = osu_file.GetArtist();
90 song_info.title = osu_file.GetTitle();
91 song_info.album = osu_file.GetAlbum();
92
93 wstring id = osu_file.GetBeatampSetId();
94 wstring folder_name = file_path.GetFolderName();
95 if (id.empty())
96 {
97 size_t index = folder_name.find(L' ');
98 id = folder_name.substr(0, index);
99 }
100 song_info.track = _wtoi(id.c_str());
101 song_info.comment = folder_name;
102 }
103 }
104
GetAlbumCover(wstring file_path)105 wstring COSUPlayerHelper::GetAlbumCover(wstring file_path)
106 {
107 wstring dir;
108 CFilePathHelper path_helper(file_path);
109 dir = path_helper.GetDir();
110
111 wstring album_cover_file_name;
112 std::vector<wstring> osu_list;
113 CCommon::GetFiles(dir + L"*.osu", osu_list);
114 std::sort(osu_list.begin(), osu_list.end()); // 不存在BeatampId标签时使用此次排序后第一个osu文件的封面
115 int beatmap_id{};
116 for (const wstring& osu_item : osu_list)
117 {
118 COSUFile osu_file{ (dir + osu_item).c_str() };
119 wstring id_s{ osu_file.GetBeatampId() };
120 if (!id_s.empty())
121 {
122 int id_i{ std::stoi(id_s) };
123 if (beatmap_id == 0 || beatmap_id > id_i) // 取得beatmap_id最小的osu文件对应封面
124 {
125 beatmap_id = id_i;
126 album_cover_file_name = osu_file.GetAlbumCoverFileName();
127 }
128 }
129 else // 如果出现id_s为空说明osu文件版本较旧,获取osu_list[0]的封面后退出循环
130 {
131 album_cover_file_name = osu_file.GetAlbumCoverFileName();
132 break;
133 }
134 }
135
136 if (!CCommon::FileExist(dir + album_cover_file_name))
137 {
138 vector<wstring> image_list;
139 CCommon::GetFiles(dir + L"*.jpg", image_list);
140 if (!image_list.empty())
141 {
142 album_cover_file_name = image_list[0];
143 }
144 }
145
146 //没有找到封面时查找osu目录下Data\bg里面的图片,并随机选择一张作为封面
147 if (!CCommon::FileExist(dir + album_cover_file_name))
148 {
149 static std::map<wstring, wstring> bg_map; //每次为一首没有封面的文件随机选择一张封面后保存起来,下次则直接返回上次获取的封面
150 auto iter = bg_map.find(file_path);
151 if (iter != bg_map.end())
152 {
153 return iter->second;
154 }
155 else
156 {
157 wstring songs_dir = path_helper.GetParentDir();
158 wstring osu_dir = CFilePathHelper(songs_dir).GetParentDir();
159 wstring bg_dir = osu_dir + L"Data\\bg\\";
160 std::vector<wstring> bg_files;
161 CCommon::GetImageFiles(bg_dir + L"*.*", bg_files);
162 if (!bg_files.empty())
163 {
164 wstring cover_path;
165 //有多个图片时随机选择一张
166 if (bg_files.size() > 1)
167 {
168 SYSTEMTIME current_time;
169 GetLocalTime(¤t_time); //获取当前时间
170 srand(current_time.wMilliseconds); //用当前时间的毫秒数设置产生随机数的种子
171 int index = rand() % static_cast<int>(bg_files.size());
172 cover_path = bg_dir + bg_files[index];
173 }
174 else
175 {
176 cover_path = bg_dir + bg_files[0];
177 }
178 bg_map[file_path] = cover_path;
179 return cover_path;
180 }
181 }
182 }
183
184 if (album_cover_file_name.empty())
185 return wstring();
186 else
187 return dir + album_cover_file_name;
188 }
189
GetOSUFile(wstring folder_path)190 void COSUPlayerHelper::GetOSUFile(wstring folder_path)
191 {
192 }
193
194
195 ////////////////////////////////////////////////////////////////////////////
COSUFile(const wchar_t * file_path)196 COSUFile::COSUFile(const wchar_t * file_path)
197 {
198 CFilePathHelper file_path_helper{ file_path };
199 wstring ext = file_path_helper.GetFileExtension();
200 if (ext != L"osu")
201 return;
202
203 CCommon::GetFileContent(file_path, m_data);
204 if (m_data.empty())
205 return;
206
207 GetTag("[General]", m_general_seg);
208 GetTag("[Metadata]", m_metadata_seg);
209 GetTag("[Events]", m_events_seg);
210 }
211
GetAudioFileName()212 wstring COSUFile::GetAudioFileName()
213 {
214 return GetTagItem("AudioFilename:", m_general_seg);
215 }
216
GetArtist()217 wstring COSUFile::GetArtist()
218 {
219 wstring artist = GetTagItem("ArtistUnicode:", m_metadata_seg);
220 if(artist.empty())
221 artist = GetTagItem("Artist:", m_metadata_seg);
222 return artist;
223 }
224
GetTitle()225 wstring COSUFile::GetTitle()
226 {
227 wstring artist = GetTagItem("TitleUnicode:", m_metadata_seg);
228 if (artist.empty())
229 artist = GetTagItem("Title:", m_metadata_seg);
230 return artist;
231 }
232
GetAlbum()233 wstring COSUFile::GetAlbum()
234 {
235 return GetTagItem("Source:", m_metadata_seg);
236 }
237
GetBeatampId()238 wstring COSUFile::GetBeatampId()
239 {
240 return GetTagItem("BeatmapID:", m_metadata_seg);
241 }
242
GetBeatampSetId()243 wstring COSUFile::GetBeatampSetId()
244 {
245 return GetTagItem("BeatmapSetID:", m_metadata_seg);
246 }
247
GetAlbumCoverFileName()248 wstring COSUFile::GetAlbumCoverFileName()
249 {
250 size_t index1{}, index2{};
251 string album_cover_name;
252 while (true)
253 {
254 //查找,"到"之间的字符串
255 index1 = m_events_seg.find(",\"", index1);
256 if (index1 == string::npos)
257 return wstring();
258 index2 = m_events_seg.find("\"", index1 + 2);
259 album_cover_name = m_events_seg.substr(index1 + 2, index2 - index1 - 2);
260 index1 = index2 + 1;
261 size_t index0 = album_cover_name.rfind('.');
262 string ext;
263 if (index0 != string::npos)
264 ext = album_cover_name.substr(index0 + 1);
265 //如果获取到的文件名是图片文件,则将其返回
266 if(CCommon::StringCompareNoCase(ext, string("jpg")) || CCommon::StringCompareNoCase(ext, string("png")) || CCommon::StringCompareNoCase(ext, string("jpeg")))
267 return CCommon::StrToUnicode(album_cover_name, CodeType::UTF8);
268 }
269 }
270
GetTag(const string & tag,string & tag_content)271 void COSUFile::GetTag(const string & tag, string & tag_content)
272 {
273 size_t start{}, end{};
274 start = m_data.find(tag);
275 if (start != string::npos)
276 end = m_data.find("\n[", start + tag.size());
277
278 tag_content = m_data.substr(start, end - start);
279
280 }
281
GetTagItem(const string & tag,const string & tag_content)282 wstring COSUFile::GetTagItem(const string & tag, const string & tag_content)
283 {
284 size_t start = tag_content.find(tag);
285 if (start != string::npos)
286 {
287 size_t end = tag_content.find('\n', start + 1);
288 string file_name = tag_content.substr(start + tag.size(), end - start - tag.size());
289 CCommon::StringNormalize(file_name);
290 return CCommon::StrToUnicode(file_name, CodeType::UTF8);
291 }
292 return wstring();
293 }
294