@@ -38,6 +39,12 @@
class="heart"
@click.native.stop="stash"
/>
+
+
@@ -244,6 +251,28 @@ async function unstash() {
}
}
+.new {
+ display: flex;
+ flex-direction: row-reverse;
+ align-items: center;
+ position: absolute;
+ bottom: 0;
+ right: .5rem;
+ padding: .2rem .5rem .1rem .5rem;
+ border-radius: .25rem .25rem 0 0;
+ background: var(--grey-dark-40);
+ color: var(--gold);
+ font-size: .7rem;
+ font-weight: bold;
+ box-shadow: 0 0 3px var(--shadow-weak-20);
+
+ .icon {
+ width: .75rem;
+ height: .75rem;
+ fill: var(--gold);
+ }
+}
+
.meta {
display: flex;
justify-content: space-between;
@@ -251,6 +280,7 @@ async function unstash() {
padding: .4rem .5rem;
border-radius: 0 0 .25rem .25rem;
margin-bottom: .5rem;
+ position: relative;
font-size: .8rem;
color: var(--text-light);
background: var(--shadow-strong-30);
diff --git a/src/actors.js b/src/actors.js
index cebdd97..a1f35df 100644
--- a/src/actors.js
+++ b/src/actors.js
@@ -71,7 +71,7 @@ export function sortActorsByGender(actors, context = {}) {
}
const alphaActors = actors.sort((actorA, actorB) => actorA.name.localeCompare(actorB.name, 'en'));
- const genderActors = ['transsexual', 'female', 'male', undefined, null].flatMap((gender) => alphaActors.filter((actor) => actor.gender === gender));
+ const genderActors = ['transsexual', 'female', 'male', undefined, null, 'male'].flatMap((gender) => alphaActors.filter((actor) => actor.gender === gender));
const titleSlug = slugify(context.title);
const titleActors = titleSlug ? genderActors.sort((actorA, actorB) => {
diff --git a/src/scenes.js b/src/scenes.js
index 010cd6f..7c18cc1 100644
--- a/src/scenes.js
+++ b/src/scenes.js
@@ -8,6 +8,7 @@ import { fetchActorsById, curateActor, sortActorsByGender } from './actors.js';
import { fetchTagsById } from './tags.js';
import { fetchEntitiesById } from './entities.js';
import { curateStash } from './stashes.js';
+import promiseProps from '../utils/promise-props.js';
function curateMedia(media) {
if (!media) {
@@ -74,59 +75,65 @@ function curateScene(rawScene, assets) {
stashes: assets.stashes?.map((stash) => curateStash(stash)) || [],
createdBatchId: rawScene.created_batch_id,
updatedBatchId: rawScene.updated_batch_id,
+ isNew: assets.lastBatchId === rawScene.created_batch_id,
};
}
export async function fetchScenesById(sceneIds, { reqUser, ...context } = {}) {
- const [scenes, channels, actors, directors, tags, posters, photos, stashes] = await Promise.all([
- knex('releases').whereIn('releases.id', sceneIds),
- knex('releases')
+ const {
+ scenes,
+ channels,
+ actors,
+ directors,
+ tags,
+ posters,
+ photos,
+ stashes,
+ lastBatch: { id: lastBatchId },
+ } = await promiseProps({
+ scenes: knex('releases').whereIn('releases.id', sceneIds),
+ channels: knex('releases')
.select('channels.*', 'networks.id as network_id', 'networks.slug as network_slug', 'networks.name as network_name', 'networks.type as network_type')
.whereIn('releases.id', sceneIds)
.leftJoin('entities as channels', 'channels.id', 'releases.entity_id')
.leftJoin('entities as networks', 'networks.id', 'channels.parent_id')
.groupBy('channels.id', 'networks.id'),
- knex('releases_actors')
+ actors: knex('releases_actors')
.select(
'actors.*',
'actors_meta.*',
'releases_actors.release_id',
- /* why would we need this for scenes?
- 'birth_countries.alpha2 as birth_country_alpha2',
- knex.raw('COALESCE(birth_countries.alias, birth_countries.name) as birth_country_name'),
- 'residence_countries.alpha2 as residence_country_alpha2',
- knex.raw('COALESCE(residence_countries.alias, residence_countries.name) as residence_country_name'),
- */
)
.leftJoin('actors', 'actors.id', 'releases_actors.actor_id')
.leftJoin('actors_meta', 'actors_meta.actor_id', 'actors.id')
.whereIn('release_id', sceneIds),
- /*
- .leftJoin('countries as birth_countries', 'birth_countries.alpha2', 'actors_meta.birth_country_alpha2')
- .leftJoin('countries as residence_countries', 'residence_countries.alpha2', 'actors_meta.residence_country_alpha2'),
- */
- knex('releases_directors')
+ directors: knex('releases_directors')
.whereIn('release_id', sceneIds)
.leftJoin('actors as directors', 'directors.id', 'releases_directors.director_id'),
- knex('releases_tags')
+ tags: knex('releases_tags')
.select('id', 'slug', 'name', 'release_id')
.leftJoin('tags', 'tags.id', 'releases_tags.tag_id')
.whereNotNull('tags.id')
.whereIn('release_id', sceneIds)
.orderBy('priority', 'desc'),
- knex('releases_posters')
+ posters: knex('releases_posters')
.whereIn('release_id', sceneIds)
.leftJoin('media', 'media.id', 'releases_posters.media_id'),
- knex('releases_photos')
+ photos: knex('releases_photos')
.whereIn('release_id', sceneIds)
.leftJoin('media', 'media.id', 'releases_photos.media_id'),
- reqUser
+ lastBatch: knex('batches')
+ .select('id')
+ .where('showcased', true)
+ .orderBy('created_at', 'desc')
+ .first(),
+ stashes: reqUser
? knex('stashes_scenes')
.leftJoin('stashes', 'stashes.id', 'stashes_scenes.stash_id')
.where('stashes.user_id', reqUser.id)
.whereIn('stashes_scenes.scene_id', sceneIds)
: [],
- ]);
+ });
const actorStashes = reqUser && context.actorStashes
? await knex('stashes_actors')
@@ -160,6 +167,7 @@ export async function fetchScenesById(sceneIds, { reqUser, ...context } = {}) {
photos: scenePhotos,
stashes: sceneStashes,
actorStashes: sceneActorStashes,
+ lastBatchId,
});
}).filter(Boolean);
}
diff --git a/utils/promise-props.js b/utils/promise-props.js
new file mode 100644
index 0000000..1c31c7c
--- /dev/null
+++ b/utils/promise-props.js
@@ -0,0 +1,5 @@
+export default async function promiseProps(obj) {
+ const resolved = await Promise.all(Object.entries(obj).map(async ([key, promise]) => [key, await promise]));
+
+ return Object.fromEntries(resolved);
+}