mirror of
https://github.com/stashapp/CommunityScripts.git
synced 2026-02-04 01:52:30 -06:00
* added .prettierrc.json * modified: .gitignore * yarn run format * fix check format workflow
428 lines
8.9 KiB
JavaScript
428 lines
8.9 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) {\
|
|
files {\
|
|
path\
|
|
}\
|
|
}\
|
|
}";
|
|
|
|
var variables = {
|
|
id: sceneID,
|
|
};
|
|
|
|
var result = gql.Do(query, variables);
|
|
var findScene = result.findScene;
|
|
if (!findScene) {
|
|
return null;
|
|
}
|
|
|
|
var path = findScene.files[0].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) {\
|
|
files {\
|
|
path\
|
|
}\
|
|
}\
|
|
}";
|
|
|
|
var variables = {
|
|
id: galleryID,
|
|
};
|
|
|
|
var result = gql.Do(query, variables);
|
|
var findGallery = result.findGallery;
|
|
if (!findGallery) {
|
|
return null;
|
|
}
|
|
|
|
var path = findGallery.files[0].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",
|
|
"mkv",
|
|
"zip",
|
|
"cbz",
|
|
"cbr",
|
|
"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\
|
|
alias_list\
|
|
}\
|
|
}\
|
|
}";
|
|
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();
|