Added actor assignment to new actors module. Showing network icon on network-specific actors. Improved dark theme. Changed tag tile design. Added Digital Playground logos.

This commit is contained in:
ThePendulum 2020-03-27 04:39:13 +01:00
parent 689dbeefbd
commit fb59bf552a
24 changed files with 202 additions and 113 deletions

View File

@ -11,11 +11,7 @@
"no-console": 0, "no-console": 0,
"indent": "off", "indent": "off",
"template-curly-spacing": "off", "template-curly-spacing": "off",
"max-len": [2, { "max-len": 0,
"code": 300,
"tabWidth": 4,
"ignoreUrls": true
}],
"vue/no-v-html": 0, "vue/no-v-html": 0,
"vue/html-indent": ["error", 4], "vue/html-indent": ["error", 4],
"vue/multiline-html-element-content-newline": 0, "vue/multiline-html-element-content-newline": 0,

View File

@ -7,7 +7,9 @@
<div class="actor-header"> <div class="actor-header">
<h2 class="header-name"> <h2 class="header-name">
{{ actor.name }} <span v-if="actor.network">{{ actor.name }} ({{ actor.network.name }})</span>
<span v-else="">{{ actor.name }}</span>
<Gender <Gender
:gender="actor.gender" :gender="actor.gender"
class="header-gender" class="header-gender"

View File

@ -109,8 +109,20 @@ export default {
<style lang="scss"> <style lang="scss">
@import 'theme'; @import 'theme';
.gender-link.selected .gender .icon { .gender-link {
fill: var(--text-light); &.selected .gender .icon {
fill: var(--text-light);
filter: none;
}
&:hover:not(.selected) .gender .icon {
fill: var(--text-light);
}
&:hover:not(.selected) .transsexual .icon {
fill: var(--female);
filter: drop-shadow(1px 0 0 var(--text-light)) drop-shadow(-1px 0 0 var(--text-light)) drop-shadow(0 1px 0 var(--text-light)) drop-shadow(0 -1px 0 var(--text-light)) drop-shadow(1px 0 0 var(--male)) drop-shadow(-1px 0 0 var(--male)) drop-shadow(0 1px 0 var(--male)) drop-shadow(0 -1px 0 var(--male)) drop-shadow(0 0 1px rgba(0, 0, 0, 0.5));
}
} }
</style> </style>
@ -159,7 +171,6 @@ export default {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-sizing: border-box; box-sizing: border-box;
padding: .2rem 0 0 0;
margin: .25rem .5rem .25rem 0; margin: .25rem .5rem .25rem 0;
color: var(--shadow); color: var(--shadow);
background: var(--background); background: var(--background);
@ -167,31 +178,29 @@ export default {
text-decoration: none; text-decoration: none;
box-shadow: 0 0 3px var(--darken-weak); box-shadow: 0 0 3px var(--darken-weak);
.male,
.female,
.transsexual {
padding: .2rem 0 0 0;
}
.icon { .icon {
fill: var(--shadow); fill: var(--shadow);
} }
&:hover { &:hover {
color: var(--primary); color: var(--text-light);
cursor: pointer; cursor: pointer;
.icon {
fill: var(--text-light);
}
} }
&.selected { &.selected {
background: var(--primary); background: var(--primary);
color: var(--text-light); color: var(--text-light);
&.male {
background: var(--male);
}
&.female {
background: var(--female);
}
&.transsexual {
background: var(--text);
}
&.other .icon { &.other .icon {
fill: var(--text-light); fill: var(--text-light);
} }

View File

@ -72,6 +72,7 @@ export default {
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
background: var(--background-dim); background: var(--background-dim);
color: var(--text);
} }
.content { .content {

View File

@ -246,6 +246,7 @@ async function mounted() {
this.release = await this.$store.dispatch('fetchReleaseById', this.$route.params.releaseId); this.release = await this.$store.dispatch('fetchReleaseById', this.$route.params.releaseId);
this.filename = format(config.filename.pattern, { this.filename = format(config.filename.pattern, {
...this.release, ...this.release,
shootId: this.release.shootId || '',
date: this.formatDate(this.release.date, config.filename.date), date: this.formatDate(this.release.date, config.filename.date),
}, { }, {
spreadSeparator: config.filename.separator, spreadSeparator: config.filename.separator,
@ -287,8 +288,8 @@ export default {
.info { .info {
padding: 1rem; padding: 1rem;
border-left: solid 1px $shadow-hint; border-left: solid 1px var(--shadow-hint);
border-right: solid 1px $shadow-hint; border-right: solid 1px var(--shadow-hint);
flex-grow: 1; flex-grow: 1;
} }
@ -304,15 +305,15 @@ export default {
.icon { .icon {
display: inline-block; display: inline-block;
width: 1rem; width: 1rem;
fill: $shadow-strong; fill: var(--shadow-strong);
margin: 0 1rem 0 0; margin: 0 1rem 0 0;
} }
} }
.details { .details {
background: $profile; background: var(--profile);
color: $text-contrast; color: var(--text-light);
box-shadow: 0 0 3px $shadow-weak; box-shadow: 0 0 3px var(--shadow-weak);
cursor: default; cursor: default;
.column { .column {
@ -322,7 +323,7 @@ export default {
} }
.link { .link {
color: $text-contrast; color: var(--text-light);
} }
} }
@ -331,11 +332,11 @@ export default {
height: 100%; height: 100%;
&:not(:last-child) { &:not(:last-child) {
border-right: solid 1px $highlight-hint; border-right: solid 1px var(--lighten-hint);
} }
.icon { .icon {
fill: $highlight-weak; fill: var(--lighten-weak);
margin: 0 .25rem 0 0; margin: 0 .25rem 0 0;
} }
@ -359,7 +360,6 @@ export default {
.logo { .logo {
display: inline-block; display: inline-block;
filter: $logo-highlight;
} }
.logo-site { .logo-site {
@ -377,7 +377,7 @@ export default {
} }
.chain { .chain {
color: $highlight; color: var(--lighten);
padding: 0 .5rem; padding: 0 .5rem;
font-weight: bold; font-weight: bold;
font-size: .8rem; font-size: .8rem;
@ -388,7 +388,7 @@ export default {
} }
.description { .description {
line-height: 1.25; line-height: 1.5;
} }
.duration { .duration {
@ -416,34 +416,36 @@ export default {
.filename { .filename {
width: 100%; width: 100%;
padding: .5rem; padding: .5rem;
border: solid 1px $shadow-weak; color: var(--text);
border: solid 1px var(--shadow-weak);
background: var(--background);
} }
.link { .link {
display: inline-block; display: inline-block;
color: $link; color: var(--link);
text-decoration: none; text-decoration: none;
&:hover { &:hover {
color: $primary; color: var(--primary);
.icon { .icon {
fill: $primary; fill: var(--primary);
} }
} }
} }
.tag .link { .tag .link {
background: $background; background: var(--background);
display: inline-block; display: inline-block;
padding: .5rem; padding: .5rem;
margin: 0 .25rem .25rem 0; margin: 0 .25rem .25rem 0;
box-shadow: 0 0 2px $shadow-weak; box-shadow: 0 0 2px var(--shadow-weak);
text-decoration: none; text-decoration: none;
text-transform: capitalize; text-transform: capitalize;
&:hover { &:hover {
color: $primary; color: var(--primary);
} }
} }

View File

@ -8,8 +8,21 @@
class="link" class="link"
> >
<span <span
v-if="actor.network"
v-tooltip.top="`${actor.name} (${actor.network.name})`"
class="handle"
>
<img
:src="`/img/logos/${actor.network.slug}/favicon.png`"
class="favicon"
>
<span class="name">{{ actor.name }}</span>
</span>
<span
v-else
v-tooltip.top="actor.name" v-tooltip.top="actor.name"
class="name" class="handle name"
>{{ actor.name }}</span> >{{ actor.name }}</span>
<div class="avatar-container"> <div class="avatar-container">
@ -89,28 +102,54 @@ export default {
.actor { .actor {
width: 100%; width: 100%;
background: $background;
display: inline-block; display: inline-block;
margin: 0 .5rem .5rem 0; margin: 0 .5rem .5rem 0;
box-shadow: 0 0 3px $shadow-weak; box-shadow: 0 0 3px var(--darken-weak);
background: var(--profile);
} }
.link { .link {
color: $text; color: var(--text-light);
text-decoration: none; text-decoration: none;
&:hover { &:hover {
color: $primary; color: var(--primary);
} }
} }
.handle {
display: flex;
align-items: center;
justify-content: center;
padding: .5rem;
font-weight: bold;
}
.favicon {
width: 1rem;
height: 1rem;
margin: 0 .5rem 0 0;
& + .name {
padding: 0 1rem 0 0;
}
}
.name {
flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
}
.avatar-container { .avatar-container {
position: relative; position: relative;
} }
.avatar { .avatar {
color: $shadow-weak; color: var(--darken-weak);
background: $shadow-hint; background: var(--darken-hint);
height: 13rem; height: 13rem;
width: 100%; width: 100%;
display: flex; display: flex;
@ -123,12 +162,12 @@ export default {
.avatar-fallback { .avatar-fallback {
max-height: 75%; max-height: 75%;
max-width: 80%; max-width: 80%;
opacity: .1; opacity: .5;
} }
.details { .details {
background: $shadow; background: var(--darken);
color: $text-contrast; color: var(--text-light);
width: 100%; width: 100%;
height: 1.75rem; height: 1.75rem;
display: flex; display: flex;
@ -156,16 +195,6 @@ export default {
} }
.age-then { .age-then {
color: $highlight; color: var(--lighten);
}
.name {
display: block;
padding: .5rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
font-weight: bold;
} }
</style> </style>

View File

@ -216,9 +216,8 @@ export default {
object-fit: cover; object-fit: cover;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
background-color: var(--shadow-hint); background-color: var(--darken-hint);
color: var(--shadow); color: var(--shadow);
text-shadow: 1px 1px 0 var(--highlight);
} }
.row { .row {

View File

@ -4,14 +4,14 @@
:title="tag.name" :title="tag.name"
class="tile" class="tile"
> >
<span class="title">{{ tag.name }}</span>
<img <img
v-if="tag.poster" v-if="tag.poster"
:src="sfw ? `/img/${tag.poster.sfw.thumbnail}` : `/img/${tag.poster.thumbnail}`" :src="sfw ? `/img/${tag.poster.sfw.thumbnail}` : `/img/${tag.poster.thumbnail}`"
:alt="tag.name" :alt="tag.name"
class="poster" class="poster"
> >
<span class="title">{{ tag.name }}</span>
</router-link> </router-link>
</template> </template>
@ -44,6 +44,7 @@ export default {
align-items: left; align-items: left;
justify-content: flex-end; justify-content: flex-end;
box-sizing: border-box; box-sizing: border-box;
position: relative;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
box-shadow: inset 0 0 3px var(--darken); box-shadow: inset 0 0 3px var(--darken);
@ -51,16 +52,23 @@ export default {
.poster { .poster {
width: 100%; width: 100%;
height: 14rem; height: 16rem;
object-fit: cover; object-fit: cover;
box-shadow: 0 0 3px var(--darken); object-position: 50% 100%;
box-shadow: 0 0 1px var(--darken);
} }
.title { .title {
width: 100%;
display: flex; display: flex;
font-size: 1rem; box-sizing: border-box;
padding: .5rem 1rem; padding: .5rem 1rem;
position: absolute;
bottom: 0;
background: var(--darken);
font-size: 1rem;
font-weight: bold; font-weight: bold;
text-transform: capitalize; text-transform: capitalize;
text-shadow: 0 0 3px var(--darken-strong);
} }
</style> </style>

View File

@ -9,7 +9,6 @@ body {
} }
body { body {
color: var(--text);
margin: 0; margin: 0;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
} }

View File

@ -77,6 +77,11 @@ function initActorActions(store, _router) {
tattoos tattoos
piercings piercings
description description
network {
id
name
slug
}
avatar: actorsAvatarByActorId { avatar: actorsAvatarByActorId {
media { media {
thumbnail thumbnail
@ -222,6 +227,11 @@ function initActorActions(store, _router) {
age age
birthdate birthdate
gender gender
network {
id
name
slug
}
avatar: actorsAvatarByActorId { avatar: actorsAvatarByActorId {
media { media {
thumbnail thumbnail

View File

@ -37,6 +37,11 @@ const actorFields = `
birthdate birthdate
age age
gender gender
network {
id
name
slug
}
originCountry: countryByBirthCountryAlpha2 { originCountry: countryByBirthCountryAlpha2 {
alpha2 alpha2
name name

View File

@ -247,7 +247,6 @@ exports.up = knex => Promise.resolve()
table.increments('id', 12); table.increments('id', 12);
table.string('name') table.string('name')
.unique()
.notNullable(); .notNullable();
table.string('slug', 32) table.string('slug', 32)
@ -261,17 +260,6 @@ exports.up = knex => Promise.resolve()
.references('id') .references('id')
.inTable('networks'); .inTable('networks');
table.datetime('created_at')
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('actors_profiles', (table) => {
table.increments('id', 12);
table.integer('actor_id')
.references('id')
.inTable('actors')
.notNullable();
table.date('birthdate'); table.date('birthdate');
table.string('gender', 18); table.string('gender', 18);
table.text('description'); table.text('description');
@ -307,6 +295,13 @@ exports.up = knex => Promise.resolve()
table.datetime('created_at') table.datetime('created_at')
.defaultTo(knex.fn.now()); .defaultTo(knex.fn.now());
}))
.then(() => knex.raw('CREATE TABLE actors_profiles AS TABLE actors WITH NO DATA;'))
.then(() => knex.schema.alterTable('actors_profiles', (table) => {
table.integer('actor_id')
.references('id')
.inTable('actors')
.notNullable();
table.datetime('scraped_at'); table.datetime('scraped_at');
table.boolean('scrape_success'); table.boolean('scrape_success');
@ -323,7 +318,9 @@ exports.up = knex => Promise.resolve()
{ slug: 'face', name: 'face' }, { slug: 'face', name: 'face' },
{ slug: 'scalp', name: 'scalp' }, { slug: 'scalp', name: 'scalp' },
{ slug: 'forehead', name: 'forehead' }, { slug: 'forehead', name: 'forehead' },
{ slug: 'temple', name: 'temple' },
{ slug: 'cheek', name: 'cheek' }, { slug: 'cheek', name: 'cheek' },
{ slug: 'jaw', name: 'jaw' },
{ slug: 'chin', name: 'chin' }, { slug: 'chin', name: 'chin' },
{ slug: 'neck', name: 'neck' }, { slug: 'neck', name: 'neck' },
{ slug: 'throat', name: 'throat' }, { slug: 'throat', name: 'throat' },
@ -337,6 +334,9 @@ exports.up = knex => Promise.resolve()
{ slug: 'upper-lip', name: 'upper lip' }, { slug: 'upper-lip', name: 'upper lip' },
{ slug: 'lower-lip', name: 'lower lip' }, { slug: 'lower-lip', name: 'lower lip' },
{ slug: 'inner-lip', name: 'inner lip' }, { slug: 'inner-lip', name: 'inner lip' },
{ slug: 'inner-lower-lip', name: 'inner lower lip' },
{ slug: 'inner-upper-lip', name: 'inner upper lip' },
{ slug: 'philtrum', name: 'philtrum' },
{ slug: 'above-lip', name: 'above lip' }, { slug: 'above-lip', name: 'above lip' },
{ slug: 'below-lip', name: 'below lip' }, { slug: 'below-lip', name: 'below lip' },
// nose // nose
@ -364,7 +364,7 @@ exports.up = knex => Promise.resolve()
// hands // hands
{ slug: 'hand', name: 'hand' }, { slug: 'hand', name: 'hand' },
{ slug: 'fingers', name: 'fingers' }, { slug: 'fingers', name: 'fingers' },
{ slug: 'knuckles', name: 'knucles' }, { slug: 'knuckles', name: 'knuckles' },
{ slug: 'thumb', name: 'thumb' }, { slug: 'thumb', name: 'thumb' },
{ slug: 'index-finger', name: 'index finger' }, { slug: 'index-finger', name: 'index finger' },
{ slug: 'middle-finger', name: 'middle finger' }, { slug: 'middle-finger', name: 'middle finger' },
@ -378,11 +378,14 @@ exports.up = knex => Promise.resolve()
{ slug: 'collarbone', name: 'collarbone' }, { slug: 'collarbone', name: 'collarbone' },
{ slug: 'chest', name: 'chest' }, { slug: 'chest', name: 'chest' },
{ slug: 'rib-cage', name: 'rib cage' }, { slug: 'rib-cage', name: 'rib cage' },
{ slug: 'breastbone', name: 'breastbone' },
{ slug: 'underboob', name: 'underboob' }, { slug: 'underboob', name: 'underboob' },
{ slug: 'sideboob', name: 'sideboob' },
{ slug: 'boob', name: 'boob' }, { slug: 'boob', name: 'boob' },
{ slug: 'nipple', name: 'nipple' }, { slug: 'nipple', name: 'nipple' },
{ slug: 'abdomen', name: 'abdomen' }, { slug: 'abdomen', name: 'abdomen' },
{ slug: 'lower-abdomen', name: 'lower abdomen' }, { slug: 'navel', name: 'navel' },
{ slug: 'pelvis', name: 'pelvis' },
// back // back
{ slug: 'back', name: 'back' }, { slug: 'back', name: 'back' },
{ slug: 'upper-back', name: 'upper back' }, { slug: 'upper-back', name: 'upper back' },
@ -392,9 +395,9 @@ exports.up = knex => Promise.resolve()
// bottom // bottom
{ slug: 'butt', name: 'butt' }, { slug: 'butt', name: 'butt' },
{ slug: 'hip', name: 'hip' }, { slug: 'hip', name: 'hip' },
{ slug: 'anus', name: 'anus' },
// genitals // genitals
{ slug: 'pubic-mound', name: 'pubic mound' }, { slug: 'pubic-mound', name: 'pubic mound' },
{ slug: 'anus', name: 'anus' },
{ slug: 'vagina', name: 'vagina' }, { slug: 'vagina', name: 'vagina' },
{ slug: 'outer-labia', name: 'outer labia' }, { slug: 'outer-labia', name: 'outer labia' },
{ slug: 'inner-labia', name: 'inner labia' }, { slug: 'inner-labia', name: 'inner labia' },
@ -748,8 +751,8 @@ exports.up = knex => Promise.resolve()
COMMENT ON VIEW movie_actors IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (actor_id) references actors (id)'; COMMENT ON VIEW movie_actors IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (actor_id) references actors (id)';
COMMENT ON VIEW movie_tags IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (tag_id) references tags (id)'; COMMENT ON VIEW movie_tags IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (tag_id) references tags (id)';
COMMENT ON COLUMN actors_profiles.height IS E'@omit read,update,create,delete,all,many'; COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many';
COMMENT ON COLUMN actors_profiles.weight IS E'@omit read,update,create,delete,all,many'; COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many';
`)); `));
exports.down = knex => knex.raw(` exports.down = knex => knex.raw(`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -1,57 +1,74 @@
'use strict'; 'use strict';
const logger = require('./logger')(__filename);
const knex = require('./knex'); const knex = require('./knex');
const slugify = require('./utils/slugify'); const slugify = require('./utils/slugify');
const capitalize = require('./utils/capitalize'); const capitalize = require('./utils/capitalize');
function toBaseActors(actorsOrNames, release) { function toBaseActors(actorsOrNames, release) {
return actorsOrNames.map((actorOrName) => { return actorsOrNames.map((actorOrName) => {
const name = capitalize(actorOrName.name || actorOrName);
const slug = slugify(name);
const baseActor = {
name,
slug,
hasSingleName: name.split(/\s+/).length === 1,
network: release.site.network,
slugWithNetworkSlug: `${slug}-${release.site.network.slug}`,
};
if (actorOrName.name) { if (actorOrName.name) {
return { return {
...actorOrName, ...actorOrName,
name: capitalize(actorOrName.name), ...baseActor,
slug: slugify(actorOrName.name),
networkId: release.site.network.id,
}; };
} }
return { return baseActor;
name: capitalize(actorOrName),
slug: slugify(actorOrName),
networkId: release.site.network.id,
};
}); });
} }
function curateActorEntry(baseActor) { function curateActorEntry(baseActor) {
const actorEntry = { if (baseActor.hasSingleName) {
logger.warn(`Assigning single name actor '${baseActor.name}' to network '${baseActor.network.name}'`);
// attach network ID to allow separating actors with the same name
return {
name: baseActor.name,
slug: baseActor.slugWithNetworkSlug,
network_id: baseActor.network.id,
};
}
return {
name: baseActor.name, name: baseActor.name,
slug: baseActor.slug, slug: baseActor.slug,
}; };
if (baseActor.name.split(/\s+/).length === 1) {
// attach network ID for single names, to reduce mismatches
actorEntry.network_id = baseActor.networkId;
}
return actorEntry;
} }
function curateActorEntries(baseActors) { function curateActorEntries(baseActors) {
return baseActors.map(baseActor => curateActorEntry(baseActor)); return baseActors.map(baseActor => curateActorEntry(baseActor));
} }
async function getActors(baseActors) { async function getOrCreateActors(baseActors) {
const existingActors = await knex('actors') const existingActors = await knex('actors')
.select('id', 'name', 'slug', 'network_id')
.whereIn('slug', baseActors.map(baseActor => baseActor.slug)) .whereIn('slug', baseActors.map(baseActor => baseActor.slug))
.orWhereIn('name', baseActors.map(baseActor => baseActor.slug)); .whereNull('network_id')
.orWhereIn(['slug', 'network_id'], baseActors.map(baseActor => [baseActor.slugWithNetworkSlug, baseActor.network.id]));
if (existingActors.length === 0) { const existingActorSlugs = new Set(existingActors.map(actor => actor.slug));
// TODO: TESTING ONLY const uniqueBaseActors = baseActors.filter(baseActor => !existingActorSlugs.has(baseActor.slug) && !existingActorSlugs.has(baseActor.slugWithNetworkSlug));
await knex('actors').insert(curateActorEntries(baseActors.slice(0, 3)));
const curatedActorEntries = curateActorEntries(uniqueBaseActors);
const newActors = await knex('actors').insert(curatedActorEntries, ['id', 'name', 'slug', 'network_id']);
if (Array.isArray(newActors)) {
return newActors.concat(existingActors);
} }
console.log(existingActors); return existingActors;
} }
async function associateActors(releases) { async function associateActors(releases) {
@ -67,9 +84,18 @@ async function associateActors(releases) {
const baseActorsBySlug = baseActors.reduce((acc, baseActor) => ({ ...acc, [baseActor.slug]: baseActor }), {}); const baseActorsBySlug = baseActors.reduce((acc, baseActor) => ({ ...acc, [baseActor.slug]: baseActor }), {});
const uniqueBaseActors = Object.values(baseActorsBySlug); const uniqueBaseActors = Object.values(baseActorsBySlug);
const actors = await getActors(uniqueBaseActors); const actors = await getOrCreateActors(uniqueBaseActors);
const actorIdsBySlug = actors.reduce((acc, actor) => ({ ...acc, [actor.slug]: actor.id }), {});
console.log(actors); const releaseActorAssociations = Object.entries(baseActorsByReleaseId)
.map(([releaseId, releaseActors]) => releaseActors
.map(releaseActor => ({
release_id: releaseId,
actor_id: actorIdsBySlug[releaseActor.slug] || actorIdsBySlug[releaseActor.slugWithNetworkSlug],
})))
.flat();
await knex.raw(`${knex('releases_actors').insert(releaseActorAssociations).toString()} ON CONFLICT DO NOTHING;`);
} }
module.exports = { module.exports = {

View File

@ -11,14 +11,14 @@ const schemaExtender = makeExtendSchemaPlugin(_build => ({
IMPERIAL IMPERIAL
} }
extend type ActorProfile { extend type Actor {
age: Int @requires(columns: ["birthdate"]) age: Int @requires(columns: ["birthdate"])
height(units:Units): String @requires(columns: ["height"]) height(units:Units): String @requires(columns: ["height"])
weight(units:Units): String @requires(columns: ["weight"]) weight(units:Units): String @requires(columns: ["weight"])
} }
`, `,
resolvers: { resolvers: {
ActorProfile: { Actor: {
age(parent, _args, _context, _info) { age(parent, _args, _context, _info) {
if (!parent.birthdate) return null; if (!parent.birthdate) return null;