diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_local/SaveQuery.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Plugins/Library/ml_local/SaveQuery.cpp')
-rw-r--r-- | Src/Plugins/Library/ml_local/SaveQuery.cpp | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_local/SaveQuery.cpp b/Src/Plugins/Library/ml_local/SaveQuery.cpp new file mode 100644 index 00000000..35cac30c --- /dev/null +++ b/Src/Plugins/Library/ml_local/SaveQuery.cpp @@ -0,0 +1,406 @@ +#include "main.h" +#include "ml_local.h" +#include <shlwapi.h> +#include <assert.h> +#include "../nu/sort.h" + +/* +#ifdef _M_IX86 +#undef min +static inline int min(int x, int y) +{ + return y+((x-y)>>31)&(x-y); +} +#undef max +static inline int max(int x, int y) +{ + return x-(((x-y)>>(31))&(x-y)); +} + +#elif defined(_WIN64) +#undef min +static inline int min(int x, int y) +{ + return y+((x-y)>>63)&(x-y); +} +#undef max +static inline int max(int x, int y) +{ + return x-(((x-y)>>(63))&(x-y)); +} +#endif +*/ + +#ifdef _M_IX86 +const size_t convert_max_characters = 16; // it's actually 11, but this probably causes less memory fragmentation +#elif defined(_M_X64) +const size_t convert_max_characters = 20; +#endif + +static inline int Compare_Int_NegativeIsNull(int v1, int v2) +{ + v1 = max(v1,0); + v2 = max(v2,0); + return(v1 - v2); +} + +typedef int (__fastcall *SortFunction)(const itemRecordW *a, const itemRecordW *b); +#define SORT(field) SortBy ## field +#define STRING_SORT(field) static int __fastcall SORT(field)(const itemRecordW *a, const itemRecordW *b) { return WCSCMP_NULLOK(a->field, b->field); } +#define EXT_STRING_SORT(field) static int __fastcall SORT(field)(const itemRecordW *a, const itemRecordW *b) { wchar_t *a_field = getRecordExtendedItem_fast(a, extended_fields.field); wchar_t *b_field = getRecordExtendedItem_fast(b, extended_fields.field); return WCSCMP_NULLOK(a_field, b_field);} +#define TIME_SORT(field) static int __fastcall SORT(field)(const itemRecordW *a, const itemRecordW *b) { time_t v1 = (time_t)a->field; time_t v2 = (time_t)b->field; if (v1 == -1) v1 = 0; if (v2 == -1) v2 = 0; return (int)(v1 - v2);} +#define EXT_TIME_SORT(field) static int __fastcall SORT(field)(const itemRecordW *a, const itemRecordW *b) { wchar_t *a_field = getRecordExtendedItem_fast(a, extended_fields.dateadded); wchar_t *b_field = getRecordExtendedItem_fast(b, extended_fields.dateadded); time_t v1 = a_field?_wtoi(a_field):0; time_t v2 = b_field?_wtoi(b_field):0; if (v1 == -1) v1 = 0; if (v2 == -1) v2 = 0; return (int)(v1 - v2);} +#define INT_SORT(field) static int __fastcall SORT(field)(const itemRecordW *a, const itemRecordW *b) { return Compare_Int_NegativeIsNull(a->field, b->field); } +#define EXT_INT_SORT(field) static int __fastcall SORT(field)(const itemRecordW *a, const itemRecordW *b) { wchar_t *a_field = getRecordExtendedItem_fast(a, extended_fields.field); wchar_t *b_field = getRecordExtendedItem_fast(b, extended_fields.field); int v1 = a_field?_wtoi(a_field):0; int v2 = b_field?_wtoi(b_field):0; return (v1-v2);} +#define FLOAT_SORT(field) static int __fastcall SORT(field)(const itemRecordW *a, const itemRecordW *b) { return FLOATWCMP_NULLOK(a->field, b->field); } +STRING_SORT(artist); +STRING_SORT(title); +STRING_SORT(album); +INT_SORT(length); +INT_SORT(track); +STRING_SORT(genre); +INT_SORT(year); +static int __fastcall SORT(filespec)(const itemRecordW *a, const itemRecordW *b) +{ + // remove path before compare... + wchar_t * af = L""; + if (a->filename) + af = PathFindFileNameW(a->filename); + + wchar_t * bf = L""; + if (b->filename) + bf = PathFindFileNameW(b->filename); + + return _wcsicmp(af, bf); +} + +INT_SORT(rating); +INT_SORT(playcount); +TIME_SORT(lastplay); +TIME_SORT(lastupd); +TIME_SORT(filetime); +STRING_SORT(comment); +INT_SORT(filesize); +INT_SORT(bitrate); +INT_SORT(type); +INT_SORT(disc); +STRING_SORT(albumartist); +STRING_SORT(filename); +FLOAT_SORT(replaygain_album_gain); +FLOAT_SORT(replaygain_track_gain); +STRING_SORT(publisher); +STRING_SORT(composer); +static int __fastcall SORT(extension)(const itemRecordW *a, const itemRecordW *b) +{ + wchar_t *extA = PathFindExtensionW(a->filename); + wchar_t *extB = PathFindExtensionW(b->filename); + if (extA && *extA) + extA++; + if (extB && *extB) + extB++; + return WCSCMP_NULLOK(extA, extB); +} +EXT_INT_SORT(ispodcast); +EXT_STRING_SORT(podcastchannel); +EXT_STRING_SORT(podcastpubdate); +INT_SORT(bpm); +STRING_SORT(category); +EXT_STRING_SORT(director); +EXT_STRING_SORT(producer); +EXT_TIME_SORT(dateadded); +EXT_STRING_SORT(cloud); + +static int __fastcall SORT(dimension)(const itemRecordW *a, const itemRecordW *b) +{ + wchar_t *a_width = getRecordExtendedItem_fast(a, extended_fields.width); + wchar_t *b_width = getRecordExtendedItem_fast(b, extended_fields.width); + wchar_t *a_height = getRecordExtendedItem_fast(a, extended_fields.height); + wchar_t *b_height = getRecordExtendedItem_fast(b, extended_fields.height); + int w1 = a_width?_wtoi(a_width):0; + int w2 = b_width?_wtoi(b_width):0; + int h1 = a_height?_wtoi(a_height):0; + int h2 = b_height?_wtoi(b_height):0; + if (w1 != w2) + return (w1-w2); + else + return (h1-h2); +} +// DISABLED FOR 5.62 RELEASE - DRO +//EXT_STRING_SORT(codec); + +#define FORCE_ASCENDING ((SortFunction)-2) +// this is where we define sort orders! +static const SortFunction sortOrder[MEDIAVIEW_COL_NUMS][MEDIAVIEW_COL_NUMS+2] = +{ + {SORT(artist), FORCE_ASCENDING, SORT(album), SORT(disc), SORT(track), SORT(title), 0}, // Artist + {SORT(title), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(album), FORCE_ASCENDING, SORT(albumartist), SORT(disc), SORT(track), SORT(title), 0}, + {SORT(length), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(track), FORCE_ASCENDING, SORT(title), SORT(artist), SORT(album), SORT(disc), 0}, + {SORT(genre), FORCE_ASCENDING, SORT(albumartist), SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(year), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(filespec), SORT(filename),0}, + {SORT(rating), SORT(playcount), SORT(lastplay), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(playcount), SORT(lastplay), FORCE_ASCENDING,SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(lastplay), FORCE_ASCENDING,SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(lastupd), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(filetime), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(comment), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(filesize),FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(bitrate), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(type), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(disc), FORCE_ASCENDING, SORT(track), SORT(title), SORT(artist), SORT(album), SORT(disc), 0}, + {SORT(albumartist), FORCE_ASCENDING, SORT(album), SORT(disc), SORT(track), 0}, + {SORT(filename), 0}, + {SORT(replaygain_album_gain), FORCE_ASCENDING, SORT(album), SORT(disc), SORT(track), SORT(title), 0}, + {SORT(replaygain_track_gain), FORCE_ASCENDING, SORT(title), 0}, + {SORT(publisher),FORCE_ASCENDING,SORT(artist), SORT(album), SORT(disc), SORT(track), SORT(title), 0}, + {SORT(composer), FORCE_ASCENDING,SORT(album), SORT(disc), SORT(track), 0}, + {SORT(extension), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(ispodcast), FORCE_ASCENDING, SORT(podcastchannel), SORT(title), 0}, + {SORT(podcastchannel), SORT(title), 0}, + {SORT(podcastpubdate), 0}, + {SORT(bpm), 0}, // TODO + {SORT(category),FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), SORT(title), 0}, + {SORT(director),FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), SORT(title), 0}, + {SORT(producer),FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), SORT(title), 0}, + {SORT(dimension), 0}, + // DISABLED FOR 5.62 RELEASE - DRO + //{SORT(codec), 0}, + {SORT(dateadded), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, + {SORT(cloud), FORCE_ASCENDING, SORT(artist), SORT(album), SORT(disc), SORT(track), 0}, +}; + +/* ---- */ +struct SortRules +{ + int by; + int dir; +}; +static int __fastcall sortFuncW(const void *elem1, const void *elem2, const void *context) +{ + assert(sizeof(sortOrder) / sizeof(*sortOrder) == MEDIAVIEW_COL_NUMS); + + const itemRecordW *a = (const itemRecordW*)elem1; + const itemRecordW *b = (const itemRecordW*)elem2; + + const SortRules *rules = (SortRules *)context; + int use_by = rules->by; + int use_dir = !!rules->dir; + + int dir_values[] = {-1, 1}; + +#define RETIFNZ(v) if ((v)<0) return dir_values[use_dir]; if ((v)>0) return -dir_values[use_dir]; + + const SortFunction *order =sortOrder[use_by]; + int i=0; + while (order[i]) + { + if (order[i]==FORCE_ASCENDING) + { + use_dir=0; + i++; + continue; + } + int v = order[i](a, b); + RETIFNZ(v); + i++; + } + return 0; +} + +void sortResults(int column, int dir, itemRecordListW *obj) // sorts the results based on the current sort mode +{ + if (obj->Size > 1) + { + SortRules rules = {column, dir}; + qsort_itemRecord(obj->Items, obj->Size, &rules, sortFuncW); + } +} + +void sortResults(C_Config *viewconf, itemRecordListW *obj) // sorts the results based on the current sort mode +{ + if (viewconf) + { + SortRules rules = {viewconf->ReadInt(L"mv_sort_by", MEDIAVIEW_COL_ARTIST), viewconf->ReadInt(L"mv_sort_dir", 0)}; + if (obj->Size > 1) + qsort_itemRecord(obj->Items, obj->Size, &rules, sortFuncW); + } +} + +void setCloudValue(itemRecordW *item, const wchar_t* value) +{ + wchar_t *temp = ndestring_malloc(convert_max_characters*sizeof(wchar_t)); + lstrcpynW(temp, value, convert_max_characters); + setRecordExtendedItem(item, extended_fields.cloud, temp); + ndestring_release(temp); +} + +int saveQueryToListW(C_Config *viewconf, nde_scanner_t s, itemRecordListW *obj, + CloudFiles *uploaded, CloudFiles *uploading, + resultsniff_funcW cb, int user32, int *killswitch, __int64 *total_bytes) +{ + __int64 total_kb = 0; + + emptyRecordList(obj); + + EnterCriticalSection(&g_db_cs); + NDE_Scanner_First(s, killswitch); + if (killswitch && *killswitch) + { + LeaveCriticalSection(&g_db_cs); + return 0; + } + + int r = 0; + unsigned int total_length_s = 0; + unsigned int uncert_cnt = 0; + unsigned int cert_cnt = 0; + int recordCount = NDE_Scanner_GetRecordsCount(s); + allocRecordList(obj, recordCount); + do + { + nde_field_t f = NDE_Scanner_GetFieldByID(s, MAINTABLE_ID_FILENAME); + if (f) + { + allocRecordList(obj, obj->Size + 1); + if (!obj->Alloc) break; + + obj->Items[obj->Size].filename = NDE_StringField_GetString(f); + ndestring_retain(obj->Items[obj->Size].filename); + total_kb += ScannerRefToObjCacheNFNW(s, obj, (cb == (resultsniff_funcW)-1 ? true : false)); + + // look for any files known to the cloud so the icon can be set accordingly + // TODO possibly need to do more here to better cope with transient states?? + if (uploaded && uploaded->size() > 0) + { + bool found = false; + for(CloudFiles::iterator iter = uploaded->begin(); iter != uploaded->end(); iter++) + { + if (nde_wcsicmp_fn(obj->Items[obj->Size - 1].filename,(*iter)) == 0) + { + bool pending = false; + found = true; + + // catches files being uploaded but not fully known to be in the cloud, etc + if (uploading && uploading->size() > 0) + { + for(CloudFiles::iterator iter2 = uploading->begin(); iter2 != uploading->end(); iter2++) + { + if (nde_wcsicmp_fn(obj->Items[obj->Size - 1].filename,(*iter2)) == 0) + { + pending = true; + setCloudValue(&obj->Items[obj->Size - 1], L"5"); + break; + } + } + } + + if (!pending) + { + setCloudValue(&obj->Items[obj->Size - 1], L"0"); + } + break; + } + } + + if (!found) + { + // catches files being uploaded but not fully known to be in the cloud, etc + if (uploading && uploading->size() > 0) + { + for(CloudFiles::iterator iter = uploading->begin(); iter != uploading->end(); iter++) + { + if (nde_wcsicmp_fn(obj->Items[obj->Size - 1].filename,(*iter)) == 0) + { + found = true; + setCloudValue(&obj->Items[obj->Size - 1], L"5"); + break; + } + } + } + + if (!found) + { + setCloudValue(&obj->Items[obj->Size - 1], L"4"); + } + } + } + + int thisl = obj->Items[obj->Size - 1].length; + + if (thisl > 0) + { + total_length_s += thisl; + cert_cnt++; + } + else + { + uncert_cnt++; + } + } + + r = NDE_Scanner_Next(s, killswitch); + if (killswitch && *killswitch) + { + LeaveCriticalSection(&g_db_cs); + return 0; + } + } + while (r && !NDE_Scanner_EOF(s)); + + if (((Table *)g_table)->HasErrors()) // TODO: don't use C++ NDE API + { + wchar_t *last_query = NULL; + if (m_media_scanner) + { + const wchar_t *lq = NDE_Scanner_GetLastQuery(m_media_scanner); + if (lq) last_query = _wcsdup(lq); + NDE_Table_DestroyScanner(g_table, m_media_scanner); + } + NDE_Table_Compact(g_table); + if (m_media_scanner) + { + m_media_scanner = NDE_Table_CreateScanner(g_table); + if (last_query != NULL) + { + NDE_Scanner_Query(m_media_scanner, last_query); + free(last_query); + } + } + } + LeaveCriticalSection(&g_db_cs); + + if (total_bytes) + { + // maintain compatibility as needed + if (cb == (resultsniff_funcW)-1) + *total_bytes = total_kb * 1024; + else + *total_bytes = total_kb; + } + compactRecordList(obj); + + if (cb && cb != (resultsniff_funcW)-1) + { + cb(obj->Items, obj->Size, user32, killswitch); + } + + if (killswitch && *killswitch) return 0; + + sortResults(viewconf, obj); + + if (killswitch && *killswitch) return 0; + + if (uncert_cnt) + { + if (cert_cnt) + { + __int64 avg_len = (__int64)total_length_s / cert_cnt; + total_length_s += (DWORD)(avg_len * uncert_cnt); + } + total_length_s |= (1 << 31); + } + + return total_length_s; +}
\ No newline at end of file |