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.
|
@ -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,
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -37,6 +37,11 @@ const actorFields = `
|
||||||
birthdate
|
birthdate
|
||||||
age
|
age
|
||||||
gender
|
gender
|
||||||
|
network {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
originCountry: countryByBirthCountryAlpha2 {
|
originCountry: countryByBirthCountryAlpha2 {
|
||||||
alpha2
|
alpha2
|
||||||
name
|
name
|
||||||
|
|
|
@ -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(`
|
||||||
|
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 258 KiB |
After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 6.2 KiB |
|
@ -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 = {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|