mirror of
https://github.com/stashapp/CommunityScripts.git
synced 2025-12-11 14:55:10 -06:00
399 lines
9.6 KiB
JavaScript
399 lines
9.6 KiB
JavaScript
function ok() {
|
|
return {
|
|
output: "ok"
|
|
};
|
|
}
|
|
|
|
function main() {
|
|
var hookContext = input.Args.hookContext;
|
|
var type = hookContext.type;
|
|
var ID = hookContext.ID;
|
|
|
|
if (!ID) {
|
|
return ok();
|
|
}
|
|
|
|
var filenameFetcher;
|
|
var saver;
|
|
if (type === 'Scene.Create.Post') {
|
|
filenameFetcher = getSceneFilename;
|
|
saver = updateScene;
|
|
} else if (type === 'Gallery.Create.Post') {
|
|
filenameFetcher = getGalleryFilename;
|
|
saver = updateGallery;
|
|
} else {
|
|
return ok();
|
|
}
|
|
|
|
var filename = filenameFetcher(ID);
|
|
if (!filename) {
|
|
return ok();
|
|
}
|
|
|
|
filename = cleanFilename(filename);
|
|
var parseResult = parseFilename(filename);
|
|
|
|
saver(ID, parseResult);
|
|
|
|
return ok();
|
|
}
|
|
|
|
function getSceneFilename(sceneID) {
|
|
var query = "\
|
|
query findScene($id: ID) {\
|
|
findScene(id: $id) {\
|
|
path\
|
|
}\
|
|
}";
|
|
|
|
var variables = {
|
|
id: sceneID
|
|
};
|
|
|
|
var result = gql.Do(query, variables);
|
|
var findScene = result.findScene;
|
|
if (!findScene) {
|
|
return null;
|
|
}
|
|
|
|
var path = findScene.path;
|
|
return path.substring(path.lastIndexOf('/') + 1);
|
|
}
|
|
|
|
function updateScene(sceneID, parseResult) {
|
|
var query = "\
|
|
mutation SceneUpdate($input: SceneUpdateInput!) {\
|
|
sceneUpdate(input: $input) {\
|
|
id\
|
|
}\
|
|
}";
|
|
|
|
var variables = {
|
|
input: parseResult
|
|
};
|
|
|
|
variables.input.id = sceneID;
|
|
|
|
gql.Do(query, variables);
|
|
}
|
|
|
|
function getGalleryFilename(galleryID) {
|
|
var query = "\
|
|
query findGallery($id: ID!) {\
|
|
findGallery(id: $id) {\
|
|
path\
|
|
}\
|
|
}";
|
|
|
|
var variables = {
|
|
id: galleryID
|
|
};
|
|
|
|
var result = gql.Do(query, variables);
|
|
var findGallery = result.findGallery;
|
|
if (!findGallery) {
|
|
return null;
|
|
}
|
|
|
|
var path = findGallery.path;
|
|
return path.substring(path.lastIndexOf('/') + 1);
|
|
}
|
|
|
|
function updateGallery(galleryID, parseResult) {
|
|
var query = "\
|
|
mutation GalleryUpdate($input: GalleryUpdateInput!) {\
|
|
galleryUpdate(input: $input) {\
|
|
id\
|
|
}\
|
|
}";
|
|
|
|
var variables = {
|
|
input: parseResult
|
|
};
|
|
|
|
variables.input.id = galleryID;
|
|
|
|
gql.Do(query, variables);
|
|
}
|
|
|
|
function matchNames(parts, name, aliases) {
|
|
var names = [name].concat(aliases);
|
|
|
|
var partRegexes = [];
|
|
|
|
for (var i = 0; i < parts.length; i++) {
|
|
partRegexes[i] = new RegExp('^' + parts[i].toLowerCase() + '[. \\-_]*');
|
|
}
|
|
|
|
var cleanRegex = /[. \-_]/g;
|
|
var longestMatch = 0;
|
|
for (var i = 0; i < names.length; i++) {
|
|
var name = names[i].replace(cleanRegex, '').toLowerCase();
|
|
for (var j = 0; j < partRegexes.length; j++) {
|
|
if (!partRegexes[j].test(name)) {
|
|
break;
|
|
}
|
|
|
|
name = name.replace(partRegexes[j], '');
|
|
|
|
if (name.length === 0) {
|
|
if (j + 1 > longestMatch) {
|
|
longestMatch = j + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return longestMatch;
|
|
}
|
|
|
|
function cleanFilename(name) {
|
|
name = name
|
|
// remove imageset-...[rarbg]
|
|
.replace(/imageset-[\w\d]+\[rarbg]/i, '')
|
|
// replace [...] with just ...
|
|
.replace(/\[(.*?)]/g, '$1')
|
|
// replace (...) with just ...
|
|
.replace(/\((.*?)\)/g, '$1')
|
|
// replace {...} with just ...
|
|
.replace(/{(.*?)}/g, '$1')
|
|
;
|
|
|
|
var blockList = [
|
|
'mp4',
|
|
'mov',
|
|
'zip',
|
|
'xxx',
|
|
'4k',
|
|
'4096x2160',
|
|
'3840x2160',
|
|
'2160p',
|
|
'1080p',
|
|
'1920x1080',
|
|
'60fps',
|
|
'30fps',
|
|
'repack',
|
|
'ktr',
|
|
];
|
|
var regExp = new RegExp('(_|[^\\w\\d]|^)(' + blockList.join('|') + ')(_|[^\\w\\d]|$)', 'i');
|
|
while (regExp.test(name)) {
|
|
name = name.replace(regExp, '$1$3');
|
|
}
|
|
|
|
// If name starts with <...>.com remove the .com (sometimes names include studio name as site/domain)
|
|
name = name.replace(/^([\w\d-]+?)\.com/, '$1');
|
|
|
|
name = name
|
|
// Remove everything except letters and digits at the start
|
|
.replace(/^(_|[^\w\d])+/, '')
|
|
// Remove everything except letters and digits at the end
|
|
.replace(/(_|[^\w\d])+$/, '')
|
|
;
|
|
|
|
return name;
|
|
}
|
|
|
|
function matchStudio(parts, result) {
|
|
var query = "\
|
|
query findStudios($studio_filter: StudioFilterType, $filter: FindFilterType!) {\
|
|
findStudios(studio_filter: $studio_filter, filter: $filter) {\
|
|
studios {\
|
|
id\
|
|
name\
|
|
aliases\
|
|
}\
|
|
}\
|
|
}";
|
|
|
|
var searchTerm = parts[0].substring(0, 2);
|
|
if (parts[0].substring(0, 1) === 'a') {
|
|
searchTerm = parts[0].substring(1, 3);
|
|
}
|
|
var variables = {
|
|
filter: {
|
|
per_page: -1,
|
|
},
|
|
studio_filter: {
|
|
name: {
|
|
modifier: "INCLUDES",
|
|
value: searchTerm
|
|
},
|
|
OR: {
|
|
aliases: {
|
|
modifier: "INCLUDES",
|
|
value: searchTerm
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var queryResult = gql.Do(query, variables);
|
|
var studios = queryResult.findStudios.studios;
|
|
if (!studios.length && parts[0].substring(0, 1) === 'a') {
|
|
variables.studio_filter.name.value = variables.studio_filter.OR.aliases.value = parts[0].substring(1, 3);
|
|
queryResult = gql.Do(query, variables);
|
|
studios = queryResult.findStudios.studios;
|
|
}
|
|
|
|
var matchingParts = 0;
|
|
for (var i = 0; i < studios.length; i++) {
|
|
var studio = studios[i];
|
|
matchingParts = matchNames(parts, studio.name, studio.aliases);
|
|
if (matchingParts === 0) {
|
|
continue;
|
|
}
|
|
|
|
result.studio_id = studio.id;
|
|
|
|
break;
|
|
}
|
|
|
|
return matchingParts;
|
|
}
|
|
|
|
function matchDate(parts, result) {
|
|
if (
|
|
parts.length < 3 ||
|
|
!/^(\d{2}|\d{4})$/.test(parts[0]) ||
|
|
!/^\d{2}$/.test(parts[1]) ||
|
|
!/^\d{2}$/.test(parts[2])
|
|
) {
|
|
return 0;
|
|
}
|
|
|
|
var year = parseInt(parts[0], 10);
|
|
var month = parseInt(parts[1], 10);
|
|
var day = parseInt(parts[2], 10);
|
|
|
|
if (year < 100) {
|
|
year += 2000;
|
|
}
|
|
|
|
if (
|
|
year < 2000 || year > 2100 ||
|
|
month < 1 || month > 12 ||
|
|
day < 1 || day > 31
|
|
) {
|
|
return 0;
|
|
}
|
|
|
|
result.date = year + "-" + (month < 10 ? "0" + month : month) + "-" + (day < 10 ? "0" + day : day);
|
|
|
|
return 3;
|
|
}
|
|
|
|
function matchPerformers(parts, result) {
|
|
var query = "\
|
|
query findPerformers($performer_filter: PerformerFilterType, $filter: FindFilterType!) {\
|
|
findPerformers(performer_filter: $performer_filter, filter: $filter) {\
|
|
performers {\
|
|
id\
|
|
name\
|
|
aliases\
|
|
}\
|
|
}\
|
|
}"
|
|
var variables = {
|
|
filter: {
|
|
per_page: -1
|
|
},
|
|
performer_filter: {
|
|
name: {
|
|
modifier: "INCLUDES"
|
|
},
|
|
OR: {
|
|
aliases: {
|
|
modifier: "INCLUDES"
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var totalMatchingParts = 0;
|
|
result.performer_ids = [];
|
|
do {
|
|
variables.performer_filter.name.value = variables.performer_filter.OR.aliases.value = parts[0].substring(0, 2);
|
|
|
|
var queryResult = gql.Do(query, variables);
|
|
var performers = queryResult.findPerformers.performers;
|
|
if (!performers.length) {
|
|
parts.shift();
|
|
continue;
|
|
}
|
|
|
|
var maxMatchLength = 0;
|
|
var matches = [];
|
|
for (var i = 0; i < performers.length; i++) {
|
|
var performer = performers[i];
|
|
var aliases = performer.aliases ? performer.aliases.split(/\s*[,;]+\s*/) : [];
|
|
var matchingParts = matchNames(parts, performer.name, aliases);
|
|
if (matchingParts === 0) {
|
|
continue;
|
|
}
|
|
|
|
if (matchingParts > maxMatchLength) {
|
|
maxMatchLength = matchingParts;
|
|
matches = [performer.id];
|
|
} else if (matchingParts === maxMatchLength) {
|
|
matches.push(performer.id);
|
|
}
|
|
}
|
|
|
|
if (maxMatchLength === 0) {
|
|
break;
|
|
}
|
|
|
|
result.performer_ids = result.performer_ids.concat(matches);
|
|
|
|
totalMatchingParts += maxMatchLength;
|
|
|
|
parts = parts.slice(maxMatchLength);
|
|
while (parts.length > 0 && (parts[0].toLowerCase() === 'and' || parts[0] === '&')) {
|
|
parts.shift();
|
|
totalMatchingParts += 1;
|
|
}
|
|
} while (parts.length > 0);
|
|
|
|
return totalMatchingParts;
|
|
}
|
|
|
|
function parseFilename(name) {
|
|
var parts = name.split(/[. \-_,]+/);
|
|
|
|
var matchers = [
|
|
matchStudio,
|
|
matchDate,
|
|
matchPerformers,
|
|
];
|
|
|
|
var result = {};
|
|
var hasMatched = false;
|
|
for (var matchTries = 0; matchTries < 3 && !hasMatched && parts.length; matchTries++) {
|
|
for (var i = 0; i < matchers.length && parts.length > 0; i++) {
|
|
var matchedParts = matchers[i](parts, result);
|
|
|
|
if (matchedParts > 0) {
|
|
hasMatched = true;
|
|
parts = parts.slice(matchedParts);
|
|
}
|
|
}
|
|
|
|
// If no matchers worked remove a part. Maybe the format is correct but studio isn't found? etc
|
|
if (!hasMatched) {
|
|
parts.shift();
|
|
}
|
|
}
|
|
|
|
if (hasMatched && parts.length > 0) {
|
|
var title = parts.join(' ');
|
|
// Look behind assertions are not supported, so can't use `replace(/(?<=.)([A-Z]/g, ' $1')` so instead have to do a loop. Otherwise for example 'FooABar' will become 'Foo ABar' instead of 'Foo A Bar'
|
|
while (/[^\s][A-Z]/.test(title)) {
|
|
title = title.replace(/([^\s])([A-Z])/g, '$1 $2');
|
|
}
|
|
result.title = title.trim();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
main();
|