diff --git a/src/actors.js b/src/actors.js index 129c25af..2d1f47ae 100644 --- a/src/actors.js +++ b/src/actors.js @@ -23,6 +23,7 @@ const logger = require('./logger')(__filename); const { toBaseReleases } = require('./deep'); const { associateAvatars, flushOrphanedMedia } = require('./media'); +const { deleteScenes } = require('./releases'); const slugify = require('./utils/slugify'); const capitalize = require('./utils/capitalize'); @@ -719,30 +720,6 @@ async function storeProfiles(profiles) { await interpolateProfiles(actorIds); } -async function flushProfiles(actorIdsOrNames) { - const profiles = await fetchProfiles(actorIdsOrNames); - const actorNames = Array.from(new Set(profiles.map(profile => profile.actor.name))); - - const deleteCount = await knex('actors_profiles') - .whereIn('id', profiles.map(profile => profile.id)) - .delete(); - - await interpolateProfiles(actorIdsOrNames); - await flushOrphanedMedia(); // don't flush until main avatar is detached by re-interpolating - - if (actorNames.length > 20) { - logger.info(`Removed ${deleteCount} profiles for ${actorNames.length} actors`); - return; - } - - if (deleteCount > 0) { - logger.info(`Removed ${deleteCount} profiles for ${actorNames.join(', ')}`); - return; - } - - logger.info(`Removed ${deleteCount} profiles`); -} - async function scrapeActors(argNames) { const actorNames = await getActorNames(argNames); const baseActors = toBaseActors(actorNames); @@ -956,9 +933,59 @@ async function searchActors(query) { return actors.map(actor => curateActor(actor)); } +async function flushProfiles(actorIdsOrNames) { + const profiles = await fetchProfiles(actorIdsOrNames); + const actorNames = Array.from(new Set(profiles.map(profile => profile.actor.name))); + + const deleteCount = await knex('actors_profiles') + .whereIn('id', profiles.map(profile => profile.id)) + .delete(); + + await interpolateProfiles(actorIdsOrNames); + await flushOrphanedMedia(); // don't flush until main avatar is detached by re-interpolating + + if (actorNames.length > 20) { + logger.info(`Removed ${deleteCount} profiles for ${actorNames.length} actors`); + return; + } + + if (deleteCount > 0) { + logger.info(`Removed ${deleteCount} profiles for ${actorNames.join(', ')}`); + return; + } + + logger.info(`Removed ${deleteCount} profiles`); +} + +async function flushActors(actorIdsOrNames) { + const actors = await knex('actors') + .whereIn('id', actorIdsOrNames.filter(idOrName => typeof idOrName === 'number')) + .orWhereIn('name', actorIdsOrNames.filter(idOrName => typeof idOrName === 'string')); + + const actorIds = actors.map(actor => actor.id); + + const sceneIds = await knex('releases_actors') + .select('releases.id') + .whereIn('actor_id', actorIds) + .leftJoin('releases', 'releases.id', 'releases_actors.release_id') + .pluck('id'); + + const [deletedScenesCount, deletedActorsCount] = await Promise.all([ + deleteScenes(sceneIds), + knex('actors') + .whereIn('id', actorIds) + .delete(), + ]); + + await flushOrphanedMedia(); + + logger.info(`Removed ${deletedActorsCount} actors with ${deletedScenesCount} scenes`); +} + module.exports = { associateActors, fetchActor, + flushActors, flushProfiles, interpolateProfiles, scrapeActors, diff --git a/src/app.js b/src/app.js index 83590ec3..60571257 100644 --- a/src/app.js +++ b/src/app.js @@ -9,7 +9,7 @@ const knex = require('./knex'); const fetchUpdates = require('./updates'); const { fetchScenes, fetchMovies } = require('./deep'); const { storeScenes, storeMovies, updateReleasesSearch } = require('./store-releases'); -const { scrapeActors, flushProfiles, interpolateProfiles } = require('./actors'); +const { scrapeActors, flushActors, flushProfiles, interpolateProfiles } = require('./actors'); const { flushEntities } = require('./entities'); const { deleteScenes, deleteMovies, flushBatches } = require('./releases'); const { flushOrphanedMedia } = require('./media'); @@ -29,6 +29,10 @@ async function init() { await interpolateProfiles(argv.flushProfiles.length > 0 ? argv.flushProfiles : null); } + if (argv.flushActors) { + await flushActors(argv.flushActors); + } + if (argv.flushProfiles) { await flushProfiles(argv.flushProfiles.length > 0 ? argv.flushProfiles : null); } diff --git a/src/argv.js b/src/argv.js index d7c99920..4ba2ca0c 100644 --- a/src/argv.js +++ b/src/argv.js @@ -268,10 +268,15 @@ const { argv } = yargs type: 'array', alias: 'flush-network', }) + .option('flush-actors', { + describe: 'Delete actors with profiles and scenes.', + type: 'array', + alias: 'flush-actor', + }) .option('flush-profiles', { describe: 'Delete all profiles for an actor.', type: 'array', - alias: ['flush-profile', 'flush-actors', 'flush-actor'], + alias: 'flush-profile', }) .option('flush-batches', { describe: 'Delete all scenes and movies from batch by ID.', diff --git a/src/store-releases.js b/src/store-releases.js index f51a3f35..f46faf98 100644 --- a/src/store-releases.js +++ b/src/store-releases.js @@ -168,6 +168,12 @@ function filterInternalDuplicateReleases(releases) { return acc; } + if (!release.entryId) { + logger.warn(`No entry ID supplied for "${release.title}" from '${release.entity.name}'`); + + return acc; + } + if (!acc[release.entity.id]) { acc[release.entity.id] = {}; }