xref: /MusicPlayer2/MusicPlayer2/CRecentList.cpp (revision 965ce478a79b0d21e8a6e2ade0490efa175855dd)
1 #include "stdafx.h"
2 #include "CRecentList.h"
3 #include "MusicPlayer2.h"
4 #include "FilePathHelper.h"
5 
6 CRecentList CRecentList::m_instance;
7 
8 std::array<ListItem, CRecentList::PlaylistType::PT_MAX> CRecentList::SP_PLAYLIST;
9 
SetSortMode(ListType type,listSortMode sort_mode)10 bool CRecentList::SetSortMode(ListType type, listSortMode sort_mode)
11 {
12     std::lock_guard<std::mutex> lock(m_mutex);
13     ASSERT(type >= 0 && type < ListType::LT_MAX);
14     if (m_sort_mode[type] == sort_mode)
15         return false;
16     m_sort_mode[type] = sort_mode;
17     ++m_ver;
18     return true;
19 }
20 
GetSortMode(ListType type) const21 CRecentList::listSortMode CRecentList::GetSortMode(ListType type) const
22 {
23     std::lock_guard<std::mutex> lock(m_mutex);
24     ASSERT(type < ListType::LT_MAX);
25     return m_sort_mode[type];
26 }
27 
SetCurrentList(ListItem list_item)28 void CRecentList::SetCurrentList(ListItem list_item)
29 {
30     std::lock_guard<std::mutex> lock(m_mutex);
31     list_item.last_played_time = CCommon::GetCurTimeElapse();
32     auto it = std::find(m_list.begin(), m_list.end(), list_item);
33     if (it != m_list.begin())                       // 此次调用会更换当前播放
34         if ((m_list.begin()->type == LT_FOLDER || m_list.begin()->type == LT_MEDIA_LIB) && m_list.begin()->total_num == 0)
35             m_list.erase(m_list.begin());           // 不保存没有歌曲的文件夹/媒体库列表项目
36     if (it != m_list.end())                         // 已存在时更新并移动位置到front
37     {   // 不要轻易销毁再构造m_list的元素,此处更新,因为链表在更改元素顺序时迭代器不会失效,在程序设计有问题时crash的概率低一些 (虽然正常的程序不应该依赖这点)
38         list_item.create_time = it->create_time;    // 继承之前的create_time
39         *it = list_item;
40         if (it != m_list.begin())
41             m_list.splice(m_list.begin(), m_list, it);
42     }
43     else                                            // 不存在时,添加到front
44     {
45         ASSERT(!list_item.empty());
46         // 将当前时间设置为创建时间
47         list_item.create_time = list_item.last_played_time;
48         // 特别的,对于LT_PLAYLIST,重新设置create_time为文件属性“创建时间”
49         if (list_item.type == LT_PLAYLIST)
50             m_list.push_front(CreateNewPlaylistListItem(list_item));
51         else
52             m_list.push_front(list_item);
53     }
54     ++m_ver;
55 }
56 
GetCurrentList() const57 ListItem CRecentList::GetCurrentList() const
58 {
59     std::lock_guard<std::mutex> lock(m_mutex);
60     return m_list.front();
61 }
62 
IsCurrentList(const ListItem & list_item) const63 bool CRecentList::IsCurrentList(const ListItem& list_item) const
64 {
65     std::lock_guard<std::mutex> lock(m_mutex);
66     if (m_list.empty())                     // 未初始化时即未播放当前列表
67         return false;
68     return m_list.front() == list_item;
69 }
70 
LoadItem(ListItem & list_item) const71 bool CRecentList::LoadItem(ListItem& list_item) const
72 {
73     std::lock_guard<std::mutex> lock(m_mutex);
74     auto it = std::find(m_list.begin(), m_list.end(), list_item);
75     if (it == m_list.end())
76         return false;
77     list_item = *it;
78     return true;
79 }
80 
AddNewItem(ListItem list_item)81 bool CRecentList::AddNewItem(ListItem list_item)
82 {
83     std::lock_guard<std::mutex> lock(m_mutex);
84     auto it = std::find(m_list.begin(), m_list.end(), list_item);
85     if (it != m_list.end())
86         return false;
87     list_item.last_track = SongKey();
88     list_item.last_position = 0;
89     list_item.last_played_time = 0;         // 为维持m_list的顺序,此处只能接受加入未播放的项目到末尾
90     list_item.create_time = CCommon::GetCurTimeElapse();
91     if (list_item.type == LT_PLAYLIST)      // 对于LT_PLAYLIST,不存在时创建文件并修改create_time为文件属性“创建时间”
92         m_list.push_back(CreateNewPlaylistListItem(list_item));
93     else
94         m_list.push_back(list_item);
95     ++m_ver;
96     return true;
97 }
98 
GetSpecPlaylist(PlaylistType playlist_type) const99 ListItem CRecentList::GetSpecPlaylist(PlaylistType playlist_type) const
100 {
101     std::lock_guard<std::mutex> lock(m_mutex);
102     ASSERT(playlist_type >= 0 && playlist_type < PlaylistType::PT_MAX);
103     auto it = std::find(m_list.begin(), m_list.end(), SP_PLAYLIST[playlist_type]);
104     if (it != m_list.end())
105         return *it;
106     ASSERT(playlist_type == PT_TEMP);
107     return SP_PLAYLIST[playlist_type];      // 这行用来在临时播放列表不存在时返回其原型
108 }
109 
IsPlayingSpecPlaylist(PlaylistType type)110 bool CRecentList::IsPlayingSpecPlaylist(PlaylistType type)
111 {
112     std::lock_guard<std::mutex> lock(m_mutex);
113     if (m_list.empty())                     // 未初始化时即未播放当前列表
114         return false;
115     if (type >= 0 && type < PlaylistType::PT_MAX)
116         return m_list.front() == SP_PLAYLIST[type];
117     for (int i{}; i < PlaylistType::PT_MAX; ++i)
118         if (m_list.front() == SP_PLAYLIST[i])
119             return true;
120     return false;
121 }
122 
IsSpecPlaylist(const ListItem & list_item,PlaylistType type)123 bool CRecentList::IsSpecPlaylist(const ListItem& list_item, PlaylistType type)
124 {
125     if (type >= 0 && type < PlaylistType::PT_MAX)
126         return list_item == SP_PLAYLIST[type];
127     for (int i{}; i < PlaylistType::PT_MAX; ++i)
128         if (list_item == SP_PLAYLIST[i])
129             return true;
130     return false;
131 }
132 
RemoveItem(const ListItem & list_item)133 bool CRecentList::RemoveItem(const ListItem& list_item)
134 {
135     std::lock_guard<std::mutex> lock(m_mutex);
136     auto it = std::find(m_list.begin(), m_list.end(), list_item);
137     if (it == m_list.begin() || it == m_list.end())
138         return false;
139     if (IsSpecPlaylist(*it, PT_DEFAULT) || IsSpecPlaylist(*it, PT_FAVOURITE))
140         return false;
141     m_list.erase(it);
142     ++m_ver;
143     return true;
144 }
145 
RemoveItemIf(std::function<bool (const ListItem & list_item)> func)146 int CRecentList::RemoveItemIf(std::function<bool(const ListItem& list_item)> func)
147 {
148     std::lock_guard<std::mutex> lock(m_mutex);
149     size_t size = m_list.size();
150     ASSERT(!m_list.empty());
151     m_list.remove_if([&](const ListItem& list_item) -> bool
152         { return func(list_item) && list_item != m_list.front() && IsSpecPlaylist(list_item, PT_DEFAULT) && IsSpecPlaylist(list_item, PT_FAVOURITE); });
153     size -= m_list.size();
154     m_ver += size;
155     return size;
156 }
157 
ResetLastPlayedTime(const ListItem & list_item)158 bool CRecentList::ResetLastPlayedTime(const ListItem& list_item)
159 {
160     std::lock_guard<std::mutex> lock(m_mutex);
161     auto it = std::find(m_list.begin(), m_list.end(), list_item);
162     if (it == m_list.begin() || it == m_list.end())
163         return false;
164     if (it->type == LT_MEDIA_LIB)
165         m_list.erase(it);
166     else
167     {
168         it->last_played_time = 0;
169         m_list.splice(m_list.end(), m_list, it);    // 移动此项到末尾
170     }
171     ++m_ver;
172     return true;
173 }
174 
SetContainSubFolder(const ListItem & list_item)175 bool CRecentList::SetContainSubFolder(const ListItem& list_item)
176 {
177     std::lock_guard<std::mutex> lock(m_mutex);
178     auto it = std::find(m_list.begin(), m_list.end(), list_item);
179     if (it == m_list.begin() || it == m_list.end() || list_item.type != LT_FOLDER)
180         return false;
181     it->contain_sub_folder = !it->contain_sub_folder;
182     ++m_ver;
183     return true;
184 }
185 
SetPlaylistTotalInfo(const ListItem & list_item,int total_num,int total_time)186 bool CRecentList::SetPlaylistTotalInfo(const ListItem& list_item, int total_num, int total_time)
187 {
188     std::lock_guard<std::mutex> lock(m_mutex);
189     auto it = std::find(m_list.begin(), m_list.end(), list_item);
190     if (it == m_list.begin() || it == m_list.end() || list_item.type != LT_PLAYLIST)
191         return false;
192     if (it->total_num == total_num && it->total_time == total_time)
193         return false;
194     it->total_num = total_num;
195     it->total_time = total_time;
196     ++m_ver;
197     return true;
198 }
199 
RenamePlaylist(const ListItem & list_item,const wstring & new_path)200 bool CRecentList::RenamePlaylist(const ListItem& list_item, const wstring& new_path)
201 {
202     std::lock_guard<std::mutex> lock(m_mutex);
203     auto it = std::find(m_list.begin(), m_list.end(), list_item);
204     if (it == m_list.end() || list_item.type != LT_PLAYLIST)
205         return false;
206     it->path = new_path;
207     ++m_ver;
208     return true;
209 }
210 
CreateNewPlaylistListItem(ListItem list_item)211 ListItem CRecentList::CreateNewPlaylistListItem(ListItem list_item)
212 {
213     ASSERT(list_item.type == LT_PLAYLIST);
214     if (!CCommon::FileExist(list_item.path))            // 如果播放列表文件不存在则创建一个空文件
215         CCommon::SaveDataToFile(string(), list_item.path);
216     uint64_t file_create_time{};
217     if (CCommon::GetFileCreateTime(list_item.path, file_create_time))
218         list_item.create_time = CCommon::FileTimeToTimeT(file_create_time);
219     return list_item;
220 }
221 
SaveData() const222 void CRecentList::SaveData() const
223 {
224     //向主窗口发送通知
225     ::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_RECENT_FOLDER_OR_PLAYLIST_CHANGED, 0, 0);  // 重新初始化快捷菜单
226     ::SendMessage(AfxGetMainWnd()->GetSafeHwnd(), WM_INIT_ADD_TO_MENU, 0, 0);   // 重新初始化右键菜单中的“添加到播放列表”子菜单
227     std::lock_guard<std::mutex> lock(m_mutex);
228     CFile file;
229     // 打开或者新建文件
230     BOOL bRet = file.Open(theApp.m_recent_list_dat_path.c_str(),
231         CFile::modeCreate | CFile::modeWrite);
232     if (!bRet)      // 打开文件失败
233         return;
234     // 构造CArchive对象
235     CArchive ar(&file, CArchive::store);
236     // 写版本号
237     const int version{ 0 };
238     ar << version;
239     // 写数据 (固定全部使用int/uint64_t/CString)
240     ar << static_cast<int>(m_list.size());
241     for (const ListItem& item : m_list)
242     {
243         ar << static_cast<int>(item.type);
244         if (item.type == LT_PLAYLIST)
245             ar << CString(CFilePathHelper(item.path).GetFileNameWithoutExtension().c_str());
246         else
247             ar << CString(item.path.c_str());
248         ar << static_cast<int>(item.sort_mode)
249             << CString(item.last_track.path.c_str())
250             << item.last_track.cue_track
251             << item.last_position
252             << item.total_time
253             << item.total_num
254             << item.last_played_time
255             << item.create_time
256             << static_cast<int>(item.medialib_type)
257             << static_cast<int>(item.contain_sub_folder)
258             ;
259     }
260     // 关闭CArchive对象
261     ar.Close();
262     // 关闭文件
263     file.Close();
264 }
265 
LoadData()266 bool CRecentList::LoadData()
267 {
268     std::lock_guard<std::mutex> lock(m_mutex);
269 
270     // 初始化特殊播放列表的原型,用来做==比较,总是为空白项目(即初始状态)
271     SP_PLAYLIST[PT_DEFAULT] = { LT_PLAYLIST, theApp.m_playlist_dir + L"default_playlist" PLAYLIST_EXTENSION };
272     SP_PLAYLIST[PT_FAVOURITE] = { LT_PLAYLIST, theApp.m_playlist_dir + L"favourite" PLAYLIST_EXTENSION };
273     SP_PLAYLIST[PT_TEMP] = { LT_PLAYLIST, theApp.m_playlist_dir + L"temp" PLAYLIST_EXTENSION };
274 
275     CFile file;
276     // 打开文件
277     if (file.Open(theApp.m_recent_list_dat_path.c_str(), CFile::modeRead))
278     {
279         // 构造CArchive对象
280         CArchive ar(&file, CArchive::load);
281         // 读数据
282         int version{}, size{}, temp_int;
283         CString temp_str;
284         try
285         {
286             ar >> version;
287             ar >> size;
288             for (int i{}; i < size; ++i)
289             {
290                 ListItem list_item{};
291                 ar >> temp_int;
292                 list_item.type = static_cast<ListType>(temp_int);
293                 ar >> temp_str;
294                 list_item.path = temp_str;
295                 ar >> temp_int;
296                 list_item.sort_mode = static_cast<SortMode>(temp_int);
297                 ar >> temp_str;
298                 list_item.last_track.path = temp_str;
299                 ar >> list_item.last_track.cue_track;
300                 ar >> list_item.last_position;
301                 ar >> list_item.total_time;
302                 ar >> list_item.total_num;
303                 ar >> list_item.last_played_time;
304                 ar >> list_item.create_time;
305                 ar >> temp_int;
306                 list_item.medialib_type = static_cast<CMediaClassifier::ClassificationType>(temp_int);
307                 ar >> temp_int;
308                 list_item.contain_sub_folder = static_cast<bool>(temp_int);
309 
310                 if (list_item.type == LT_PLAYLIST)
311                     list_item.path = theApp.m_playlist_dir + list_item.path + PLAYLIST_EXTENSION;
312                 // 插入m_list
313                 m_list.push_back(std::move(list_item));
314             }
315         }
316         catch (CArchiveException* exception)
317         {
318             // 捕获序列化时出现的异常
319             wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_SERIALIZE_ERROR", { theApp.m_recent_list_dat_path, exception->m_cause });
320             theApp.WriteLog(info);
321         }
322         // 关闭对象
323         ar.Close();
324         // 关闭文件
325         file.Close();
326     }
327     else
328     {
329         LoadOldData();  // 文件不存在时试着加载旧版文件
330     }
331 
332     AfterLoadData();
333     ++m_ver;
334     return true;
335 }
336 
AfterLoadData()337 void CRecentList::AfterLoadData()
338 {
339     // 获取playlist目录下的播放列表文件
340     vector<wstring> file_list;
341     CCommon::GetFiles(theApp.m_playlist_dir + L'*' + PLAYLIST_EXTENSION, file_list);
342     // 移除不符合条件的项目
343     m_list.remove_if([&](const ListItem& list_item) -> bool
344         {
345             switch (list_item.type)
346             {
347             case LT_FOLDER: return list_item.path.size() < 2;
348             case LT_PLAYLIST: return std::find(file_list.begin(), file_list.end(), CFilePathHelper(list_item.path).GetFileName()) == file_list.end();
349             case LT_MEDIA_LIB: return list_item.medialib_type < 0 || list_item.medialib_type >= CMediaClassifier::CT_MAX;
350             default: return true;
351             }
352         });
353     // 检查必须存在的特殊播放列表,不存在时添加 (必须添加在其他播放列表之前,因为对全新程序来说m_list.front()是其当前播放的列表)
354     if (std::find(m_list.begin(), m_list.end(), SP_PLAYLIST[PT_DEFAULT]) == m_list.end())
355         m_list.push_back(CreateNewPlaylistListItem(SP_PLAYLIST[PT_DEFAULT]));
356     if (std::find(m_list.begin(), m_list.end(), SP_PLAYLIST[PT_FAVOURITE]) == m_list.end())
357         m_list.push_back(CreateNewPlaylistListItem(SP_PLAYLIST[PT_FAVOURITE]));
358     // 向m_list添加未记录的播放列表(用户不经程序自行添加的那些)
359     for (const wstring& file : file_list)
360     {
361         ListItem list_item{ LT_PLAYLIST, theApp.m_playlist_dir + file };
362         if (std::find(m_list.begin(), m_list.end(), list_item) == m_list.end())
363             m_list.push_back(CreateNewPlaylistListItem(list_item));
364     }
365     // 校验&旧版兼容
366     uint64_t cur_time = CCommon::GetCurTimeElapse();
367     for (ListItem& item : m_list)
368     {
369         if (item.create_time == 0 && item.type == LT_PLAYLIST)  // 对于播放列表,优先尝试文件创建时间
370         {
371             uint64_t file_create_time{};
372             if (CCommon::GetFileCreateTime(item.path, file_create_time))
373                 item.create_time = CCommon::FileTimeToTimeT(file_create_time);
374         }
375         if (item.create_time == 0)
376             item.create_time = item.last_played_time;
377         if (item.create_time == 0)
378             item.create_time = cur_time;
379         // 如果读取到的文件夹路径末尾没有斜杠,则在末尾加上一个
380         if (item.type == LT_FOLDER && item.path.back() != L'/' && item.path.back() != L'\\')
381             item.path.push_back(L'\\');
382     }
383     // 按最近播放时间降序排序,链表容器的成员排序方法是stable的
384     m_list.sort();
385 }
386 
LoadOldData()387 void CRecentList::LoadOldData()
388 {
389     CFile file;
390     // 打开文件 recent_path.dat
391     if (file.Open(theApp.m_recent_path_dat_path.c_str(), CFile::modeRead))
392     {
393         // 为了保持和以前版本的数据兼容,先读取前8个字节,以判断是否是以前版本
394         char buff[8]{};
395         file.Read(buff, 8);
396         file.SeekToBegin();
397 
398         // 构造CArchive对象
399         CArchive ar(&file, CArchive::load);
400         // 读数据
401         unsigned int size{};
402         CString temp;
403         int sort_mode;
404         unsigned int version{};
405         try
406         {
407             ar >> size;     //读取映射容器的长度
408             if (buff[4] == '\xff' && buff[5] == '\xfe')     //如果第4个字节和第5个字节是FFFE,则说明数据文件是以前版本,此时不读取version
409                 version = 0;
410             else
411                 ar >> version;  //读取数据文件的版本
412             for (unsigned int i{}; i < size; i++)
413             {
414                 ListItem list_item{};
415                 list_item.type = LT_FOLDER;
416                 ar >> temp;
417                 list_item.path = temp;
418                 // 丢弃PathInfo的track与position,ListItem改为使用SongKey描述,此处无法转换
419                 int tmp{};
420                 ar >> tmp;  // track
421                 ar >> tmp;  // position
422                 ar >> sort_mode;
423                 list_item.sort_mode = static_cast<SortMode>(sort_mode);
424                 if (version >= 2 && version <= 3)   // 在版本4变量descending不再独立存储,功能整合到sort_mode内,这里做读取兼容
425                 {
426                     BYTE descending;
427                     ar >> descending;
428                     switch (sort_mode)
429                     {
430                     case 0: list_item.sort_mode = descending ? SM_D_FILE : SM_U_FILE; break;
431                     case 1: list_item.sort_mode = descending ? SM_D_PATH : SM_U_PATH; break;
432                     case 2: list_item.sort_mode = descending ? SM_D_TITLE : SM_U_TITLE; break;
433                     case 3: list_item.sort_mode = descending ? SM_D_ARTIST : SM_U_ARTIST; break;
434                     case 4: list_item.sort_mode = descending ? SM_D_ALBUM : SM_U_ALBUM; break;
435                     case 5: list_item.sort_mode = descending ? SM_D_TRACK : SM_U_TRACK; break;
436                     case 6: list_item.sort_mode = descending ? SM_D_TIME : SM_U_TIME; break;
437                     default: break;
438                     }
439                 }
440                 ar >> list_item.total_num;
441                 ar >> list_item.total_time;
442                 if (version >= 1)
443                 {
444                     BYTE contain_sub_folder;
445                     ar >> contain_sub_folder;
446                     list_item.contain_sub_folder = (contain_sub_folder != 0);
447                 }
448                 if (version >= 3)
449                     ar >> list_item.last_played_time;
450                 if (version >= 5)
451                     ar >> list_item.create_time;
452 
453                 m_list.push_back(std::move(list_item));
454             }
455         }
456         catch (CArchiveException* exception)
457         {
458             //捕获序列化时出现的异常
459             wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_SERIALIZE_ERROR", { theApp.m_recent_path_dat_path, exception->m_cause });
460             theApp.WriteLog(info);
461         }
462         // 关闭对象
463         ar.Close();
464         // 关闭文件
465         file.Close();
466     }
467     // 打开文件 recent_path.dat
468     if (file.Open(theApp.m_recent_playlist_data_path.c_str(), CFile::modeRead))
469     {
470         // 构造CArchive对象
471         CArchive ar(&file, CArchive::load);
472         // 读数据
473         unsigned int size{};
474         CString temp;
475         try
476         {
477             int version{};
478             ar >> version;
479             int temp;
480             ar >> temp;     // 丢弃m_cur_playlist_type
481             m_list.push_back(SP_PLAYLIST[PT_DEFAULT]);
482             ar >> temp;     // 丢弃默认播放列表track
483             ar >> temp;     // 丢弃默认播放列表position
484             ar >> m_list.back().total_num;
485             ar >> m_list.back().total_time;
486             if (version >= 4)
487                 ar >> m_list.back().last_played_time;
488             if (version >= 2)
489             {
490                 m_list.push_back(SP_PLAYLIST[PT_FAVOURITE]);
491                 ar >> temp;     // 丢弃FAVOURITE播放列表track
492                 ar >> temp;     // 丢弃FAVOURITE播放列表position
493                 ar >> m_list.back().total_num;
494                 ar >> m_list.back().total_time;
495                 if (version >= 4)
496                     ar >> m_list.back().last_played_time;
497             }
498             // 原来temp播放列表以total_num为0表示“已删除”而不是真的删除文件
499             // 这里不再特殊处理,表现为原来“已删除”的temp列表会重新出现(问题不大)
500             if (version >= 3)
501             {
502                 m_list.push_back(SP_PLAYLIST[PT_TEMP]);
503                 ar >> temp;     // 丢弃TEMP播放列表track
504                 ar >> temp;     // 丢弃TEMP播放列表position
505                 ar >> m_list.back().total_num;
506                 ar >> m_list.back().total_time;
507                 if (version >= 4)
508                     ar >> m_list.back().last_played_time;
509             }
510             ar >> size;         // 读取映射容器的长度
511             unsigned __int64 not_use{};
512             for (unsigned int i{}; i < size; ++i)
513             {
514                 ListItem list_item{};
515                 list_item.type = LT_PLAYLIST;
516                 CString strTmp;
517                 ar >> strTmp;
518                 list_item.path = theApp.m_playlist_dir + strTmp.GetString() + PLAYLIST_EXTENSION;
519                 ar >> temp;     // track
520                 ar >> temp;     // position;
521                 ar >> list_item.total_num;
522                 ar >> list_item.total_time;
523                 if (version >= 4)
524                     ar >> list_item.last_played_time;
525                 if (version >= 5)
526                     ar >> not_use;  // 丢弃原来的create_time,对于播放列表,现已改用文件属性“创建时间”
527 
528                 m_list.push_back(std::move(list_item));
529             }
530         }
531         catch (CArchiveException* exception)
532         {
533             //捕获序列化时出现的异常
534             wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_SERIALIZE_ERROR", { theApp.m_recent_playlist_data_path, exception->m_cause });
535             theApp.WriteLog(info);
536         }
537         // 关闭对象
538         ar.Close();
539         // 关闭文件
540         file.Close();
541     }
542     // 打开文件 recent_medialib_item.dat
543     if (file.Open(theApp.m_recent_medialib_playlist_path.c_str(), CFile::modeRead))
544     {
545         // 构造CArchive对象
546         CArchive ar(&file, CArchive::load);
547         // 读数据
548         unsigned int size{};
549         try
550         {
551             int version{}, temp{};
552             ar >> version;
553             ar >> size;         // 读取长度
554             for (unsigned int i{}; i < size; i++)
555             {
556                 ListItem list_item{};
557                 list_item.type = LT_MEDIA_LIB;
558                 CString strTmp;
559                 ar >> strTmp;
560                 list_item.path = strTmp.GetString();
561                 ar >> temp;     // 丢弃track
562                 ar >> temp;     // 丢弃position
563                 ar >> list_item.total_num;
564                 ar >> list_item.total_time;
565                 ar >> list_item.last_played_time;
566                 ar >> temp;
567                 list_item.medialib_type = static_cast<CMediaClassifier::ClassificationType>(temp);
568                 ar >> temp;
569                 list_item.sort_mode = static_cast<SortMode>(temp);
570 
571                 m_list.push_back(std::move(list_item));
572             }
573         }
574         catch (CArchiveException* exception)
575         {
576             //捕获序列化时出现的异常
577             wstring info = theApp.m_str_table.LoadTextFormat(L"MSG_SERIALIZE_ERROR", { theApp.m_recent_medialib_playlist_path, exception->m_cause });
578             theApp.WriteLog(info);
579         }
580         // 关闭对象
581         ar.Close();
582         // 关闭文件
583         file.Close();
584     }
585 }
586 
587