Compare commits
5 Commits
cb51a2a81b
...
6584a46d53
Author | SHA1 | Date |
---|---|---|
|
6584a46d53 | |
|
5b886b3917 | |
|
c62df2228b | |
|
17b3ba1272 | |
|
eca54c2a09 |
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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')"
|
||||||
>
|
>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
fill: var(--primary);
|
||||||
|
padding: .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
display: inline-block;
|
||||||
fill: var(--shadow-modest);
|
fill: var(--shadow-modest);
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
height: 100%;
|
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
|
<div class="sidebar-container">
|
||||||
<div
|
<div
|
||||||
class="sidebar"
|
class="sidebar"
|
||||||
@click.stop
|
@click.stop
|
||||||
>
|
>
|
||||||
|
<div class="sidebar-section">
|
||||||
<div class="sidebar-header">
|
<div class="sidebar-header">
|
||||||
<Icon
|
<Icon
|
||||||
icon="cross2"
|
icon="cross2"
|
||||||
|
@ -88,11 +90,57 @@
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</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>
|
||||||
</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,19 +232,49 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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,10 +283,8 @@ function initActorActions(store, router) {
|
||||||
name: {
|
name: {
|
||||||
startsWith: $letter
|
startsWith: $letter
|
||||||
}
|
}
|
||||||
gender: {
|
|
||||||
${genderFilter}
|
${genderFilter}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
totalCount
|
totalCount
|
||||||
actors: nodes {
|
actors: nodes {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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');
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 9.9 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 170 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 8.7 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 40 KiB |
|
@ -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',
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
11
src/app.js
|
@ -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);
|
||||||
|
|
12
src/argv.js
|
@ -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',
|
||||||
|
|
|
@ -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],
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
};
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
|
@ -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;
|
||||||
|
|