Redesigned release page. Added 'single site' marker, linking directly to network page. Fixed Dogfart scraper duration.

This commit is contained in:
ThePendulum 2019-11-14 05:13:38 +01:00
parent 4fa13bb163
commit bf223adc55
38 changed files with 624 additions and 205 deletions

View File

@ -157,7 +157,6 @@ export default {
padding: .5rem;
margin: 0 .25rem;
border: solid 1px transparent;
border-radius: .5rem;
font-size: .9rem;
font-weight: bold;
cursor: pointer;

View File

@ -12,11 +12,10 @@
rel="noopener noreferrer"
class="title"
>
<object
:data="`/img/logos/${network.slug}/network.png`"
type="image/png"
<img
:src="`/img/logos/${network.slug}/network.png`"
class="logo"
><h2>{{ network.name }}</h2></object>
>
<Icon
icon="new-tab"
@ -27,16 +26,18 @@
<p class="description">{{ network.description }}</p>
</div>
<h3 class="heading">Sites</h3>
<template v-if="sites.length">
<h3 class="heading">Sites</h3>
<ul class="nolist sites">
<li
v-for="site in sites"
:key="`site-${site.id}`"
>
<SiteTile :site="site" />
</li>
</ul>
<ul class="nolist sites">
<li
v-for="site in sites"
:key="`site-${site.id}`"
>
<SiteTile :site="site" />
</li>
</ul>
</template>
<h3 class="heading">Latest releases</h3>
@ -60,7 +61,9 @@ async function mounted() {
[this.network] = await this.$store.dispatch('fetchNetworks', this.$route.params.networkSlug);
this.releases = await this.$store.dispatch('fetchNetworkReleases', this.$route.params.networkSlug);
this.sites = this.network.sites.sort(({ name: nameA }, { name: nameB }) => nameA.localeCompare(nameB));
this.sites = this.network.sites
.filter(site => !site.independent)
.sort(({ name: nameA }, { name: nameB }) => nameA.localeCompare(nameB));
this.pageTitle = this.network.name;
}

View File

@ -77,7 +77,6 @@ export default {
flex-shrink: 0;
white-space: nowrap;
overflow-x: auto;
margin: 0 0 1rem 0;
scrollbar-width: none;
box-shadow: 0 0 3px $shadow;
font-size: 0;
@ -97,6 +96,7 @@ export default {
}
.item {
height: 100%;
max-height: 18rem;
vertical-align: middle;
}

View File

@ -5,117 +5,193 @@
>
<Banner :release="release" />
<h2 class="row title">{{ release.title }}</h2>
<ul class="row actors">
<Icon icon="star" />
<li
v-for="actor in release.actors"
:key="actor.id"
class="actor"
>
<div class="info">
<div class="column">
<a
:href="`/actor/${actor.slug}`"
class="actor-link"
>{{ actor.name }}</a>
</li>
</ul>
v-if="release.date"
:title="`View scene on ${release.site.name}`"
:href="release.url"
target="_blank"
rel="noopener noreferrer"
class="tidbit date link hideable"
>
<Icon icon="calendar2" />
{{ formatDate(release.date, 'MMMM D, YYYY') }}
</a>
<span
v-if="release.date"
class="row"
>
<Icon icon="calendar2" />
<a
v-if="release.date"
:title="`View scene on ${release.site.name}`"
:href="release.url"
target="_blank"
rel="noopener noreferrer"
class="tidbit date link showable"
>
<Icon icon="calendar2" />
{{ formatDate(release.date, 'MMM D, YYYY') }}
</a>
<a
:href="release.url"
:title="`Released on ${formatDate(release.date, 'MMMM D, YYYY')}`"
target="_blank"
rel="noopener noreferrer"
class="date date-link"
>{{ formatDate(release.date, 'MMMM D, YYYY') }}</a>
</span>
<span
v-if="release.shootId"
class="tidbit shoot hideable"
>
<Icon icon="clapboard-play" />
{{ release.shootId }}
</span>
<span class="row site">
<Icon icon="clapboard-play" />
<span
v-if="release.duration"
class="tidbit duration hideable"
>
<Icon icon="stopwatch" />
<span
v-if="release.duration >= 3600"
class="duration-segment"
>{{ Math.floor(release.duration / 3600) }}:</span>
<span class="duration-segment">{{ Math.floor((release.duration % 3600) / 60).toString().padStart(2, '0') }}:</span>
<span class="duration-segment">{{ (release.duration % 60).toString().padStart(2, '0') }}</span>
</span>
<span class="tidbit site">
<a
v-if="release.site.independent"
:href="`/network/${release.network.slug}`"
>
<img
:src="`/img/logos/${release.network.slug}/network.png`"
:title="release.network.name"
class="logo logo-site"
>
</a>
<template v-else>
<a :href="`/network/${release.network.slug}`">
<img
:src="`/img/logos/${release.network.slug}/network.png`"
:title="release.network.name"
:alt="release.network.name"
class="logo logo-network"
>
</a>
<span class="chain">presents</span>
<a :href="`/site/${release.site.slug}`">
<img
:src="`/img/logos/${release.network.slug}/${release.site.slug}.png`"
:title="release.site.name"
class="logo logo-site"
>
</a>
</template>
</span>
</div>
</div>
<div class="column">
<h2 class="row title">{{ release.title }}</h2>
<div class="row">
<Icon icon="star" />
<ul class="actors nolist">
<li
v-for="actor in release.actors"
:key="actor.id"
class="actor"
>
<Actor :actor="actor" />
</li>
</ul>
</div>
<div
v-if="release.tags.length > 0"
class="row"
>
<Icon icon="price-tags3" />
<ul class="tags nolist">
<li
v-for="tag in release.tags"
:key="`tag-${tag.slug}`"
class="tag"
>
<a
:href="`/tag/${tag.slug}`"
class="link"
>{{ tag.name }}</a>
</li>
</ul>
</div>
<p
v-if="release.description"
class="row description"
>
<Icon icon="info2" />
{{ release.description }}
</p>
<div
v-if="release.studio"
class="row"
>
<Icon icon="video-camera2" />
<template v-if="release.studio">
<a
v-if="release.studio"
:href="release.studio.url"
target="_blank"
rel="noopener noreferrer"
class="site-link"
>{{ release.studio.name }}</a>,
</template>
class="link"
>{{ release.studio.name }}</a>
</div>
<a
:href="`/network/${release.network.slug}`"
class="network-link"
>{{ release.network.name }}:</a>
<a
:href="`/site/${release.site.slug}`"
class="site-link"
>{{ release.site.name }}</a>
</span>
<p
v-if="release.duration"
class="row duration"
>
<Icon icon="stopwatch" />
<span
v-if="release.duration >= 3600"
class="duration-segment"
>{{ Math.floor(release.duration / 3600) }}:</span>
<span class="duration-segment">{{ Math.floor((release.duration % 3600) / 60).toString().padStart(2, '0') }}:</span>
<span class="duration-segment">{{ (release.duration % 60).toString().padStart(2, '0') }}</span>
</p>
<p
v-if="release.description"
class="row description"
>
<Icon icon="info2" />
{{ release.description }}
</p>
<ul
v-if="release.tags.length > 0"
class="row tags"
>
<Icon icon="price-tags" />
<li
v-for="tag in release.tags"
:key="`tag-${tag.slug}`"
class="tag"
>
<a
:href="`/tag/${tag.slug}`"
class="tag-link"
>{{ tag.name }}</a>
</li>
</ul>
<span class="row">
<Icon icon="drawer-in" />
<a
:href="`/added/${formatDate(release.dateAdded, 'YYYY-MM-DD')}`"
:title="`Added on ${formatDate(release.dateAdded, 'MMMM D, YYYY')}`"
v-if="release.shootId"
:href="release.url"
:title="`release.shootId`"
target="_blank"
rel="noopener noreferrer"
class="date date-link"
>{{ formatDate(release.dateAdded, 'MMMM D, YYYY') }}</a>
</span>
class="row shoot showable"
>
<Icon icon="clapboard-play" />{{ release.shootId }}
</a>
<div
v-if="release.duration"
class="row duration showable"
>
<Icon icon="stopwatch" />
<span
v-if="release.duration >= 3600"
class="duration-segment"
>{{ Math.floor(release.duration / 3600) }}:</span>
<span class="duration-segment">{{ Math.floor((release.duration % 3600) / 60).toString().padStart(2, '0') }}:</span>
<span class="duration-segment">{{ (release.duration % 60).toString().padStart(2, '0') }}</span>
</div>
<span class="row">
<Icon icon="drawer-in" />
<a
:href="`/added/${formatDate(release.dateAdded, 'YYYY-MM-DD')}`"
:title="`Added on ${formatDate(release.dateAdded, 'MMMM D, YYYY')}`"
target="_blank"
rel="noopener noreferrer"
class="link added"
>{{ formatDate(release.dateAdded, 'MMMM D, YYYY') }}</a>
</span>
</div>
</div>
</template>
<script>
import Actor from '../tile/actor.vue';
import Banner from './banner.vue';
function pageTitle() {
@ -128,6 +204,7 @@ async function mounted() {
export default {
components: {
Actor,
Banner,
},
data() {
@ -144,33 +221,99 @@ export default {
<style lang="scss" scoped>
@import 'theme';
.row {
display: block;
.column {
width: 1200px;
max-width: 100%;
padding: 0 1rem;
margin: 0 0 .5rem 0;
margin: 0 auto;
box-sizing: border-box;
}
.row {
display: flex;
align-items: center;
margin: 0 0 1rem 0;
.icon {
display: inline-block;
width: 1rem;
fill: $shadow-strong;
margin: 0 .5rem 0 0;
margin: 0 1rem 0 0;
}
}
.actors,
.tags {
list-style: none;
.info {
background: $background;
margin: 0 0 1.5rem 0;
box-shadow: 0 0 3px $shadow-weak;
cursor: default;
.column {
display: flex;
align-items: center;
padding: 0 1rem;
}
}
.actor,
.tag {
.tidbit {
display: inline-block;
text-transform: capitalize;
height: 100%;
&:not(:last-child)::after {
content: ',';
display: inline-block;
width: .6rem;
&:not(:last-child) {
border-right: solid 1px $shadow-hint;
}
.icon {
fill: $shadow-strong;
margin: 0 .25rem 0 0;
}
&.date,
&.duration,
&.shoot {
padding: 1.25rem 1rem 1.25rem 0;
margin: 0 1rem 0 0;
}
}
.site {
display: inline-flex;
flex-grow: 1;
align-items: center;
justify-content: flex-end;
padding: .25rem 0;
font-size: 0;
}
.logo {
display: inline-block;
}
.logo-site {
height: 3rem;
max-width: 15rem;
object-fit: contain;
}
.logo-network {
height: 1.5rem;
max-width: 10rem;
object-fit: contain;
}
.chain {
color: $shadow;
padding: 0 .5rem;
font-weight: bold;
font-size: .8rem;
}
.title {
margin: 0 0 1.5rem 0;
}
.description {
line-height: 1.25;
}
.duration {
@ -181,16 +324,56 @@ export default {
font-size: 1rem;
}
.date-link,
.site-link,
.network-link,
.actor-link,
.tag-link {
.link {
display: inline-block;
color: $link;
text-decoration: none;
&:hover {
color: $primary;
.icon {
fill: $primary;
}
}
}
.tag .link {
background: $background;
display: inline-block;
padding: .5rem;
margin: 0 .25rem .25rem 0;
box-shadow: 0 0 2px $shadow-weak;
text-decoration: none;
text-transform: capitalize;
&:hover {
color: $primary;
}
}
.showable {
display: none;
}
@media(max-width: $breakpoint3) {
.logo-network,
.chain {
display: none;
}
}
@media(max-width: $breakpoint) {
.hideable {
display: none;
}
.showable {
display: block;
}
.logo-site {
max-width: 10rem;
}
}
</style>

View File

@ -5,7 +5,10 @@
>
<div class="header">
<span>
<h2 class="title">{{ tag.name }}</h2>
<h2 class="title">
<Icon icon="price-tag4" />
{{ tag.name }}
</h2>
<span class="description">{{ tag.description }}</span>
</span>
@ -64,6 +67,11 @@ export default {
display: inline-block;
margin: 0 .5rem 0 0;
text-transform: capitalize;
.icon {
width: 1.25rem;
height: 1.25rem;
}
}
.heading {

View File

@ -0,0 +1,40 @@
<template>
<div
v-if="actor"
class="actor"
>
<a
:href="`/actor/${actor.slug}`"
class="name"
>{{ actor.name }}</a>
</div>
</template>
<script>
export default {
props: {
actor: {
type: Object,
default: null,
},
},
};
</script>
<style lang="scss" scoped>
@import 'theme';
.actor {
background: $background;
display: inline-block;
margin: 0 .25rem .25rem 0;
box-shadow: 0 0 3px $shadow-weak;
}
.name {
color: $link;
display: inline-block;
padding: .5rem;
text-decoration: none;
}
</style>

View File

@ -3,6 +3,13 @@
<span class="banner">
<span class="details">
<a
v-if="release.site.independent"
:href="`/network/${release.network.slug}`"
class="site site-link"
>{{ release.network.name }}</a>
<a
v-else
v-tooltip.bottom="`Part of ${release.network.name}`"
:title="`Part of ${release.network.name}`"
:href="`/site/${release.site.slug}`"
@ -120,9 +127,8 @@ export default {
flex-direction: column;
box-sizing: border-box;
padding: 0 0 .5rem 0;
border-radius: .25rem;
overflow: hidden;
box-shadow: 0 0 3px rgba(0, 0, 0, .25);
box-shadow: 0 0 3px $shadow-weak;
height: 100%;
}
@ -151,7 +157,7 @@ export default {
align-items: center;
box-sizing: border-box;
padding: 0 .5rem;
margin: 0 0 .5rem 0;
margin: 0 0 .25rem 0;
}
.details {
@ -172,14 +178,9 @@ export default {
}
.site {
border-radius: 0 0 .25rem 0;
font-weight: bold;
}
.date {
border-radius: 0 0 0 .25rem;
}
.info {
display: flex;
flex-direction: column;
@ -209,12 +210,12 @@ export default {
.actors {
word-wrap: break-word;
overflow: hidden;
max-height: 2.5rem;
line-height: 1.25rem;
max-height: 2.75rem;
line-height: 1.5rem;
}
.tags {
max-height: 2.5rem;
max-height: 2.85rem;
padding: .25rem .5rem 1rem .5rem;
line-height: 1.25rem;
word-wrap: break-word;
@ -226,7 +227,7 @@ export default {
}
.tag {
margin: 0 .25rem .5rem 0;
margin: 0 .25rem .25rem 0;
}
.actor:not(:last-of-type)::after {
@ -247,8 +248,8 @@ export default {
.tag-link {
color: $shadow;
display: inline-block;
padding: .25rem;
border-radius: .25rem;
box-shadow: 0 0 2px $shadow-weak;
font-size: .75rem;
font-weight: bold;

View File

@ -27,6 +27,7 @@ export default {
@import 'theme';
.tile {
background: $background;
display: flex;
flex-direction: column;
align-items: center;

View File

@ -5,3 +5,15 @@
-ms-user-select: none;
-webkit-tap-highlight-color: transparent;
}
.nolist {
list-style: none;
padding: 0;
margin: 0;
li {
display: inline-block;
padding: 0;
margin: 0;
}
}

View File

@ -1,5 +1,7 @@
/* $primary: #ff886c; */
$breakpoint: 720px;
$breakpoint2: 900px;
$breakpoint3: 1200px;
$primary: #ff6c88;
$background: #fff;

5
assets/img/key.svg Normal file
View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>key</title>
<path d="M11 0c-2.761 0-5 2.239-5 5 0 0.313 0.029 0.619 0.084 0.916l-6.084 6.084v3c0 0.552 0.448 1 1 1h1v-1h2v-2h2v-2h2l1.298-1.298c0.531 0.192 1.105 0.298 1.702 0.298 2.761 0 5-2.239 5-5s-2.239-5-5-5zM12.498 5.002c-0.828 0-1.5-0.672-1.5-1.5s0.672-1.5 1.5-1.5 1.5 0.672 1.5 1.5-0.672 1.5-1.5 1.5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 463 B

5
assets/img/key2.svg Normal file
View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>key2</title>
<path d="M15.658 4.91l-1.58-1.58c-0.387-0.387-1.021-1.021-1.409-1.409l-1.58-1.58c-0.387-0.387-1.077-0.456-1.533-0.152l-4.319 2.88c-0.456 0.304-0.628 0.954-0.383 1.444l1.101 2.203c0.034 0.067 0.073 0.139 0.115 0.213l-5.571 5.571-0.5 3.5h3v-1h2v-2h2v-2h2v-1.112c0.1 0.060 0.196 0.113 0.284 0.157l2.203 1.101c0.49 0.245 1.14 0.072 1.444-0.383l2.88-4.319c0.304-0.456 0.236-1.146-0.152-1.533zM2.354 13.354l-0.707-0.707 4.868-4.868 0.707 0.707-4.868 4.868zM14.328 6.621l-0.707 0.707c-0.194 0.194-0.513 0.194-0.707 0l-4.243-4.243c-0.194-0.194-0.194-0.513 0-0.707l0.707-0.707c0.194-0.194 0.513-0.194 0.707 0l4.243 4.243c0.194 0.194 0.194 0.513 0 0.707z"></path>
</svg>

After

Width:  |  Height:  |  Size: 812 B

5
assets/img/key5.svg Normal file
View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>key5</title>
<path d="M15 6h-7.535c-0.692-1.196-1.984-2-3.465-2-2.209 0-4 1.791-4 4s1.791 4 4 4c1.481 0 2.773-0.804 3.465-2h0.535l1-1h1v1h1l1-1h1v1h1l2-2-1-2zM3 9.414c-0.781 0-1.414-0.633-1.414-1.414s0.633-1.414 1.414-1.414 1.414 0.633 1.414 1.414c0 0.781-0.633 1.414-1.414 1.414zM8 7.5v-0.5h6l0.25 0.5h-6.25z"></path>
</svg>

After

Width:  |  Height:  |  Size: 464 B

5
assets/img/lock.svg Normal file
View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>lock</title>
<path d="M14 6h-1v-5c0-0.55-0.45-1-1-1h-8c-0.55 0-1 0.45-1 1v5h-1c-0.55 0-1 0.45-1 1v8c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1v-8c0-0.55-0.45-1-1-1zM9 13h-2l0.435-2.175c-0.263-0.18-0.435-0.482-0.435-0.825 0-0.552 0.448-1 1-1s1 0.448 1 1c0 0.343-0.172 0.645-0.435 0.825l0.435 2.175zM11 6h-6v-4h6v4z"></path>
</svg>

After

Width:  |  Height:  |  Size: 464 B

5
assets/img/new.svg Normal file
View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>new</title>
<path d="M14 3h-12c-1.1 0-2 0.9-2 2v7c0 1.1 0.9 2 2 2h12c1.1 0 2-0.9 2-2v-7c0-1.1-0.9-2-2-2zM5 11h-1l-2-3.333v3.333h-1v-5h1l2 3.333v-3.333h1v5zM9 7h-2v1h2v1h-2v1h2v1l-3 0v-5h3v1zM15 11h-1.5l-1-2-1 2h-1.5v-5h1v4l1-2h1l1 2v-4h1v5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 395 B

View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>price-tag2</title>
<path d="M15.25 0h-6c-0.412 0-0.989 0.239-1.28 0.53l-7.439 7.439c-0.292 0.292-0.292 0.769 0 1.061l6.439 6.439c0.292 0.292 0.769 0.292 1.061 0l7.439-7.439c0.292-0.292 0.53-0.868 0.53-1.28v-6c0-0.412-0.338-0.75-0.75-0.75zM11.5 6c-0.828 0-1.5-0.672-1.5-1.5s0.672-1.5 1.5-1.5 1.5 0.672 1.5 1.5-0.672 1.5-1.5 1.5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 482 B

View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>price-tag4</title>
<path d="M15.47 7.97l-4.439-4.439c-0.292-0.292-0.868-0.53-1.28-0.53h-9c-0.412 0-0.75 0.337-0.75 0.75v9.5c0 0.412 0.338 0.75 0.75 0.75h9c0.412 0 0.989-0.239 1.28-0.53l4.439-4.439c0.292-0.292 0.292-0.769-0-1.061zM10.5 10c-0.828 0-1.5-0.672-1.5-1.5s0.672-1.5 1.5-1.5 1.5 0.672 1.5 1.5-0.672 1.5-1.5 1.5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 474 B

View File

@ -0,0 +1,6 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="18" height="16" viewBox="0 0 18 16">
<title>price-tags3</title>
<path d="M17.47 9.97l-4.439-4.439c-0.292-0.292-0.868-0.53-1.28-0.53h-9c-0.413 0-0.75 0.338-0.75 0.75v9.5c0 0.412 0.337 0.75 0.75 0.75h9c0.412 0 0.989-0.239 1.28-0.53l4.439-4.439c0.292-0.292 0.292-0.769-0-1.061zM12.5 12c-0.828 0-1.5-0.672-1.5-1.5s0.672-1.5 1.5-1.5 1.5 0.672 1.5 1.5-0.672 1.5-1.5 1.5z"></path>
<path d="M1 4h10.5l-0.47-0.47c-0.292-0.292-0.868-0.53-1.28-0.53h-9c-0.412 0-0.75 0.337-0.75 0.75v9.5c0 0.412 0.338 0.75 0.75 0.75h0.25v-10z"></path>
</svg>

After

Width:  |  Height:  |  Size: 624 B

8
assets/img/user6.svg Normal file
View File

@ -0,0 +1,8 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>user6</title>
<path d="M11.5 5.5c0 2.485-1.567 4.5-3.5 4.5s-3.5-2.015-3.5-4.5c0-2.485 1.567-4.5 3.5-4.5s3.5 2.015 3.5 4.5z"></path>
<path d="M7 8.922h2v2.078h-2v-2.078z"></path>
<path d="M1 12c0-1.105 3.134-2 7-2s7 0.895 7 2z"></path>
<path d="M1 12h14v2h-14v-2z"></path>
</svg>

After

Width:  |  Height:  |  Size: 417 B

7
assets/img/users4.svg Normal file
View File

@ -0,0 +1,7 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="22" height="16" viewBox="0 0 22 16">
<title>users4</title>
<path d="M12 11.020v-0.207c1.446-0.553 2.5-2.275 2.5-4.313 0-2.485-1.567-4.5-3.5-4.5s-3.5 2.015-3.5 4.5c0 2.038 1.054 3.76 2.5 4.313v0.207c-3.392 0.139-6 0.972-6 1.98v2h14v-2c0-1.008-2.608-1.841-6-1.98z"></path>
<path d="M18 7.009v-0.079c1.141-0.324 2-1.737 2-3.43 0-1.933-1.119-3.5-2.5-3.5s-2.5 1.567-2.5 3.5c0 1.693 0.859 3.106 2 3.43v0.079c-0.497 0.018-0.97 0.064-1.404 0.131-0.098 1.066-0.439 2.051-0.965 2.859h7.369v-1.5c0-0.772-1.75-1.408-4-1.491z"></path>
<path d="M6.404 7.141c-0.435-0.068-0.907-0.113-1.404-0.131v-0.079c1.141-0.324 2-1.737 2-3.43 0-1.933-1.119-3.5-2.5-3.5s-2.5 1.567-2.5 3.5c0 1.693 0.859 3.106 2 3.43v0.079c-2.25 0.083-4 0.719-4 1.491v1.5h7.369c-0.526-0.809-0.867-1.794-0.965-2.859z"></path>
</svg>

After

Width:  |  Height:  |  Size: 879 B

5
assets/img/vcard.svg Normal file
View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>vcard</title>
<path d="M14 3h-12c-1.1 0-2 0.9-2 2v7c0 1.1 0.9 2 2 2h12c1.1 0 2-0.9 2-2v-7c0-1.1-0.9-2-2-2zM2 12c0-2.209 1.119-4 2.5-4-0.828 0-1.5-0.672-1.5-1.5s0.672-1.5 1.5-1.5 1.5 0.672 1.5 1.5-0.672 1.5-1.5 1.5c1.381 0 2.5 1.791 2.5 4h-5zM14 12h-5v-1h5v1zM14 10h-5v-1h5v1zM14 8h-5v-1h5v1z"></path>
</svg>

After

Width:  |  Height:  |  Size: 446 B

View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>video-camera2</title>
<path d="M15.294 4.004c-0.165 0-0.335 0.058-0.491 0.168l-2.803 1.978v-1.651c0-0.825-0.675-1.5-1.5-1.5h-9c-0.825 0-1.5 0.675-1.5 1.5v7c0 0.825 0.675 1.5 1.5 1.5h9c0.825 0 1.5-0.675 1.5-1.5v-1.65l2.803 1.978c0.156 0.11 0.326 0.168 0.491 0.168 0 0 0 0 0 0 0.22 0 0.421-0.101 0.551-0.278 0.101-0.137 0.154-0.313 0.154-0.51v-6.415c-0-0.518-0.355-0.788-0.706-0.788z"></path>
</svg>

After

Width:  |  Height:  |  Size: 536 B

View File

@ -24,7 +24,6 @@
padding: .5rem;
margin: 0 .25rem;
border: solid 1px transparent;
border-radius: .5rem;
font-size: .9rem;
font-weight: bold;
cursor: pointer;
@ -76,9 +75,8 @@
flex-direction: column;
box-sizing: border-box;
padding: 0 0 .5rem 0;
border-radius: .25rem;
overflow: hidden;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.25);
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
height: 100%;
}
.banner[data-v-3abcf101] {
@ -105,7 +103,7 @@
align-items: center;
box-sizing: border-box;
padding: 0 .5rem;
margin: 0 0 .5rem 0;
margin: 0 0 .25rem 0;
}
.details[data-v-3abcf101] {
width: 100%;
@ -123,12 +121,8 @@
text-decoration: none;
}
.site[data-v-3abcf101] {
border-radius: 0 0 .25rem 0;
font-weight: bold;
}
.date[data-v-3abcf101] {
border-radius: 0 0 0 .25rem;
}
.info[data-v-3abcf101] {
display: flex;
flex-direction: column;
@ -154,11 +148,11 @@
.actors[data-v-3abcf101] {
word-wrap: break-word;
overflow: hidden;
max-height: 2.5rem;
line-height: 1.25rem;
max-height: 2.75rem;
line-height: 1.5rem;
}
.tags[data-v-3abcf101] {
max-height: 2.5rem;
max-height: 2.85rem;
padding: .25rem .5rem 1rem .5rem;
line-height: 1.25rem;
word-wrap: break-word;
@ -168,7 +162,7 @@
margin: 0 .25rem 0 0;
}
.tag[data-v-3abcf101] {
margin: 0 .25rem .5rem 0;
margin: 0 .25rem .25rem 0;
}
.actor[data-v-3abcf101]:not(:last-of-type)::after {
content: ",";
@ -184,8 +178,8 @@
}
.tag-link[data-v-3abcf101] {
color: rgba(0, 0, 0, 0.5);
display: inline-block;
padding: .25rem;
border-radius: .25rem;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
font-size: .75rem;
font-weight: bold;
@ -195,13 +189,26 @@
color: #ff6c88;
}
/* $primary: #ff886c; */
.actor[data-v-6989dc6f] {
background: #fff;
display: inline-block;
margin: 0 .25rem .25rem 0;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
}
.name[data-v-6989dc6f] {
color: #cc4466;
display: inline-block;
padding: .5rem;
text-decoration: none;
}
/* $primary: #ff886c; */
.banner[data-v-cbb14462] {
background: #222;
flex-shrink: 0;
white-space: nowrap;
overflow-x: auto;
margin: 0 0 1rem 0;
scrollbar-width: none;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
font-size: 0;
@ -217,35 +224,90 @@
max-width: 100%;
}
.item[data-v-cbb14462] {
height: 100%;
max-height: 18rem;
vertical-align: middle;
}
/* $primary: #ff886c; */
.row[data-v-2bc41e74] {
display: block;
.column[data-v-2bc41e74] {
width: 1200px;
max-width: 100%;
padding: 0 1rem;
margin: 0 0 .5rem 0;
margin: 0 auto;
box-sizing: border-box;
}
.row[data-v-2bc41e74] {
display: flex;
align-items: center;
margin: 0 0 1rem 0;
}
.row .icon[data-v-2bc41e74] {
display: inline-block;
width: 1rem;
fill: rgba(0, 0, 0, 0.7);
margin: 0 .5rem 0 0;
margin: 0 1rem 0 0;
}
.actors[data-v-2bc41e74],
.tags[data-v-2bc41e74] {
list-style: none;
.info[data-v-2bc41e74] {
background: #fff;
margin: 0 0 1.5rem 0;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
cursor: default;
}
.actor[data-v-2bc41e74],
.tag[data-v-2bc41e74] {
.info .column[data-v-2bc41e74] {
display: flex;
align-items: center;
padding: 0 1rem;
}
.tidbit[data-v-2bc41e74] {
display: inline-block;
text-transform: capitalize;
height: 100%;
}
.actor[data-v-2bc41e74]:not(:last-child)::after,
.tag[data-v-2bc41e74]:not(:last-child)::after {
content: ',';
display: inline-block;
width: .6rem;
.tidbit[data-v-2bc41e74]:not(:last-child) {
border-right: solid 1px rgba(0, 0, 0, 0.1);
}
.tidbit .icon[data-v-2bc41e74] {
fill: rgba(0, 0, 0, 0.7);
margin: 0 .25rem 0 0;
}
.tidbit.date[data-v-2bc41e74], .tidbit.duration[data-v-2bc41e74], .tidbit.shoot[data-v-2bc41e74] {
padding: 1.25rem 1rem 1.25rem 0;
margin: 0 1rem 0 0;
}
.site[data-v-2bc41e74] {
display: inline-flex;
flex-grow: 1;
align-items: center;
justify-content: flex-end;
padding: .25rem 0;
font-size: 0;
}
.logo[data-v-2bc41e74] {
display: inline-block;
}
.logo-site[data-v-2bc41e74] {
height: 3rem;
max-width: 15rem;
-o-object-fit: contain;
object-fit: contain;
}
.logo-network[data-v-2bc41e74] {
height: 1.5rem;
max-width: 10rem;
-o-object-fit: contain;
object-fit: contain;
}
.chain[data-v-2bc41e74] {
color: rgba(0, 0, 0, 0.5);
padding: 0 .5rem;
font-weight: bold;
font-size: .8rem;
}
.title[data-v-2bc41e74] {
margin: 0 0 1.5rem 0;
}
.description[data-v-2bc41e74] {
line-height: 1.25;
}
.duration[data-v-2bc41e74] {
font-size: 0;
@ -253,21 +315,49 @@
.duration-segment[data-v-2bc41e74] {
font-size: 1rem;
}
.date-link[data-v-2bc41e74],
.site-link[data-v-2bc41e74],
.network-link[data-v-2bc41e74],
.actor-link[data-v-2bc41e74],
.tag-link[data-v-2bc41e74] {
.link[data-v-2bc41e74] {
display: inline-block;
color: #cc4466;
text-decoration: none;
}
.date-link[data-v-2bc41e74]:hover,
.site-link[data-v-2bc41e74]:hover,
.network-link[data-v-2bc41e74]:hover,
.actor-link[data-v-2bc41e74]:hover,
.tag-link[data-v-2bc41e74]:hover {
.link[data-v-2bc41e74]:hover {
color: #ff6c88;
}
.link:hover .icon[data-v-2bc41e74] {
fill: #ff6c88;
}
.tag .link[data-v-2bc41e74] {
background: #fff;
display: inline-block;
padding: .5rem;
margin: 0 .25rem .25rem 0;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
text-decoration: none;
text-transform: capitalize;
}
.tag .link[data-v-2bc41e74]:hover {
color: #ff6c88;
}
.showable[data-v-2bc41e74] {
display: none;
}
@media (max-width: 1200px) {
.logo-network[data-v-2bc41e74],
.chain[data-v-2bc41e74] {
display: none;
}
}
@media (max-width: 720px) {
.hideable[data-v-2bc41e74] {
display: none;
}
.showable[data-v-2bc41e74] {
display: block;
}
.logo-site[data-v-2bc41e74] {
max-width: 10rem;
}
}
/* $primary: #ff886c; */
.header[data-v-3e57cf44] {
@ -327,6 +417,7 @@
/* $primary: #ff886c; */
.tile[data-v-f4958086] {
background: #fff;
display: flex;
flex-direction: column;
align-items: center;
@ -431,6 +522,10 @@
margin: 0 .5rem 0 0;
text-transform: capitalize;
}
.title .icon[data-v-80991bcc] {
width: 1.25rem;
height: 1.25rem;
}
.heading[data-v-80991bcc] {
padding: 0;
margin: 0 0 1rem 0;
@ -471,6 +566,15 @@
-ms-user-select: none;
-webkit-tap-highlight-color: transparent; }
.nolist {
list-style: none;
padding: 0;
margin: 0; }
.nolist li {
display: inline-block;
padding: 0;
margin: 0; }
.tooltip {
display: block !important;
z-index: 10000; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 138 KiB

View File

@ -1000,6 +1000,7 @@ function getSites(networksMap) {
name: 'Jules Jordan',
url: 'https://www.julesjordan.com',
description: 'Jules Jordan\'s Official Membership Site',
parameters: JSON.stringify({ independent: true }),
network_id: networksMap['julesjordan'],
},
// KINK
@ -1233,6 +1234,7 @@ function getSites(networksMap) {
name: 'LegalPorno',
url: 'https://www.legalporno.com',
description: 'The Best HD Porn For You!',
parameters: JSON.stringify({ independent: true }),
network_id: networksMap['legalporno'],
},
{

View File

@ -131,6 +131,7 @@ function getTags(groupsMap) {
{
name: 'ass to mouth',
slug: 'ass-to-mouth',
priority: 8,
alias_for: null,
},
{
@ -411,6 +412,7 @@ function getTags(groupsMap) {
{
name: 'gay',
slug: 'gay',
priority: 10,
alias_for: null,
},
{
@ -761,6 +763,7 @@ function getTags(groupsMap) {
{
name: 'transsexual',
slug: 'transsexual',
priority: 10,
alias_for: null,
},
{

View File

@ -2,11 +2,11 @@
const knex = require('./knex');
const whereOr = require('./utils/where-or');
const { fetchSites } = require('./sites');
async function curateNetwork(network) {
const [sites, studios] = await Promise.all([
knex('sites')
.where({ network_id: network.id }),
fetchSites({ network_id: network.id }),
knex('studios')
.where({ network_id: network.id }),
]);
@ -17,20 +17,7 @@ async function curateNetwork(network) {
url: network.url,
description: network.description,
slug: network.slug,
sites: sites.map(site => ({
id: site.id,
name: site.name,
url: site.url,
description: site.description,
slug: site.slug,
network: {
id: network.id,
name: network.name,
url: network.url,
description: network.description,
slug: network.slug,
},
})),
sites,
studios: studios.map(studio => ({
id: studio.id,
name: studio.name,

View File

@ -42,6 +42,9 @@ async function curateRelease(release) {
site: {
id: release.site_id,
name: release.site_name,
independent: release.site_parameters
? (JSON.parse(release.site_parameters).independent || false)
: false,
slug: release.site_slug,
url: release.site_url,
},
@ -56,6 +59,7 @@ async function curateRelease(release) {
network: {
id: release.network_id,
name: release.network_name,
description: release.network_description,
slug: release.network_slug,
url: release.network_url,
},
@ -75,9 +79,9 @@ async function fetchReleases(releaseId, filter = []) {
.leftJoin('networks', 'sites.network_id', 'networks.id')
.select(
'releases.*',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id', 'sites.parameters as site_parameters',
'studios.name as studio_name', 'sites.slug as site_slug', 'studios.url as studio_url',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url', 'networks.description as network_description',
)
.whereNotExists((builder) => {
// apply filters
@ -101,7 +105,7 @@ async function fetchSiteReleases(siteId, siteSlug) {
.orWhere({ 'sites.slug': siteSlug })
.select(
'releases.*',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id', 'sites.parameters as site_parameters',
'studios.name as studio_name', 'sites.slug as site_slug', 'studios.url as studio_url',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',
)
@ -120,7 +124,7 @@ async function fetchNetworkReleases(networkId, networkSlug) {
.orWhere({ 'networks.slug': networkSlug })
.select(
'releases.*',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id', 'sites.parameters as site_parameters',
'studios.name as studio_name', 'sites.slug as site_slug', 'studios.url as studio_url',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',
)
@ -140,7 +144,7 @@ async function fetchActorReleases(actorId, actorSlug) {
.select(
'releases.*',
'actors.name as actor_name',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id', 'sites.parameters as site_parameters',
'studios.name as studio_name', 'sites.slug as site_slug', 'studios.url as studio_url',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',
)

View File

@ -104,10 +104,10 @@ async function scrapeScene(html, url, site) {
const siteSlug = document.querySelector('.site-name').textContent.split('.')[0].toLowerCase();
const date = new Date(document.querySelector('meta[itemprop="uploadDate"]').content);
const duration = moment
.duration(document
.duration(`00:${document
.querySelectorAll('.extra-info p')[1]
.textContent
.match(/\d+:\d+$/)[0])
.match(/\d+:\d+$/)[0]}`)
.asSeconds();
const trailerElement = document.querySelector('.html5-video');

View File

@ -4,15 +4,19 @@ const knex = require('./knex');
const whereOr = require('./utils/where-or');
async function curateSite(site) {
const parameters = JSON.parse(site.parameters);
return {
id: site.id,
name: site.name,
url: site.url,
description: site.description,
slug: site.slug,
independent: !!parameters && parameters.independent,
network: {
id: site.network_id,
name: site.network_name,
description: site.network_description,
slug: site.network_slug,
url: site.network_url,
},
@ -28,7 +32,7 @@ async function fetchSites(queryObject) {
.where(builder => whereOr(queryObject, 'sites', builder))
.select(
'sites.*',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url', 'networks.description as networks_description',
)
.leftJoin('networks', 'sites.network_id', 'networks.id')
.limit(100);