mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-10 06:41:00 +03:00
Added support for MongoDB Added tests relating to new DB system Category rules are now case insensitive Fixed playlist modification change state
149 lines
5.2 KiB
JavaScript
149 lines
5.2 KiB
JavaScript
const config_api = require('./config');
|
|
const utils = require('./utils');
|
|
|
|
var logger = null;
|
|
var db = null;
|
|
var users_db = null;
|
|
var db_api = null;
|
|
|
|
function setDB(input_db, input_users_db, input_db_api) { db = input_db; users_db = input_users_db; db_api = input_db_api }
|
|
function setLogger(input_logger) { logger = input_logger; }
|
|
|
|
function initialize(input_db, input_users_db, input_logger, input_db_api) {
|
|
setDB(input_db, input_users_db, input_db_api);
|
|
setLogger(input_logger);
|
|
}
|
|
|
|
/*
|
|
|
|
Categories:
|
|
|
|
Categories are a way to organize videos based on dynamic rules set by the user. Categories are universal (so not per-user).
|
|
|
|
Categories, besides rules, have an optional custom output. This custom output can help users create their
|
|
desired directory structure.
|
|
|
|
Rules:
|
|
A category rule consists of a property, a comparison, and a value. For example, "uploader includes 'VEVO'"
|
|
|
|
Rules are stored as an object with the above fields. In addition to those fields, it also has a preceding_operator, which
|
|
is either OR or AND, and signifies whether the rule should be ANDed with the previous rules, or just ORed. For the first
|
|
rule, this field is null.
|
|
|
|
Ex. (title includes 'Rihanna' OR title includes 'Beyonce' AND uploader includes 'VEVO')
|
|
|
|
*/
|
|
|
|
async function categorize(file_jsons) {
|
|
// to make the logic easier, let's assume the file metadata is an array
|
|
if (!Array.isArray(file_jsons)) file_jsons = [file_jsons];
|
|
|
|
let selected_category = null;
|
|
const categories = await getCategories();
|
|
if (!categories) {
|
|
logger.warn('Categories could not be found.');
|
|
return null;
|
|
}
|
|
|
|
for (let i = 0; i < file_jsons.length; i++) {
|
|
const file_json = file_jsons[i];
|
|
for (let j = 0; j < categories.length; j++) {
|
|
const category = categories[j];
|
|
const rules = category['rules'];
|
|
|
|
// if rules for current category apply, then that is the selected category
|
|
if (applyCategoryRules(file_json, rules, category['name'])) {
|
|
selected_category = category;
|
|
logger.verbose(`Selected category ${category['name']} for ${file_json['webpage_url']}`);
|
|
return selected_category;
|
|
}
|
|
}
|
|
}
|
|
|
|
return selected_category;
|
|
}
|
|
|
|
async function getCategories() {
|
|
const categories = await db_api.getRecords('categories');
|
|
return categories ? categories : null;
|
|
}
|
|
|
|
async function getCategoriesAsPlaylists(files = null) {
|
|
const categories_as_playlists = [];
|
|
const available_categories = await getCategories();
|
|
if (available_categories && files) {
|
|
for (category of available_categories) {
|
|
const files_that_match = utils.addUIDsToCategory(category, files);
|
|
if (files_that_match && files_that_match.length > 0) {
|
|
category['thumbnailURL'] = files_that_match[0].thumbnailURL;
|
|
category['thumbnailPath'] = files_that_match[0].thumbnailPath;
|
|
category['duration'] = files_that_match.reduce((a, b) => a + utils.durationStringToNumber(b.duration), 0);
|
|
category['id'] = category['uid'];
|
|
categories_as_playlists.push(category);
|
|
}
|
|
}
|
|
}
|
|
return categories_as_playlists;
|
|
}
|
|
|
|
function applyCategoryRules(file_json, rules, category_name) {
|
|
let rules_apply = false;
|
|
for (let i = 0; i < rules.length; i++) {
|
|
const rule = rules[i];
|
|
let rule_applies = null;
|
|
|
|
let preceding_operator = rule['preceding_operator'];
|
|
|
|
switch (rule['comparator']) {
|
|
case 'includes':
|
|
rule_applies = file_json[rule['property']].toLowerCase().includes(rule['value'].toLowerCase());
|
|
break;
|
|
case 'not_includes':
|
|
rule_applies = !(file_json[rule['property']].toLowerCase().includes(rule['value'].toLowerCase()));
|
|
break;
|
|
case 'equals':
|
|
rule_applies = file_json[rule['property']] === rule['value'];
|
|
break;
|
|
case 'not_equals':
|
|
rule_applies = file_json[rule['property']] !== rule['value'];
|
|
break;
|
|
default:
|
|
logger.warn(`Invalid comparison used for category ${category_name}`)
|
|
break;
|
|
}
|
|
|
|
// OR the first rule with rules_apply, which will be initially false
|
|
if (i === 0) preceding_operator = 'or';
|
|
|
|
// update rules_apply based on current rule
|
|
if (preceding_operator === 'or')
|
|
rules_apply = rules_apply || rule_applies;
|
|
else
|
|
rules_apply = rules_apply && rule_applies;
|
|
}
|
|
|
|
return rules_apply;
|
|
}
|
|
|
|
async function addTagToVideo(tag, video, user_uid) {
|
|
// TODO: Implement
|
|
}
|
|
|
|
async function removeTagFromVideo(tag, video, user_uid) {
|
|
// TODO: Implement
|
|
}
|
|
|
|
// adds tag to list of existing tags (used for tag suggestions)
|
|
async function addTagToExistingTags(tag) {
|
|
const existing_tags = db.get('tags').value();
|
|
if (!existing_tags.includes(tag)) {
|
|
db.get('tags').push(tag).write();
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
initialize: initialize,
|
|
categorize: categorize,
|
|
getCategories: getCategories,
|
|
getCategoriesAsPlaylists: getCategoriesAsPlaylists
|
|
} |