1 Commits

Author SHA1 Message Date
boi12321
fde9312fa9 cleanup some unused dependencies 2023-07-14 13:12:54 +02:00
3780 changed files with 24254 additions and 29297 deletions

View File

@@ -11,7 +11,6 @@
"no-tabs": "off",
"no-unused-vars": ["error", {"argsIgnorePattern": "^_"}],
"no-console": 0,
"default-param-last": 0,
"template-curly-spacing": "off",
"max-len": 0,
"vue/no-v-html": 0,
@@ -19,7 +18,6 @@
"vue/multiline-html-element-content-newline": 0,
"vue/singleline-html-element-content-newline": 0,
"vue/multi-word-component-names": 0,
"vue/no-reserved-component-names": 0,
"no-param-reassign": ["error", {
"props": true,
"ignorePropertyModificationsFor": ["state", "acc"]

3
.gitignore vendored
View File

@@ -3,12 +3,9 @@ dist/
log/
media/
html/
data/
tmp/*
public/js/*
public/css/*
public/img/tags
public/img/logos/
config/*
!config/default.js
assets/js/config/

2
.nvmrc
View File

@@ -1 +1 @@
21.2.0
16.18.0

View File

@@ -1,7 +1,6 @@
<template>
<RouterLink
<router-link
:to="`/actor/${actor.id}/${actor.slug}`"
:target="target"
class="actor nolink"
>
<div class="avatar">
@@ -19,7 +18,7 @@
</div>
<span class="name">{{ actor.name }}</span>
</RouterLink>
</router-link>
</template>
<script>
@@ -37,10 +36,6 @@ export default {
type: Object,
default: null,
},
target: {
type: String,
default: null,
},
},
methods: {
unstashActor,

View File

@@ -41,9 +41,9 @@
/>
</span>
<RouterLink
:to="hasScrolled ? '' : { name: 'actor', params: { actorId: actor.id, actorSlug: actor.slug } }"
<a
class="avatar-container"
@click="goToActor"
>
<img
v-if="actor.avatar"
@@ -130,7 +130,7 @@
class="country"
/>
</span>
</RouterLink>
</a>
</div>
</div>
</template>
@@ -138,6 +138,13 @@
<script>
import Gender from './gender.vue';
function goToActor() {
// can't seem to control behavior with RouterLink
if (!this.hasScrolled) {
this.$router.push({ name: 'actor', params: { actorId: this.actor.id, actorSlug: this.actor.slug } });
}
}
async function stashActor() {
this.favorited = true;
@@ -208,6 +215,7 @@ export default {
methods: {
stashActor,
unstashActor,
goToActor,
},
};
</script>

View File

@@ -3,28 +3,13 @@
title="Add alert"
@close="$emit('close')"
>
<div
v-if="error"
class="dialog-error"
>{{ error }}</div>
<form
class="dialog-body"
@submit.prevent="addAlert"
>
<div class="dialog-section">
<h3 class="dialog-heading">
When
<label class="dialog-description noselect">
<template v-if="all">Scene must match&nbsp;<strong>all</strong>&nbsp;fields</template>
<template v-else>Scene must match&nbsp;<strong>any</strong>&nbsp;field</template>
<Toggle
:checked="all"
@change="(checked) => all = checked"
/>
</label>
When<span class="dialog-description">All to appear in the same scene</span>
</h3>
<div class="alert-section">
@@ -44,10 +29,7 @@
:key="`actor-${actor.id}`"
class="actor"
>
<ActorPreview
:actor="actor"
target="_blank"
/>
<ActorPreview :actor="actor" />
<Icon
icon="cross3"
@@ -122,15 +104,10 @@
<div class="entities">
<div
v-for="(entity, index) in entities"
:key="`entity-${entity.id}`"
:class="{ invalid: all && index > 0 }"
v-if="entity"
class="entity"
>
<Entity
:entity="entity"
target="_blank"
/>
<Entity :entity="entity" />
<Icon
icon="cross3"
@@ -139,7 +116,7 @@
/>
</div>
<Tooltip v-if="entities.length < 1 || !all">
<Tooltip v-if="!entity">
<div class="entity placeholder">
Any channel
@@ -159,72 +136,6 @@
</Tooltip>
</div>
</div>
<div class="alert-section">
<h4 class="alert-heading">Matching</h4>
<ul class="matches nolist">
<li
v-for="(match, index) in matches"
:key="`match-${index}`"
class="match"
>
<span class="match-property">{{ match.property }}:&nbsp;</span>
<span
v-if="match.expression.slice(0, 1) === '/' && match.expression.slice(-1) === '/'"
class="match-expression"
><span class="match-slash">/</span>{{ match.expression.slice(1, -1) }}<span class="match-slash">/</span></span>
<span
v-else
class="match-expression"
>{{ match.expression }}</span>
<Icon
icon="cross3"
class="remove"
@click.native="removeMatch(index)"
/>
</li>
<Tooltip
v-if="entities.length === 0"
@open="$refs.expression?.focus()"
>
<li class="match placeholder">
Anything
<Icon
icon="plus3"
class="add"
/>
</li>
<template #tooltip>
<form
class="pattern-tooltip"
@submit.prevent="addMatch"
>
<select
v-model="matchProperty"
class="input"
>
<option value="title">Title</option>
<option value="description">Description</option>
</select>
<input
ref="expression"
v-model="matchExpression"
class="input"
placeholder="Expression, // for RegExp"
>
</form>
</template>
</Tooltip>
</ul>
</div>
</div>
<div class="dialog-section">
@@ -283,7 +194,7 @@
<div class="dialog-actions right">
<button
:disabled="actors.length === 0 && tags.length === 0 && entities.length === 0 && matches.length === 0"
:disabled="actors.length === 0 && tags.length === 0 && !entity"
type="submit"
class="button button-primary"
>Add alert</button>
@@ -296,28 +207,19 @@
import ActorPreview from '../actors/preview.vue';
import Entity from '../entities/tile.vue';
import Checkbox from '../form/checkbox.vue';
import Toggle from '../form/toggle.vue';
import Search from './search.vue';
async function addAlert() {
this.error = null;
await this.$store.dispatch('addAlert', {
actors: this.actors.map((actor) => actor.id),
tags: this.tags.map((tag) => tag.id),
entity: this.entity?.id,
notify: this.notify,
email: this.email,
stashes: this.stashes.map((stash) => stash.id),
});
try {
await this.$store.dispatch('addAlert', {
all: this.all,
actors: this.actors.map((actor) => actor.id),
tags: this.tags.map((tag) => tag.id),
matches: this.matches,
entities: this.entities.map((entity) => entity.id),
notify: this.notify,
email: this.email,
stashes: this.stashes.map((stash) => stash.id),
});
this.$emit('close', true);
} catch (error) {
this.error = error.message;
}
this.$emit('close', true);
}
function addActor(actor) {
@@ -329,7 +231,7 @@ function addActor(actor) {
}
function addEntity(entity) {
this.entities = this.entities.concat(entity);
this.entity = entity;
this.events.emit('blur');
}
@@ -345,34 +247,14 @@ function removeActor(actor) {
this.actors = this.actors.filter((listedActor) => listedActor.id !== actor.id);
}
function removeEntity(entity) {
this.entities = this.entities.filter((alertEntity) => alertEntity.id !== entity.id);
function removeEntity() {
this.entity = null;
}
function removeTag(tag) {
this.tags = this.tags.filter((listedTag) => listedTag.id !== tag.id);
}
function addMatch() {
if (!this.matchExpression) {
return;
}
this.matches = this.matches.concat({
property: this.matchProperty,
expression: this.matchExpression,
});
this.matchProperty = 'title';
this.matchExpression = null;
this.events.emit('blur');
}
function removeMatch(removeIndex) {
this.matches = this.matches.filter((match, matchIndex) => matchIndex !== removeIndex);
}
function addStash(stash) {
if (!this.stashes.some((selectedStash) => selectedStash.id === stash.id)) {
this.stashes = this.stashes.concat(stash);
@@ -391,19 +273,13 @@ export default {
Checkbox,
Entity,
Search,
Toggle,
},
emits: ['close'],
data() {
return {
error: null,
actors: [],
tags: [],
all: true,
entities: [],
matches: [],
matchProperty: 'title',
matchExpression: null,
entity: null,
notify: true,
email: false,
stashes: [],
@@ -414,12 +290,10 @@ export default {
addActor,
addAlert,
addEntity,
addMatch,
addTag,
addStash,
removeActor,
removeEntity,
removeMatch,
removeTag,
removeStash,
},
@@ -446,24 +320,9 @@ export default {
}
.dialog-description {
display: flex;
align-items: center;
color: var(--shadow);
font-size: .9rem;
font-weight: normal;
.toggle-container {
margin-left: .5rem;
}
}
.dialog-error {
padding: 1rem;
margin-bottom: 1rem;
background: var(--error);
color: var(--text-light);
font-weight: bold;
text-align: center;
}
.alert-heading {
@@ -479,34 +338,6 @@ export default {
font-size: 0;
}
.match {
display: flex;
align-items: center;
padding: .25rem 0;
font-family: inherit;
.remove {
position: relative;
top: -.1rem;
right: 0;
}
}
.match-property {
text-transform: capitalize;
color: var(--shadow);
}
.match-expression {
flex-grow: 1;
}
.match-slash {
padding: 0 .1rem;
color: var(--primary);
font-weight: bold;
}
.actors > .actor,
.entity,
.tag,
@@ -516,11 +347,6 @@ export default {
margin: 0 .5rem .5rem 0;
}
.entity.invalid {
opacity: .5;
pointer-events: none;
}
.entity .tile {
width: 10rem;
height: 2.5rem;
@@ -540,14 +366,6 @@ export default {
color: var(--text);
}
.pattern-tooltip {
display: flex;
gap: .5rem;
position: relative;
padding: .5rem;
overflow: hidden;
}
.remove {
width: 1rem;
height: 1rem;

View File

@@ -1,7 +1,6 @@
<template>
<iframe
v-if="campaign?.banner?.type === 'html'"
ref="iframe"
:width="campaign.banner.width"
:height="campaign.banner.height"
:src="getSource(campaign)"
@@ -9,8 +8,6 @@
marginwidth="0"
marginheight="0"
class="campaign frame"
data-umami-event="campaign-click"
:data-umami-event-campaign-id="`${campaign.entity.slug}-${campaign.id}`"
/>
<a
@@ -18,8 +15,6 @@
:href="campaign.url || campaign.affiliate?.url"
target="_blank"
class="campaign"
data-umami-event="campaign-click"
:data-umami-event-campaign-id="`${campaign.entity.slug}-${campaign.id}`"
>
<img
:src="getSource(campaign)"
@@ -46,6 +41,7 @@ function ratioFilter(banner) {
if (banner.type === 'html' && banner.width > window.innerWidth) {
// usually non-scalable iframes
console.log('TOO WIDE');
return false;
}
@@ -221,17 +217,4 @@ export default {
max-height: 100%;
max-width: 100%;
}
.frame-container {
position: relative;
font-size: 0;
}
.frame-target {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
</style>

View File

@@ -96,29 +96,17 @@ function scrollToTop() {
this.$refs.content.scrollTop = 0;
}
function trackIframeCampaign() {
// no way to capture clicks from an iframe directly
if (window.umami && document.activeElement.tagName === 'IFRAME' && document.activeElement.dataset.umamiEvent === 'campaign-click') {
window.umami.track('campaign-click', {
'campaign-id': document.activeElement.dataset.umamiEventCampaignId,
});
}
}
function mounted() {
document.addEventListener('click', this.blur);
window.addEventListener('resize', this.resize);
this.events.on('toggleSettings', this.toggleSettings);
this.events.on('toggleSidebar', this.toggleSidebar);
window.addEventListener('blur', this.trackIframeCampaign);
}
function beforeUnmount() {
document.removeEventListener('click', this.blur);
window.removeEventListener('resize', this.resize);
window.removeEventListener('blur', this.trackIframeCampaign);
}
export default {
@@ -141,11 +129,10 @@ export default {
mounted,
beforeUnmount,
methods: {
setConsent,
toggleSidebar,
toggleFilters,
toggleSettings,
trackIframeCampaign,
setConsent,
blur,
resize,
scroll,

View File

@@ -20,13 +20,13 @@ export default {
components: {
EntityTile,
},
emits: ['load'],
props: {
entity: {
type: Object,
default: null,
},
},
emits: ['load'],
};
</script>

View File

@@ -1,8 +1,7 @@
<template>
<RouterLink
<router-link
:to="`/${entity.type}/${entity.slug}`"
:title="entity.name"
:target="target"
class="tile"
>
<div class="tile-logo">
@@ -48,7 +47,7 @@
<span v-if="typeof entity.sceneTotal !== 'undefined'">{{ entity.sceneTotal }} scenes</span>
<span v-if="entity.type === 'network'">{{ entity.childrenTotal }} channels</span>
</span>
</RouterLink>
</router-link>
</template>
<script>
@@ -58,10 +57,6 @@ export default {
type: Object,
default: null,
},
target: {
type: String,
default: null,
},
},
emits: ['load'],
};

View File

@@ -99,7 +99,7 @@
<Icon
v-if="notification.alert"
v-tooltip="`You set an alert for scenes with <strong>${notification.alert.all ? 'all of' : 'any of'}</strong> <strong>${notification.alert.actors.map(actor => actor.name).join(', ') || 'any actor'}</strong> containing <strong>${notification.alert.tags.map(tag => tag.name).join(', ') || 'any tags'}</strong> from <strong>${notification.alert.entities.map((entity) => entity.name).join(', ') || 'any channel'}</strong> matching <strong>${notification.alert.matches.map((match) => `${match.property}: ${match.expression}`).join(', ') || 'any text'}</strong>`"
v-tooltip="`You set an alert for <strong>${notification.alert.tags.map(tag => tag.name).join(', ') || 'all'}</strong> scenes with <strong>${notification.alert.actors.map(actor => actor.name).join(', ') || 'any actor'}</strong> for <strong>${notification.alert.entity?.name || 'any channel'}</strong>`"
icon="question5"
@click.prevent.stop
/>
@@ -145,12 +145,12 @@ export default {
default: 0,
},
},
emits: ['addAlert'],
data() {
return {
showAddAlert: false,
};
},
emits: ['addAlert'],
methods: {
checkNotifications,
checkNotification,

View File

@@ -2,7 +2,7 @@
<div class="media-container">
<div
class="media"
:class="{ center: (release.photos?.length || 0) + (release.caps?.length || 0) + (release.scenesPhotos?.length || 0) < 2, preview: !me }"
:class="{ center: (release.photos?.length || 0) + (release.scenesPhotos?.length || 0) < 2, preview: !me }"
>
<div
v-if="release.trailer || release.teaser"
@@ -169,10 +169,9 @@ function photos() {
const clips = this.release.clips || [];
const clipPostersById = clips.reduce((acc, clip) => ({ ...acc, [clip.poster.id]: clip.poster }), {});
const uniqueClipPosters = Array.from(new Set(clips.map((clip) => clip.poster.id) || [])).map((posterId) => clipPostersById[posterId]);
const photosWithClipPosters = (this.release.photos || []).concat(this.release.caps || []).concat(this.release.scenesPhotos || []).concat(uniqueClipPosters);
const photosWithClipPosters = (this.release.photos || []).concat(this.release.scenesPhotos || []).concat(uniqueClipPosters);
if (this.release.trailer || (this.release.teaser && this.release.teaser.mime !== 'image/gif')) {
// if (this.release.trailer) {
// poster will be on trailer video
return photosWithClipPosters;
}

View File

@@ -21,24 +21,21 @@
<Details :release="release" />
<button
v-if="showAlbum"
v-if="release.photos?.length > 0 || release.scenesPhotos?.length > 0"
class="album-toggle"
@click="$router.push({ hash: '#album' })"
><Icon icon="grid3" />View album</button>
<Album
v-if="showAlbum && $route.hash === '#album'"
:items="[release.poster, ...(release.photos || []), ...(release.caps || []), ...(release.scenesPhotos || [])]"
v-if="showAlbum"
:items="[release.poster, ...(release.photos || []), ...(release.scenesPhotos || [])]"
:title="release.title"
:path="config.media.mediaPath"
@close="$router.replace({ hash: undefined })"
/>
<div class="info column">
<div
class="row row-title"
:class="{ 'has-alt': release.altTitles?.length > 0 }"
>
<div class="row row-title">
<h2
v-if="release.title"
class="title"
@@ -65,19 +62,6 @@
/>
</div>
<div
v-if="release.altTitles?.length > 0"
class="row alttitles"
>
<h2
v-for="(altTitle, index) in release.altTitles"
:key="`altitle-${index}`"
class="alttitle"
>
{{ altTitle }}
</h2>
</div>
<Releases
v-if="release.scenes && release.scenes.length > 0"
:releases="release.scenes"
@@ -171,14 +155,6 @@
<div class="duration">{{ formatDuration(release.duration) }}</div>
</div>
<div
v-if="release.photoCount"
class="row-tidbit"
>
<span class="row-label">Photos</span>
{{ release.photoCount }}
</div>
<div
v-if="release.shootId"
class="row-tidbit"
@@ -415,7 +391,7 @@ function pageTitle() {
}
function showAlbum() {
return this.release.photos?.length > 0 || this.release.caps?.length > 0 || this.release.scenesPhotos?.length > 0;
return (this.release.photos?.length > 0 || this.release.scenesPhotos?.length > 0) && this.$route.hash === '#album';
}
async function mounted() {
@@ -544,11 +520,6 @@ export default {
color: var(--shadow);
}
.alttitle {
color: var(--shadow);
font-size: 1rem;
}
.album-toggle {
height: fit-content;
display: inline-flex;

View File

@@ -57,12 +57,7 @@
<script setup>
import config from 'config';
import {
defineProps,
defineEmits,
computed,
} from 'vue';
import { defineProps, defineEmits, computed } from 'vue';
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';

View File

@@ -28,12 +28,7 @@
</template>
<span
v-if="error"
class="error summary"
>{{ error }}</span>
<span
v-else-if="!loading && actors.length === 0 && releases.length === 0"
v-if="!loading && actors.length === 0 && releases.length === 0"
class="summary"
>No results</span>
</div>
@@ -44,23 +39,16 @@ import Actor from '../actors/tile.vue';
import Releases from '../releases/releases.vue';
async function search() {
try {
const results = await this.$store.dispatch('search', {
query: this.query,
limit: 10,
});
const results = await this.$store.dispatch('search', {
query: this.query,
limit: 10,
});
this.loading = false;
this.loading = false;
if (results) {
this.actors = results.actors;
this.releases = results.releases;
}
} catch (error) {
this.loading = false;
this.error = 'Failed to retrieve search results, sorry about that.';
console.error(error);
if (results) {
this.actors = results.actors;
this.releases = results.releases;
}
}
@@ -113,10 +101,6 @@ export default {
margin: 0 0 1rem 0;
color: var(--shadow);
font-weight: bold;
&.error {
color: var(--error);
}
}
.tiles {

View File

@@ -125,7 +125,6 @@ function mounted() {
}
export default {
emits: ['open', 'close'],
data() {
return {
opened: false,
@@ -134,6 +133,7 @@ export default {
arrowOffset: 0,
};
},
emits: ['open', 'close'],
mounted,
methods: {
calculate,

View File

@@ -93,43 +93,17 @@
</div>
<div
v-if="alert.entities.length > 0"
v-if="alert.entity"
class="alert-section alert-trigger"
>
<h4 class="alert-heading">{{ alert.entities.length > 1 ? 'Channels' : 'Channel' }}</h4>
<h4 class="alert-heading">Channel</h4>
<Entity
v-for="entity in alert.entities"
:key="`${alert.id}${entity.id}`"
:entity="entity"
v-if="alert.entity"
:entity="alert.entity"
class="entity"
/>
</div>
<div
v-if="alert.matches.length > 0"
class="alert-section alert-trigger"
>
<h4 class="alert-heading">Matches</h4>
<ul class="alert-matches nolist">
<li
v-for="match in alert.matches"
:key="`match-${match.id}`"
class="match"
>
<span
v-if="match.expression.slice(0, 1) === '/' && match.expression.slice(-1) === '/'"
class="match-expression"
><span class="match-slash">/</span>{{ match.expression.slice(1, -1) }}<span class="match-slash">/</span></span>
<span
v-else
class="match-expression"
>{{ match.expression }}</span>
</li>
</ul>
</div>
</div>
</div>
</template>
@@ -253,34 +227,26 @@ export default {
}
.alert-actors,
.alert-tags,
.alert-matches {
.alert-tags {
display: flex;
grid-gap: .5rem;
}
.tag,
.match {
.tag {
color: var(--shadow-strong);
padding: .5rem;
border: solid 1px var(--shadow-hint);
font-size: .9rem;
font-weight: bold;
}
.tag:hover {
cursor: pointer;
border: solid 1px var(--primary);
&:hover {
cursor: pointer;
border: solid 1px var(--primary);
}
}
.entity {
width: 10rem;
height: 2.5rem;
}
.match-slash {
padding: 0 .1rem;
color: var(--primary);
font-weight: bold;
}
</style>

View File

@@ -18,10 +18,6 @@
<link rel="stylesheet" href="/css/style.css">
<script src="/js/bundle.js" defer></script>
<% if (analytics.enabled) { %>
<script async src="<%- analytics.address %>" data-website-id="<%- analytics.siteId %>"></script>
<% } %>
</head>
<body>
<div id="container"></div>

View File

@@ -80,7 +80,6 @@ function curateRelease(release, type = 'scene', context = {}) {
curatedRelease.series = release.series?.filter(Boolean).map(({ serie }) => curateRelease(serie, 'serie', context)) || [];
curatedRelease.chapters = release.chapters?.filter(Boolean).map((chapter) => curateRelease(chapter, 'chapter', context)) || [];
curatedRelease.photos = release.photos?.filter(Boolean).map((photo) => photo.media || photo) || [];
curatedRelease.caps = release.caps?.filter(Boolean).map((cap) => cap.media || cap) || [];
curatedRelease.scenesPhotos = release.scenesPhotos?.filter(Boolean).map((photo) => photo.media || photo) || [];
curatedRelease.covers = release.covers?.filter(Boolean).map(({ media }) => media) || [];
@@ -191,10 +190,6 @@ function curateAlert(alert) {
curatedAlert.entity = curateEntity(alert.entity.entity || alert.entity);
}
if (alert.entities) {
curatedAlert.entities = alert.entities.map((entity) => curateEntity(entity.entity || entity));
}
if (alert.stashes) {
curatedAlert.stashes = alert.stashes.map((stash) => curateStash(stash.stash || stash));
}

View File

@@ -22,7 +22,7 @@ function initEntitiesActions(store, router) {
$offset: Int = 0,
$after: Datetime = "1900-01-01",
$before: Datetime = "2100-01-01",
$orderBy: [ReleasesSummariesOrderBy!]
$orderBy: [ReleasesOrderBy!]
$exclude: [String!]
$hasAuth: Boolean!
$userId: Int
@@ -67,6 +67,7 @@ function initEntitiesActions(store, router) {
independent
hasLogo
${campaignsFragment}
sceneTotal
children: childEntitiesConnection {
totalCount
}
@@ -84,47 +85,50 @@ function initEntitiesActions(store, router) {
${campaignsFragment}
}
}
connection: releasesSummariesConnection(
connection: releasesConnection(
first: $limit
offset: $offset
orderBy: $orderBy
filter: {
effectiveDate: { lessThan: $before, greaterThan: $after }
showcased: { equalTo: true }
and: [
{
or: [
{
not: { tags: { overlaps: $exclude } }
entity: {
or: [
{
slug: { equalTo: $entitySlug }
type: { equalTo: $entityType }
}
{
parent:{
slug: { equalTo: $entitySlug }
type: { equalTo: $entityType }
}
{
tags: { isNull: true }
}
{
parent:{
parent: {
slug: { equalTo: $entitySlug }
type: { equalTo: $entityType }
}
}
]
}
]
}
effectiveDate: {
lessThan: $before,
greaterThan: $after
}
releasesTagsConnection: {
none: {
tag: {
slug: {
in: $exclude
}
}
}
{
or: [
{
channelSlug: { equalTo: $entitySlug }
channelType: { equalTo: $entityType }
}
{
networkSlug: { equalTo: $entitySlug }
networkType: { equalTo: $entityType }
}
{
parentNetworkSlug: { equalTo: $entitySlug }
parentNetworkType: { equalTo: $entityType }
}
]
}
]
}
}
) {
releases: nodes {
release {
${releaseFields}
}
${releaseFields}
}
totalCount
}
@@ -149,7 +153,7 @@ function initEntitiesActions(store, router) {
}
return {
entity: curateEntity(entity, null, connection.releases.map(({ release }) => release), { lastBatch: lastBatch?.id }),
entity: curateEntity(entity, null, connection.releases, { lastBatch: lastBatch?.id }),
totalCount: connection.totalCount,
};
}

View File

@@ -97,13 +97,6 @@ const actorFields = `
${actorStashesFields}
`;
const basicActorFields = `
id
name
slug
gender
`;
const movieFields = `
id
title
@@ -247,14 +240,6 @@ const releaseActorsFragment = `
}
`;
const releaseBasicActorsFragment = `
actors: releasesActors(orderBy: ACTOR_BY_ACTOR_ID__GENDER_ASC) {
actor {
${basicActorFields}
}
}
`;
const releaseDirectorFragment = `
directors: releasesDirectors(orderBy: ACTOR_BY_DIRECTOR_ID__NAME_ASC) {
director {
@@ -354,31 +339,6 @@ const releasePhotosFragment = `
}
`;
const releaseCapsFragment = `
caps: releasesCaps(orderBy: MEDIA_BY_MEDIA_ID__INDEX_ASC) {
media {
id
index
path
thumbnail
width
height
thumbnailWidth
thumbnailHeight
lazy
isS3
comment
sfw: sfwMedia {
id
thumbnail
lazy
path
comment
}
}
}
`;
const releaseTrailerFragment = `
trailer: releasesTrailer {
media {
@@ -419,11 +379,11 @@ const releaseFields = `
createdAt
url
createdBatchId
${releaseBasicActorsFragment}
${releaseActorsFragment}
${releaseTagsFragment}
${releasePosterFragment}
${releaseCoversFragment}
${releasePhotosFragment}
${releaseCapsFragment}
${siteFragment}
studio {
id
@@ -459,7 +419,6 @@ const releaseFields = `
`;
// isNew too performance-intensive
/*
const releasesFragment = `
connection: releasesConnection(
filter: {
@@ -488,35 +447,6 @@ const releasesFragment = `
totalCount
}
`;
*/
const releasesFragment = `
connection: releasesSummariesConnection(
first: $limit
offset: $offset
orderBy: $orderBy
filter: {
or: [
{
not: { tags: { overlaps: $exclude } }
}
{
tags: { isNull: true }
}
]
effectiveDate: { lessThan: $before, greaterThan: $after }
showcased: { equalTo: true }
batchShowcased: { in: $batchShowcased }
}
) {
releases: nodes {
release {
${releaseFields}
}
}
totalCount
}
`;
const mediaFields = `
id
@@ -545,7 +475,6 @@ const releaseFragment = `
release(id: $releaseId) {
id
title
altTitles
description
date
datePrecision
@@ -553,7 +482,6 @@ const releaseFragment = `
createdAt
shootId
qualities
photoCount
productionDate
createdBatchId
productionLocation
@@ -571,7 +499,6 @@ const releaseFragment = `
${releaseTagsFragment}
${releasePosterFragment}
${releasePhotosFragment}
${releaseCapsFragment}
${releaseCoversFragment}
${releaseTrailerFragment}
${releaseTeaserFragment}
@@ -675,11 +602,7 @@ const releaseFragment = `
`;
const batchFragment = `
batches(
first: 1,
orderBy: CREATED_AT_DESC,
filter: { showcased: { equalTo: true } }
) {
batches(first: 1, orderBy: CREATED_AT_DESC) {
id
}
`;

View File

@@ -23,9 +23,8 @@ function initReleasesActions(store, router) {
$offset:Int = 0,
$after:Datetime = "1900-01-01 00:00:00",
$before:Datetime = "2100-01-01 00:00:00",
$orderBy: [ReleasesSummariesOrderBy!],
$exclude: [String!],
$batchShowcased: [Boolean!]
$orderBy: [ReleasesOrderBy!],
$exclude: [String!]
) {
${releasesFragment}
${batchFragment}
@@ -39,7 +38,6 @@ function initReleasesActions(store, router) {
before,
orderBy,
exclude: store.state.ui.tagFilter,
batchShowcased: range === 'new' ? true : [true, false],
});
return {

View File

@@ -15,19 +15,19 @@ function initTagsActions(store, _router) {
}) {
const { before, after, orderBy } = getDateRange(range);
const { tagBySlug, scenesConnection, batches: [lastBatch] } = await graphql(`
const { tagBySlug, batches: [lastBatch] } = await graphql(`
query Tag(
$tagSlug: String!
$tagSlug:String!
$offset: Int = 0,
$limit:Int = 1000,
$after:Datetime = "1900-01-01",
$before:Datetime = "2100-01-01",
$orderBy: [ReleasesSummariesOrderBy!],
$orderBy: [ReleasesOrderBy!],
$exclude: [String!]
$hasAuth: Boolean!
$userId: Int
) {
tagBySlug(slug: $tagSlug) {
tagBySlug(slug:$tagSlug) {
id
name
slug
@@ -155,32 +155,32 @@ function initTagsActions(store, _router) {
}
}
}
}
scenesConnection: releasesSummariesConnection(
first: $limit
offset: $offset
orderBy: $orderBy
filter: {
or: [
{
not: { tags: { overlaps: $exclude } }
}
{
tags: { isNull: true }
}
]
tags: { anyEqualTo: $tagSlug }
effectiveDate: { lessThan: $before, greaterThan: $after }
showcased: { equalTo: true }
}
) {
releases: nodes {
release {
scenesConnection(
filter: {
effectiveDate: {
lessThan: $before,
greaterThan: $after,
},
releasesTagsConnection: {
none: {
tag: {
slug: {
in: $exclude
}
}
}
}
},
first: $limit,
orderBy: $orderBy,
offset: $offset
) {
releases: nodes {
${releaseFields}
}
totalCount
}
totalCount
}
}
${batchFragment}
}
`, {
@@ -197,8 +197,8 @@ function initTagsActions(store, _router) {
return {
tag: curateTag(tagBySlug, null, curateRelease),
releases: scenesConnection.releases.map(({ release }) => curateRelease(release, 'scene', { lastBatch: lastBatch.id })),
totalCount: scenesConnection.totalCount,
releases: tagBySlug.scenesConnection.releases.map((release) => curateRelease(release, 'scene', { lastBatch: lastBatch.id })),
totalCount: tagBySlug.scenesConnection.totalCount,
};
}

View File

@@ -68,7 +68,6 @@ function initUiActions(store, _router) {
${releaseFields}
}
alert {
all
tags: alertsTags {
tag {
id
@@ -83,7 +82,7 @@ function initUiActions(store, _router) {
slug
}
}
entities: alertsEntities {
entity: alertsEntity {
entity {
id
name
@@ -91,10 +90,6 @@ function initUiActions(store, _router) {
independent
}
}
matches: alertsMatches {
property
expression
}
}
}
totalCount
@@ -264,6 +259,7 @@ function initUiActions(store, _router) {
}
async function fetchCampaign(context, campaignId) {
console.log(campaignId);
const { campaign } = await graphql(`
query Campaign(
$campaignId: Int!

View File

@@ -71,7 +71,6 @@ function initUsersActions(store, _router) {
id
notify
email
all
stashes: alertsStashes {
stash {
id
@@ -86,17 +85,12 @@ function initUsersActions(store, _router) {
slug
}
}
matches: alertsMatches {
id
property
expression
}
actors: alertsActors {
actor {
${actorFields}
}
}
entities: alertsEntities {
entity: alertsEntity {
entity {
id
name

View File

@@ -1,53 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="theme-color" content="#ff2288">
<title>traxxx | maintenance</title>
<link rel="icon" href="/img/favicon/favicon-32.ico">
<link rel="icon" href="/img/favicon/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/img/favicon/favicon-180.png">
<link rel="manifest" href="/img/favicon/manifest.webmanifest">
<meta name="msapplication-TileColor" content="#aa2c66">
<meta name="msapplication-config" content="/img/favicon/browserconfig.xml">
<style>
body,
html {
width: 100%;
height: 100%;
margin: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
font-family: sans-serif;
background: url('/maintenance/maintenance_shay_evans_2.jpeg');
background-position: top center;
background-size: cover
}
.text {
padding: 2rem;
margin: 1rem;
color: white;
text-align: center;
text-shadow: 0 0 5px black;
font-size: 1.5rem;
font-weight: bold;
border-radius: 2rem;
backdrop-filter: blur(.5rem);
}
</style>
</head>
<body>
<div class="text">Traxxx is currently under maintenance. We will be back shortly!</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

View File

@@ -12,20 +12,8 @@ module.exports = {
password: 'password',
database: 'traxxx',
},
manticore: {
host: '127.0.0.1',
sqlPort: 9306,
httpPort: 9308,
},
timeout: 5000,
graphiql: false,
pool: {
min: 0,
max: 20,
acquireTimeoutMillis: 300000,
createTimeoutMillis: 300000,
destroyTimeoutMillis: 300000,
},
},
web: {
host: '0.0.0.0',
@@ -42,20 +30,6 @@ module.exports = {
},
},
},
redis: {
host: 'localhost',
port: 6379,
username: null,
password: null,
},
location: {
userAgent: 'contact via https://traxxx.me/',
},
analytics: {
enabled: false,
address: 'http://localhost:3000/script.js',
siteId: '1b28ac3b-d229-43bf-aec9-75cf0a72a466',
},
s3: {
enabled: false,
bucket: 'traxxx',
@@ -68,9 +42,6 @@ module.exports = {
usernameLength: [2, 24],
usernamePattern: /^[a-zA-Z0-9_-]+$/,
},
stashes: {
viewRefreshCooldown: 60, // minutes
},
exclude: {
channels: [
// 21sextreme, no longer updated
@@ -86,7 +57,6 @@ module.exports = {
'amberathome',
'marycarey',
'racqueldevonshire',
'aziani',
// blowpass
'sunlustxxx',
// ddfnetwork
@@ -390,7 +360,7 @@ module.exports = {
thumbnailQuality: 100,
lazySize: 90,
lazyQuality: 90,
trailerQuality: [540, 720, 480, 360, 960, 1080, 320, 1440, 1600, 1920, 2160, 270, 240, 180],
trailerQuality: [480, 540, 360, 720, 960, 1080, 320, 1440, 1600, 1920, 2160, 270, 240, 180],
limit: 25, // max number of photos per release
attempts: 2,
fetchStreams: true,

View File

@@ -1,4 +0,0 @@
# Puppeteer
Puppeteer has several dependencies that may not be available in Debian 12 by default:
`apt install libasound2 libatk-bridge2.0-0 libcairo2 libcups2 libdrm2 libgbm-dev libpango-1.0-0 libxcomposite1 libxdamage1 libxfixes3 libxkbcommon-x11-0 libxrandr2 `

View File

@@ -1,4 +1,4 @@
const config = require('config');
// const config = require('config');
module.exports = {
apps: [
@@ -14,15 +14,5 @@ module.exports = {
NODE_ENV: 'production',
},
},
...(config.analytics.enabled ? [{
name: 'umami',
script: 'npm start',
cwd: process.env.UMAMI_DIR || '../umami',
restart_delay: 3000,
merge_logs: true,
env: {
NODE_ENV: 'production',
},
}] : []),
],
};

View File

@@ -1,47 +0,0 @@
const config = require('config');
exports.up = async (knex) => {
await knex.raw(`
CREATE MATERIALIZED VIEW releases_summaries AS (
SELECT
releases.id as release_id,
channels.slug as channel_slug,
channels.type as channel_type,
networks.slug as network_slug,
networks.type as network_type,
parent_networks.slug as parent_network_slug,
parent_networks.type as parent_network_type,
studios.showcased IS NOT false
AND (channels.showcased IS NOT false OR COALESCE(studios.showcased, false) = true)
AND (networks.showcased IS NOT false OR COALESCE(channels.showcased, false) = true OR COALESCE(studios.showcased, false) = true)
AS showcased,
batches.showcased AS batch_showcased,
releases.effective_date,
releases.created_at,
array_agg(tags.slug ORDER BY tags.priority DESC) FILTER (WHERE tags.slug IS NOT NULL) AS tags
FROM releases
LEFT JOIN releases_tags ON releases_tags.release_id = releases.id
LEFT JOIN tags ON tags.id = releases_tags.tag_id
LEFT JOIN entities AS channels ON channels.id = releases.entity_id
LEFT JOIN entities AS studios ON studios.id = releases.studio_id
LEFT JOIN entities AS networks ON networks.id = channels.parent_id
LEFT JOIN entities AS parent_networks ON parent_networks.id = networks.parent_id
LEFT JOIN batches ON batches.id = releases.updated_batch_id
GROUP BY releases.id, studios.showcased, batches.showcased,
channels.showcased, channels.slug, channels.type,
networks.showcased, networks.slug, networks.type,
parent_networks.slug, parent_networks.type
);
COMMENT ON MATERIALIZED VIEW releases_summaries IS E'@foreignKey (release_id) references releases (id)';
GRANT ALL ON releases_summaries TO :visitor;
`, {
visitor: knex.raw(config.database.query.user),
});
};
exports.down = async (knex) => {
await knex.raw(`
DROP MATERIALIZED VIEW IF EXISTS releases_summaries;
`);
};

View File

@@ -1,27 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('actors_social', (table) => {
table.integer('profile_id')
.references('id')
.inTable('actors_profiles');
table.dropUnique(['url', 'actor_id']);
table.unique(['url', 'actor_id', 'profile_id']);
});
await knex.raw(`
CREATE UNIQUE INDEX actors_social_url_actor_id_null_unique ON actors_social (url, actor_id) WHERE profile_id IS NULL;
`);
};
exports.down = async (knex) => {
await knex.raw(`
DROP INDEX actors_social_url_actor_id_null_unique;
`);
await knex.schema.alterTable('actors_social', (table) => {
table.dropUnique(['url', 'actor_id', 'profile_id']);
table.unique(['url', 'actor_id']);
table.dropColumn('profile_id');
});
};

View File

@@ -1,24 +0,0 @@
const config = require('config');
exports.up = async (knex) => {
await knex.schema.createTable('releases_caps', (table) => {
table.integer('release_id')
.notNullable()
.references('id')
.inTable('releases')
.onDelete('cascade');
table.text('media_id')
.notNullable()
.references('id')
.inTable('media');
});
await knex.raw('GRANT ALL ON releases_caps TO :visitor;', {
visitor: knex.raw(config.database.query.user),
});
};
exports.down = async (knex) => {
await knex.schema.dropTable('releases_caps');
};

View File

@@ -1,27 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('actors_profiles', (table) => {
table.string('hair_type');
table.decimal('shoe_size');
table.string('blood_type');
});
await knex.schema.alterTable('actors', (table) => {
table.string('hair_type');
table.decimal('shoe_size');
table.string('blood_type');
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('actors_profiles', (table) => {
table.dropColumn('hair_type');
table.dropColumn('shoe_size');
table.dropColumn('blood_type');
});
await knex.schema.alterTable('actors', (table) => {
table.dropColumn('hair_type');
table.dropColumn('shoe_size');
table.dropColumn('blood_type');
});
};

View File

@@ -1,13 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('batches', (table) => {
table.boolean('showcased')
.notNullable()
.defaultTo(true);
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('batches', (table) => {
table.dropColumn('showcased');
});
};

View File

@@ -1,27 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('releases', (table) => {
table.specificType('alt_titles', 'text ARRAY');
});
await knex.schema.alterTable('movies', (table) => {
table.specificType('alt_titles', 'text ARRAY');
});
await knex.schema.alterTable('series', (table) => {
table.specificType('alt_titles', 'text ARRAY');
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('releases', (table) => {
table.dropColumn('alt_titles');
});
await knex.schema.alterTable('movies', (table) => {
table.dropColumn('alt_titles');
});
await knex.schema.alterTable('series', (table) => {
table.dropColumn('alt_titles');
});
};

View File

@@ -1,36 +0,0 @@
exports.up = async (knex) => {
await knex.schema.createTable('movies_teasers', (table) => {
table.integer('movie_id', 16)
.notNullable()
.references('id')
.inTable('movies')
.onDelete('cascade');
table.text('media_id', 21)
.notNullable()
.references('id')
.inTable('media');
table.unique('movie_id');
});
await knex.schema.createTable('series_teasers', (table) => {
table.integer('serie_id', 16)
.notNullable()
.references('id')
.inTable('series')
.onDelete('cascade');
table.text('media_id', 21)
.notNullable()
.references('id')
.inTable('media');
table.unique('serie_id');
});
};
exports.down = async (knex) => {
await knex.schema.dropTable('movies_teasers');
await knex.schema.dropTable('series_teasers');
};

View File

@@ -1,19 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('releases', (table) => {
table.integer('photo_count');
});
await knex.schema.alterTable('movies', (table) => {
table.integer('photo_count');
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('releases', (table) => {
table.dropColumn('photo_count');
});
await knex.schema.alterTable('movies', (table) => {
table.dropColumn('photo_count');
});
};

View File

@@ -1,42 +0,0 @@
const config = require('config');
exports.up = async (knex) => {
await knex.schema.alterTable('alerts', (table) => {
table.boolean('all')
.defaultTo(true);
});
await knex.schema.alterTable('alerts_entities', (table) => {
table.dropUnique('alert_id');
});
await knex.schema.createTable('alerts_matches', (table) => {
table.increments('id');
table.integer('alert_id')
.references('id')
.inTable('alerts')
.onDelete('cascade');
table.string('property');
table.string('expression');
});
await knex.raw(`
GRANT SELECT ON alerts_matches TO :visitor;
`, {
visitor: knex.raw(config.database.query.user),
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('alerts', (table) => {
table.dropColumn('all');
});
await knex.schema.alterTable('alerts_entities', (table) => {
table.unique('alert_id');
});
await knex.schema.dropTable('alerts_matches');
};

View File

@@ -1,21 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('tags', (table) => {
table.specificType('implied_tag_ids', 'integer[]');
});
await knex.schema.alterTable('releases_tags', (table) => {
table.enum('source', ['scraper', 'editor', 'implied'])
.notNullable()
.defaultTo('scraper');
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('tags', (table) => {
table.dropColumn('implied_tag_ids');
});
await knex.schema.alterTable('releases_tags', (table) => {
table.dropColumn('source');
});
};

View File

@@ -1,19 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('movies', (table) => {
table.integer('photo_count');
});
await knex.schema.alterTable('series', (table) => {
table.integer('photo_count');
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('movies', (table) => {
table.dropColumn('photo_count');
});
await knex.schema.alterTable('series', (table) => {
table.dropColumn('photo_count');
});
};

View File

@@ -1,62 +0,0 @@
const config = require('config');
exports.up = async function up(knex) {
await knex.raw(`
CREATE MATERIALIZED VIEW actors_meta AS (
SELECT
actors.id as actor_id,
COUNT(DISTINCT stashes_actors)::integer as stashed,
COUNT(DISTINCT releases_actors)::integer as scenes,
row_to_json(avatars) as avatar
FROM actors
LEFT JOIN stashes_actors ON stashes_actors.actor_id = actors.id
LEFT JOIN releases_actors ON releases_actors.actor_id = actors.id
LEFT JOIN media AS avatars ON avatars.id = actors.avatar_media_id
GROUP BY
actors.id,
avatars.id
);
CREATE MATERIALIZED VIEW scenes_meta AS (
SELECT
releases.id as scene_id,
COUNT(DISTINCT stashes_scenes)::integer as stashed
FROM releases
LEFT JOIN stashes_scenes ON stashes_scenes.scene_id = releases.id
GROUP BY releases.id
);
CREATE MATERIALIZED VIEW movies_meta AS (
SELECT
movie_id,
stashed,
stashed_scenes,
stashed + stashed_scenes as stashed_total
FROM (
SELECT
movies.id as movie_id,
COUNT(DISTINCT stashes_movies)::integer as stashed,
COUNT(DISTINCT stashes_scenes)::integer as stashed_scenes
FROM movies
LEFT JOIN stashes_movies ON stashes_movies.movie_id = movies.id
LEFT JOIN movies_scenes ON movies_scenes.movie_id = movies.id
LEFT JOIN stashes_scenes ON stashes_scenes.scene_id = movies_scenes.scene_id
GROUP BY movies.id
) AS meta
);
GRANT ALL ON actors_meta TO :visitor;
GRANT ALL ON scenes_meta TO :visitor;
GRANT ALL ON movies_meta TO :visitor;
`, {
visitor: knex.raw(config.database.query.user),
});
};
exports.down = async function down(knex) {
await knex.raw(`
DROP MATERIALIZED VIEW IF EXISTS actors_meta;
DROP MATERIALIZED VIEW IF EXISTS scenes_meta;
DROP MATERIALIZED VIEW IF EXISTS movies_meta;
`);
};

View File

@@ -1,127 +0,0 @@
const config = require('config');
const manticore = require('manticoresearch');
const mantiClient = new manticore.ApiClient();
mantiClient.basePath = `http://${config.database.manticore.host}:${config.database.manticore.httpPort}`;
const utilsApi = new manticore.UtilsApi(mantiClient);
const scenesFields = `
id int,
title text,
title_filtered text,
shoot_id text,
channel_id int,
channel_name text,
channel_slug text,
network_id int,
network_name text,
network_slug text,
entity_ids multi,
actor_ids multi,
actors text,
tag_ids multi,
tags text,
meta text,
date timestamp,
is_showcased bool,
created_at timestamp,
effective_date timestamp,
stashed int
`;
const moviesFields = `
id int,
title text,
title_filtered text,
channel_id int,
channel_name text,
channel_slug text,
network_id int,
network_name text,
network_slug text,
entity_ids multi,
actor_ids multi,
actors text,
tag_ids multi,
tags text,
meta text,
date timestamp,
has_cover bool,
created_at timestamp,
effective_date timestamp,
stashed int,
stashed_scenes int,
stashed_total int
`;
const actorsFields = `
id int,
name text,
slug string,
gender string,
date_of_birth timestamp,
country string,
has_avatar bool,
mass int,
height int,
cup string,
natural_boobs int,
penis_length int,
penis_girth int,
stashed int,
scenes int
`;
exports.up = async (knex) => {
try {
await utilsApi.sql(`create table scenes (${scenesFields})`);
await utilsApi.sql(`create table scenes_stashed (
scene_id int,
stash_id int,
user_id int,
created_at timestamp
)`);
await utilsApi.sql(`create table movies (${moviesFields})`);
await utilsApi.sql(`create table movies_stashed (
movie_id int,
stash_id int,
user_id int,
created_at timestamp
)`);
await utilsApi.sql(`create table actors (${actorsFields})`);
await utilsApi.sql(`create table actors_stashed (
actor_id int,
stash_id int,
user_id int,
created_at timestamp
)`);
await knex.schema.alterTable('stashes_scenes', (table) => table.increments('id'));
await knex.schema.alterTable('stashes_movies', (table) => table.increments('id'));
await knex.schema.alterTable('stashes_actors', (table) => table.increments('id'));
await knex.schema.alterTable('stashes_series', (table) => table.increments('id'));
} catch (error) {
console.log(error);
}
};
exports.down = async (knex) => {
await utilsApi.sql('drop table if exists scenes');
await utilsApi.sql('drop table if exists scenes_stashed');
await utilsApi.sql('drop table if exists movies');
await utilsApi.sql('drop table if exists movies_stashed');
await utilsApi.sql('drop table if exists actors');
await utilsApi.sql('drop table if exists actors_stashed');
await knex.schema.alterTable('stashes_scenes', (table) => table.dropColumn('id'));
await knex.schema.alterTable('stashes_movies', (table) => table.dropColumn('id'));
await knex.schema.alterTable('stashes_actors', (table) => table.dropColumn('id'));
await knex.schema.alterTable('stashes_series', (table) => table.dropColumn('id'));
};

View File

@@ -1,21 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('users', (table) => {
table.dropUnique('username');
});
await knex.raw(`
CREATE UNIQUE INDEX username_unique_index ON users (LOWER(username));
CREATE UNIQUE INDEX email_unique_index ON users (LOWER(email));
`);
};
exports.down = async (knex) => {
await knex.raw(`
DROP INDEX IF EXISTS username_unique_index;
DROP INDEX IF EXISTS email_unique_index;
`);
await knex.schema.alterTable('users', (table) => {
table.unique('username');
});
};

View File

@@ -1,22 +0,0 @@
exports.up = async function up(knex) {
await knex.raw(`
CREATE MATERIALIZED VIEW stashes_meta AS (
SELECT
stashes.id as stash_id,
COUNT(DISTINCT stashes_scenes)::integer as stashed_scenes,
COUNT(DISTINCT stashes_movies)::integer as stashed_movies,
COUNT(DISTINCT stashes_actors)::integer as stashed_actors
FROM stashes
LEFT JOIN stashes_scenes ON stashes_scenes.stash_id = stashes.id
LEFT JOIN stashes_movies ON stashes_movies.stash_id = stashes.id
LEFT JOIN stashes_actors ON stashes_actors.stash_id = stashes.id
GROUP BY stashes.id
);
`);
};
exports.down = async function down(knex) {
await knex.raw(`
DROP MATERIALIZED VIEW IF EXISTS stashes_meta;
`);
};

View File

@@ -1,28 +0,0 @@
exports.up = async (knex) => {
await knex.schema.alterTable('alerts', (table) => {
table.boolean('all_actors')
.notNullable()
.defaultTo(true);
table.boolean('all_entities')
.notNullable()
.defaultTo(true);
table.boolean('all_tags')
.notNullable()
.defaultTo(true);
table.boolean('all_matches')
.notNullable()
.defaultTo(true);
});
};
exports.down = async (knex) => {
await knex.schema.alterTable('alerts', (table) => {
table.dropColumn('all_actors');
table.dropColumn('all_entities');
table.dropColumn('all_tags');
table.dropColumn('all_matches');
});
};

31851
package-lock.json generated Normal file → Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "traxxx",
"version": "1.237.11",
"version": "1.228.33",
"description": "All the latest porn releases in one place",
"main": "src/app.js",
"scripts": {
@@ -38,126 +38,103 @@
"author": "DebaucheryLibrarian",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.23.4",
"@babel/core": "^7.23.3",
"@babel/eslint-parser": "^7.23.3",
"@babel/cli": "^7.12.10",
"@babel/core": "^7.8.4",
"@babel/eslint-parser": "^7.16.0",
"@babel/plugin-proposal-optional-chaining": "^7.8.3",
"@babel/preset-env": "^7.23.3",
"@babel/register": "^7.22.15",
"autoprefixer": "^10.4.16",
"babel-loader": "^9.1.3",
"@babel/preset-env": "^7.8.4",
"@babel/register": "^7.8.3",
"autoprefixer": "^10.4.0",
"babel-loader": "^8.0.6",
"babel-preset-airbnb": "^5.0.0",
"css-loader": "^6.8.1",
"eslint": "^8.54.0",
"css-loader": "^6.5.0",
"eslint": "^8.44.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-vue": "^9.18.1",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-vue": "^8.0.3",
"eslint-watch": "^8.0.0",
"eslint-webpack-plugin": "^4.0.1",
"mini-css-extract-plugin": "^2.7.6",
"node-sass": "^9.0.0",
"postcss-loader": "^7.3.3",
"eslint-webpack-plugin": "^3.1.0",
"mini-css-extract-plugin": "^2.4.3",
"node-sass": "^6.0.1",
"postcss-loader": "^6.2.0",
"raw-loader": "^4.0.2",
"sass-loader": "^13.3.2",
"style-loader": "^3.3.3",
"vue-loader": "^17.3.1",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4"
"sass-loader": "^12.3.0",
"vue-loader": "^16.8.2",
"webpack": "^5.11.0",
"webpack-cli": "^4.9.1"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.458.0",
"@aws-sdk/credential-provider-ini": "^3.458.0",
"@aws-sdk/lib-storage": "^3.458.0",
"@casl/ability": "^6.5.0",
"@faker-js/faker": "^8.3.1",
"@graphile-contrib/pg-order-by-related": "^1.0.0",
"@graphile-contrib/pg-order-by-related": "^1.0.0-beta.6",
"@graphile-contrib/pg-simplify-inflector": "^6.1.0",
"@graphile/pg-aggregates": "^0.1.1",
"acorn": "^8.11.2",
"array-equal": "^1.0.2",
"array-equal": "^1.0.0",
"aws-sdk": "^2.847.0",
"babel-polyfill": "^6.26.0",
"bhttp": "^1.2.8",
"blake2": "^5.0.0",
"blake2": "^4.0.0",
"bluebird": "^3.7.2",
"body-parser": "^1.20.2",
"bottleneck": "^2.19.5",
"canvas": "^2.11.2",
"casual": "^1.6.2",
"cheerio": "^1.0.0-rc.12",
"cheerio": "^1.0.0-rc.3",
"cli-confirm": "^1.0.1",
"cloudscraper": "^4.6.0",
"config": "^3.3.9",
"connect-session-knex": "^4.0.0",
"convert": "^4.14.0",
"cookie": "^0.6.0",
"csv-stringify": "^6.4.4",
"config": "^3.2.5",
"connect-session-knex": "^2.0.0",
"convert": "^4.2.4",
"cookie": "^0.4.0",
"csv-stringify": "^5.3.6",
"date-fns": "^2.30.0",
"dayjs": "^1.11.10",
"dompurify": "^3.0.6",
"ejs": "^3.1.9",
"escape-string-regexp": "^4.0.0",
"express": "^4.18.2",
"express-promise-router": "^4.1.1",
"express-query-boolean": "^2.0.0",
"express-react-views": "^0.11.0",
"express-session": "^1.17.3",
"dayjs": "^1.8.21",
"dompurify": "^2.0.11",
"ejs": "^3.0.1",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"express-session": "^1.17.1",
"face-api.js": "^0.22.2",
"file-type": "^18.7.0",
"faker": "^5.1.0",
"file-type": "^16.5.3",
"fluent-ffmpeg": "^2.1.2",
"fs-extra": "^11.1.1",
"graphile-build": "^4.14.0",
"graphile-utils": "^4.14.0",
"graphql": "^15.8.0",
"html-entities": "^2.4.0",
"fs-extra": "^10.0.0",
"graphile-utils": "^4.12.2",
"graphql": "^15.4.0",
"html-entities": "^2.3.2",
"iconv-lite": "^0.6.3",
"inquirer": "^8.2.6",
"inspector-api": "^1.4.8",
"jsdom": "^23.0.1",
"knex": "^3.0.1",
"inquirer": "^8.2.0",
"inspector-api": "^1.4.2",
"jsdom": "^18.0.0",
"knex": "^0.95.12",
"knex-migrate": "^1.7.4",
"longjohn": "^0.2.12",
"manticoresearch": "^4.0.0",
"merge-anything": "^5.1.7",
"mime": "^3.0.0",
"mitt": "^3.0.1",
"moment": "^2.29.4",
"mysql": "^2.18.1",
"nanoid": "^3.3.7",
"node-fetch": "^3.3.2",
"mime": "^2.4.4",
"moment": "^2.24.0",
"nanoid": "^3.1.30",
"node-fetch": "^2.6.7",
"object-merge-advanced": "^12.1.0",
"object.omit": "^3.0.0",
"pg": "^8.11.3",
"postgraphile": "^4.14.0",
"postgraphile-plugin-connection-filter": "^2.3.0",
"pg": "^8.5.1",
"postgraphile": "^4.13.0",
"postgraphile-plugin-connection-filter": "^2.2.2",
"promise-task-queue": "^1.2.0",
"prop-types": "^15.8.1",
"puppeteer": "^21.5.2",
"puppeteer": "^20.5.0",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2",
"redis": "^4.6.11",
"sharp": "^0.33.0-rc.2",
"showdown": "^2.1.0",
"source-map-support": "^0.5.21",
"sharp": "^0.29.2",
"showdown": "^1.9.1",
"source-map-support": "^0.5.16",
"template-format": "^1.2.5",
"tippy.js": "^6.3.7",
"tough-cookie": "^4.1.3",
"tough-cookie": "^4.0.0",
"tunnel": "0.0.6",
"ua-parser-js": "^1.0.37",
"undici": "^5.28.1",
"unprint": "^0.10.11",
"ua-parser-js": "^1.0.32",
"unprint": "^0.10.1",
"url-pattern": "^1.0.3",
"v-tooltip": "^2.1.3",
"video.js": "^8.6.1",
"videojs-vr": "^2.0.0",
"vue": "^3.3.9",
"vue-router": "^4.2.5",
"vuex": "^4.1.0",
"why-is-node-running": "^2.2.2",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1",
"yargs": "^17.7.2"
"v-tooltip": "^2.0.3",
"vue": "^3.2.20",
"vue-router": "^4.0.12",
"vuex": "^4.0.2",
"why-is-node-running": "^2.2.0",
"winston": "^3.2.1",
"winston-daily-rotate-file": "^4.4.2",
"yargs": "^17.2.1"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
public/img/logos/analvids/lazy/analvids.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
public/img/logos/analvids/lazy/favicon.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
public/img/logos/analvids/lazy/favicon_dark.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
public/img/logos/analvids/lazy/favicon_light.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
public/img/logos/analvids/lazy/legalporno.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
public/img/logos/analvids/lazy/network.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 19 KiB

BIN
public/img/logos/analvids/thumbs/analvids.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 18 KiB

BIN
public/img/logos/analvids/thumbs/favicon.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
public/img/logos/analvids/thumbs/favicon_dark.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
public/img/logos/analvids/thumbs/favicon_light.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
public/img/logos/analvids/thumbs/legalporno.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/img/logos/analvids/thumbs/network.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Some files were not shown because too many files have changed in this diff Show More