Added secondary stash button, centralized bookmark (heart) component.

This commit is contained in:
2024-03-27 02:28:21 +01:00
parent c018f54a12
commit b1e336381c
15 changed files with 426 additions and 552 deletions

View File

@@ -45,82 +45,102 @@ function showFeedback(isSuccess, options = {}, errorMessage) {
}
export async function get(path, query = {}, options = {}) {
const res = await fetch(`/api${path}${getQuery(query)}`);
const body = parse(await res.text());
try {
const res = await fetch(`/api${path}${getQuery(query)}`);
const body = parse(await res.text());
if (res.ok) {
showFeedback(true, options);
return body;
if (res.ok) {
showFeedback(true, options);
return body;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
} catch (error) {
showFeedback(false, options, error.message);
throw error;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
}
export async function post(path, data, options = {}) {
const res = await fetch(`/api${path}${getQuery(options.query)}`, {
method: 'POST',
body: JSON.stringify(data),
...postHeaders,
});
try {
const res = await fetch(`/api${path}${getQuery(options.query)}`, {
method: 'POST',
body: JSON.stringify(data),
...postHeaders,
});
if (res.status === 204) {
showFeedback(true, options);
return null;
if (res.status === 204) {
showFeedback(true, options);
return null;
}
const body = parse(await res.text());
if (res.ok) {
showFeedback(true, options);
return body;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
} catch (error) {
showFeedback(false, options, error.message);
throw error;
}
const body = parse(await res.text());
if (res.ok) {
showFeedback(true, options);
return body;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
}
export async function patch(path, data, options = {}) {
const res = await fetch(`/api${path}${getQuery(options.query)}`, {
method: 'PATCH',
body: JSON.stringify(data),
...postHeaders,
});
try {
const res = await fetch(`/api${path}${getQuery(options.query)}`, {
method: 'PATCH',
body: JSON.stringify(data),
...postHeaders,
});
if (res.status === 204) {
return null;
if (res.status === 204) {
return null;
}
const body = parse(await res.text());
if (res.ok) {
showFeedback(true, options);
return body;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
} catch (error) {
showFeedback(false, options, error.message);
throw error;
}
const body = parse(await res.text());
if (res.ok) {
showFeedback(true, options);
return body;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
}
export async function del(path, options = {}) {
const res = await fetch(`/api${path}${getQuery(options.query)}`, {
method: 'DELETE',
body: JSON.stringify(options.data),
...postHeaders,
});
try {
const res = await fetch(`/api${path}${getQuery(options.query)}`, {
method: 'DELETE',
body: JSON.stringify(options.data),
...postHeaders,
});
if (res.status === 204) {
showFeedback(true, options);
return null;
if (res.status === 204) {
showFeedback(true, options);
return null;
}
const body = parse(await res.text());
if (res.ok) {
showFeedback(true, options);
return body;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
} catch (error) {
showFeedback(false, options, error.message);
throw error;
}
const body = parse(await res.text());
if (res.ok) {
showFeedback(true, options);
return body;
}
showFeedback(false, options, body.statusMessage);
throw new Error(body.statusMessage);
}

View File

@@ -128,7 +128,8 @@ export async function fetchMoviesById(movieIds, reqUser) {
.orderBy('priority', 'desc'),
covers: knex('movies_covers')
.whereIn('movie_id', movieIds)
.leftJoin('media', 'media.id', 'movies_covers.media_id'),
.leftJoin('media', 'media.id', 'movies_covers.media_id')
.orderBy('media.index'),
photos: knex('movies')
.whereIn('movies.id', movieIds)
.leftJoin('movies_scenes', 'movies_scenes.movie_id', 'movies.id')

View File

@@ -1,4 +1,5 @@
import config from 'config';
import { CronJob } from 'cron';
import { knexOwner as knex } from './knex.js';
import { indexApi } from './manticore.js';
@@ -8,7 +9,10 @@ import initLogger from './logger.js';
const logger = initLogger();
let lastActorsViewRefresh = 0;
const lastViewRefresh = {
actors: 0,
stashes: 0,
};
export function curateStash(stash, assets = {}) {
if (!stash) {
@@ -85,11 +89,11 @@ export async function fetchStashByUsernameAndSlug(username, stashSlug, sessionUs
export async function fetchStashes(domain, itemId, sessionUser) {
const stashes = await knex(`stashes_${domain}s`)
.select('stashes.*')
.leftJoin('stashes', 'stashes.id', `stashes_${domain}s.stash_id`)
.where({
[`${domain}_id`]: itemId,
user_id: sessionUser.id,
})
.leftJoin('stashes', 'stashes.id', `stashes_${domain}s.stash_id`);
});
return stashes.map((stash) => curateStash(stash));
}
@@ -112,6 +116,24 @@ function verifyStashName(stash) {
}
}
export async function refreshView(domain = 'stashes') {
// throttle view refreshes
if (new Date() - lastViewRefresh[domain] > config.stashes.viewRefreshCooldowns[domain] * 60000) {
lastViewRefresh[domain] = new Date();
logger.verbose(`Refreshing ${domain} view`);
await knex.schema.refreshMaterializedView(`${domain}_meta`);
await knex.schema.refreshMaterializedView('stashes_meta');
return true;
}
logger.debug(`Skipping ${domain} view refresh`);
return false;
}
export async function createStash(newStash, sessionUser) {
if (!sessionUser) {
throw new HttpError('You are not authenthicated', 401);
@@ -184,21 +206,6 @@ export async function removeStash(stashId, sessionUser) {
}
}
export async function refreshActorsView() {
if (new Date() - lastActorsViewRefresh > config.stashes.viewRefreshCooldown * 60000) {
// don't refresh actors view more than once an hour
lastActorsViewRefresh = new Date();
logger.debug('Refreshing actors view');
return knex.schema.refreshMaterializedView('actors_meta');
}
logger.silly('Skipping actors view refresh');
return false;
}
export async function stashActor(actorId, stashId, sessionUser) {
const stash = await fetchStashById(stashId, sessionUser);
@@ -222,7 +229,7 @@ export async function stashActor(actorId, stashId, sessionUser) {
logger.verbose(`${sessionUser.username} (${sessionUser.id}) stashed actor ${actorId} to stash ${stash.id} (${stash.name})`);
refreshActorsView();
refreshView('actors');
return fetchStashes('actor', actorId, sessionUser);
}
@@ -257,7 +264,7 @@ export async function unstashActor(actorId, stashId, sessionUser) {
logger.verbose(`${sessionUser.username} (${sessionUser.id}) unstashed actor ${actorId} from stash ${stashId}`);
refreshActorsView();
refreshView('actors');
return fetchStashes('actor', actorId, sessionUser);
}
@@ -286,6 +293,8 @@ export async function stashScene(sceneId, stashId, sessionUser) {
logger.verbose(`${sessionUser.username} (${sessionUser.id}) stashed scene ${sceneId} to stash ${stash.id} (${stash.name})`);
refreshView('scenes');
return fetchStashes('scene', sceneId, sessionUser);
}
@@ -315,6 +324,8 @@ export async function unstashScene(sceneId, stashId, sessionUser) {
logger.verbose(`${sessionUser.username} (${sessionUser.id}) unstashed scene ${sceneId} from stash ${stashId}`);
refreshView('scenes');
return fetchStashes('scene', sceneId, sessionUser);
}
@@ -341,6 +352,8 @@ export async function stashMovie(movieId, stashId, sessionUser) {
logger.verbose(`${sessionUser.username} (${sessionUser.id}) stashed movie ${movieId} to stash ${stash.id} (${stash.name})`);
refreshView('movies');
return fetchStashes('movie', movieId, sessionUser);
}
@@ -370,5 +383,21 @@ export async function unstashMovie(movieId, stashId, sessionUser) {
logger.verbose(`${sessionUser.username} (${sessionUser.id}) unstashed movie ${movieId} from stash ${stashId}`);
refreshView('movies');
return fetchStashes('movie', movieId, sessionUser);
}
CronJob.from({
cronTime: config.stashes.viewRefreshCron,
async onTick() {
logger.verbose('Updating stash views');
await refreshView('scenes');
await refreshView('actors');
await refreshView('movies');
await refreshView('stashes');
},
start: true,
runOnInit: true,
});

View File

@@ -51,13 +51,14 @@ export async function fetchUser(userId, options = {}, reqUser) {
}
const stashes = await knex('stashes')
.select('stashes.*', 'stashes_meta.*')
.leftJoin('stashes_meta', 'stashes_meta.stash_id', 'stashes.id')
.where('user_id', user.id)
.modify((builder) => {
if (reqUser?.id !== user.id && !options.includeStashes) {
builder.where('public', true);
}
})
.leftJoin('stashes_meta', 'stashes_meta.stash_id', 'stashes.id');
});
if (options.raw) {
return { user, stashes };