Compare commits

...

3 Commits

Author SHA1 Message Date
DebaucheryLibrarian afbae24f43 1.196.0 2021-06-28 00:05:32 +02:00
DebaucheryLibrarian eb7009832a Added rudimentary affiliate banner setup. Separated login and signup disable. Added various tag photos. 2021-06-28 00:05:24 +02:00
DebaucheryLibrarian d1480da076 Added effective date column. Changed warning page theme. 2021-06-19 18:09:58 +02:00
101 changed files with 627 additions and 52 deletions

View File

@ -36,6 +36,7 @@
>Log in</button>
<router-link
v-if="$store.state.auth.signup"
:to="{ name: 'signup', query: { ref: $route.query.ref } }"
class="link link-external signup"
>Sign up</router-link>
@ -65,7 +66,7 @@ async function login() {
}
function mounted() {
if (!this.$store.state.auth.enabled) {
if (!this.$store.state.auth.login) {
this.$router.replace({ name: 'not-found' });
}
}

View File

@ -44,6 +44,7 @@
>Sign up</button>
<router-link
v-if="$store.state.auth.login"
:to="{ name: 'login', query: { ref: $route.query.ref } }"
class="link link-external login"
>Log in</router-link>
@ -74,7 +75,7 @@ async function signup() {
}
function mounted() {
if (!this.$store.state.auth.enabled) {
if (!this.$store.state.auth.signup) {
this.$router.replace({ name: 'not-found' });
}
}

View File

@ -67,12 +67,13 @@ export default {
justify-content: center;
position: absolute;
z-index: 10;
background: var(--darken-censor);
background: var(--background-censor);
backdrop-filter: blur(.25rem);
overflow-y: auto;
}
.warning {
color: var(--text-light);
color: var(--text);
width: 50rem;
max-height: 100%;
max-width: 100%;
@ -87,8 +88,8 @@ export default {
.title {
display: block;
font-size: 2rem;
margin: 1rem 0 0 0;
color: var(--text-light);
margin: 1rem 0;
color: var(--text);
text-align: center;
}
@ -113,7 +114,7 @@ export default {
.rules {
margin: 0 0 0 1rem;
text-align: left;
text-shadow: 0 0 3px var(--darken-extreme);
text-shadow: 0 0 3px var(--highlight-strong);
}
.rule {
@ -134,16 +135,16 @@ export default {
align-items: center;
justify-content: center;
border: none;
border-radius: .25rem;
padding: 0;
position: relative;
border-radius: 1rem;
color: var(--lighten-strong);
cursor: pointer;
font-size: 1.5rem;
text-decoration: none;
transition: border .5s ease;
transition: border-radius .2s ease;
&.leave {
color: var(--shadow-strong);
flex-direction: row;
padding: 1rem;
@ -151,7 +152,11 @@ export default {
width: 1.5rem;
height: 1.5rem;
margin: 0 1rem 0 0;
fill: var(--lighten);
fill: var(--shadow);
}
&:hover {
color: var(--text);
}
}
@ -161,6 +166,7 @@ export default {
&.straight,
&.queer {
color: var(--lighten-strong);
background: var(--darken-censor);
&:before {
@ -169,10 +175,18 @@ export default {
height: calc(100% + .25rem);
position: absolute;
z-index: -1;
border-radius: 1.1rem;
filter: blur(.25rem);
transition: filter .2s ease;
}
&:hover {
color: var(--text-light);
border-radius: 0;
.button-sub {
color: var(--text-light);
}
}
}
&.straight:before {
@ -188,14 +202,8 @@ export default {
}
&:hover {
color: var(--text-light);
.button-sub {
color: var(--lighten-strong);
}
.icon {
fill: var(--text-light);
fill: var(--text);
}
&.straight:before,
@ -225,7 +233,7 @@ export default {
}
.preferences {
color: var(--lighten);
color: var(--shadow);
display: block;
padding: .5rem 0 1rem 0;
text-align: center;
@ -234,11 +242,11 @@ export default {
@media(max-width: $breakpoint) {
.title {
font-size: 1.5rem;
font-size: 1.75rem;
}
.logo {
width: 5rem;
width: 5.75rem;
margin: 0 .5rem 0 0;
}
}

View File

@ -5,7 +5,7 @@
>
<div class="info">
<a
:href="entity.url"
:href="entityUrl"
target="_blank"
rel="noopener"
class="link link-child"
@ -41,6 +41,25 @@
/>
</a>
<a
v-if="campaign"
:href="campaign.affiliate.url"
target="_blank"
class="campaign"
>
<img
v-if="campaign.banner.entity.type === 'network'"
:src="`/img/banners/${campaign.banner.entity.slug}/${campaign.banner.id}.jpeg`"
class="campaign-banner"
>
<img
v-if="campaign.banner.entity.type === 'channel' && campaign.banner.entity.parent?.type === 'network'"
:src="`/img/banners/${campaign.banner.entity.parent.slug}/${campaign.banner.entity.slug}/${campaign.banner.id}.jpeg`"
class="campaign-banner"
>
</a>
<ul
v-if="entity.tags.length > 0"
class="tags"
@ -72,6 +91,8 @@
v-else
class="name parent-name"
>{{ entity.parent.name }}</h3>
<Icon icon="device_hub" />
</router-link>
</div>
@ -124,6 +145,9 @@ import Children from './children.vue';
import Scroll from '../scroll/scroll.vue';
async function fetchEntity(scroll = true) {
this.campaign = null;
this.entityUrl = null;
const { entity, totalCount } = await this.$store.dispatch('fetchEntityBySlugAndType', {
entitySlug: this.$route.params.entitySlug,
entityType: this.$route.name,
@ -137,6 +161,16 @@ async function fetchEntity(scroll = true) {
this.pageTitle = entity.name;
const channelBannerCampaigns = entity.campaigns.filter(campaign => campaign.banner);
const networkBannerCampaigns = entity.parent?.campaigns.filter(campaign => campaign.banner);
const bannerCampaigns = channelBannerCampaigns.length > 0 ? channelBannerCampaigns : networkBannerCampaigns;
if (bannerCampaigns.length > 0) {
this.campaign = bannerCampaigns[Math.floor(Math.random() * bannerCampaigns.length)];
}
this.entityUrl = entity.campaigns.find(campaign => !campaign.banner)?.affiliate.url || entity.url;
if (scroll && this.$refs.filter?.$el) {
this.$refs.filter.$el.scrollIntoView();
}
@ -168,6 +202,8 @@ export default {
totalCount: null,
limit: Number(this.$route.query.limit) || 20,
expanded: false,
campaign: null,
entityUrl: null,
};
},
watch: {
@ -185,6 +221,7 @@ export default {
@import 'breakpoints';
.info {
height: 6rem;
display: flex;
justify-content: space-between;
background: var(--profile);
@ -214,6 +251,13 @@ export default {
.link-parent {
flex-direction: row-reverse;
margin: 0 0 0 3rem;
.icon {
width: 1.25rem;
height: 1.25rem;
fill: var(--lighten);
margin: 0 .5rem 0 0;
}
}
.logo {
@ -223,7 +267,7 @@ export default {
}
.logo-child {
height: 2rem;
height: 3rem;
}
.logo-parent {
@ -234,6 +278,14 @@ export default {
height: 1rem;
}
.campaign {
height: 100%;
}
.campaign-banner {
height: 100%;
}
.content-inner {
display: flex;
flex-direction: column;

View File

@ -2,13 +2,13 @@
<div class="menu">
<ul class="menu-items noselect">
<router-link
v-if="auth && me"
v-if="login && me"
:to="{ name: 'user', params: { username: me.username } }"
class="menu-username"
>{{ me.username }}</router-link>
<router-link
v-else-if="auth"
v-else-if="login"
:to="{ name: 'login', query: { ref: $route.path } }"
class="menu-item"
@click.stop
@ -17,7 +17,7 @@
</router-link>
<li
v-if="auth && me"
v-if="login && me"
class="menu-item"
@click.stop="$store.dispatch('logout')"
>
@ -89,8 +89,12 @@ function theme(state) {
return state.ui.theme;
}
function auth(state) {
return state.auth.enabled;
function login(state) {
return state.auth.login;
}
function signup(state) {
return state.auth.signup;
}
function me(state) {
@ -108,7 +112,8 @@ function setSfw(enabled) {
export default {
computed: {
...mapState({
auth,
login,
signup,
sfw,
theme,
me,

View File

@ -47,6 +47,27 @@
@close="$router.replace({ hash: undefined })"
/>
<div class="campaign-container">
<a
v-if="campaign"
:href="campaign.affiliate.url"
target="_blank"
class="campaign"
>
<img
v-if="campaign.banner.entity.type === 'network'"
:src="`/img/banners/${campaign.banner.entity.slug}/${campaign.banner.id}.jpeg`"
class="campaign-banner"
>
<img
v-if="campaign.banner.entity.type === 'channel' && campaign.banner.entity.parent?.type === 'network'"
:src="`/img/banners/${campaign.banner.entity.parent.slug}/${campaign.banner.entity.slug}/${campaign.banner.id}.jpeg`"
class="campaign-banner"
>
</a>
</div>
<FilterBar
ref="filter"
:fetch-releases="fetchReleases"
@ -94,6 +115,15 @@ async function fetchReleases(scroll = true) {
this.hasMedia = this.tag.poster || this.tag.photos.length > 0;
this.description = this.tag.description && converter.makeHtml(escapeHtml(this.tag.description));
if (tag.banners.length > 0) {
const banner = tag.banners[Math.floor(Math.random() * tag.banners.length)];
this.campaign = {
...banner.campaigns[Math.floor(Math.random() * banner.campaigns.length)],
banner,
};
}
if (scroll && this.$refs.filter) {
this.$refs.filter.$el.scrollIntoView();
}
@ -133,6 +163,7 @@ export default {
pageTitle: null,
hasMedia: false,
expanded: false,
campaign: null,
};
},
computed: {
@ -172,12 +203,14 @@ export default {
@import 'theme';
.header {
display: flex;
background: var(--profile);
color: var(--text-light);
justify-content: space-between;
}
.title {
display: inline-block;
padding: .5rem 1rem;
margin: 0;
flex-shrink: 0;
@ -200,4 +233,21 @@ export default {
.scroll {
background: var(--background-dim);
}
.campaign-container {
max-height: 90px;
padding: .5rem 1rem 0 1rem;
background: var(--background-dim);
text-align: center;
}
.campaign {
display: inline-block;
height: 100%;
.campaign-banner {
max-height: 100%;
max-width: 100%;
}
}
</style>

View File

@ -21,16 +21,17 @@ $breakpoint4: 1500px;
--background-dark: #222;
--darken: rgba(0, 0, 0, .5);
--darken-strong: rgba(0, 0, 0, .7);
--darken-extreme: rgba(0, 0, 0, .9);
--darken-censor: rgba(0, 0, 0, .95);
--darken-extreme: rgba(0, 0, 0, .9);
--darken-strong: rgba(0, 0, 0, .7);
--darken-weak: rgba(0, 0, 0, .2);
--darken-hint: rgba(0, 0, 0, .1);
--darken-touch: rgba(0, 0, 0, .05);
--lighten: rgba(255, 255, 255, .5);
--lighten-strong: rgba(255, 255, 255, .7);
--lighten-censor: rgba(255, 255, 255, .95);
--lighten-extreme: rgba(255, 255, 255, .9);
--lighten-strong: rgba(255, 255, 255, .7);
--lighten: rgba(255, 255, 255, .5);
--lighten-weak: rgba(255, 255, 255, .2);
--lighten-hint: rgba(255, 255, 255, .05);
--lighten-touch: rgba(255, 255, 255, .03);
@ -58,6 +59,7 @@ $breakpoint4: 1500px;
--text-contrast: #fff;
--background: var(--background-light);
--background-censor: rgba(255, 255, 255, .95);
--background-dim: #f5f5f5;
--background-soft: #fdfdfd;
@ -71,6 +73,7 @@ $breakpoint4: 1500px;
--crease: #eaeaea;
--shadow: rgba(0, 0, 0, .5);
--shadow-censor: rgba(0, 0, 0, .95);
--shadow-extreme: rgba(0, 0, 0, .9);
--shadow-strong: rgba(0, 0, 0, .7);
--shadow-modest: rgba(0, 0, 0, .3);
@ -91,6 +94,7 @@ $breakpoint4: 1500px;
--text-contrast: #222;
--background: #181818;
--background-censor: rgba(0, 0, 0, .95);
--background-dim: #111;
--background-soft: #000;

View File

@ -1,4 +1,5 @@
export default {
enabled: window.env.auth,
login: window.env.login,
signup: window.env.signup,
user: null,
};

View File

@ -126,6 +126,7 @@ function curateTag(tag) {
};
if (tag.releases) curatedTag.releases = tag.releases.map(({ release }) => curateRelease(release));
if (tag.banners) curatedTag.banners = tag.banners.map(({ banner }) => banner);
if (tag.photos) curatedTag.photos = tag.photos.map(({ media }) => media);
if (tag.poster) curatedTag.poster = tag.poster.media;

View File

@ -1,6 +1,6 @@
import { graphql } from '../api';
// import { sitesFragment, releaseFields } from '../fragments';
import { releaseFields } from '../fragments';
import { releaseFields, campaignsFragment } from '../fragments';
import { curateEntity } from '../curate';
import getDateRange from '../get-date-range';
@ -65,6 +65,7 @@ function initEntitiesActions(store, router) {
hasLogo
}
}
${campaignsFragment}
parent {
id
name
@ -73,6 +74,7 @@ function initEntitiesActions(store, router) {
url
independent
hasLogo
${campaignsFragment}
}
}
connection: releasesConnection(

View File

@ -96,6 +96,56 @@ const actorFields = `
${actorStashesFields}
`;
const campaignsFragment = `
campaigns(filter: {
banner: {
bannersTagsConnection: {
none: {
tag: {
slug: {
in: $exclude
}
}
}
}
}
}) {
affiliate {
id
url
}
banner {
id
width
height
entity {
id
type
name
slug
parent {
id
type
name
slug
}
}
}
entity {
id
type
name
slug
parent {
id
type
name
slug
}
}
}
`;
const releaseActorsFragment = `
actors: releasesActors(orderBy: ACTOR_BY_ACTOR_ID__GENDER_ASC) {
actor {
@ -480,6 +530,7 @@ function getIncludedActors(router) {
export {
actorFields,
actorStashesFields,
campaignsFragment,
releaseActorsFragment,
releaseFields,
releaseTagsFragment,

View File

@ -26,6 +26,31 @@ const dateRanges = {
}),
};
/* requires PostgreSQL 12.x> not available in production yet
const dateRanges = {
latest: () => ({
after: '1900-01-01',
before: dayjs.utc().toDate(),
orderBy: ['EFFECTIVE_DATE_DESC'],
}),
upcoming: () => ({
after: dayjs.utc().toDate(),
before: '2100-01-01',
orderBy: ['EFFECTIVE_DATE_DESC'],
}),
new: () => ({
after: '1900-01-01 00:00:00',
before: '2100-01-01',
orderBy: ['CREATED_AT_DESC', 'EFFECTIVE_DATE_ASC'],
}),
all: () => ({
after: '1900-01-01',
before: '2100-01-01',
orderBy: ['EFFECTIVE_DATE_DESC'],
}),
};
*/
function getDateRange(range) {
return (dateRanges[range] || dateRanges.all)();
}

View File

@ -103,6 +103,57 @@ function initTagsActions(store, _router) {
}
}
}
banners: bannersTags(filter: {
banner: {
bannersTagsConnection: {
none: {
tag: {
slug: {
in: $exclude
}
}
}
}
}
}) {
banner {
id
width
height
entity {
id
type
name
slug
independent
parent {
id
type
name
slug
independent
}
}
campaigns {
affiliate {
id
url
}
entity {
id
type
name
slug
parent {
id
type
name
slug
}
}
}
}
}
scenesConnection(
filter: {
date: {

View File

@ -35,7 +35,8 @@ module.exports = {
secretKey: 'abcdefghijklmnopqrstuvwxyz1234567890ABCD',
},
auth: {
enabled: true,
login: true,
signup: true,
},
exclude: {
channels: [

View File

@ -1274,11 +1274,93 @@ exports.up = knex => Promise.resolve()
.notNullable()
.defaultTo(knex.fn.now());
}))
// SEARCH
.then(() => knex.schema.createTable('affiliates', (table) => {
table.string('id')
.primary()
.unique()
.notNullable();
table.text('url')
.notNullable();
table.text('comment');
table.datetime('created_at')
.notNullable()
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('banners', (table) => {
table.string('id')
.primary()
.unique()
.notNullable();
table.integer('width')
.notNullable();
table.integer('height')
.notNullable();
table.integer('entity_id', 12)
.references('id')
.inTable('entities');
table.text('comment');
table.datetime('created_at')
.notNullable()
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('banners_tags', (table) => {
table.increments('id');
table.string('banner_id')
.notNullable()
.references('id')
.inTable('banners');
table.integer('tag_id')
.notNullable()
.references('id')
.inTable('tags');
table.unique(['banner_id', 'tag_id']);
table.datetime('created_at')
.notNullable()
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('campaigns', (table) => {
table.increments('id');
table.integer('entity_id', 12)
.notNullable()
.references('id')
.inTable('entities');
table.string('affiliate_id')
.notNullable()
.references('id')
.inTable('affiliates');
table.string('banner_id')
.references('id')
.inTable('banners');
table.datetime('created_at')
.notNullable()
.defaultTo(knex.fn.now());
}))
// SEARCH AND SORT
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
ALTER TABLE releases_search ADD COLUMN document tsvector;
/* allow scenes without dates to be mixed inbetween scenes with dates */
ALTER TABLE releases
ADD COLUMN effective_date timestamptz
GENERATED ALWAYS AS (COALESCE(date, created_at)) STORED;
`);
})
// INDEXES
@ -1288,6 +1370,9 @@ exports.up = knex => Promise.resolve()
CREATE UNIQUE INDEX unique_actor_slugs_network ON actors (slug, entity_id, entry_id);
CREATE UNIQUE INDEX unique_actor_slugs ON actors (slug) WHERE entity_id IS NULL;
CREATE UNIQUE INDEX unique_entity_campaigns_banner ON campaigns (entity_id, affiliate_id, banner_id);
CREATE UNIQUE INDEX unique_entity_campaigns ON campaigns (entity_id, affiliate_id) WHERE banner_id IS NULL;
CREATE UNIQUE INDEX releases_search_unique ON releases_search (release_id);
CREATE INDEX releases_search_index ON releases_search USING GIN (document);
`);
@ -1642,6 +1727,10 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
DROP TABLE IF EXISTS chapters_posters CASCADE;
DROP TABLE IF EXISTS chapters_photos CASCADE;
DROP TABLE IF EXISTS banners_tags CASCADE;
DROP TABLE IF EXISTS banners CASCADE;
DROP TABLE IF EXISTS affiliates CASCADE;
DROP TABLE IF EXISTS campaigns CASCADE;
DROP TABLE IF EXISTS batches CASCADE;
DROP TABLE IF EXISTS actors_avatars CASCADE;
@ -1654,6 +1743,7 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
DROP TABLE IF EXISTS entities_tags CASCADE;
DROP TABLE IF EXISTS entities_social CASCADE;
DROP TABLE IF EXISTS sites_tags CASCADE;
DROP TABLE IF EXISTS sites_social CASCADE;
DROP TABLE IF EXISTS networks_social CASCADE;

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "traxxx",
"version": "1.195.0",
"version": "1.196.0",
"lockfileVersion": 2,
"requires": true,
"packages": {

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -223,6 +223,11 @@ const tags = [
slug: 'bisexual',
priority: 10,
},
{
name: 'black cock',
slug: 'black-cock',
group: 'body',
},
{
name: 'black hair',
slug: 'black-hair',
@ -1022,6 +1027,11 @@ const tags = [
priority: 7,
group: 'ethnicity',
},
{
name: 'white cock',
slug: 'white-cock',
group: 'body',
},
{
name: 'wife',
slug: 'wife',

View File

@ -594,22 +594,23 @@ const tagMedia = [
['69', 0, 'Abby Lee Brazil and Ramon Nomar', 'wicked'],
['69', 4, 'Abella Danger and Karma Rx in "Neon Dreaming"', 'brazzers'],
['69', 2, 'Abigail Mac and Kissa Sins in "Lesbian Anal Workout"', 'hardx'],
['airtight', 2, 'Dakota Skye in "Dakota Goes Nuts"', 'archangel'],
['airtight', 7, 'Lana Rhoades in "Gangbang Me 3"', 'hardx'],
['airtight', 6, 'Remy Lacroix in "Ass Worship 14"', 'julesjordan'],
['airtight', 11, 'Malena Nazionale in "Rocco\'s Perverted Secretaries 2: Italian Edition"', 'roccosiffredi'],
['airtight', 3, 'Anita Bellini in "Triple Dick Gangbang"', 'handsonhardcore'],
['airtight', 'venera_maxima_legalporno', 'Venera Maxima in LegalPorno SZ2645', 'legalporno'],
['airtight', 'mina_ddfnetwork', 'Remy Lacroix in "Ass Worship 14"', 'julesjordan'],
['airtight', 1, 'Jynx Maze in "Pump My Ass Full of Cum 3"', 'julesjordan'],
['airtight', 10, 'Asa Akira in "Asa Akira To The Limit"', 'julesjordan'],
['airtight', 8, 'Veronica Leal in SZ2520'],
['airtight', 3, 'Anita Bellini in "Triple Dick Gangbang"', 'handsonhardcore'],
['airtight', 5, 'Chloe Amour in "DP Masters 4"', 'julesjordan'],
['airtight', 9, 'Cindy Shine in GP1658'],
['anal', 5, 'Abella Danger', 'hardx'],
['anal', 'kira_noir_julesjordan', 'Kira Noir in "Kira Noir Opens Her Ass For Manuel"', 'julesjordan'],
['anal', 7, 'Anastasia Brokelyn', 'bangbros'],
['anal', 'jane_wilde_evilangel_2', 'Jane Wilde and Brock Cooper in "The Cock Hungry Chronicles"', 'evilangel'],
['anal', 0, 'Adriana Chechik in "Manuel Creampies Their Asses 3"', 'julesjordan'],
['anal', 'nikki_benz_bigwetbutts', 'Nikki Benz in "Pantyhose Playtime"', 'bigwetbutts'],
['anal', 7, 'Anastasia Brokelyn', 'bangbros'],
['anal', 6, 'Chloe Cherry in "Chloe\'s Big Anal"', 'darkx'],
['anal', 4, 'Lana Roy in "Anal In The Club"', '21naturals'],
['anal', 3, 'Dakota Skye', 'brazzers'],
@ -650,11 +651,13 @@ const tagMedia = [
['blonde', 2, 'Isabelle Deltore', 'herlimit'],
['blowbang', 0, 'Lacy Lennon in "Lacy Lennon\'s First Blowbang"', 'hardx'],
['blowbang', 'zaawaadi_roccosiffredi_1', 'Zaawaadi in "My Name Is Zaawaadi"', 'roccosiffredi'],
['blowbang', 'gina_gerson_assholefever', 'Gina Gerson in "Oppa Gangbang Style"', 'assholefever'],
['blowbang', 1, 'Nicole Black in GIO1680', 'legalporno'],
['blowjob', 1, 'Kylie Page in "Stepsis Gives Soapy Handjob In Shower"', 'spyfam'],
['blowjob', 'clanddi_jinkcego_ddfbusty_1', 'Clanddi Jinkcego', 'ddfbusty'],
['blowjob', 4, 'Chloe Cherry in "Chloe\'s Big Anal"', 'darkx'],
['blowjob', 'cecilia_lion_wefuckblackgirls', 'Cecilia Lion in "Cecilia Lion\'s Second Appearance"', 'wefuckblackgirls'],
['blowjob', 1, 'Kylie Page in "Stepsis Gives Soapy Handjob In Shower"', 'spyfam'],
['blowjob', 'jane_wilde_evilangel', 'Jane Wilde and Brock Cooper in "The Cock Hungry Chronicles"', 'evilangel'],
['blowjob', 'cecilia_lion_wefuckblackgirls', 'Cecilia Lion in "Cecilia Lion\'s Second Appearance"', 'wefuckblackgirls'],
['blowjob', 0, 'Adriana Chechik in "The Dinner Party"', 'realwifestories'],
['blowjob', 5, 'Kaylynn', 'mommyblowsbest'],
['blowjob', 'azul_hermosa_realitykings', 'Azul Hermosa and Scott Nails in "Diva For A Day"', 'brazzers'],
@ -717,8 +720,8 @@ const tagMedia = [
['double-dildo', 0, 'Kali Roses in "Double Dildo Party"'],
['double-dildo', 4, 'Claudia Macc and Victoria Pure', 'eurogirlsongirls'],
['double-dildo', 8, 'Harmony Wonder, Katie Kush and Jewelz Blu in "Pick Your Pleasure"', 'realitykings'],
['double-dildo', 6, 'Abella Danger and Karma Rx in "Neon Dreaming"', 'brazzers'],
['double-dildo', 5, 'Kimber Woods and Mandy Muse in "Big Oiled Asses"', 'naughtyamerica'],
['double-dildo', 6, 'Abella Danger and Karma Rx in "Neon Dreaming"', 'brazzers'],
['double-dildo-anal', 0, 'Vina Sky and Kenzie Reeves in "Vina Sky\'s 1st Lesbian Anal"', 'hardx'],
['double-dildo-anal', 1, 'Sammie Rhodes and Ainsley Addision in "Tickle Me Pink"', 'welivetogether'],
['double-dildo-anal', 6, 'Anikka Albrite, Jenna Sativa and Tori Black in "Tori Black\'s Lesbian Gangbang"', 'lesbianx'],
@ -787,7 +790,8 @@ const tagMedia = [
['enhanced-boobs', 17, 'Felina in "With Flowers On The Floor"', 'louisdemirabert'],
['enhanced-boobs', 1, 'Lela Star in "Thick"', 'julesjordan'],
['enhanced-boobs', 18, 'Ebony Godess', 'actiongirls'],
['enhanced-boobs', 'hunter_bryce_penthouse', 'Hunter Bryce in "On The Bed"', 'Penthouse'],
['enhanced-boobs', 'hunter_bryce_penthouse', 'Hunter Bryce in "On The Bed"', 'penthouse'],
['enhanced-boobs', 'clanddi_jinkcego_ddfbusty_5', 'Clanddi Jinkcego & Rebecca Jessop', 'ddfbusty'],
['enhanced-boobs', 'trudy_photodromm_1', 'Trudy', 'photodromm'],
['enhanced-boobs', 'kenzie_anne_playboy', 'Miss Kenzie Anne in "Supercharged"', 'playboy'],
['enhanced-boobs', 9, 'Putri Cinta', 'watch4beauty'],
@ -811,6 +815,7 @@ const tagMedia = [
['fake-cum', 2, 'Mimi Allen', 'fuckedupfacials'],
['fake-cum', 3, 'Alexia Anders in "Thanksgiving Creampies"', 'cum4k'],
['fake-cum', 0, 'Jynx Maze in "Showering Slut Gets Sludged"', 'cumshotsurprise'],
['fake-cum', 'franceska_le_fortyozbounce', 'Franceska Le and Luscious Lopez', 'fortyozbounce'],
['fake-cum', 1, 'Ricki White', 'fuckedupfacials'],
['fake-cum', 4, 'Vina Sky in "Creaming Her Pipes"', 'anal4k'],
['family', 0, 'Teanna Trump in "A Family Appear: Part One"', 'brazzers'],
@ -826,6 +831,7 @@ const tagMedia = [
['gangbang', 'kristen_scott_julesjordan', 'Kristen Scott in "Interracial Gangbang!"', 'julesjordan'],
['gangbang', 'lara_frost_legalporno_1', 'Lara Frost in NRX070', 'legalporno'],
['gangbang', 7, 'Alexa Flexy in GL376', 'legalporno'],
['gangbang', 'gina_gerson_assholefever', 'Gina Gerson in "Oppa Gangbang Style"', 'assholefever'],
['gangbang', 0, '"4 On 1 Gangbangs"', 'doghousedigital'],
['gangbang', 4, 'Marley Brinx in "The Gangbang of Marley Brinx"', 'julesjordan'],
['gangbang', 1, 'Ginger Lynn in "Gangbang Mystique", a photoset shot by Suze Randall, 1984. Depicting a woman \'airtight\' pushed the boundaries of pornography at the time.'],
@ -849,6 +855,7 @@ const tagMedia = [
['lesbian', 0, 'Jenna Sativa and Alina Lopez in "Opposites Attract"', 'girlgirl'],
['maid', 0, 'Whitney Wright in "Dredd Up Your Ass 2"', 'julesjordan'],
['maid', 1, 'Alessandra Jane', 'brazzers'],
['milf', 'nikki_benz_bigwetbutts', 'Nikki Benz in "Pantyhose Playtime"', 'bigwetbutts'],
['milf', 'silvia_saige_ddfnetwork', 'Silvia Saige', 'pornworld'],
['milf', 2, 'Shalina Devine', 'analmom'],
['milf', 1, 'Francesca Le', 'evilangel'],
@ -859,6 +866,7 @@ const tagMedia = [
['mfm', 0, 'Vina Sky in "Jules Jordan\'s Three Ways"', 'julesjordan'],
['mfm', 8, 'Ariana Marie in "DP Masters 7"', 'julesjordan'],
['mfm', 1, 'Lana Rhoades in "Gangbang Me 3"', 'hardx'],
['mfm', 'franceska_jaimes_digitalplayground', 'Franceska Jaimes in "Monarch"', 'digitalplayground'],
['mfm', 'hazel_moore_legalporno', 'Hazel Moore', 'legalporno'],
['mfm', 7, 'Rose Valerie', 'eurosexparties'],
['mfm', 6, 'Honey Gold in "Slut Puppies 12"', 'julesjordan'],
@ -938,6 +946,7 @@ const tagMedia = [
['toys', 1, 'Chloe Lamour in "Curives In All The Right Places"', 'wetandpuffy'],
['toys', 'shawna_lenee_sunrisekings', 'Shawna Lenee', 'sunrisekings'],
['trainbang', 'poster', 'Kali Roses in "Passing Me Around"', 'blacked'],
['trainbang', 'gina_gerson_assholefever', 'Gina Gerson in "Oppa Gangbang Style"', 'assholefever'],
['vr', 0, 'Michelle H', 'metart'],
['vr', '1a', 'Jenna Fox and Tommy Pistol in "Virtual Reality Jenna Fox Fucks So Real"', 'bangbros'],
['white', 2, 'Kenzie Reeves', 'bang'],

212
seeds/06_affiliates.js Normal file
View File

@ -0,0 +1,212 @@
const bulkInsert = require('../src/utils/bulk-insert');
const affiliates = {
julesjordan_signup: {
url: 'https://enter.julesjordan.com/track/Mzk3MS4yLjMuNi4wLjAuMC4wLjA',
comment: '$30 per signup',
},
manuelferrara_signup: {
url: 'https://enter.manuelferrara.com/track/Mzk3MS4yLjcuMTYuMC4wLjAuMC4w',
comment: '$30 per signup',
},
spermswallowers_signup: {
url: 'https://enter.spermswallowers.com/track/Mzk3MS4yLjUuMTMuMC4wLjAuMC4w',
comment: '$30 per signup',
},
theassfactory_signup: {
url: 'https://enter.theassfactory.com/track/Mzk3MS4yLjEuMS4wLjAuMC4wLjA',
comment: '$30 per signup',
},
legalporno_new: {
url: 'https://www.legalporno.com/new-videos?aff=BW90MHT1DP____',
comment: 'default offer',
},
pornworld_new: {
url: 'https://pornworld.com/new-videos?aff=BW90MHT1DP____',
comment: 'default offer',
},
};
const banners = [
{
id: 'julesjordan_728_90_jill_kassidy',
width: 728,
height: 90,
network: 'julesjordan',
tags: ['sex', 'blowjob', 'black-cock', 'brunette'],
},
{
id: 'julesjordan_728_90_angela_white',
width: 728,
height: 90,
network: 'julesjordan',
tags: ['sex', 'black-cock', 'brunette'],
},
{
id: 'julesjordan_728_90_adriana_chechik',
width: 728,
height: 90,
network: 'julesjordan',
tags: ['anal', 'black-cock', 'brunette'],
},
{
id: 'julesjordan_728_90_autumn_falls',
width: 728,
height: 90,
network: 'julesjordan',
tags: ['sex', 'big-boobs', 'brunette'],
},
{
id: 'julesjordan_728_90_gabbie_carter',
width: 728,
height: 90,
network: 'julesjordan',
tags: ['sex', 'blowjob', 'big-boobs', 'brunette'],
},
{
id: 'manuelferrara_728_90_asses',
width: 728,
height: 90,
channel: 'manuelferrara',
tags: ['big-butt'],
},
{
id: 'pornworld_600_120_1',
width: 600,
height: 120,
network: 'pornworld',
tags: ['anal', 'brunette'],
},
{
id: 'pornworld_600_120_2',
width: 600,
height: 120,
network: 'pornworld',
tags: ['mfm', 'sex', 'brunette'],
},
];
const links = [
{
network: 'julesjordan',
affiliate: 'julesjordan_signup',
},
{
network: 'julesjordan',
affiliate: 'julesjordan_signup',
banner: 'julesjordan_728_90_jill_kassidy',
},
{
network: 'julesjordan',
affiliate: 'julesjordan_signup',
banner: 'julesjordan_728_90_angela_white',
},
{
network: 'julesjordan',
affiliate: 'julesjordan_signup',
banner: 'julesjordan_728_90_adriana_chechik',
},
{
network: 'julesjordan',
affiliate: 'julesjordan_signup',
banner: 'julesjordan_728_90_autumn_falls',
},
{
network: 'julesjordan',
affiliate: 'julesjordan_signup',
banner: 'julesjordan_728_90_gabbie_carter',
},
{
channel: 'manuelferrara',
affiliate: 'manuelferrara_signup',
},
{
channel: 'manuelferrara',
affiliate: 'manuelferrara_signup',
banner: 'manuelferrara_728_90_asses',
},
{
channel: 'spermswallowers',
affiliate: 'spermswallowers_signup',
},
{
channel: 'theassfactory',
affiliate: 'theassfactory_signup',
},
{
network: 'legalporno',
affiliate: 'legalporno_new',
},
{
channel: 'legalporno',
affiliate: 'legalporno_new',
banner: 'pornworld_600_120_1',
},
{
channel: 'legalporno',
affiliate: 'legalporno_new',
banner: 'pornworld_600_120_2',
},
{
network: 'pornworld',
affiliate: 'pornworld_new',
},
{
network: 'pornworld',
affiliate: 'pornworld_new',
banner: 'pornworld_600_120_1',
},
{
network: 'pornworld',
affiliate: 'pornworld_new',
banner: 'pornworld_600_120_2',
},
];
exports.seed = async knex => Promise.resolve()
.then(async () => {
await Promise.all([
knex('campaigns').delete(),
knex('affiliates').delete(),
knex('banners').delete(),
]);
await bulkInsert('affiliates', Object.entries(affiliates).map(([key, value]) => ({ id: key, ...value })), false);
const [networks, channels, tags] = await Promise.all([
knex('entities')
.where('type', 'network')
.whereIn('slug', links.concat(banners).map(link => link.network).filter(Boolean)),
knex('entities')
.where('type', 'channel')
.whereIn('slug', links.concat(banners).map(link => link.channel).filter(Boolean)),
knex('tags')
.whereIn('slug', banners.flatMap(banner => banner.tags || [])),
]);
const networksBySlug = networks.reduce((acc, network) => ({ ...acc, [network.slug]: network }), {});
const channelsBySlug = channels.reduce((acc, channel) => ({ ...acc, [channel.slug]: channel }), {});
const tagsBySlug = tags.reduce((acc, tag) => ({ ...acc, [tag.slug]: tag }), {});
const linksWithEntityIdAndAffiliateId = links.map(link => ({
entity_id: networksBySlug[link.network]?.id || channelsBySlug[link.channel]?.id,
affiliate_id: link.affiliate,
banner_id: link.banner,
})).filter(link => link.entity_id && link.affiliate_id);
const bannersWithEntityId = banners.map(banner => ({
id: banner.id,
width: banner.width,
height: banner.height,
entity_id: networksBySlug[banner.network]?.id || channelsBySlug[banner.channel]?.id || null,
}));
const bannerTags = banners.flatMap(banner => banner.tags?.map(tag => ({
banner_id: banner.id,
tag_id: tagsBySlug[tag].id,
})) || []);
await bulkInsert('banners', bannersWithEntityId, false);
await bulkInsert('banners_tags', bannerTags, false);
await bulkInsert('campaigns', linksWithEntityIdAndAffiliateId, false);
});

View File

@ -22,7 +22,7 @@ async function verifyPassword(password, storedPassword) {
}
async function login(credentials) {
if (!config.auth.enabled) {
if (!config.auth.login) {
throw new HttpError('Authentication is disabled', 405);
}
@ -38,7 +38,7 @@ async function login(credentials) {
}
async function signup(credentials) {
if (!config.auth.enabled) {
if (!config.auth.signup) {
throw new HttpError('Authentication is disabled', 405);
}

View File

@ -152,7 +152,8 @@ async function initServer() {
res.render(path.join(__dirname, '../../assets/index.ejs'), {
env: JSON.stringify({
sfw: !!req.headers.sfw || Object.prototype.hasOwnProperty.call(req.query, 'sfw'),
auth: config.auth.enabled,
login: config.auth.login,
signup: config.auth.signup,
sessionId: req.session.safeId,
}),
});