mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-19 01:31:29 +03:00
Refactored retrieval of categories and improved runtime search of files in category
Fixed issue with editing/saving categories Database queries can now handle nested object paths Code cleanup
This commit is contained in:
@@ -933,20 +933,13 @@ app.post('/api/getAllFiles', optionalJwt, async function (req, res) {
|
|||||||
else if (file_type_filter === 'video_only') filter_obj['isAudio'] = false;
|
else if (file_type_filter === 'video_only') filter_obj['isAudio'] = false;
|
||||||
|
|
||||||
files = await db_api.getRecords('files', filter_obj, false, sort, range, text_search);
|
files = await db_api.getRecords('files', filter_obj, false, sort, range, text_search);
|
||||||
let file_count = await db_api.getRecords('files', filter_obj, true);
|
const file_count = await db_api.getRecords('files', filter_obj, true);
|
||||||
playlists = await db_api.getRecords('playlists', {user_uid: uuid});
|
|
||||||
|
|
||||||
const categories = await categories_api.getCategoriesAsPlaylists(files);
|
|
||||||
if (categories) {
|
|
||||||
playlists = playlists.concat(categories);
|
|
||||||
}
|
|
||||||
|
|
||||||
files = JSON.parse(JSON.stringify(files));
|
files = JSON.parse(JSON.stringify(files));
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
files: files,
|
files: files,
|
||||||
file_count: file_count,
|
file_count: file_count,
|
||||||
playlists: playlists
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1383,7 +1376,7 @@ app.post('/api/getPlaylists', optionalJwt, async (req, res) => {
|
|||||||
|
|
||||||
let playlists = await db_api.getRecords('playlists', {user_uid: uuid});
|
let playlists = await db_api.getRecords('playlists', {user_uid: uuid});
|
||||||
if (include_categories) {
|
if (include_categories) {
|
||||||
const categories = await categories_api.getCategoriesAsPlaylists(files);
|
const categories = await categories_api.getCategoriesAsPlaylists();
|
||||||
if (categories) {
|
if (categories) {
|
||||||
playlists = playlists.concat(categories);
|
playlists = playlists.concat(categories);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,12 +55,12 @@ async function getCategories() {
|
|||||||
return categories ? categories : null;
|
return categories ? categories : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getCategoriesAsPlaylists(files = null) {
|
async function getCategoriesAsPlaylists() {
|
||||||
const categories_as_playlists = [];
|
const categories_as_playlists = [];
|
||||||
const available_categories = await getCategories();
|
const available_categories = await getCategories();
|
||||||
if (available_categories && files) {
|
if (available_categories) {
|
||||||
for (let category of available_categories) {
|
for (let category of available_categories) {
|
||||||
const files_that_match = utils.addUIDsToCategory(category, files);
|
const files_that_match = await db_api.getRecords('files', {'category.uid': category['uid']});
|
||||||
if (files_that_match && files_that_match.length > 0) {
|
if (files_that_match && files_that_match.length > 0) {
|
||||||
category['thumbnailURL'] = files_that_match[0].thumbnailURL;
|
category['thumbnailURL'] = files_that_match[0].thumbnailURL;
|
||||||
category['thumbnailPath'] = files_that_match[0].thumbnailPath;
|
category['thumbnailPath'] = files_that_match[0].thumbnailPath;
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ function setConfigItem(key, value) {
|
|||||||
success = setConfigFile(config_json);
|
success = setConfigFile(config_json);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
};
|
}
|
||||||
|
|
||||||
function setConfigItems(items) {
|
function setConfigItems(items) {
|
||||||
let success = false;
|
let success = false;
|
||||||
|
|||||||
@@ -387,9 +387,9 @@ exports.getPlaylist = async (playlist_id, user_uid = null, require_sharing = fal
|
|||||||
if (!playlist) {
|
if (!playlist) {
|
||||||
playlist = await exports.getRecord('categories', {uid: playlist_id});
|
playlist = await exports.getRecord('categories', {uid: playlist_id});
|
||||||
if (playlist) {
|
if (playlist) {
|
||||||
// category found
|
const uids = (await exports.getRecords('files', {'category.uid': playlist_id})).map(file => file.uid);
|
||||||
const files = await exports.getFiles(user_uid);
|
playlist['uids'] = uids;
|
||||||
utils.addUIDsToCategory(playlist, files);
|
playlist['auto'] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,7 +1090,7 @@ exports.applyFilterLocalDB = (db_path, filter_obj, operation) => {
|
|||||||
const filter_prop = filter_props[i];
|
const filter_prop = filter_props[i];
|
||||||
const filter_prop_value = filter_obj[filter_prop];
|
const filter_prop_value = filter_obj[filter_prop];
|
||||||
if (filter_prop_value === undefined || filter_prop_value === null) {
|
if (filter_prop_value === undefined || filter_prop_value === null) {
|
||||||
filtered &= record[filter_prop] === undefined || record[filter_prop] === null
|
filtered &= record[filter_prop] === undefined || record[filter_prop] === null;
|
||||||
} else {
|
} else {
|
||||||
if (typeof filter_prop_value === 'object') {
|
if (typeof filter_prop_value === 'object') {
|
||||||
if ('$regex' in filter_prop_value) {
|
if ('$regex' in filter_prop_value) {
|
||||||
@@ -1099,7 +1099,11 @@ exports.applyFilterLocalDB = (db_path, filter_obj, operation) => {
|
|||||||
filtered &= filter_prop in record && record[filter_prop] !== filter_prop_value['$ne'];
|
filtered &= filter_prop in record && record[filter_prop] !== filter_prop_value['$ne'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
filtered &= record[filter_prop] === filter_prop_value;
|
// handle case of nested property check
|
||||||
|
if (filter_prop.includes('.'))
|
||||||
|
filtered &= utils.searchObjectByString(record, filter_prop) === filter_prop_value;
|
||||||
|
else
|
||||||
|
filtered &= record[filter_prop] === filter_prop_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,6 +272,11 @@ describe('Database', async function() {
|
|||||||
const result = db_api.applyFilterLocalDB([{test: 'test'}, {test: 'test1'}], {test: filter}, 'find');
|
const result = db_api.applyFilterLocalDB([{test: 'test'}, {test: 'test1'}], {test: filter}, 'find');
|
||||||
assert(result && result['test'] === 'test1');
|
assert(result && result['test'] === 'test1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Nested', async function() {
|
||||||
|
const result = db_api.applyFilterLocalDB([{test1: {test2: 'test3'}}, {test4: 'test5'}], {'test1.test2': 'test3'}, 'find');
|
||||||
|
assert(result && result['test1']['test2'] === 'test3');
|
||||||
|
});
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -456,6 +456,21 @@ function injectArgs(original_args, new_args) {
|
|||||||
return updated_args;
|
return updated_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const searchObjectByString = function(o, s) {
|
||||||
|
s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
|
||||||
|
s = s.replace(/^\./, ''); // strip a leading dot
|
||||||
|
var a = s.split('.');
|
||||||
|
for (var i = 0, n = a.length; i < n; ++i) {
|
||||||
|
var k = a[i];
|
||||||
|
if (k in o) {
|
||||||
|
o = o[k];
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
// objects
|
// objects
|
||||||
|
|
||||||
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date, description, view_count, height, abr) {
|
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date, description, view_count, height, abr) {
|
||||||
@@ -489,7 +504,6 @@ module.exports = {
|
|||||||
createContainerZipFile: createContainerZipFile,
|
createContainerZipFile: createContainerZipFile,
|
||||||
durationStringToNumber: durationStringToNumber,
|
durationStringToNumber: durationStringToNumber,
|
||||||
getMatchingCategoryFiles: getMatchingCategoryFiles,
|
getMatchingCategoryFiles: getMatchingCategoryFiles,
|
||||||
addUIDsToCategory: addUIDsToCategory,
|
|
||||||
getCurrentDownloader: getCurrentDownloader,
|
getCurrentDownloader: getCurrentDownloader,
|
||||||
recFindByExt: recFindByExt,
|
recFindByExt: recFindByExt,
|
||||||
removeFileExtension: removeFileExtension,
|
removeFileExtension: removeFileExtension,
|
||||||
@@ -501,5 +515,6 @@ module.exports = {
|
|||||||
fetchFile: fetchFile,
|
fetchFile: fetchFile,
|
||||||
restartServer: restartServer,
|
restartServer: restartServer,
|
||||||
injectArgs: injectArgs,
|
injectArgs: injectArgs,
|
||||||
|
searchObjectByString: searchObjectByString,
|
||||||
File: File
|
File: File
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export class CustomPlaylistsComponent implements OnInit {
|
|||||||
getAllPlaylists() {
|
getAllPlaylists() {
|
||||||
this.playlists_received = false;
|
this.playlists_received = false;
|
||||||
// must call getAllFiles as we need to get category playlists as well
|
// must call getAllFiles as we need to get category playlists as well
|
||||||
this.postsService.getPlaylists().subscribe(res => {
|
this.postsService.getPlaylists(true).subscribe(res => {
|
||||||
this.playlists = res['playlists'];
|
this.playlists = res['playlists'];
|
||||||
this.playlists_received = true;
|
this.playlists_received = true;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,12 +28,12 @@
|
|||||||
<mat-form-field class="info-field">
|
<mat-form-field class="info-field">
|
||||||
<input [(ngModel)]="new_file.thumbnailURL" matInput placeholder="Thumbnail URL" i18n-placeholder="Thumbnail URL" [disabled]="!editing || new_file.thumbnailPath">
|
<input [(ngModel)]="new_file.thumbnailURL" matInput placeholder="Thumbnail URL" i18n-placeholder="Thumbnail URL" [disabled]="!editing || new_file.thumbnailPath">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="info-field">
|
<mat-form-field *ngIf="initialized && postsService.categories" class="info-field">
|
||||||
<mat-select placeholder="Category" i18n-placeholder="Category" [value]="category" (valueChange)="categoryChanged($event)" [compareWith]="categoryComparisonFunction" [disabled]="!editing">
|
<mat-select placeholder="Category" i18n-placeholder="Category" [value]="category" (selectionChange)="categoryChanged($event)" [compareWith]="categoryComparisonFunction" [disabled]="!editing">
|
||||||
<mat-option [value]="{}">
|
<mat-option [value]="{}">
|
||||||
N/A
|
N/A
|
||||||
</mat-option>
|
</mat-option>
|
||||||
<mat-option *ngFor="let available_category of postsService.categories | keyvalue" [value]="available_category">
|
<mat-option *ngFor="let available_category of postsService.categories | keyvalue" [value]="available_category.value">
|
||||||
{{available_category.value.name}}
|
{{available_category.value.name}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export class VideoInfoDialogComponent implements OnInit {
|
|||||||
upload_date: Date;
|
upload_date: Date;
|
||||||
category: Category;
|
category: Category;
|
||||||
editing = false;
|
editing = false;
|
||||||
|
initialized = false;
|
||||||
|
|
||||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any, public postsService: PostsService, private datePipe: DatePipe) { }
|
constructor(@Inject(MAT_DIALOG_DATA) public data: any, public postsService: PostsService, private datePipe: DatePipe) { }
|
||||||
|
|
||||||
@@ -37,15 +38,16 @@ export class VideoInfoDialogComponent implements OnInit {
|
|||||||
this.upload_date = new Date(this.new_file.upload_date);
|
this.upload_date = new Date(this.new_file.upload_date);
|
||||||
this.upload_date.setMinutes( this.upload_date.getMinutes() + this.upload_date.getTimezoneOffset() );
|
this.upload_date.setMinutes( this.upload_date.getMinutes() + this.upload_date.getTimezoneOffset() );
|
||||||
|
|
||||||
this.category = this.file.category ? this.category : {};
|
this.category = this.file.category ? this.file.category : {};
|
||||||
|
|
||||||
// we need to align whether missing category is null or undefined. this line helps with that.
|
// we need to align whether missing category is null or undefined. this line helps with that.
|
||||||
if (!this.file.category) { this.new_file.category = null; this.file.category = null; }
|
if (!this.file.category) { this.new_file.category = null; this.file.category = null; }
|
||||||
|
this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveChanges(): void {
|
saveChanges(): void {
|
||||||
const change_obj = {};
|
const change_obj = {};
|
||||||
const keys = Object.keys(this.file);
|
const keys = Object.keys(this.new_file);
|
||||||
keys.forEach(key => {
|
keys.forEach(key => {
|
||||||
if (this.file[key] !== this.new_file[key]) change_obj[key] = this.new_file[key];
|
if (this.file[key] !== this.new_file[key]) change_obj[key] = this.new_file[key];
|
||||||
});
|
});
|
||||||
@@ -67,7 +69,8 @@ export class VideoInfoDialogComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
categoryChanged(event): void {
|
categoryChanged(event): void {
|
||||||
this.new_file.category = Object.keys(event).length ? {uid: event.uid, name: event.name} : null;
|
const new_category = event.value;
|
||||||
|
this.new_file.category = Object.keys(new_category).length ? {uid: new_category.uid, name: new_category.name} : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
categoryComparisonFunction(option: Category, value: Category): boolean {
|
categoryComparisonFunction(option: Category, value: Category): boolean {
|
||||||
|
|||||||
@@ -457,15 +457,15 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.post<GetPlaylistResponse>(this.path + 'getPlaylist', body, this.httpOptions);
|
return this.http.post<GetPlaylistResponse>(this.path + 'getPlaylist', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPlaylists(include_categories = false) {
|
||||||
|
return this.http.post<GetPlaylistsRequest>(this.path + 'getPlaylists', {include_categories: include_categories}, this.httpOptions);
|
||||||
|
}
|
||||||
|
|
||||||
incrementViewCount(file_uid, sub_id, uuid) {
|
incrementViewCount(file_uid, sub_id, uuid) {
|
||||||
const body: IncrementViewCountRequest = {file_uid: file_uid, sub_id: sub_id, uuid: uuid};
|
const body: IncrementViewCountRequest = {file_uid: file_uid, sub_id: sub_id, uuid: uuid};
|
||||||
return this.http.post<SuccessObject>(this.path + 'incrementViewCount', body, this.httpOptions);
|
return this.http.post<SuccessObject>(this.path + 'incrementViewCount', body, this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlaylists() {
|
|
||||||
return this.http.post<GetPlaylistsRequest>(this.path + 'getPlaylists', {}, this.httpOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePlaylist(playlist: Playlist) {
|
updatePlaylist(playlist: Playlist) {
|
||||||
const body: UpdatePlaylistRequest = {playlist: playlist};
|
const body: UpdatePlaylistRequest = {playlist: playlist};
|
||||||
return this.http.post<SuccessObject>(this.path + 'updatePlaylist', body, this.httpOptions);
|
return this.http.post<SuccessObject>(this.path + 'updatePlaylist', body, this.httpOptions);
|
||||||
|
|||||||
Reference in New Issue
Block a user