Added fingerprint table and WIP StashDB import tool.
This commit is contained in:
parent
63f0410c5c
commit
c34905247c
|
|
@ -0,0 +1,66 @@
|
||||||
|
const config = require('config');
|
||||||
|
|
||||||
|
exports.up = async (knex) => {
|
||||||
|
await knex.schema.createTable('fingerprints_types', (table) => {
|
||||||
|
table.string('type')
|
||||||
|
.primary();
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex('fingerprints_types').insert([
|
||||||
|
'oshash',
|
||||||
|
'phash',
|
||||||
|
'md5',
|
||||||
|
'blake2',
|
||||||
|
].map((type) => ({ type })));
|
||||||
|
|
||||||
|
await knex.schema.createTable('releases_fingerprints', (table) => {
|
||||||
|
table.increments('id');
|
||||||
|
|
||||||
|
table.integer('scene_id')
|
||||||
|
.notNullable()
|
||||||
|
.references('id')
|
||||||
|
.inTable('releases');
|
||||||
|
|
||||||
|
table.string('hash')
|
||||||
|
.notNullable()
|
||||||
|
.index();
|
||||||
|
|
||||||
|
table.string('type')
|
||||||
|
.notNullable()
|
||||||
|
.references('type')
|
||||||
|
.inTable('fingerprints_types');
|
||||||
|
|
||||||
|
table.integer('duration');
|
||||||
|
table.integer('width');
|
||||||
|
table.integer('height');
|
||||||
|
|
||||||
|
table.integer('user_id')
|
||||||
|
.references('id')
|
||||||
|
.inTable('users');
|
||||||
|
|
||||||
|
table.string('source');
|
||||||
|
table.integer('source_submissions');
|
||||||
|
table.json('source_meta');
|
||||||
|
|
||||||
|
table.datetime('source_created_at');
|
||||||
|
|
||||||
|
table.datetime('created_at')
|
||||||
|
.notNullable()
|
||||||
|
.defaultTo(knex.fn.now());
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.raw(`
|
||||||
|
create unique index scenes_fingerprints_unique
|
||||||
|
on releases_fingerprints (scene_id, hash, source, user_id)
|
||||||
|
nulls not distinct
|
||||||
|
`);
|
||||||
|
|
||||||
|
await knex.raw('GRANT ALL ON ALL TABLES IN SCHEMA public TO :visitor;', {
|
||||||
|
visitor: knex.raw(config.database.query.user),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = async function(knex) {
|
||||||
|
await knex.schema.dropTable('releases_fingerprints');
|
||||||
|
await knex.schema.dropTable('fingerprints_types');
|
||||||
|
};
|
||||||
|
|
@ -44,6 +44,7 @@ async function fetchScenes() {
|
||||||
COALESCE(JSON_AGG(DISTINCT (tags.id, tags.name, tags.priority, tags_aliases.name)) FILTER (WHERE tags.id IS NOT NULL), '[]') as tags,
|
COALESCE(JSON_AGG(DISTINCT (tags.id, tags.name, tags.priority, tags_aliases.name)) FILTER (WHERE tags.id IS NOT NULL), '[]') as tags,
|
||||||
COALESCE(JSON_AGG(DISTINCT (movies.id, movies.title)) FILTER (WHERE movies.id IS NOT NULL), '[]') as movies,
|
COALESCE(JSON_AGG(DISTINCT (movies.id, movies.title)) FILTER (WHERE movies.id IS NOT NULL), '[]') as movies,
|
||||||
COALESCE(JSON_AGG(DISTINCT (series.id, series.title)) FILTER (WHERE series.id IS NOT NULL), '[]') as series,
|
COALESCE(JSON_AGG(DISTINCT (series.id, series.title)) FILTER (WHERE series.id IS NOT NULL), '[]') as series,
|
||||||
|
COALESCE(JSON_AGG(DISTINCT (releases_fingerprints.hash)) FILTER (WHERE releases_fingerprints.hash IS NOT NULL), '[]') as fingerprints,
|
||||||
studios.showcased IS NOT false
|
studios.showcased IS NOT false
|
||||||
AND (entities.showcased IS NOT false OR COALESCE(studios.showcased, false) = true)
|
AND (entities.showcased IS NOT false OR COALESCE(studios.showcased, false) = true)
|
||||||
AND (parents.showcased IS NOT false OR COALESCE(entities.showcased, false) = true OR COALESCE(studios.showcased, false) = true)
|
AND (parents.showcased IS NOT false OR COALESCE(entities.showcased, false) = true OR COALESCE(studios.showcased, false) = true)
|
||||||
|
|
@ -60,6 +61,7 @@ async function fetchScenes() {
|
||||||
LEFT JOIN releases_actors AS local_actors ON local_actors.release_id = releases.id
|
LEFT JOIN releases_actors AS local_actors ON local_actors.release_id = releases.id
|
||||||
LEFT JOIN releases_directors AS local_directors ON local_directors.release_id = releases.id
|
LEFT JOIN releases_directors AS local_directors ON local_directors.release_id = releases.id
|
||||||
LEFT JOIN releases_tags AS local_tags ON local_tags.release_id = releases.id
|
LEFT JOIN releases_tags AS local_tags ON local_tags.release_id = releases.id
|
||||||
|
LEFT JOIN releases_fingerprints ON releases_fingerprints.scene_id = releases.id
|
||||||
LEFT JOIN actors ON local_actors.actor_id = actors.id
|
LEFT JOIN actors ON local_actors.actor_id = actors.id
|
||||||
LEFT JOIN actors AS directors ON local_directors.director_id = directors.id
|
LEFT JOIN actors AS directors ON local_directors.director_id = directors.id
|
||||||
LEFT JOIN tags ON local_tags.tag_id = tags.id
|
LEFT JOIN tags ON local_tags.tag_id = tags.id
|
||||||
|
|
@ -126,6 +128,7 @@ async function init() {
|
||||||
series text,
|
series text,
|
||||||
meta text,
|
meta text,
|
||||||
date timestamp,
|
date timestamp,
|
||||||
|
fingerprints text,
|
||||||
is_showcased bool,
|
is_showcased bool,
|
||||||
created_at timestamp,
|
created_at timestamp,
|
||||||
effective_date timestamp,
|
effective_date timestamp,
|
||||||
|
|
@ -176,6 +179,7 @@ async function init() {
|
||||||
movies: scene.movies.map((movie) => movie.f2).join(' '),
|
movies: scene.movies.map((movie) => movie.f2).join(' '),
|
||||||
serie_ids: scene.series.map((serie) => serie.f1),
|
serie_ids: scene.series.map((serie) => serie.f1),
|
||||||
series: scene.series.map((serie) => serie.f2).join(' '),
|
series: scene.series.map((serie) => serie.f2).join(' '),
|
||||||
|
fingerprints: scene.fingerprints.join(' '),
|
||||||
meta: scene.date ? format(scene.date, 'y yy M MM MMM MMMM d dd') : undefined,
|
meta: scene.date ? format(scene.date, 'y yy M MM MMM MMMM d dd') : undefined,
|
||||||
stashed: scene.stashed || 0,
|
stashed: scene.stashed || 0,
|
||||||
dupe_index: scene.dupe_index || 0,
|
dupe_index: scene.dupe_index || 0,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const util = require('util');
|
||||||
|
const unprint = require('unprint');
|
||||||
|
const args = require('yargs').argv;
|
||||||
|
|
||||||
|
const knex = require('../knex');
|
||||||
|
const bulkInsert = require('../utils/bulk-insert');
|
||||||
|
|
||||||
|
const query = `query Scenes(
|
||||||
|
$page: Int! = 1
|
||||||
|
$limit: Int! = 10
|
||||||
|
$studioId: String!
|
||||||
|
) {
|
||||||
|
queryScenes(
|
||||||
|
input: {
|
||||||
|
page: $page
|
||||||
|
per_page: $limit
|
||||||
|
sort: DATE
|
||||||
|
direction: DESC
|
||||||
|
parentStudio: $studioId
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
count
|
||||||
|
scenes {
|
||||||
|
id
|
||||||
|
code
|
||||||
|
release_date
|
||||||
|
title
|
||||||
|
duration
|
||||||
|
fingerprints {
|
||||||
|
hash
|
||||||
|
algorithm
|
||||||
|
created
|
||||||
|
updated
|
||||||
|
duration
|
||||||
|
submissions
|
||||||
|
reports
|
||||||
|
}
|
||||||
|
urls {
|
||||||
|
url
|
||||||
|
site {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
studio {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
|
||||||
|
async function curateData(data) {
|
||||||
|
const stashScenes = data.queryScenes.scenes.map((stashScene) => {
|
||||||
|
const release = {};
|
||||||
|
|
||||||
|
release.id = stashScene.id;
|
||||||
|
release.title = stashScene.title;
|
||||||
|
release.url = stashScene.urls.find((url) => url.site.name?.toLowerCase() === 'studio')?.url;
|
||||||
|
release.date = stashScene.release_date;
|
||||||
|
release.duration = stashScene.duration;
|
||||||
|
|
||||||
|
release.entryId = stashScene.code;
|
||||||
|
|
||||||
|
// FOR XEMPIRE
|
||||||
|
release.urlId = new URL(release.url).pathname.match(/\/(\d+)$/)?.[1] || null;
|
||||||
|
|
||||||
|
release.fingerprints = stashScene.fingerprints.map((fingerprint) => ({
|
||||||
|
hash: fingerprint.hash,
|
||||||
|
algorithm: fingerprint.algorithm,
|
||||||
|
duration: fingerprint.duration,
|
||||||
|
submissions: fingerprint.submissions,
|
||||||
|
createdAt: fingerprint.created,
|
||||||
|
updatedAt: fingerprint.updated,
|
||||||
|
reports: fingerprint.reports,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return release;
|
||||||
|
});
|
||||||
|
|
||||||
|
const stashScenesByIdentifiers = Object.fromEntries(stashScenes.flatMap((scene) => [[scene.entryId || scene.urlId, scene], [scene.url, scene]]));
|
||||||
|
|
||||||
|
const sceneEntries = await knex('releases')
|
||||||
|
.select('releases.*')
|
||||||
|
.leftJoin('entities', 'entities.id', 'releases.entity_id')
|
||||||
|
.leftJoin('entities as parents', 'parents.id', 'entities.parent_id')
|
||||||
|
.where('entities.slug', 'hardx')
|
||||||
|
.whereIn('entry_id', stashScenes.map((scene) => scene.entryId || scene.urlId));
|
||||||
|
|
||||||
|
const fpEntries = sceneEntries.flatMap((scene) => {
|
||||||
|
const stashScene = stashScenesByIdentifiers[scene.entry_id]
|
||||||
|
|| stashScenesByIdentifiers[scene.url];
|
||||||
|
|
||||||
|
return stashScene.fingerprints.map((fingerprint) => ({
|
||||||
|
scene_id: scene.id,
|
||||||
|
hash: fingerprint.hash,
|
||||||
|
type: fingerprint.algorithm.toLowerCase(),
|
||||||
|
duration: fingerprint.duration,
|
||||||
|
source: 'stashdb',
|
||||||
|
source_created_at: fingerprint.createdAt,
|
||||||
|
source_submissions: fingerprint.submissions,
|
||||||
|
source_meta: {
|
||||||
|
reports: fingerprint.reports,
|
||||||
|
sceneId: stashScene.id,
|
||||||
|
entryId: stashScene.entryId,
|
||||||
|
title: stashScene.title,
|
||||||
|
url: stashScene.url,
|
||||||
|
date: stashScene.date,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(util.inspect(fpEntries, { colors: true, depth: null, maxArrayLength: null }));
|
||||||
|
|
||||||
|
if (args.update) {
|
||||||
|
await bulkInsert('releases_fingerprints', fpEntries, false);
|
||||||
|
|
||||||
|
console.log(`Inserted ${fpEntries.length} hash entries`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
const res = await unprint.post('https://stashdb.org/graphql', {
|
||||||
|
operationName: 'Scenes',
|
||||||
|
query,
|
||||||
|
variables: {
|
||||||
|
limit: 1000,
|
||||||
|
studioId: '8c7ad24a-4756-4163-b328-28e8391602cd',
|
||||||
|
page: 1,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
ApiKey: process.env.STASHDB_API_KEY,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
await curateData(res.data.data);
|
||||||
|
await knex.destroy();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error('FAILED', res.status, res.data);
|
||||||
|
console.log(res.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
Loading…
Reference in New Issue