|
1
|
1 #pragma once
|
|
|
2 #include "filesystem.h" // t_filestats
|
|
|
3 #include "playable_location.h"
|
|
|
4 #include "file_info.h"
|
|
|
5
|
|
|
6 class titleformat_hook;
|
|
|
7 class titleformat_text_filter;
|
|
|
8 class titleformat_object;
|
|
|
9
|
|
|
10
|
|
|
11 class metadb_info_container : public service_base {
|
|
|
12 FB2K_MAKE_SERVICE_INTERFACE(metadb_info_container, service_base);
|
|
|
13 public:
|
|
|
14 virtual file_info const & info() = 0;
|
|
|
15 virtual t_filestats const & stats() = 0;
|
|
|
16 virtual bool isInfoPartial() = 0;
|
|
|
17
|
|
|
18 t_filestats2 stats2_();
|
|
|
19 };
|
|
|
20
|
|
|
21
|
|
|
22 //! \since 2.0
|
|
|
23 class metadb_info_container_v2 : public metadb_info_container {
|
|
|
24 FB2K_MAKE_SERVICE_INTERFACE(metadb_info_container_v2, metadb_info_container);
|
|
|
25 public:
|
|
|
26 virtual t_filestats2 const & stats2() = 0;
|
|
|
27 };
|
|
|
28
|
|
|
29 struct metadb_v2_rec_t {
|
|
|
30 metadb_info_container::ptr info, infoBrowse;
|
|
|
31 service_ptr reserved;
|
|
|
32 };
|
|
|
33
|
|
|
34
|
|
|
35 //! A metadb_handle object represents interface to reference-counted file_info cache entry for the specified location.\n
|
|
|
36 //! To obtain a metadb_handle to specific location, use metadb::handle_create(). To obtain a list of metadb_handle objects corresponding to specific path (directory, playlist, multitrack file, etc), use relevant playlist_incoming_item_filter methods (recommended), or call playlist_loader methods directly.\n
|
|
|
37 //! A metadb_handle is also the most efficient way of passing playable object locations around because it provides fast access to both location and infos, and is reference counted so duplicating it is as fast as possible.\n
|
|
|
38 //! To retrieve a path of a file from a metadb_handle, use metadb_handle::get_path() function. Note that metadb_handle is NOT just file path, some formats support multiple subsongs per physical file, which are signaled using subsong indexes.
|
|
|
39 class NOVTABLE metadb_handle : public service_base
|
|
|
40 {
|
|
|
41 public:
|
|
|
42 //! Retrieves location represented by this metadb_handle object. Returned reference is valid until calling context releases metadb_handle that returned it (metadb_handle_ptr is deallocated etc).
|
|
|
43 virtual const playable_location & get_location() const = 0;//never fails, returned pointer valid till the object is released
|
|
|
44
|
|
|
45
|
|
|
46 //! Renders information about item referenced by this metadb_handle object.
|
|
|
47 //! @param p_hook Optional callback object overriding fields and functions; set to NULL if not used.
|
|
|
48 //! @param p_out String receiving the output on success.
|
|
|
49 //! @param p_script Titleformat script to use. Use titleformat_compiler service to create one.
|
|
|
50 //! @param p_filter Optional callback object allowing input to be filtered according to context (i.e. removal of linebreak characters present in tags when rendering playlist lines). Set to NULL when not used.
|
|
|
51 //! @returns true on success, false when dummy file_info instance was used because actual info is was not (yet) known.
|
|
|
52 virtual bool format_title(titleformat_hook * p_hook,pfc::string_base & p_out,const service_ptr_t<titleformat_object> & p_script,titleformat_text_filter * p_filter) = 0;
|
|
|
53
|
|
|
54 //! OBSOLETE, DO NOT CALL
|
|
|
55 FB2K_DEPRECATED virtual void metadb_lock() = 0;
|
|
|
56 //! OBSOLETE, DO NOT CALL
|
|
|
57 FB2K_DEPRECATED virtual void metadb_unlock() = 0;
|
|
|
58
|
|
|
59 //! Returns last seen file stats, filestats_invalid if unknown.
|
|
|
60 virtual t_filestats get_filestats() const = 0;
|
|
|
61
|
|
|
62 //! Obsolete, use get_info_ref() family of methods instead. \n
|
|
|
63 //! Queries whether cached info about item referenced by this metadb_handle object is already available. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden.\n
|
|
|
64 //! Note that state of cached info changes only inside main thread, so you can safely assume that it doesn't change while some block of your code inside main thread is being executed.
|
|
|
65 virtual bool is_info_loaded() const = 0;
|
|
|
66 //! Obsolete, use get_info_ref() instead. \n
|
|
|
67 //! Queries cached info about item referenced by this metadb_handle object. Returns true on success, false when info is not yet known. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden. \n
|
|
|
68 //! Note that state of cached info changes only inside main thread, so you can safely assume that it doesn't change while some block of your code inside main thread is being executed.
|
|
|
69 virtual bool get_info(file_info & p_info) const = 0;
|
|
|
70
|
|
|
71 //! OBSOLETE, DO NOT CALL
|
|
|
72 FB2K_DEPRECATED virtual bool get_info_locked(const file_info * & p_info) const = 0;
|
|
|
73
|
|
|
74 //! Obsolete, use get_info_ref() family of methods instead. \n
|
|
|
75 //! Queries whether cached info about item referenced by this metadb_handle object is already available.\n
|
|
|
76 //! This is intended for use in special cases when you need to immediately retrieve info sent by metadb_io hint from another thread; state of returned data can be altered by any thread, as opposed to non-async methods.
|
|
|
77 virtual bool is_info_loaded_async() const = 0;
|
|
|
78 //! Obsolete, use get_info_ref() family of methods instead. \n
|
|
|
79 //! Queries cached info about item referenced by this metadb_handle object. Returns true on success, false when info is not yet known. Note that this function causes the metadb to be temporarily locked; you can not use it in context that where locking is forbidden.\n
|
|
|
80 //! This is intended for use in special cases when you need to immediately retrieve info sent by metadb_io hint from another thread; state of returned data can be altered by any thread, as opposed to non-async methods.
|
|
|
81 virtual bool get_info_async(file_info & p_info) const = 0;
|
|
|
82
|
|
|
83 //! OBSOLETE, DO NOT CALL
|
|
|
84 FB2K_DEPRECATED virtual bool get_info_async_locked(const file_info * & p_info) const = 0;
|
|
|
85
|
|
|
86 //! Renders information about item referenced by this metadb_handle object, using external file_info data.
|
|
|
87 virtual void format_title_from_external_info(const file_info & p_info,titleformat_hook * p_hook,pfc::string_base & p_out,const service_ptr_t<titleformat_object> & p_script,titleformat_text_filter * p_filter) = 0;
|
|
|
88
|
|
|
89 //! OBSOLETE, DO NOT CALL
|
|
|
90 FB2K_DEPRECATED virtual bool format_title_nonlocking(titleformat_hook * p_hook,pfc::string_base & p_out,const service_ptr_t<titleformat_object> & p_script,titleformat_text_filter * p_filter) = 0;
|
|
|
91 //! OBSOLETE, DO NOT CALL
|
|
|
92 FB2K_DEPRECATED virtual void format_title_from_external_info_nonlocking(const file_info & p_info,titleformat_hook * p_hook,pfc::string_base & p_out,const service_ptr_t<titleformat_object> & p_script,titleformat_text_filter * p_filter) = 0;
|
|
|
93
|
|
|
94 #if FOOBAR2000_TARGET_VERSION >= 76
|
|
|
95 //! \since 1.0
|
|
|
96 //! Returns browse info for this track. \n
|
|
|
97 //! Browse info comes from an external source - such as internet playlist metadata - not from the media file itself, and is maintained separately. \n
|
|
|
98 //! When title formatting calls are invoked on for a track having browse info present, data for title formatting is sourced from both primary and browse info. \n
|
|
|
99 //! Example: internet radio stream provides no metadata but its playlist XML has title (radio station name), %title% resolves to the radio station name from the playlist.
|
|
|
100 virtual bool get_browse_info(file_info & info, t_filetimestamp & ts) const = 0;
|
|
|
101
|
|
|
102 //! \since 1.0
|
|
|
103 //! OBSOLETE, DO NOT CALL
|
|
|
104 FB2K_DEPRECATED virtual bool get_browse_info_locked(const file_info * & p_info, t_filetimestamp & ts) const = 0;
|
|
|
105 #endif
|
|
|
106 #if FOOBAR2000_TARGET_VERSION >= 78
|
|
|
107 //! \since 1.3
|
|
|
108 //! Retrieve a reference to the primary info. \n
|
|
|
109 //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n
|
|
|
110 //! Returns true and sets outInfo to a reference to this item's primary info on success, returns false on failure (no info known at this time).
|
|
|
111 virtual bool get_info_ref(metadb_info_container::ptr & outInfo) const = 0;
|
|
|
112
|
|
|
113 //! \since 1.3
|
|
|
114 //! Retrieve a reference to the async info (pending info update). If async info isn't set, a reference to the primary info is returned.\n
|
|
|
115 //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n
|
|
|
116 //! Returns true and sets outInfo to a reference to this item's async or primary info on success, returns false on failure (no info known at this time).
|
|
|
117 virtual bool get_async_info_ref(metadb_info_container::ptr & outInfo) const = 0;
|
|
|
118
|
|
|
119 //! \since 1.3
|
|
|
120 //! Retrieve references to the item's primary and browse infos. If no info is set, NULL pointers are returned. For most local files, browse info is not available and you get a NULL for it.\n
|
|
|
121 //! Since browse info is usually used along with the primary info (as a fallback for missing metas), you can get the two with one call for better performance. \n
|
|
|
122 //! You can hold the reference to the info as long as you like, call the method in any context you like with no lock semantics involved. The info held by the returned reference will remain constant even if the metadb content changes. \n
|
|
|
123 //! See also: get_browse_info(), for browse info rationale.
|
|
|
124 virtual void get_browse_info_ref(metadb_info_container::ptr & outInfo, metadb_info_container::ptr & outBrowse) const = 0;
|
|
|
125
|
|
|
126 //! Simplified method, always returns non-null, dummy info if nothing to return.
|
|
|
127 virtual metadb_info_container::ptr get_info_ref() const = 0;
|
|
|
128 //! Simplified method, always returns non-null, dummy info if nothing to return.
|
|
|
129 virtual metadb_info_container::ptr get_async_info_ref() const = 0;
|
|
|
130
|
|
|
131 //! \since 1.3
|
|
|
132 //! Retrieve full info using available means - read actual file if not cached. \n
|
|
|
133 //! Throws exceptions on failure.
|
|
|
134 metadb_info_container::ptr get_full_info_ref( abort_callback & aborter ) const;
|
|
|
135 #endif
|
|
|
136
|
|
|
137 t_filestats2 get_stats2_() const;
|
|
|
138
|
|
|
139 //! \since 1.3
|
|
|
140 //! Helper using get_browse_info_ref(). \n
|
|
|
141 //! Retrieves primary info + browse info merged together. \n
|
|
|
142 //! Returns true on success, false if neither info is available. \n
|
|
|
143 //! If neither info is avaialble, output data structure is emptied. \n
|
|
|
144 //! See also: get_browse_info() for browse info rationale.
|
|
|
145 bool get_browse_info_merged(file_info & infoMerged) const;
|
|
|
146
|
|
|
147
|
|
|
148 static bool g_should_reload(const t_filestats & p_old_stats,const t_filestats & p_new_stats,bool p_fresh);
|
|
|
149 static bool g_should_reload_ex(const t_filestats& p_old_stats, const t_filestats& p_new_stats, t_filetimestamp p_readtime);
|
|
|
150 bool should_reload(const t_filestats & p_new_stats,bool p_fresh) const;
|
|
|
151
|
|
|
152
|
|
|
153 //! Helper provided for backwards compatibility; takes formatting script as text string and calls relevant titleformat_compiler methods; returns false when the script could not be compiled.\n
|
|
|
154 //! See format_title() for descriptions of parameters.\n
|
|
|
155 //! Bottleneck warning: you should consider using precompiled titleformat script object and calling regular format_title() instead when processing large numbers of items.
|
|
|
156 bool format_title_legacy(titleformat_hook * p_hook,pfc::string_base & out,const char * p_spec,titleformat_text_filter * p_filter);
|
|
|
157
|
|
|
158 //! Retrieves path of item described by this metadb_handle instance. Returned string is valid until calling context releases metadb_handle that returned it (metadb_handle_ptr is deallocated etc).
|
|
|
159 inline const char * get_path() const {return get_location().get_path();}
|
|
|
160 //! Retrieves subsong index of item described by this metadb_handle instance (used for multiple playable tracks within single physical file).
|
|
|
161 inline t_uint32 get_subsong_index() const {return get_location().get_subsong_index();}
|
|
|
162
|
|
|
163 double get_length();//helper
|
|
|
164
|
|
|
165 t_filetimestamp get_filetimestamp();
|
|
|
166 t_filesize get_filesize();
|
|
|
167
|
|
|
168 //! Internal method, do not use
|
|
|
169 inline const char * _get_path() const { return get_path(); }
|
|
|
170
|
|
|
171 metadb_v2_rec_t query_v2_();
|
|
|
172 void formatTitle_v2_(const metadb_v2_rec_t& rec, titleformat_hook* p_hook, pfc::string_base& p_out, const service_ptr_t<titleformat_object>& p_script, titleformat_text_filter* p_filter);
|
|
|
173
|
|
|
174 FB2K_MAKE_SERVICE_INTERFACE(metadb_handle,service_base);
|
|
|
175 };
|
|
|
176
|
|
|
177 //! \since 2.0
|
|
|
178 class metadb_handle_v2 : public metadb_handle {
|
|
|
179 FB2K_MAKE_SERVICE_INTERFACE(metadb_handle_v2, metadb_handle);
|
|
|
180 public:
|
|
|
181 typedef metadb_v2_rec_t rec_t;
|
|
|
182
|
|
|
183 virtual rec_t query_v2() const = 0;
|
|
|
184 virtual t_filestats2 get_stats2() const = 0;
|
|
|
185 virtual void formatTitle_v2(const rec_t& rec, titleformat_hook* p_hook, pfc::string_base& p_out, const service_ptr_t<titleformat_object>& p_script, titleformat_text_filter* p_filter) = 0;
|
|
|
186 };
|
|
|
187
|
|
|
188 typedef pfc::list_base_t<metadb_handle_ptr>* metadb_handle_list_ptr;
|
|
|
189 typedef pfc::list_base_const_t<metadb_handle_ptr> const * metadb_handle_list_cptr;
|
|
|
190
|
|
|
191 typedef pfc::list_base_t<metadb_handle_ptr> & metadb_handle_list_ref;
|
|
|
192 typedef pfc::list_base_const_t<metadb_handle_ptr> const & metadb_handle_list_cref;
|
|
|
193
|
|
|
194 namespace metadb_handle_list_helper {
|
|
|
195 void sort_by_format(metadb_handle_list_ref p_list,const char * spec,titleformat_hook * p_hook);
|
|
|
196 void sort_by_format_get_order(metadb_handle_list_cref p_list,t_size* order,const char * spec,titleformat_hook * p_hook);
|
|
|
197 void sort_by_format(metadb_handle_list_ref p_list,const service_ptr_t<titleformat_object> & p_script,titleformat_hook * p_hook, int direction = 1);
|
|
|
198 void sort_by_format_get_order(metadb_handle_list_cref p_list,t_size* order,const service_ptr_t<titleformat_object> & p_script,titleformat_hook * p_hook,int p_direction = 1);
|
|
|
199
|
|
|
200 void sort_by_relative_path(metadb_handle_list_ref p_list);
|
|
|
201 void sort_by_relative_path_get_order(metadb_handle_list_cref p_list,t_size* order);
|
|
|
202
|
|
|
203 void remove_duplicates(pfc::list_base_t<metadb_handle_ptr> & p_list);
|
|
|
204 void sort_by_pointer_remove_duplicates(pfc::list_base_t<metadb_handle_ptr> & p_list);
|
|
|
205 void sort_by_path_quick(pfc::list_base_t<metadb_handle_ptr> & p_list);
|
|
|
206
|
|
|
207 void sort_by_pointer(pfc::list_base_t<metadb_handle_ptr> & p_list);
|
|
|
208 t_size bsearch_by_pointer(const pfc::list_base_const_t<metadb_handle_ptr> & p_list,const metadb_handle_ptr & val);
|
|
|
209
|
|
|
210 double calc_total_duration(metadb_handle_list_cref p_list);
|
|
|
211 pfc::string8 format_total_size(metadb_handle_list_cref p_list);
|
|
|
212
|
|
|
213 //! New method to deal with slower metadb in foobar2000 v2
|
|
|
214 double calc_total_duration_v2(metadb_handle_list_cref p_list, unsigned maxThreads, abort_callback & aborter);
|
|
|
215
|
|
|
216
|
|
|
217 void sort_by_path(pfc::list_base_t<metadb_handle_ptr> & p_list);
|
|
|
218
|
|
|
219 t_filesize calc_total_size(metadb_handle_list_cref list, bool skipUnknown = false);
|
|
|
220 t_filesize calc_total_size_ex(metadb_handle_list_cref list, bool & foundUnknown);
|
|
|
221
|
|
|
222 bool extract_single_path(metadb_handle_list_cref list, const char * &path);
|
|
|
223 bool extract_folder_path(metadb_handle_list_cref list, pfc::string_base & path);
|
|
|
224
|
|
|
225 void sort_by_format_get_order_v2( metadb_handle_list_cref p_list, size_t * order, const service_ptr_t<titleformat_object> & script, titleformat_hook * hook, int direction, abort_callback & aborter );
|
|
|
226 void sort_by_format_v2(metadb_handle_list_ref p_list, const service_ptr_t<titleformat_object> & script, titleformat_hook * hook, int direction, abort_callback & aborter);
|
|
|
227
|
|
|
228 struct sorter_t {
|
|
|
229 service_ptr_t < titleformat_object > obj;
|
|
|
230 int direction = 1;
|
|
|
231 titleformat_hook* hook = nullptr;
|
|
|
232 };
|
|
|
233
|
|
|
234 //! Late-2023 addition (new fb2k not required) \n
|
|
|
235 //! Multilayer stablesort using single info query pass, with multiple sort objects that can have different directions.
|
|
|
236 //! @param inOutOrder input & output order, please set to a valid permutration (such as identity) on input.
|
|
|
237 void sort_by_format_get_order_v3(metadb_handle_list_cref p_list, size_t* inOutOrder, sorter_t const * sorters, size_t nSorters, abort_callback& aborter);
|
|
|
238 };
|
|
|
239
|
|
|
240 template<template<typename> class t_alloc = pfc::alloc_fast >
|
|
|
241 class metadb_handle_list_t : public service_list_t<metadb_handle,t_alloc> {
|
|
|
242 private:
|
|
|
243 typedef metadb_handle_list_t<t_alloc> t_self;
|
|
|
244 typedef pfc::list_base_const_t<metadb_handle_ptr> t_interface;
|
|
|
245 public:
|
|
|
246 inline void sort_by_format(const char * spec,titleformat_hook * p_hook) {
|
|
|
247 return metadb_handle_list_helper::sort_by_format(*this, spec, p_hook);
|
|
|
248 }
|
|
|
249 inline void sort_by_format_get_order(t_size* order,const char * spec,titleformat_hook * p_hook) const {
|
|
|
250 metadb_handle_list_helper::sort_by_format_get_order(*this, order, spec, p_hook);
|
|
|
251 }
|
|
|
252
|
|
|
253 inline void sort_by_format(const service_ptr_t<titleformat_object> & p_script,titleformat_hook * p_hook, int direction = 1) {
|
|
|
254 metadb_handle_list_helper::sort_by_format(*this, p_script, p_hook, direction);
|
|
|
255 }
|
|
|
256 inline void sort_by_format_get_order(t_size* order,const service_ptr_t<titleformat_object> & p_script,titleformat_hook * p_hook) const {
|
|
|
257 metadb_handle_list_helper::sort_by_format_get_order(*this, order, p_script, p_hook);
|
|
|
258 }
|
|
|
259
|
|
|
260 inline void sort_by_relative_path() {
|
|
|
261 metadb_handle_list_helper::sort_by_relative_path(*this);
|
|
|
262 }
|
|
|
263 inline void sort_by_relative_path_get_order(t_size* order) const {
|
|
|
264 metadb_handle_list_helper::sort_by_relative_path_get_order(*this,order);
|
|
|
265 }
|
|
|
266
|
|
|
267 inline void remove_duplicates() {metadb_handle_list_helper::remove_duplicates(*this);}
|
|
|
268 inline void sort_by_pointer_remove_duplicates() {metadb_handle_list_helper::sort_by_pointer_remove_duplicates(*this);}
|
|
|
269 inline void sort_by_path_quick() {metadb_handle_list_helper::sort_by_path_quick(*this);}
|
|
|
270
|
|
|
271 inline void sort_by_pointer() {metadb_handle_list_helper::sort_by_pointer(*this);}
|
|
|
272 inline t_size bsearch_by_pointer(const metadb_handle_ptr & val) const {return metadb_handle_list_helper::bsearch_by_pointer(*this,val);}
|
|
|
273
|
|
|
274 inline double calc_total_duration() const {return metadb_handle_list_helper::calc_total_duration(*this);}
|
|
|
275 pfc::string8 format_total_size() const { return metadb_handle_list_helper::format_total_size(*this); }
|
|
|
276
|
|
|
277 inline void sort_by_path() {metadb_handle_list_helper::sort_by_path(*this);}
|
|
|
278
|
|
|
279 const t_self & operator=(const t_self & p_source) { this->remove_all(); this->add_items(p_source);return *this;}
|
|
|
280 const t_self & operator=(const t_interface & p_source) {this->remove_all(); this->add_items(p_source);return *this;}
|
|
|
281 const t_self & operator=(t_self && p_source) {this->move_from(p_source); return *this; }
|
|
|
282 metadb_handle_list_t(const t_self & p_source) { this->add_items(p_source);}
|
|
|
283 metadb_handle_list_t(const t_interface & p_source) { this->add_items(p_source);}
|
|
|
284 metadb_handle_list_t() {}
|
|
|
285
|
|
|
286 metadb_handle_list_t(t_self && p_source) { this->move_from(p_source);}
|
|
|
287
|
|
|
288 t_self & operator+=(const t_interface & source) { this->add_items(source); return *this;}
|
|
|
289 t_self & operator+=(const metadb_handle_ptr & source) { this->add_item(source); return *this;}
|
|
|
290
|
|
|
291 bool extract_single_path(const char * &path) const {return metadb_handle_list_helper::extract_single_path(*this, path);}
|
|
|
292 };
|
|
|
293
|
|
|
294 typedef metadb_handle_list_t<> metadb_handle_list;
|
|
|
295
|
|
|
296 namespace metadb_handle_list_helper {
|
|
|
297 void sorted_by_pointer_extract_difference(metadb_handle_list const & p_list_1,metadb_handle_list const & p_list_2,metadb_handle_list & p_list_1_specific,metadb_handle_list & p_list_2_specific);
|
|
|
298 };
|
|
|
299
|
|
|
300
|
|
|
301 inline pfc::string_base & operator<<(pfc::string_base & p_fmt,const metadb_handle_ptr & p_location) {
|
|
|
302 if (p_location.is_valid())
|
|
|
303 return p_fmt << p_location->get_location();
|
|
|
304 else
|
|
|
305 return p_fmt << "[invalid location]";
|
|
|
306 }
|
|
|
307
|
|
|
308
|
|
|
309
|
|
|
310 namespace fb2k {
|
|
|
311 pfc::string_formatter formatTrackList( metadb_handle_list_cref );
|
|
|
312 pfc::string_formatter formatTrackTitle(metadb_handle_ptr item, const char * script = "%title%" );
|
|
|
313 pfc::string_formatter formatTrackTitle(metadb_handle_ptr item,service_ptr_t<class titleformat_object> script);
|
|
|
314 }
|
|
|
315
|