Compare commits
No commits in common. "3fc63b1934315008a3e076c4a0e3337ee3d910d4" and "62617ec6bfd8f714480e6acef51785bef3fc7e58" have entirely different histories.
3fc63b1934
...
62617ec6bf
|
@ -62,11 +62,6 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Releases
|
|
||||||
v-if="release.scenes && release.scenes.length > 0"
|
|
||||||
:releases="release.scenes"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="row associations">
|
<div class="row associations">
|
||||||
<ul
|
<ul
|
||||||
ref="actors"
|
ref="actors"
|
||||||
|
@ -114,6 +109,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Releases
|
||||||
|
v-if="release.scenes && release.scenes.length > 0"
|
||||||
|
:releases="release.scenes"
|
||||||
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="release.directors && release.directors.length > 0"
|
v-if="release.directors && release.directors.length > 0"
|
||||||
class="row"
|
class="row"
|
||||||
|
|
|
@ -337,7 +337,6 @@ module.exports = {
|
||||||
},
|
},
|
||||||
media: {
|
media: {
|
||||||
path: './media',
|
path: './media',
|
||||||
transferSource: 'http://localhost:5000/media',
|
|
||||||
maxSize: 1000,
|
maxSize: 1000,
|
||||||
quality: 80,
|
quality: 80,
|
||||||
thumbnailSize: 320, // width for 16:9 will be exactly 576px
|
thumbnailSize: 320, // width for 16:9 will be exactly 576px
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.226.1",
|
"version": "1.226.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.226.1",
|
"version": "1.226.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@casl/ability": "^5.2.2",
|
"@casl/ability": "^5.2.2",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.226.1",
|
"version": "1.226.0",
|
||||||
"description": "All the latest porn releases in one place",
|
"description": "All the latest porn releases in one place",
|
||||||
"main": "src/app.js",
|
"main": "src/app.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
13
src/argv.js
13
src/argv.js
|
@ -272,15 +272,9 @@ const { argv } = yargs
|
||||||
})
|
})
|
||||||
.option('flush-orphaned-media', {
|
.option('flush-orphaned-media', {
|
||||||
describe: 'Remove all orphaned media items from database and disk.',
|
describe: 'Remove all orphaned media items from database and disk.',
|
||||||
type: 'boolean',
|
type: 'array',
|
||||||
alias: 'flush-media',
|
alias: 'flush-media',
|
||||||
})
|
})
|
||||||
.option('flush-media-files', {
|
|
||||||
describe: 'Remove files from storage when flushing media.',
|
|
||||||
type: 'boolean',
|
|
||||||
alias: 'flush-files',
|
|
||||||
default: true,
|
|
||||||
})
|
|
||||||
.option('flush-channels', {
|
.option('flush-channels', {
|
||||||
describe: 'Delete all scenes and movies from channels.',
|
describe: 'Delete all scenes and movies from channels.',
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
@ -345,11 +339,6 @@ const { argv } = yargs
|
||||||
alias: ['timeout'],
|
alias: ['timeout'],
|
||||||
default: 60000,
|
default: 60000,
|
||||||
})
|
})
|
||||||
.option('media-source', {
|
|
||||||
describe: 'Traxxx host to use for media transfers.',
|
|
||||||
type: 'string',
|
|
||||||
default: config.media.transferSource,
|
|
||||||
})
|
|
||||||
.coerce('after', interpretAfter)
|
.coerce('after', interpretAfter)
|
||||||
.coerce('actors-update', (after) => interpretAfter(after, true));
|
.coerce('actors-update', (after) => interpretAfter(after, true));
|
||||||
|
|
||||||
|
|
|
@ -393,9 +393,7 @@ async function flushEntities(networkSlugs = [], channelSlugs = []) {
|
||||||
|
|
||||||
logger.info(`Removed ${deletedScenesCount} scenes, ${deletedMoviesCount} movies and ${deletedSeriesCount} series for ${entitySlugs}`);
|
logger.info(`Removed ${deletedScenesCount} scenes, ${deletedMoviesCount} movies and ${deletedSeriesCount} series for ${entitySlugs}`);
|
||||||
|
|
||||||
if (argv.flushOrphanedMedia !== false) {
|
|
||||||
await flushOrphanedMedia();
|
await flushOrphanedMedia();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -997,22 +997,18 @@ async function flushOrphanedMedia() {
|
||||||
.returning(['media.id', 'media.is_s3', 'media.path', 'media.thumbnail', 'media.lazy'])
|
.returning(['media.id', 'media.is_s3', 'media.path', 'media.thumbnail', 'media.lazy'])
|
||||||
.delete();
|
.delete();
|
||||||
|
|
||||||
if (argv.flushMediaFiles) {
|
|
||||||
await Promise.all(orphanedMedia.filter((media) => !media.is_s3).map((media) => Promise.all([
|
await Promise.all(orphanedMedia.filter((media) => !media.is_s3).map((media) => Promise.all([
|
||||||
media.path && fsPromises.unlink(path.join(config.media.path, media.path)).catch(() => { /* probably file not found */ }),
|
media.path && fsPromises.unlink(path.join(config.media.path, media.path)).catch(() => { /* probably file not found */ }),
|
||||||
media.thumbnail && fsPromises.unlink(path.join(config.media.path, media.thumbnail)).catch(() => { /* probably file not found */ }),
|
media.thumbnail && fsPromises.unlink(path.join(config.media.path, media.thumbnail)).catch(() => { /* probably file not found */ }),
|
||||||
media.lazy && fsPromises.unlink(path.join(config.media.path, media.lazy)).catch(() => { /* probably file not found */ }),
|
media.lazy && fsPromises.unlink(path.join(config.media.path, media.lazy)).catch(() => { /* probably file not found */ }),
|
||||||
])));
|
])));
|
||||||
|
|
||||||
|
logger.info(`Removed ${orphanedMedia.length} media files from database and storage`);
|
||||||
|
|
||||||
if (config.s3.enabled) {
|
if (config.s3.enabled) {
|
||||||
await deleteS3Objects(orphanedMedia.filter((media) => media.is_s3));
|
await deleteS3Objects(orphanedMedia.filter((media) => media.is_s3));
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`Removed ${orphanedMedia.length} media files from database and storage`);
|
|
||||||
} else {
|
|
||||||
logger.info(`Removed ${orphanedMedia.length} media files from database, but not from storage`);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fsPromises.rm(path.join(config.media.path, 'temp'), { recursive: true });
|
await fsPromises.rm(path.join(config.media.path, 'temp'), { recursive: true });
|
||||||
logger.info('Cleared temporary media directory');
|
logger.info('Cleared temporary media directory');
|
||||||
|
|
|
@ -4,7 +4,6 @@ const inquirer = require('inquirer');
|
||||||
|
|
||||||
const logger = require('./logger')(__filename);
|
const logger = require('./logger')(__filename);
|
||||||
const knex = require('./knex');
|
const knex = require('./knex');
|
||||||
const argv = require('./argv');
|
|
||||||
const { flushOrphanedMedia } = require('./media');
|
const { flushOrphanedMedia } = require('./media');
|
||||||
|
|
||||||
const { graphql } = require('./web/graphql');
|
const { graphql } = require('./web/graphql');
|
||||||
|
@ -360,9 +359,7 @@ async function flushScenes() {
|
||||||
}
|
}
|
||||||
const deleteCount = await deleteScenes(sceneIds);
|
const deleteCount = await deleteScenes(sceneIds);
|
||||||
|
|
||||||
if (argv.flushOrphanedMedia !== false) {
|
|
||||||
await flushOrphanedMedia();
|
await flushOrphanedMedia();
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(`Removed ${deleteCount}/${sceneIds.length} scenes`);
|
logger.info(`Removed ${deleteCount}/${sceneIds.length} scenes`);
|
||||||
}
|
}
|
||||||
|
@ -383,9 +380,7 @@ async function flushMovies() {
|
||||||
}
|
}
|
||||||
const deleteCount = await deleteMovies(movieIds);
|
const deleteCount = await deleteMovies(movieIds);
|
||||||
|
|
||||||
if (argv.flushOrphanedMedia !== false) {
|
|
||||||
await flushOrphanedMedia();
|
await flushOrphanedMedia();
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(`Removed ${deleteCount}/${movieIds.length} movies`);
|
logger.info(`Removed ${deleteCount}/${movieIds.length} movies`);
|
||||||
}
|
}
|
||||||
|
@ -406,9 +401,7 @@ async function flushSeries() {
|
||||||
}
|
}
|
||||||
const deleteCount = await deleteSeries(serieIds);
|
const deleteCount = await deleteSeries(serieIds);
|
||||||
|
|
||||||
if (argv.flushOrphanedMedia !== false) {
|
|
||||||
await flushOrphanedMedia();
|
await flushOrphanedMedia();
|
||||||
}
|
|
||||||
|
|
||||||
logger.info(`Removed ${deleteCount}/${serieIds.length} series`);
|
logger.info(`Removed ${deleteCount}/${serieIds.length} series`);
|
||||||
}
|
}
|
||||||
|
@ -444,9 +437,7 @@ async function flushBatches(batchIds) {
|
||||||
|
|
||||||
logger.info(`Removed ${deletedScenesCount} scenes and ${deletedMoviesCount} movies for batches ${batchIds}`);
|
logger.info(`Removed ${deletedScenesCount} scenes and ${deletedMoviesCount} movies for batches ${batchIds}`);
|
||||||
|
|
||||||
if (argv.flushOrphanedMedia !== false) {
|
|
||||||
await flushOrphanedMedia();
|
await flushOrphanedMedia();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const config = require('config');
|
const config = require('config');
|
||||||
const fs = require('fs');
|
const fs = require('fs').promises;
|
||||||
const path = require('path');
|
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const Promise = require('bluebird');
|
const Promise = require('bluebird');
|
||||||
const bhttp = require('bhttp');
|
|
||||||
const { nanoid } = require('nanoid/non-secure');
|
const { nanoid } = require('nanoid/non-secure');
|
||||||
const AWS = require('aws-sdk');
|
const AWS = require('aws-sdk');
|
||||||
|
|
||||||
|
@ -24,9 +22,11 @@ const s3 = new AWS.S3({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(Object.keys(s3));
|
||||||
|
|
||||||
// NOT TRANSFERRED, unutilized on old server: production location, availabile qualities, actor alias for, actor entry id, chapter posters, chapter photos
|
// NOT TRANSFERRED, unutilized on old server: production location, availabile qualities, actor alias for, actor entry id, chapter posters, chapter photos
|
||||||
|
|
||||||
const sceneFields = `
|
const releaseFields = `
|
||||||
entryId
|
entryId
|
||||||
shootId
|
shootId
|
||||||
title
|
title
|
||||||
|
@ -43,16 +43,6 @@ const sceneFields = `
|
||||||
studio {
|
studio {
|
||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
movies: moviesScenesBySceneId {
|
|
||||||
movie {
|
|
||||||
title
|
|
||||||
entryId
|
|
||||||
entity {
|
|
||||||
slug
|
|
||||||
type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actors: releasesActors {
|
actors: releasesActors {
|
||||||
actor {
|
actor {
|
||||||
name
|
name
|
||||||
|
@ -66,7 +56,6 @@ const sceneFields = `
|
||||||
}
|
}
|
||||||
directors: releasesDirectors {
|
directors: releasesDirectors {
|
||||||
director {
|
director {
|
||||||
name
|
|
||||||
slug
|
slug
|
||||||
entryId
|
entryId
|
||||||
entity {
|
entity {
|
||||||
|
@ -175,57 +164,12 @@ const sceneFields = `
|
||||||
createdAt
|
createdAt
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const movieFields = `
|
|
||||||
entryId
|
|
||||||
title
|
|
||||||
url
|
|
||||||
date
|
|
||||||
datePrecision
|
|
||||||
entity {
|
|
||||||
slug
|
|
||||||
type
|
|
||||||
}
|
|
||||||
poster: moviesPoster {
|
|
||||||
media {
|
|
||||||
hash
|
|
||||||
path
|
|
||||||
thumbnail
|
|
||||||
lazy
|
|
||||||
s3: isS3
|
|
||||||
mime
|
|
||||||
index
|
|
||||||
width
|
|
||||||
height
|
|
||||||
size
|
|
||||||
source
|
|
||||||
sourcePage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
covers: moviesCovers {
|
|
||||||
media {
|
|
||||||
hash
|
|
||||||
path
|
|
||||||
thumbnail
|
|
||||||
lazy
|
|
||||||
s3: isS3
|
|
||||||
mime
|
|
||||||
index
|
|
||||||
width
|
|
||||||
height
|
|
||||||
size
|
|
||||||
source
|
|
||||||
sourcePage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createdAt
|
|
||||||
`;
|
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
const limit = args.limit || 1000;
|
const limit = args.limit || 1000;
|
||||||
const offset = args.offset || 0;
|
const offset = args.offset || 0;
|
||||||
|
|
||||||
const { releases } = await graphql(`
|
const { releases } = await graphql(`
|
||||||
query SearchScenes(
|
query SearchReleases(
|
||||||
$limit: Int = 20
|
$limit: Int = 20
|
||||||
$offset: Int = 0
|
$offset: Int = 0
|
||||||
) {
|
) {
|
||||||
|
@ -234,40 +178,20 @@ async function save() {
|
||||||
offset: $offset
|
offset: $offset
|
||||||
orderBy: DATE_DESC
|
orderBy: DATE_DESC
|
||||||
) {
|
) {
|
||||||
${sceneFields}
|
${releaseFields}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`, {
|
`, {
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
}, 'owner');
|
});
|
||||||
|
|
||||||
const { movies } = await graphql(`
|
const curatedReleases = releases.map((release) => ({
|
||||||
query SearchScenes(
|
|
||||||
$limit: Int = 20
|
|
||||||
$offset: Int = 0
|
|
||||||
) {
|
|
||||||
movies(
|
|
||||||
first: $limit
|
|
||||||
offset: $offset
|
|
||||||
orderBy: DATE_DESC
|
|
||||||
) {
|
|
||||||
${movieFields}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, {
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
}, 'owner');
|
|
||||||
|
|
||||||
const curatedScenes = releases.map((release) => ({
|
|
||||||
...release,
|
...release,
|
||||||
type: 'release',
|
|
||||||
actors: release.actors.filter(Boolean).map(({ actor }) => actor),
|
actors: release.actors.filter(Boolean).map(({ actor }) => actor),
|
||||||
directors: release.directors.filter(Boolean).map(({ director }) => director),
|
directors: release.directors.filter(Boolean).map(({ director }) => director),
|
||||||
studio: release.studio?.slug,
|
studio: release.studio?.slug,
|
||||||
tags: release.tags.map(({ tag }) => tag?.slug).filter(Boolean),
|
tags: release.tags.map(({ tag }) => tag?.slug).filter(Boolean),
|
||||||
movies: release.movies?.map(({ movie }) => movie) || [],
|
|
||||||
chapters: release.chapters.filter(Boolean).map((chapter) => ({
|
chapters: release.chapters.filter(Boolean).map((chapter) => ({
|
||||||
...chapter,
|
...chapter,
|
||||||
tags: chapter.tags.map(({ tag }) => tag?.slug).filter(Boolean),
|
tags: chapter.tags.map(({ tag }) => tag?.slug).filter(Boolean),
|
||||||
|
@ -279,17 +203,10 @@ async function save() {
|
||||||
covers: release.covers.filter(Boolean).map(({ media }) => media),
|
covers: release.covers.filter(Boolean).map(({ media }) => media),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const curatedMovies = movies.map((movie) => ({
|
|
||||||
...movie,
|
|
||||||
type: 'movie',
|
|
||||||
poster: movie.poster?.media,
|
|
||||||
covers: movie.covers.filter(Boolean).map(({ media }) => media),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const filename = `export-${offset}-${offset + limit}-${moment().format('YYYY-MM-DD_hh_mm_ss')}.json`;
|
const filename = `export-${offset}-${offset + limit}-${moment().format('YYYY-MM-DD_hh_mm_ss')}.json`;
|
||||||
const serializedData = JSON.stringify([...curatedScenes, ...curatedMovies], null, 4);
|
const serializedData = JSON.stringify(curatedReleases, null, 4);
|
||||||
|
|
||||||
await fs.promises.writeFile(filename, serializedData);
|
await fs.writeFile(filename, serializedData);
|
||||||
|
|
||||||
console.log(`Saved ${releases.length} releases to ${filename}`);
|
console.log(`Saved ${releases.length} releases to ${filename}`);
|
||||||
|
|
||||||
|
@ -383,73 +300,18 @@ async function addReleaseChapters(release, context) {
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
const dirs = {
|
|
||||||
path: '',
|
|
||||||
thumbnail: 'thumbs',
|
|
||||||
lazy: 'lazy',
|
|
||||||
};
|
|
||||||
|
|
||||||
async function transferMedia(media, target) {
|
|
||||||
return ['path', 'thumbnail', 'lazy'].reduce(async (chain, type) => {
|
|
||||||
await chain;
|
|
||||||
|
|
||||||
const filename = `${media.hash}${path.extname(media[type])}`;
|
|
||||||
const filepath = path.join(target, dirs[type], filename);
|
|
||||||
const temp = path.join('media/temp', filepath);
|
|
||||||
const url = new URL(media[type], `${args.mediaSource}/`).href;
|
|
||||||
|
|
||||||
console.log('Transferring media', url);
|
|
||||||
|
|
||||||
const res = await bhttp.get(url, { stream: true });
|
|
||||||
|
|
||||||
if (res.statusCode !== 200) {
|
|
||||||
console.warn(`Missing ${target} ${url}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await fs.promises.mkdir(path.dirname(temp), { recursive: true });
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
const fileStream = fs.createWriteStream(temp);
|
|
||||||
|
|
||||||
res.pipe(fileStream);
|
|
||||||
|
|
||||||
res.on('error', () => { reject(); });
|
|
||||||
|
|
||||||
fileStream.on('finish', () => { resolve(); });
|
|
||||||
fileStream.on('error', () => { reject(); });
|
|
||||||
});
|
|
||||||
|
|
||||||
if (args.s3) {
|
|
||||||
await s3.upload({
|
|
||||||
Bucket: config.s3.bucket,
|
|
||||||
Body: fs.createReadStream(temp),
|
|
||||||
Key: filepath,
|
|
||||||
ContentType: media.mime,
|
|
||||||
}).promise();
|
|
||||||
|
|
||||||
await fs.promises.unlink(temp);
|
|
||||||
}
|
|
||||||
}, Promise.resolve());
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addReleaseMedia(medias, release, target) {
|
async function addReleaseMedia(medias, release, target) {
|
||||||
return Promise.all(medias.filter(Boolean).map(async (media) => {
|
return Promise.all(medias.filter(Boolean).map(async (media) => {
|
||||||
const existingMedia = await knex('media')
|
try {
|
||||||
.where('hash', media.hash)
|
const id = nanoid();
|
||||||
.first();
|
|
||||||
|
|
||||||
const id = existingMedia?.id || nanoid();
|
|
||||||
|
|
||||||
if (!existingMedia) {
|
|
||||||
await knex('media').insert({
|
await knex('media').insert({
|
||||||
id,
|
id,
|
||||||
hash: media.hash,
|
hash: media.hash,
|
||||||
path: path.join(target, '', `${media.hash}${path.extname(media.path)}`),
|
path: media.path,
|
||||||
thumbnail: path.join(target, 'thumbs', `${media.hash}${path.extname(media.thumbnail)}`),
|
thumbnail: media.thumbnail,
|
||||||
lazy: path.join(target, 'lazy', `${media.hash}${path.extname(media.lazy)}`),
|
lazy: media.lazy,
|
||||||
// is_s3: media.s3,
|
is_s3: media.s3,
|
||||||
is_s3: true,
|
|
||||||
index: media.index,
|
index: media.index,
|
||||||
mime: media.mime,
|
mime: media.mime,
|
||||||
size: media.size,
|
size: media.size,
|
||||||
|
@ -459,42 +321,19 @@ async function addReleaseMedia(medias, release, target) {
|
||||||
source_page: media.sourcePage,
|
source_page: media.sourcePage,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (args.mediaSource) {
|
await knex(`releases_${target}`).insert({
|
||||||
await transferMedia(media, target);
|
release_id: release.id,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await knex(`${release.type}s_${target}`).insert({
|
|
||||||
[`${release.type}_id`]: release.id,
|
|
||||||
media_id: id,
|
media_id: id,
|
||||||
});
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Skipped existing media ${media.hash} from ${media.url}: ${error.message}`);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function linkMovieScenes(release, context) {
|
|
||||||
await release.movies.reduce(async (chain, linkedMovie) => {
|
|
||||||
await chain;
|
|
||||||
|
|
||||||
const movie = context.movies.find((storedMovie) => storedMovie.entryId === linkedMovie.entryId
|
|
||||||
&& storedMovie.entity.slug === linkedMovie.entity.slug
|
|
||||||
&& storedMovie.entity.type === linkedMovie.entity.type);
|
|
||||||
|
|
||||||
console.log('movie', linkedMovie, movie);
|
|
||||||
|
|
||||||
if (!movie) {
|
|
||||||
throw new Error(`Missing ${linkedMovie.entity.slug} movie '${linkedMovie.title}' in '${release.title}'`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await knex('movies_scenes').insert({
|
|
||||||
movie_id: movie.id,
|
|
||||||
scene_id: release.id,
|
|
||||||
});
|
|
||||||
}, Promise.resolve());
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addRelease(release, context) {
|
async function addRelease(release, context) {
|
||||||
const existingRelease = await knex(`${release.type}s`)
|
const existingRelease = await knex('releases')
|
||||||
.leftJoin('entities', 'entities.id', `${release.type}s.entity_id`)
|
.leftJoin('entities', 'entities.id', 'releases.entity_id')
|
||||||
.where('entry_id', release.entryId)
|
.where('entry_id', release.entryId)
|
||||||
.where('entities.slug', release.entity.slug)
|
.where('entities.slug', release.entity.slug)
|
||||||
.where('entities.type', release.entity.type)
|
.where('entities.type', release.entity.type)
|
||||||
|
@ -512,58 +351,47 @@ async function addRelease(release, context) {
|
||||||
throw new Error(`Release contains non-existent ${release.entity.type} '${release.entity.slug}'`);
|
throw new Error(`Release contains non-existent ${release.entity.type} '${release.entity.slug}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [releaseEntry] = await knex(`${release.type}s`)
|
const [releaseId] = await knex('releases')
|
||||||
.insert({
|
.insert({
|
||||||
entry_id: release.entryId,
|
entry_id: release.entryId,
|
||||||
entity_id: entity.id,
|
entity_id: entity.id,
|
||||||
|
studio_id: context.studioIdsBySlug[release.studio],
|
||||||
|
shoot_id: release.shootId,
|
||||||
url: release.url,
|
url: release.url,
|
||||||
title: release.title,
|
title: release.title,
|
||||||
slug: release.slug,
|
slug: release.slug,
|
||||||
date: release.date,
|
date: release.date,
|
||||||
date_precision: release.datePrecision,
|
date_precision: release.datePrecision,
|
||||||
created_batch_id: context.batchId,
|
|
||||||
updated_batch_id: context.batchId,
|
|
||||||
...(release.type === 'scene' && {
|
|
||||||
shoot_id: release.shootId,
|
|
||||||
studio_id: context.studioIdsBySlug[release.studio],
|
|
||||||
production_date: release.productionDate,
|
production_date: release.productionDate,
|
||||||
description: release.description,
|
description: release.description,
|
||||||
duration: release.duration,
|
duration: release.duration,
|
||||||
}),
|
created_batch_id: context.batchId,
|
||||||
|
updated_batch_id: context.batchId,
|
||||||
})
|
})
|
||||||
.returning(['id', 'entry_id']);
|
.returning('id');
|
||||||
|
|
||||||
const releaseWithId = {
|
const releaseWithId = { ...release, id: releaseId };
|
||||||
...release,
|
|
||||||
id: releaseEntry.id,
|
|
||||||
entityId: entity.id,
|
|
||||||
};
|
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
addReleaseMedia([releaseWithId.poster], releaseWithId, 'posters', context),
|
|
||||||
...(release.type === 'release' ? [
|
|
||||||
addReleaseTags(releaseWithId, context),
|
addReleaseTags(releaseWithId, context),
|
||||||
addReleaseActors(releaseWithId, context),
|
addReleaseActors(releaseWithId, context),
|
||||||
addReleaseDirectors(releaseWithId, context),
|
addReleaseDirectors(releaseWithId, context),
|
||||||
addReleaseChapters(releaseWithId, context),
|
addReleaseChapters(releaseWithId, context),
|
||||||
|
addReleaseMedia([releaseWithId.poster], releaseWithId, 'posters', context),
|
||||||
addReleaseMedia(releaseWithId.photos, releaseWithId, 'photos', context),
|
addReleaseMedia(releaseWithId.photos, releaseWithId, 'photos', context),
|
||||||
linkMovieScenes(releaseWithId, context),
|
// addReleaseMedia(releaseWithId.covers, releaseWithId, 'covers', context),
|
||||||
] : []),
|
|
||||||
...(release.type === 'movie' ? [
|
|
||||||
addReleaseMedia(releaseWithId.covers, releaseWithId, 'covers', context),
|
|
||||||
] : []),
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return releaseWithId;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
const file = await fs.promises.readFile(args.file, 'utf8');
|
const file = await fs.readFile(args.file, 'utf8');
|
||||||
const releases = JSON.parse(file).slice(0, args.limit || Infinity);
|
const releases = JSON.parse(file);
|
||||||
|
|
||||||
const [batchId] = await knex('batches').insert({ comment: `import ${args.file}` }).returning('id');
|
const [batchId] = await knex('batches').insert({ comment: `import ${args.file}` }).returning('id');
|
||||||
|
|
||||||
const aggTags = Array.from(new Set(releases.filter((release) => release.type === 'release').flatMap((release) => [...release.tags, ...release.chapters.flatMap((chapter) => chapter.tags)]).filter(Boolean)));
|
const aggTags = Array.from(new Set(releases.flatMap((release) => [...release.tags, ...release.chapters.flatMap((chapter) => chapter.tags)]).filter(Boolean)));
|
||||||
const aggStudios = Array.from(new Set(releases.map((release) => release.studio).filter(Boolean)));
|
const aggStudios = Array.from(new Set(releases.map((release) => release.studio).filter(Boolean)));
|
||||||
|
|
||||||
const tags = await knex('tags')
|
const tags = await knex('tags')
|
||||||
|
@ -578,22 +406,14 @@ async function load() {
|
||||||
const tagIdsBySlug = Object.fromEntries(tags.map((tag) => [tag.slug, tag.id]));
|
const tagIdsBySlug = Object.fromEntries(tags.map((tag) => [tag.slug, tag.id]));
|
||||||
const studioIdsBySlug = Object.fromEntries(studios.map((studio) => [studio.slug, studio.id]));
|
const studioIdsBySlug = Object.fromEntries(studios.map((studio) => [studio.slug, studio.id]));
|
||||||
|
|
||||||
const addedMovies = await releases.filter((release) => release.type === 'movie').reduce(async (chain, release) => {
|
const added = await releases.reduce(async (chain, release) => {
|
||||||
const acc = await chain;
|
const acc = await chain;
|
||||||
const movie = await addRelease(release, { batchId, tagIdsBySlug, studioIdsBySlug });
|
const isAdded = await addRelease(release, { batchId, tagIdsBySlug, studioIdsBySlug });
|
||||||
|
|
||||||
return acc.concat(movie);
|
return acc.concat(isAdded);
|
||||||
}, Promise.resolve([]));
|
}, Promise.resolve([]));
|
||||||
|
|
||||||
const addedScenes = await releases.filter((release) => release.type === 'release').reduce(async (chain, release) => {
|
console.log(`Loaded ${added.filter(Boolean).length}/${releases.length} scenes in batch ${batchId}`);
|
||||||
const acc = await chain;
|
|
||||||
const scene = await addRelease(release, { batchId, movies: addedMovies, tagIdsBySlug, studioIdsBySlug });
|
|
||||||
|
|
||||||
return acc.concat(scene);
|
|
||||||
}, Promise.resolve([]));
|
|
||||||
|
|
||||||
console.log(`Loaded ${addedMovies.filter(Boolean).length}/${releases.filter((release) => release.type === 'movie').length} movies in batch ${batchId}`);
|
|
||||||
console.log(`Loaded ${addedScenes.filter(Boolean).length}/${releases.filter((release) => release.type === 'release').length} scenes in batch ${batchId}`);
|
|
||||||
|
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const config = require('config');
|
|
||||||
const { withPostGraphileContext } = require('postgraphile');
|
const { withPostGraphileContext } = require('postgraphile');
|
||||||
const { graphql } = require('graphql');
|
const { graphql } = require('graphql');
|
||||||
|
|
||||||
const initPg = require('./postgraphile');
|
const pg = require('./postgraphile');
|
||||||
const logger = require('../logger')(__filename);
|
const logger = require('../logger')(__filename);
|
||||||
|
|
||||||
async function query(graphqlQuery, params, role = 'query') {
|
async function query(graphqlQuery, params) {
|
||||||
const pg = initPg(config.database[role]);
|
|
||||||
|
|
||||||
return withPostGraphileContext(pg, async (context) => {
|
return withPostGraphileContext(pg, async (context) => {
|
||||||
const schema = await pg.getGraphQLSchema();
|
const schema = await pg.getGraphQLSchema();
|
||||||
const result = await graphql(schema, graphqlQuery, null, context, params);
|
const result = await graphql(schema, graphqlQuery, null, context, params);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/* eslint-disable arrow-body-style */
|
/* eslint-disable arrow-body-style */
|
||||||
|
const config = require('config');
|
||||||
|
|
||||||
const { postgraphile } = require('postgraphile');
|
const { postgraphile } = require('postgraphile');
|
||||||
|
|
||||||
const PgConnectionFilterPlugin = require('postgraphile-plugin-connection-filter');
|
const PgConnectionFilterPlugin = require('postgraphile-plugin-connection-filter');
|
||||||
|
@ -9,16 +11,15 @@ const PgOrderByRelatedPlugin = require('@graphile-contrib/pg-order-by-related');
|
||||||
|
|
||||||
const { ActorPlugins, SitePlugins, ReleasePlugins, MediaPlugins } = require('./plugins/plugins');
|
const { ActorPlugins, SitePlugins, ReleasePlugins, MediaPlugins } = require('./plugins/plugins');
|
||||||
|
|
||||||
|
const connectionString = `postgres://${config.database.query.user}:${config.database.query.password}@${config.database.query.host}:5432/${config.database.query.database}`;
|
||||||
|
|
||||||
async function pgSettings(req) {
|
async function pgSettings(req) {
|
||||||
return {
|
return {
|
||||||
'user.id': req.session.user?.id || null, // undefined is passed as an empty string, avoid
|
'user.id': req.session.user?.id || null, // undefined is passed as an empty string, avoid
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPostgraphile(credentials) {
|
module.exports = postgraphile(
|
||||||
const connectionString = `postgres://${credentials.user}:${credentials.password}@${credentials.host}:5432/${credentials.database}`;
|
|
||||||
|
|
||||||
return postgraphile(
|
|
||||||
connectionString,
|
connectionString,
|
||||||
'public',
|
'public',
|
||||||
{
|
{
|
||||||
|
@ -47,7 +48,4 @@ function initPostgraphile(credentials) {
|
||||||
pgSettings,
|
pgSettings,
|
||||||
},
|
},
|
||||||
pgSettings,
|
pgSettings,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = initPostgraphile;
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const logger = require('../logger')(__filename);
|
||||||
const knex = require('../knex');
|
const knex = require('../knex');
|
||||||
const errorHandler = require('./error');
|
const errorHandler = require('./error');
|
||||||
|
|
||||||
const initPg = require('./postgraphile');
|
const pg = require('./postgraphile');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
login,
|
login,
|
||||||
|
@ -83,7 +83,7 @@ async function initServer() {
|
||||||
router.use(bodyParser.json({ strict: false }));
|
router.use(bodyParser.json({ strict: false }));
|
||||||
router.use(session({ ...config.web.session, store }));
|
router.use(session({ ...config.web.session, store }));
|
||||||
|
|
||||||
router.use(initPg(config.database.query));
|
router.use(pg);
|
||||||
|
|
||||||
router.use((req, res, next) => {
|
router.use((req, res, next) => {
|
||||||
req.session.safeId = req.session.safeId || nanoid();
|
req.session.safeId = req.session.safeId || nanoid();
|
||||||
|
|
Loading…
Reference in New Issue