Compare commits

..

5 Commits

Author SHA1 Message Date
DebaucheryLibrarian 6584a46d53 1.119.0 2020-07-15 05:12:43 +02:00
DebaucheryLibrarian 5b886b3917 Improved actor extraction for fcuk scraper. Changed 'copyright' to 'credit'. Redused entity page favicon size. 2020-07-15 05:12:29 +02:00
DebaucheryLibrarian c62df2228b Added scraper for FCUK's coed sites. 2020-07-15 04:51:39 +02:00
DebaucheryLibrarian 17b3ba1272 Added partial 'fcuk' (Exploited College Girls) scraper. Added file parameter for actor names and scene URLs. 2020-07-15 03:24:47 +02:00
DebaucheryLibrarian eca54c2a09 Improved sidebar design, added sfw and theme toggles. 2020-07-15 00:15:00 +02:00
99 changed files with 589 additions and 156 deletions

View File

@ -43,7 +43,7 @@
> >
<img <img
:src="sfw ? `/img/${actor.avatar.sfw.thumbnail}` : `/media/${actor.avatar.thumbnail}`" :src="sfw ? `/img/${actor.avatar.sfw.thumbnail}` : `/media/${actor.avatar.thumbnail}`"
:title="actor.avatar.copyright && `© ${actor.avatar.copyright}`" :title="actor.avatar.credit && `© ${actor.avatar.credit}`"
class="avatar" class="avatar"
> >
</a> </a>

View File

@ -33,6 +33,13 @@
replace replace
><Icon icon="question5" /></router-link> ><Icon icon="question5" /></router-link>
</li> </li>
<li class="gender">
<router-link
:to="{ name: 'actors', params: { gender: 'all', letter, pageNumber: 1 } }"
:class="{ selected: gender === 'all' }"
class="gender-link all"
>all</router-link>
</li>
</ul> </ul>
<ul class="letters nolist"> <ul class="letters nolist">
@ -143,8 +150,6 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
@import 'theme';
.gender-link { .gender-link {
&.selected .gender .icon { &.selected .gender .icon {
fill: var(--text-light); fill: var(--text-light);
@ -173,7 +178,7 @@ export default {
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
@import 'theme'; @import 'breakpoints';
.actors { .actors {
display: flex; display: flex;
@ -253,13 +258,15 @@ export default {
} }
} }
@media(max-width: $breakpoint0) { @media(max-width: $breakpoint) {
.tiles {
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
}
.genders { .genders {
flex-direction: column; flex-direction: column;
} }
} }
@media(max-width: $breakpoint-micro) {
.tiles {
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
}
}
</style> </style>

View File

@ -18,7 +18,7 @@
:src="sfw ? `/img/${actor.avatar.sfw.thumbnail}` : `/media/${actor.avatar.thumbnail}`" :src="sfw ? `/img/${actor.avatar.sfw.thumbnail}` : `/media/${actor.avatar.thumbnail}`"
:data-src="sfw ? `/img/${actor.avatar.sfw.thumbnail}` : `/media/${actor.avatar.thumbnail}`" :data-src="sfw ? `/img/${actor.avatar.sfw.thumbnail}` : `/media/${actor.avatar.thumbnail}`"
:data-loading="sfw ? `/img/${actor.avatar.sfw.lazy}` : `/media/${actor.avatar.lazy}`" :data-loading="sfw ? `/img/${actor.avatar.sfw.lazy}` : `/media/${actor.avatar.lazy}`"
:title="actor.avatar.copyright && `© ${actor.avatar.copyright}`" :title="actor.avatar.credit && `© ${actor.avatar.credit}`"
class="avatar photo" class="avatar photo"
@load="$parent.$emit('load')" @load="$parent.$emit('load')"
> >
@ -36,7 +36,7 @@
:src="sfw ? `/img/${photo.sfw.thumbnail}` : `/media/${photo.thumbnail}`" :src="sfw ? `/img/${photo.sfw.thumbnail}` : `/media/${photo.thumbnail}`"
:data-src="sfw ? `/img/${photo.sfw.thumbnail}` : `/media/${photo.thumbnail}`" :data-src="sfw ? `/img/${photo.sfw.thumbnail}` : `/media/${photo.thumbnail}`"
:data-loading="sfw ? `/img/${photo.sfw.lazy}` : `/media/${photo.lazy}`" :data-loading="sfw ? `/img/${photo.sfw.lazy}` : `/media/${photo.lazy}`"
:title="`© ${photo.copyright || photo.entity.name}`" :title="`© ${photo.credit || photo.entity.name}`"
class="photo" class="photo"
@load="$parent.$emit('load')" @load="$parent.$emit('load')"
> >

View File

@ -215,11 +215,14 @@ export default {
height: 2.5rem; height: 2.5rem;
} }
.logo-parent, .logo-parent {
.favicon {
height: 1.5rem; height: 1.5rem;
} }
.favicon {
height: 1rem;
}
.name { .name {
color: var(--text-light); color: var(--text-light);
display: flex; display: flex;

View File

@ -1,11 +1,16 @@
<template> <template>
<header class="header"> <header class="header">
<div class="header-nav"> <div class="header-nav">
<Icon <div
icon="menu"
class="sidebar-toggle" class="sidebar-toggle"
@click.native.stop="toggleSidebar" @click.stop="toggleSidebar"
/> >
<Icon icon="menu" />
<div
class="logo"
v-html="logo"
/>
</div>
<router-link <router-link
to="/" to="/"
@ -68,7 +73,7 @@
<div class="header-toggles"> <div class="header-toggles">
<Icon <Icon
v-show="!sfw" v-show="!sfw"
v-tooltip="'Hit S to use SFW mode'" v-tooltip="'Hit S to enable safe mode'"
icon="flower" icon="flower"
class="toggle noselect" class="toggle noselect"
@click.native="setSfw(true)" @click.native="setSfw(true)"
@ -76,9 +81,9 @@
<Icon <Icon
v-show="sfw" v-show="sfw"
v-tooltip="'Hit N to use NSFW mode'" v-tooltip="'Hit N to disable safe mode'"
icon="flower" icon="evil2"
class="toggle active noselect" class="toggle noselect"
@click.native="setSfw(false)" @click.native="setSfw(false)"
/> />
@ -207,14 +212,27 @@ export default {
.sidebar-toggle { .sidebar-toggle {
display: none; display: none;
fill: var(--shadow-modest); height: 100%;
padding: 0 1rem;
width: 1.5rem; .logo {
height: 100%; fill: var(--primary);
padding: .5rem;
}
.icon {
display: inline-block;
fill: var(--shadow-modest);
padding: 0 1rem;
width: 1.5rem;
height: 100%;
}
&:hover { &:hover {
fill: var(--primary); cursor: pointer;
cursor: pointer;
.icon {
fill: var(--primary);
}
} }
} }
@ -335,16 +353,13 @@ export default {
} }
@media(max-width: $breakpoint-micro) { @media(max-width: $breakpoint-micro) {
.nav { .nav,
.header-logo {
display: none; display: none;
} }
.sidebar-toggle { .sidebar-toggle {
display: inline-block; display: flex;
}
.header-logo {
padding: 0 0 0 .5rem;
} }
} }

View File

@ -1,98 +1,146 @@
<template> <template>
<div <div class="sidebar-container">
class="sidebar" <div
@click.stop class="sidebar"
> @click.stop
<div class="sidebar-header"> >
<Icon <div class="sidebar-section">
icon="cross2" <div class="sidebar-header">
class="sidebar-close" <Icon
@click.native="toggleSidebar(false)" icon="cross2"
/> class="sidebar-close"
@click.native="toggleSidebar(false)"
<router-link
to="/updates"
class="logo-link"
@click.native="toggleSidebar(false)"
>
<h1 class="sidebar-logo">
<div
class="logo"
v-html="logo"
/> />
</h1>
</router-link>
</div>
<nav class="nav">
<ul class="nolist">
<li class="nav-item">
<router-link <router-link
v-slot="{ href, isActive, navigate }"
to="/updates" to="/updates"
class="logo-link"
@click.native="toggleSidebar(false)" @click.native="toggleSidebar(false)"
> >
<a <h1 class="sidebar-logo">
class="nav-link" <div
:href="href" class="logo"
:class="{ active: isActive }" v-html="logo"
@click="navigate" />
>Home</a> </h1>
</router-link> </router-link>
</li> </div>
<li class="nav-item"> <nav class="nav">
<router-link <ul class="nolist">
v-slot="{ href, isActive, navigate }" <li class="nav-item">
to="/actors" <router-link
@click.native="toggleSidebar(false)" v-slot="{ href, isActive, navigate }"
> to="/updates"
<a @click.native="toggleSidebar(false)"
class="nav-link" >
:href="href" <a
:class="{ active: isActive }" class="nav-link"
@click="navigate" :href="href"
>Actors</a> :class="{ active: isActive }"
</router-link> @click="navigate"
</li> >Home</a>
</router-link>
</li>
<li class="nav-item"> <li class="nav-item">
<router-link <router-link
v-slot="{ href, isActive, navigate }" v-slot="{ href, isActive, navigate }"
to="/networks" to="/actors"
@click.native="toggleSidebar(false)" @click.native="toggleSidebar(false)"
> >
<a <a
class="nav-link" class="nav-link"
:href="href" :href="href"
:class="{ active: isActive }" :class="{ active: isActive }"
@click="navigate" @click="navigate"
>Channels</a> >Actors</a>
</router-link> </router-link>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<router-link <router-link
v-slot="{ href, isActive, navigate }" v-slot="{ href, isActive, navigate }"
to="/tags" to="/networks"
@click.native="toggleSidebar(false)" @click.native="toggleSidebar(false)"
> >
<a <a
class="nav-link" class="nav-link"
:href="href" :href="href"
:class="{ active: isActive }" :class="{ active: isActive }"
@click="navigate" @click="navigate"
>Tags</a> >Channels</a>
</router-link> </router-link>
</li> </li>
</ul>
</nav> <li class="nav-item">
<router-link
v-slot="{ href, isActive, navigate }"
to="/tags"
@click.native="toggleSidebar(false)"
>
<a
class="nav-link"
:href="href"
:class="{ active: isActive }"
@click="navigate"
>Tags</a>
</router-link>
</li>
</ul>
</nav>
</div>
<div class="sidebar-section toggles noselect">
<label
v-show="sfw"
class="toggle"
@click="setSfw(false)"
><Icon icon="evil2" />Disable safe mode</label>
<label
v-show="!sfw"
class="toggle"
@click="setSfw(true)"
><Icon icon="flower" />Enable safe mode</label>
<label
v-show="theme === 'dark'"
class="toggle"
@click="setTheme('light')"
><Icon icon="sun" />Use light theme</label>
<label
v-show="theme === 'light'"
class="toggle"
@click="setTheme('dark')"
><Icon icon="moon" />Use dark theme</label>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex';
import logo from '../../img/logo.svg'; import logo from '../../img/logo.svg';
function sfw(state) {
return state.ui.sfw;
}
function theme(state) {
return state.ui.theme;
}
function setTheme(newTheme) {
this.$store.dispatch('setTheme', newTheme);
}
function setSfw(enabled) {
this.$store.dispatch('setSfw', enabled);
}
export default { export default {
props: { props: {
toggleSidebar: { toggleSidebar: {
@ -105,17 +153,34 @@ export default {
logo, logo,
}; };
}, },
computed: {
...mapState({
sfw,
theme,
}),
},
methods: {
setTheme,
setSfw,
},
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.sidebar-container {
height: 100%;
width: 100%;
position: absolute;
z-index: 10;
background: var(--darken-hint);
}
.sidebar { .sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between;
width: 15rem; width: 15rem;
height: 100%; height: 100%;
position: absolute;
z-index: 10;
color: var(--text); color: var(--text);
background: var(--background); background: var(--background);
box-shadow: 0 0 3px var(--darken); box-shadow: 0 0 3px var(--darken);
@ -130,13 +195,13 @@ export default {
} }
.sidebar-close { .sidebar-close {
width: 1.5rem; width: 1.25rem;
height: 100%; height: 100%;
padding: 0 1rem; padding: 0 1.125rem;
fill: var(--darken); fill: var(--shadow-modest);
&:hover { &:hover {
fill: var(--text); fill: var(--primary);
cursor: pointer; cursor: pointer;
} }
} }
@ -167,22 +232,52 @@ export default {
} }
.nav-link { .nav-link {
color: var(--shadow-strong); color: var(--shadow);
display: block; display: block;
padding: 1rem; padding: 1rem;
text-decoration: none; text-decoration: none;
font-weight: bold; font-weight: bold;
&:hover { &:hover {
color: var(--primary); color: var(--shadow-strong);
} }
&.active { &.active {
background: var(--primary); color: var(--primary);
color: var(--text-light);
} }
} }
.toggles {
border-top: solid 1px var(--shadow-hint);
margin: .5rem 0 0 0;
}
.toggle {
display: flex;
align-self: flex-end;
padding: 1rem;
color: var(--shadow);
font-weight: bold;
.icon {
fill: var(--shadow);
margin: 0 1rem 0 0;
}
&.active .icon {
fill: var(--primary);
}
&:hover {
cursor: pointer;
color: var(--shadow-strong);
&:not(.active) .icon {
fill: var(--shadow-strong);
}
}
}
.dark .sidebar { .dark .sidebar {
background: var(--profile); background: var(--profile);

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>cherry</title>
<path d="M13 6c-1.111 0-2.080 0.604-2.599 1.501-1.043-0.305-2.026-0.688-2.939-1.149-1.219-0.616-2.317-1.369-3.264-2.238-1.212-1.113-1.939-2.219-2.198-2.728v-0.385c0-0.552-0.448-1-1-1s-1 0.448-1 1 0.448 1 1 1c0.006 0 0.013-0 0.019-0 0.117 1.618 0.765 3.819 1.719 5.781 0.587 1.208 1.248 2.255 1.965 3.11 0.026 0.031 0.051 0.061 0.077 0.091-0.484 0.533-0.78 1.241-0.78 2.018 0 1.657 1.343 3 3 3s3-1.343 3-3-1.343-3-3-3c-0.52 0-1.009 0.132-1.435 0.365-0.689-0.796-1.342-1.816-1.928-3.021-0.599-1.233-1.077-2.59-1.359-3.797 0.325 0.391 0.722 0.82 1.2 1.263 1.015 0.94 2.191 1.752 3.497 2.416 0.958 0.486 1.987 0.892 3.077 1.215-0.034 0.181-0.052 0.368-0.052 0.56 0 1.657 1.343 3 3 3s3-1.343 3-3-1.343-3-3-3z"></path>
</svg>

After

Width:  |  Height:  |  Size: 873 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>cool2</title>
<path d="M8 0c-4.418 0-8 3.582-8 8s3.582 8 8 8c4.418 0 8-3.582 8-8s-3.582-8-8-8zM8 13c-0.757 0-1.475-0.169-2.118-0.47l0.518-0.864c0.49 0.214 1.031 0.334 1.6 0.334 1.456 0 2.731-0.778 3.43-1.942l0.858 0.515c-0.874 1.454-2.467 2.427-4.288 2.427zM13 6c0 0.55-0.45 1-1 1h-2c-0.55 0-1-0.45-1-1h-2c0 0.55-0.45 1-1 1h-2c-0.55 0-1-0.45-1-1v-1.5c0-0.275 0.225-0.5 0.5-0.5h3c0.275 0 0.5 0.225 0.5 0.5v0.5h2v-0.5c0-0.275 0.225-0.5 0.5-0.5h3c0.275 0 0.5 0.225 0.5 0.5v1.5z"></path>
</svg>

After

Width:  |  Height:  |  Size: 629 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>evil2</title>
<path d="M16 1c0-0.711-0.149-1.387-0.416-2-0.525 1.201-1.507 2.155-2.726 2.643-1.347-1.031-3.030-1.643-4.857-1.643s-3.51 0.613-4.857 1.643c-1.22-0.488-2.202-1.443-2.726-2.643-0.268 0.613-0.416 1.289-0.416 2 0 1.15 0.388 2.208 1.040 3.053-0.662 1.165-1.040 2.512-1.040 3.947 0 4.418 3.582 8 8 8s8-3.582 8-8c0-1.436-0.378-2.783-1.040-3.947 0.652-0.845 1.040-1.903 1.040-3.053zM9.001 5.946c0.032-0.741 0.706-1.234 1.275-1.518 0.543-0.271 1.080-0.407 1.102-0.413 0.268-0.067 0.539 0.096 0.606 0.364s-0.096 0.539-0.364 0.606c-0.275 0.070-0.602 0.189-0.89 0.334 0.166 0.179 0.268 0.418 0.268 0.681 0 0.552-0.448 1-1 1s-1-0.448-1-1c0-0.018 0.001-0.036 0.002-0.054zM4.015 4.379c0.067-0.268 0.338-0.431 0.606-0.364 0.023 0.006 0.559 0.141 1.102 0.413 0.568 0.284 1.243 0.776 1.275 1.518 0.001 0.018 0.002 0.036 0.002 0.054 0 0.552-0.448 1-1 1s-1-0.448-1-1c0-0.263 0.102-0.503 0.268-0.681-0.288-0.144-0.614-0.264-0.89-0.334-0.268-0.067-0.431-0.338-0.364-0.606zM8 13c-1.82 0-3.413-0.973-4.288-2.427l1.286-0.772c0.612 1.018 1.727 1.699 3.002 1.699s2.389-0.681 3.002-1.699l1.286 0.772c-0.874 1.454-2.467 2.427-4.288 2.427z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

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>fire</title>
<path d="M5.016 16c-1.066-2.219-0.498-3.49 0.321-4.688 0.897-1.312 1.129-2.61 1.129-2.61s0.706 0.917 0.423 2.352c1.246-1.387 1.482-3.598 1.293-4.445 2.817 1.969 4.021 6.232 2.399 9.392 8.631-4.883 2.147-12.19 1.018-13.013 0.376 0.823 0.448 2.216-0.313 2.893-1.287-4.879-4.468-5.879-4.468-5.879 0.376 2.516-1.364 5.268-3.042 7.324-0.059-1.003-0.122-1.696-0.649-2.656-0.118 1.823-1.511 3.309-1.889 5.135-0.511 2.473 0.383 4.284 3.777 6.197z"></path>
</svg>

After

Width:  |  Height:  |  Size: 606 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>grid6</title>
<path d="M0 0h7v7h-7zM9 0h7v7h-7zM0 9h7v7h-7zM9 9h7v7h-7z"></path>
</svg>

After

Width:  |  Height:  |  Size: 226 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>leaf</title>
<path d="M15.802 2.102c-1.73-1.311-4.393-2.094-7.124-2.094-3.377 0-6.129 1.179-7.549 3.235-0.667 0.965-1.036 2.109-1.097 3.398-0.054 1.148 0.139 2.418 0.573 3.784 1.482-4.444 5.622-7.923 10.395-7.923 0 0-4.466 1.175-7.274 4.816-0.002 0.002-0.039 0.048-0.103 0.136-0.564 0.754-1.055 1.612-1.423 2.583-0.623 1.482-1.2 3.515-1.2 5.965h2c0 0-0.304-1.91 0.224-4.106 0.873 0.118 1.654 0.177 2.357 0.177 1.839 0 3.146-0.398 4.115-1.252 0.868-0.765 1.347-1.794 1.854-2.882 0.774-1.663 1.651-3.547 4.198-5.002 0.146-0.083 0.24-0.234 0.251-0.402s-0.063-0.329-0.197-0.431z"></path>
</svg>

After

Width:  |  Height:  |  Size: 729 B

View File

@ -0,0 +1,7 @@
<!-- 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>menu7</title>
<path d="M1 3h14v2h-14v-2z"></path>
<path d="M1 7h14v2h-14v-2z"></path>
<path d="M1 11h14v2h-14v-2z"></path>
</svg>

After

Width:  |  Height:  |  Size: 268 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>screwdriver</title>
<path d="M15.852 12.352l-6.204-6.204c-0.345-0.345-1.2-0.067-2.043 0.617l-4.605-4.605-0.5-1.16-1.601-1-0.899 0.899 1 1.601 1.16 0.5 4.605 4.605c-0.685 0.843-0.962 1.698-0.617 2.043 0 0 0 0 0 0l6.203 6.203c0.405 0.405 1.518-0.049 2.484-1.016s1.421-2.079 1.016-2.484zM13.92 13.92c-0.116 0.116-0.268 0.174-0.42 0.174s-0.304-0.058-0.42-0.174l-5-5c-0.232-0.232-0.232-0.608 0-0.84s0.608-0.232 0.84 0l5 5c0.232 0.232 0.232 0.608 0 0.84z"></path>
</svg>

After

Width:  |  Height:  |  Size: 603 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>screwdriver2</title>
<path d="M15.852 12.352l-3.403-3.403c-0.649 0.149-1.358-0.029-1.863-0.535s-0.683-1.214-0.535-1.863l-0.403-0.403c-0.345-0.345-1.2-0.067-2.043 0.617l-4.605-4.605-0.5-1.16-1.601-1-0.899 0.899 1 1.601 1.16 0.5 4.605 4.605c-0.685 0.843-0.962 1.698-0.617 2.043 0 0 0 0 0 0l0.403 0.403c0.649-0.149 1.358 0.029 1.863 0.535s0.683 1.214 0.535 1.863l3.403 3.403c0.405 0.405 1.518-0.049 2.484-1.016s1.421-2.079 1.016-2.484zM13.92 13.92c-0.116 0.116-0.268 0.174-0.42 0.174s-0.304-0.058-0.42-0.174l-5-5c-0.232-0.232-0.232-0.608 0-0.84s0.608-0.232 0.84 0l5 5c0.232 0.232 0.232 0.608 0 0.84z"></path>
</svg>

After

Width:  |  Height:  |  Size: 751 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>skull</title>
<path d="M12.803 3.197c-1.417-1.417-3.3-2.197-5.303-2.197s-3.887 0.78-5.303 2.197-2.197 3.3-2.197 5.303c0 0.276 0.224 0.5 0.5 0.5 1.93 0 3.5 1.57 3.5 3.5v2c0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5v-2c0-0.276 0.224-0.5 0.5-0.5s0.5 0.224 0.5 0.5v3c0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5v-3c0-0.276 0.224-0.5 0.5-0.5s0.5 0.224 0.5 0.5v3c0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5v-3c0-0.276 0.224-0.5 0.5-0.5s0.5 0.224 0.5 0.5v2c0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5v-2c0-1.93 1.57-3.5 3.5-3.5 0.276 0 0.5-0.224 0.5-0.5 0-2.003-0.78-3.887-2.197-5.303zM6 7c0 0.55-0.45 1-1 1h-1c-0.55 0-1-0.45-1-1v-1c0-0.55 0.45-1 1-1h1c0.55 0 1 0.45 1 1v1zM12 7c0 0.55-0.45 1-1 1h-1c-0.55 0-1-0.45-1-1v-1c0-0.55 0.45-1 1-1h1c0.55 0 1 0.45 1 1v1z"></path>
</svg>

After

Width:  |  Height:  |  Size: 909 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>smile2</title>
<path d="M8 0c-4.418 0-8 3.582-8 8s3.582 8 8 8 8-3.582 8-8-3.582-8-8-8zM11 4c0.552 0 1 0.448 1 1s-0.448 1-1 1-1-0.448-1-1 0.448-1 1-1zM5 4c0.552 0 1 0.448 1 1s-0.448 1-1 1-1-0.448-1-1 0.448-1 1-1zM8 13c-1.82 0-3.413-0.973-4.288-2.427l1.286-0.772c0.612 1.018 1.727 1.699 3.002 1.699s2.389-0.681 3.002-1.699l1.286 0.772c-0.874 1.454-2.467 2.427-4.288 2.427z"></path>
</svg>

After

Width:  |  Height:  |  Size: 525 B

View File

@ -262,9 +262,9 @@ function initActorActions(store, router) {
letter, letter,
gender, gender,
}) { }) {
const genderFilter = gender === null const genderFilter = (gender === null && 'gender: { isNull: true }')
? 'isNull: true' || (gender === 'all' && ' ')
: `equalTo: "${gender}"`; || `gender: { equalTo: "${gender}" }`;
const { connection: { actors, totalCount } } = await graphql(` const { connection: { actors, totalCount } } = await graphql(`
query Actors( query Actors(
@ -283,9 +283,7 @@ function initActorActions(store, router) {
name: { name: {
startsWith: $letter startsWith: $letter
} }
gender: { ${genderFilter}
${genderFilter}
}
} }
) { ) {
totalCount totalCount

View File

@ -116,7 +116,7 @@ function initUiActions(_store, _router) {
thumbnail thumbnail
lazy lazy
comment comment
copyright credit
} }
birthCountry: countryByBirthCountryAlpha2 { birthCountry: countryByBirthCountryAlpha2 {
alpha2 alpha2
@ -135,7 +135,7 @@ function initUiActions(_store, _router) {
thumbnail thumbnail
lazy lazy
comment comment
copyright credit
} }
birthCountry: countryByBirthCountryAlpha2 { birthCountry: countryByBirthCountryAlpha2 {
alpha2 alpha2

View File

@ -37,7 +37,7 @@ exports.up = knex => Promise.resolve()
table.float('entropy'); table.float('entropy');
table.text('scraper', 32); table.text('scraper', 32);
table.text('copyright', 100); table.text('credit', 100);
table.text('source', 2100); table.text('source', 2100);
table.text('source_page', 2100); table.text('source_page', 2100);
@ -279,6 +279,9 @@ exports.up = knex => Promise.resolve()
table.integer('hip', 3); table.integer('hip', 3);
table.boolean('natural_boobs'); table.boolean('natural_boobs');
table.integer('penis_length', 3);
table.integer('penis_girth', 3);
table.integer('height', 3); table.integer('height', 3);
table.integer('weight', 3); table.integer('weight', 3);
table.text('eyes'); table.text('eyes');
@ -349,6 +352,9 @@ exports.up = knex => Promise.resolve()
table.integer('hip', 3); table.integer('hip', 3);
table.boolean('natural_boobs'); table.boolean('natural_boobs');
table.integer('penis_length', 3);
table.integer('penis_girth', 3);
table.integer('height', 3); table.integer('height', 3);
table.integer('weight', 3); table.integer('weight', 3);
table.text('eyes'); table.text('eyes');

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "traxxx", "name": "traxxx",
"version": "1.118.1", "version": "1.119.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "traxxx", "name": "traxxx",
"version": "1.118.1", "version": "1.119.0",
"description": "All the latest porn releases in one place", "description": "All the latest porn releases in one place",
"main": "src/app.js", "main": "src/app.js",
"scripts": { "scripts": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -180,6 +180,7 @@ const tags = [
{ {
name: 'behind the scenes', name: 'behind the scenes',
slug: 'behind-the-scenes', slug: 'behind-the-scenes',
priority: 6,
}, },
{ {
name: 'big dick', name: 'big dick',

View File

@ -139,6 +139,10 @@ const networks = [
url: 'https://www.cherrypimps.com', url: 'https://www.cherrypimps.com',
description: 'CherryPimps your premium porn site to Download and Stream the hottest and most exclusive 4K HD videos and pictures on your phone, tablet, TV or console.', description: 'CherryPimps your premium porn site to Download and Stream the hottest and most exclusive 4K HD videos and pictures on your phone, tablet, TV or console.',
}, },
{
slug: 'fcuk',
name: 'Fcuk',
},
{ {
slug: 'freeones', slug: 'freeones',
name: 'FreeOnes', name: 'FreeOnes',

View File

@ -2085,6 +2085,66 @@ const sites = [
url: 'https://www.freeones.com', url: 'https://www.freeones.com',
parent: 'freeones', parent: 'freeones',
}, },
// FCUK
{
name: 'Exploited College Girls',
slug: 'exploitedcollegegirls',
alias: ['excogi', 'ecg'],
url: 'https://exploitedcollegegirls.com',
parent: 'fcuk',
parameters: {
blog: true,
},
},
{
name: 'Backroom Casting Couch',
slug: 'backroomcastingcouch',
url: 'https://backroomcastingcouch.com',
parent: 'fcuk',
parameters: {
blog: true,
},
},
{
name: 'Black Ambush',
slug: 'blackambush',
alias: ['interracial', 'bbc'],
url: 'https://blackambush.com',
parent: 'fcuk',
parameters: {
blog: true,
},
},
{
name: 'Nebraska Coeds',
slug: 'nebraskacoeds',
url: 'https://nebraskacoeds.com',
parent: 'fcuk',
},
{
name: 'South Beach Coeds',
slug: 'southbeachcoeds',
url: 'https://southbeachcoeds.com',
parent: 'fcuk',
},
{
name: 'Spring Break Life',
slug: 'springbreaklife',
url: 'https://springbreaklife.com',
parent: 'fcuk',
},
{
name: 'Euro Coeds',
slug: 'eurocoeds',
url: 'https://eurocoeds.com',
parent: 'fcuk',
},
{
name: 'After Hours Exposed',
slug: 'afterhoursexposed',
url: 'https://afterhoursexposed.com',
parent: 'fcuk',
},
// FOR BONDAGE // FOR BONDAGE
{ {
name: 'Crowd Bondage', name: 'Crowd Bondage',

View File

@ -571,7 +571,7 @@ const sfw = Object.entries({
['iFBIdX54BOk', 'Keagan Henman'], ['iFBIdX54BOk', 'Keagan Henman'],
], ],
}) })
.map(([category, photos]) => photos.map(([photo, copyright], index) => ({ .map(([category, photos]) => photos.map(([photo, credit], index) => ({
id: photo, id: photo,
path: `sfw/${category}/${photo}.jpeg`, path: `sfw/${category}/${photo}.jpeg`,
thumbnail: `sfw/${category}/thumbs/${photo}.jpeg`, thumbnail: `sfw/${category}/thumbs/${photo}.jpeg`,
@ -580,8 +580,7 @@ const sfw = Object.entries({
sfw_media_id: null, sfw_media_id: null,
group: category, group: category,
index, index,
copyright, credit,
comment: `Courtesy of ${copyright}`,
}))) })))
.flat(); .flat();

View File

@ -10,6 +10,7 @@ const fetchUpdates = require('./updates');
const { fetchScenes, fetchMovies } = require('./deep'); const { fetchScenes, fetchMovies } = require('./deep');
const { storeReleases, updateReleasesSearch } = require('./store-releases'); const { storeReleases, updateReleasesSearch } = require('./store-releases');
const { scrapeActors } = require('./actors'); const { scrapeActors } = require('./actors');
const getFileEntries = require('./utils/file-entries');
async function init() { async function init() {
if (argv.server) { if (argv.server) {
@ -21,13 +22,19 @@ async function init() {
await updateReleasesSearch(); await updateReleasesSearch();
} }
const actors = argv.actors && await scrapeActors(argv.actors); const actorsFromFile = argv.actorsFile && await getFileEntries(argv.actorsFile);
const actorNames = (argv.actors || []).concat(actorsFromFile || []);
const actors = actorNames.length > 0 && await scrapeActors(actorNames);
const actorBaseScenes = argv.actors && argv.actorScenes && actors.map(actor => actor.releases).flat().filter(Boolean); const actorBaseScenes = argv.actors && argv.actorScenes && actors.map(actor => actor.releases).flat().filter(Boolean);
const updateBaseScenes = (argv.all || argv.channels || argv.networks) && await fetchUpdates(); const updateBaseScenes = (argv.all || argv.channels || argv.networks) && await fetchUpdates();
const scenesFromFile = argv.scenesFile && await getFileEntries(argv.scenesFile);
const sceneUrls = (argv.scenes || []).concat(scenesFromFile || []);
const deepScenes = argv.deep const deepScenes = argv.deep
? await fetchScenes([...(argv.scenes || []), ...(updateBaseScenes || []), ...(actorBaseScenes || [])]) ? await fetchScenes([...(sceneUrls), ...(updateBaseScenes || []), ...(actorBaseScenes || [])])
: [...(updateBaseScenes || []), ...(actorBaseScenes || [])]; : [...(updateBaseScenes || []), ...(actorBaseScenes || [])];
const sceneMovies = deepScenes && argv.sceneMovies && deepScenes.map(scene => scene.movie).filter(Boolean); const sceneMovies = deepScenes && argv.sceneMovies && deepScenes.map(scene => scene.movie).filter(Boolean);

View File

@ -30,6 +30,10 @@ const { argv } = yargs
type: 'array', type: 'array',
alias: 'actor', alias: 'actor',
}) })
.option('actors-file', {
describe: 'Scrape actors names from file',
type: 'string',
})
.option('actor-scenes', { .option('actor-scenes', {
describe: 'Fetch all scenes for an actor', describe: 'Fetch all scenes for an actor',
type: 'boolean', type: 'boolean',
@ -53,10 +57,14 @@ const { argv } = yargs
alias: 'with-profiles', alias: 'with-profiles',
default: false, default: false,
}) })
.option('scene', { .option('scenes', {
describe: 'Scrape scene info from URL', describe: 'Scrape scene info from URL',
type: 'array', type: 'array',
alias: 'scenes', alias: 'scene',
})
.option('scenes-file', {
describe: 'Scrape scene info from URLs in a file',
type: 'string',
}) })
.option('movie', { .option('movie', {
describe: 'Scrape movie info from URL', describe: 'Scrape movie info from URL',

View File

@ -101,7 +101,7 @@ function toBaseSource(rawSource) {
if (rawSource.attempts) baseSource.attempts = rawSource.attempts; if (rawSource.attempts) baseSource.attempts = rawSource.attempts;
if (rawSource.queueMethod) baseSource.queueMethod = rawSource.queueMethod; if (rawSource.queueMethod) baseSource.queueMethod = rawSource.queueMethod;
if (rawSource.copyright) baseSource.copyright = rawSource.copyright; if (rawSource.credit !== undefined) baseSource.credit = rawSource.credit;
if (rawSource.comment) baseSource.comment = rawSource.comment; if (rawSource.comment) baseSource.comment = rawSource.comment;
if (rawSource.group) baseSource.group = rawSource.group; if (rawSource.group) baseSource.group = rawSource.group;
@ -569,7 +569,7 @@ function curateMediaEntry(media, index) {
source: media.src, source: media.src,
source_page: media.url, source_page: media.url,
scraper: media.scraper, scraper: media.scraper,
copyright: media.copyright, credit: media.credit,
comment: media.comment, comment: media.comment,
}; };
@ -685,7 +685,7 @@ async function associateAvatars(profiles) {
? { ? {
...profile, ...profile,
avatarBaseMedia: toBaseMedias([profile.avatar], 'avatars', { avatarBaseMedia: toBaseMedias([profile.avatar], 'avatars', {
copyright: profile.network?.name || profile.site?.name || null, credit: (profile.credit !== undefined && (profile.network?.name || profile.site?.name)) || null,
scraper: profile.scraper || null, scraper: profile.scraper || null,
})[0], })[0],
} }

View File

@ -69,7 +69,7 @@ function scrapeProfile(html) {
profile.avatar = { profile.avatar = {
src: `http://www.boobpedia.com${avatarPath}`, src: `http://www.boobpedia.com${avatarPath}`,
copyright: null, credit: null,
}; };
} }

155
src/scrapers/fcuk.js Normal file
View File

@ -0,0 +1,155 @@
'use strict';
const qu = require('../utils/qu');
// TODO: profile scraping
function scrapeLatestBlog(scenes, channel) {
return scenes.map(({ query }) => {
const release = {};
release.url = query.url('a.more:not([href*="/join.php"])', 'href', { origin: channel.url });
if (release.url) {
release.entryId = new URL(release.url).pathname.match(/\/scene\/(\d+)\/(\d+)/).slice(1, 3).join('-');
} else {
release.entryId = query.img('.bigthumb').match(/\/scenes\/(\w+)/)?.[1];
}
release.title = query.q('h5 strong', true)?.match(/. - (.+)$/)[1] || query.text('.videos h3');
release.description = query.text('p');
release.date = query.date('h5 strong, .videos h3', 'MMM. DD, YYYY', /\w+. \d{2}, \d{4}/);
// remove common patterns so only the name is left
const curatedTitle = release.title.replace(/\b(part \d|\banal|bts)\b/gi, '').trim();
if (!/\band\b/.test(curatedTitle) && new RegExp(curatedTitle).test(release.description)) {
// scene title is probably the actor name
release.actors = [release.title];
}
release.poster = query.img('.bigthumb', null, { origin: channel.url });
release.photos = query.imgs('.smallthumb', null, { origin: channel.url });
release.tags = query.all('a[href*="/keywords"]', true);
return release;
});
}
function scrapeAll(scenes, channel) {
return scenes.map(({ query }) => {
const release = {};
release.url = query.url('.updateInfo h5 a:not([href*="content/"]):not([href*="#coming"])');
release.entryId = query.url('.updateThumb img', 'alt');
release.title = query.q('.updateInfo h5 a', true);
release.actors = query.all('.tour_update_models a', true);
release.date = query.date('.availdate, .updateInfo p span:nth-child(2)', 'MM/DD/YYYY');
release.poster = query.img('.updateThumb img');
const trailer = query.q('.updateInfo h5 a', 'onclick')?.match(/'(.+)'/)?.[1];
if (trailer) {
release.trailer = {
src: `${channel.url}${trailer}`,
};
}
return release;
});
}
function scrapeSceneBlog({ query }, url, channel) {
const release = {};
release.entryId = new URL(url).pathname.match(/\/scene\/(\d+)\/(\d+)/).slice(1, 3).join('-');
release.title = query.text('h4 strong, .videos h3');
release.description = query.q('#about p, .videos p', true);
const actors = query.urls('a[href*="/girl/"]').map(actorUrl => actorUrl.match(/video-([\w\s]+)/)?.[1]).filter(Boolean);
if (actors.length > 0) {
release.actors = actors;
} else {
// release.actors = [query.q('.previewmed h5 strong', true)?.match(/^([\w\s]+),/)?.[0] || query.q('.videos h3', true)].filter(Boolean);
release.actors = [release.title];
}
release.tags = query.all('.info a[href*="/keywords"], .buttons a[href*="/keywords"]', true);
release.poster = query.img('#info .main-preview, .bigthumb', null, { origin: channel.url });
release.photos = [query.img('.previewmed img', null, { origin: channel.url })].concat(query.imgs('.hd-clip img, .smallthumb', null, { origin: channel.url })).filter(photo => photo);
return release;
}
function scrapeScene({ query, html }, url, channel) {
const release = {};
release.title = query.q('.updatesBlock h2', true);
release.poster = query.meta('property="og:image"');
release.entryId = release.poster.match(/\/content\/(.*)\//)?.[1];
const trailer = html.match(/src="(.+\.mp4)"/)?.[1];
if (trailer) {
release.trailer = {
src: `${channel.url}${trailer}`,
};
}
return release;
}
async function fetchLatestBlog(channel, page) {
const url = `${channel.url}/free/updates/videos/${(page - 1) * 10}`;
const res = await qu.getAll(url, '.videos');
return res.ok ? scrapeLatestBlog(res.items, channel) : res.status;
}
async function fetchLatest(channel, page = 1) {
if (channel.parameters?.blog) {
return fetchLatestBlog(channel, page);
}
const url = `${channel.url}/categories/Movies_${page}_d.html`;
const res = await qu.getAll(url, '.bodyArea .updateItem');
return res.ok ? scrapeAll(res.items, channel) : res.status;
}
async function fetchUpcoming(channel) {
if (channel.parameters?.blog) {
return [];
}
const res = await qu.getAll(channel.url, '#owl-upcomingScenes .updateItem');
return res.ok ? scrapeAll(res.items, channel) : res.status;
}
async function fetchScene(url, channel) {
const res = await qu.get(url);
if (res.ok) {
if (channel.parameters?.blog) {
return scrapeSceneBlog(res.item, url, channel);
}
return scrapeScene(res.item, url, channel);
}
return res.status;
}
module.exports = {
fetchLatest,
fetchScene,
fetchUpcoming,
};

View File

@ -52,7 +52,7 @@ function scrapeProfile(html, actorName) {
profile.social = Array.from(document.querySelectorAll('.profile-meta-item a.social-icons'), el => el.href); profile.social = Array.from(document.querySelectorAll('.profile-meta-item a.social-icons'), el => el.href);
const avatar = document.querySelector('.profile-image-large img').src; const avatar = document.querySelector('.profile-image-large img').src;
if (!avatar.match('placeholder')) profile.avatar = { src: avatar, copyright: null }; if (!avatar.match('placeholder')) profile.avatar = { src: avatar, credit: null };
return profile; return profile;
} }

View File

@ -19,6 +19,7 @@ const evilangel = require('./evilangel');
const fakehub = require('./fakehub'); const fakehub = require('./fakehub');
const famedigital = require('./famedigital'); const famedigital = require('./famedigital');
const fantasymassage = require('./fantasymassage'); const fantasymassage = require('./fantasymassage');
const fcuk = require('./fcuk');
const fullpornnetwork = require('./fullpornnetwork'); const fullpornnetwork = require('./fullpornnetwork');
const girlsway = require('./girlsway'); const girlsway = require('./girlsway');
const hush = require('./hush'); const hush = require('./hush');
@ -93,6 +94,7 @@ module.exports = {
fakehub, fakehub,
famedigital, famedigital,
fantasymassage, fantasymassage,
fcuk,
forbondage: porndoe, forbondage: porndoe,
fullpornnetwork, fullpornnetwork,
girlsway, girlsway,

View File

@ -53,15 +53,15 @@ async function filterUniqueReleases(latestReleases, accReleases) {
} }
function needNextPage(uniqueReleases, pageAccReleases) { function needNextPage(uniqueReleases, pageAccReleases) {
if (argv.last && pageAccReleases.length < argv.last) {
// request for last N releases not yet satisfied
return true;
}
if (uniqueReleases.length === 0) { if (uniqueReleases.length === 0) {
return false; return false;
} }
if (argv.last && pageAccReleases.length < argv.last) {
// TODO: find a way to paginate if scraper filters page with multiple channels, see Kelly Madison
return true;
}
if (uniqueReleases.every(release => !!release.date)) { if (uniqueReleases.every(release => !!release.date)) {
const oldestReleaseOnPage = uniqueReleases const oldestReleaseOnPage = uniqueReleases
.sort((releaseA, releaseB) => releaseB.date - releaseA.date) .sort((releaseA, releaseB) => releaseB.date - releaseA.date)

16
src/utils/file-entries.js Normal file
View File

@ -0,0 +1,16 @@
'use strict';
const fs = require('fs');
async function getFileEntries(location) {
if (!location) {
throw new Error('No filepath provided');
}
const file = await fs.promises.readFile(location, 'utf-8');
const entries = file.split(/\n/).map(entry => entry.trim()).filter(Boolean);
return entries;
}
module.exports = getFileEntries;

View File

@ -125,7 +125,7 @@ function date(context, selector, format, match, attr = 'textContent') {
return extractDate(dateString, format, match); return extractDate(dateString, format, match);
} }
function image(context, selector = 'img', attr, origin, protocol = 'https') { function image(context, selector = 'img', attr, { origin, protocol = 'https' } = {}) {
const imageEl = (attr && q(context, selector, attr)) const imageEl = (attr && q(context, selector, attr))
|| q(context, selector, 'data-src') || q(context, selector, 'data-src')
|| q(context, selector, 'src'); || q(context, selector, 'src');
@ -133,7 +133,7 @@ function image(context, selector = 'img', attr, origin, protocol = 'https') {
return prefixUrl(imageEl, origin, protocol); return prefixUrl(imageEl, origin, protocol);
} }
function images(context, selector = 'img', attr, origin, protocol = 'https') { function images(context, selector = 'img', attr, { origin, protocol = 'https' } = {}) {
const attribute = attr const attribute = attr
|| (q(context, selector, 'data-src') && 'data-src') || (q(context, selector, 'data-src') && 'data-src')
|| (q(context, selector, 'src') && 'src'); || (q(context, selector, 'src') && 'src');
@ -143,31 +143,31 @@ function images(context, selector = 'img', attr, origin, protocol = 'https') {
return imageEls.map(imageEl => prefixUrl(imageEl, origin, protocol)); return imageEls.map(imageEl => prefixUrl(imageEl, origin, protocol));
} }
function url(context, selector = 'a', attr = 'href', origin, protocol = 'https') { function url(context, selector = 'a', attr = 'href', { origin, protocol = 'https' } = {}) {
const urlEl = q(context, selector, attr); const urlEl = q(context, selector, attr);
return attr ? prefixUrl(urlEl, origin, protocol) : urlEl; return attr ? prefixUrl(urlEl, origin, protocol) : urlEl;
} }
function urls(context, selector = 'a', attr = 'href', origin, protocol = 'https') { function urls(context, selector = 'a', attr = 'href', { origin, protocol = 'https' } = {}) {
const urlEls = all(context, selector, attr); const urlEls = all(context, selector, attr);
return attr ? urlEls.map(urlEl => prefixUrl(urlEl, origin, protocol)) : urlEls; return attr ? urlEls.map(urlEl => prefixUrl(urlEl, origin, protocol)) : urlEls;
} }
function poster(context, selector = 'video', attr = 'poster', origin, protocol = 'https') { function poster(context, selector = 'video', attr = 'poster', { origin, protocol = 'https' } = {}) {
const posterEl = q(context, selector, attr); const posterEl = q(context, selector, attr);
return attr ? prefixUrl(posterEl, origin, protocol) : posterEl; return attr ? prefixUrl(posterEl, origin, protocol) : posterEl;
} }
function video(context, selector = 'source', attr = 'src', origin, protocol = 'https') { function video(context, selector = 'source', attr = 'src', { origin, protocol = 'https' } = {}) {
const trailerEl = q(context, selector, attr); const trailerEl = q(context, selector, attr);
return attr ? prefixUrl(trailerEl, origin, protocol) : trailerEl; return attr ? prefixUrl(trailerEl, origin, protocol) : trailerEl;
} }
function videos(context, selector = 'source', attr = 'src', origin, protocol = 'https') { function videos(context, selector = 'source', attr = 'src', { origin, protocol = 'https' } = {}) {
const trailerEls = all(context, selector, attr); const trailerEls = all(context, selector, attr);
return attr ? trailerEls.map(trailerEl => prefixUrl(trailerEl, origin, protocol)) : trailerEls; return attr ? trailerEls.map(trailerEl => prefixUrl(trailerEl, origin, protocol)) : trailerEls;