Compare commits

..

94 Commits

Author SHA1 Message Date
DebaucheryLibrarian 90aa29d2d4 1.233.0 2023-11-24 02:10:06 +01:00
DebaucheryLibrarian 0369446681 Added AND/OR toggle to alerts. 2023-11-24 02:10:03 +01:00
DebaucheryLibrarian 238dce78b5 Refactored alerts to use application code, added regex. Updated Jules Jordan for the Ass Factory relaunch. 2023-11-24 01:29:22 +01:00
DebaucheryLibrarian 124ff3f5e3 1.232.2 2023-11-09 01:10:08 +01:00
DebaucheryLibrarian 1cf06a8b49 Fixed Vixen upcoming. 2023-11-09 01:10:05 +01:00
DebaucheryLibrarian a8bdb7ab59 1.232.1 2023-11-08 03:41:44 +01:00
DebaucheryLibrarian 08fd69af39 Added photo_count to movies table. 2023-11-08 03:41:41 +01:00
DebaucheryLibrarian 560ff103ce 1.232.0 2023-11-07 04:46:48 +01:00
DebaucheryLibrarian edc724b475 Storing photo counts. 2023-11-07 04:46:45 +01:00
DebaucheryLibrarian ac904c849d Fixed The Flourish POV URL. 2023-11-07 04:39:14 +01:00
DebaucheryLibrarian 5481b6e0a6 1.231.31 2023-11-07 04:29:38 +01:00
DebaucheryLibrarian eba96df631 Added The Flourish, adapted Arch Angel scraper. 2023-11-07 04:29:35 +01:00
DebaucheryLibrarian 7caa325c5f 1.231.30 2023-11-07 03:06:42 +01:00
DebaucheryLibrarian e20641e101 Fixed Teen Mega World scraper. 2023-11-07 03:06:39 +01:00
DebaucheryLibrarian 8f81f71802 1.231.29 2023-09-24 04:29:46 +02:00
DebaucheryLibrarian e7a4ccecf3 Renamed Natasha Teen Productions to Natasha Teen Films. 2023-09-24 04:29:43 +02:00
DebaucheryLibrarian ec33a8b5a9 1.231.28 2023-09-17 21:59:18 +02:00
DebaucheryLibrarian 4a9aa62831 Changed inadvertent click prevention in actor tile scrolling for improved native interactions. 2023-09-17 21:59:15 +02:00
DebaucheryLibrarian 8b5eada088 1.231.27 2023-08-28 02:53:38 +02:00
DebaucheryLibrarian eeb947d311 Catching media store fail unlink error to prevent batch failure. 2023-08-28 02:53:35 +02:00
DebaucheryLibrarian 430d7a8cdd 1.231.26 2023-08-16 06:31:51 +02:00
DebaucheryLibrarian c94dcdd9e6 Updated Radical to support Top Web Models. 2023-08-16 06:31:49 +02:00
DebaucheryLibrarian 46c514f530 1.231.25 2023-08-16 03:08:50 +02:00
DebaucheryLibrarian b29a34c76a Updated AnalVids. 2023-08-16 03:08:47 +02:00
DebaucheryLibrarian 20ba833147 1.231.24 2023-08-14 01:54:19 +02:00
DebaucheryLibrarian 1ed47c3173 Updated Radical scraper. Added town property to location resolve tool. 2023-08-14 01:54:17 +02:00
DebaucheryLibrarian ccac1f96dd 1.231.23 2023-08-13 21:57:35 +02:00
DebaucheryLibrarian c860bfebc1 Separated error log. Added search/summary update tool. 2023-08-13 21:57:32 +02:00
DebaucheryLibrarian d5806c3d31 1.231.22 2023-08-12 23:19:33 +02:00
DebaucheryLibrarian bf36825fce Added Say Uncle channels. 2023-08-12 23:19:30 +02:00
DebaucheryLibrarian a1780e2c4b 1.231.21 2023-08-11 03:56:12 +02:00
DebaucheryLibrarian 02850eb6e3 Updated Team Skeet and MYLF. 2023-08-11 03:56:08 +02:00
DebaucheryLibrarian 71efd7a96f 1.231.20 2023-08-05 01:39:02 +02:00
DebaucheryLibrarian 3508e47600 Added alt_titles to series table. 2023-08-05 01:38:58 +02:00
DebaucheryLibrarian eef0be09b3 1.231.19 2023-08-05 00:09:15 +02:00
DebaucheryLibrarian 2df20aea38 Moved Aziani to Gamma. 2023-08-05 00:09:13 +02:00
DebaucheryLibrarian 1032c3cb57 1.231.18 2023-08-04 22:30:20 +02:00
DebaucheryLibrarian 5f26f8de27 Excluding studios from entity aggregration. Added profile scraping to Teste de Fudelidade. 2023-08-04 22:30:18 +02:00
DebaucheryLibrarian 328550b9a3 Added Teste de Fudelidade. 2023-08-04 22:02:28 +02:00
DebaucheryLibrarian 28455ecd5d 1.231.17 2023-08-04 21:43:58 +02:00
DebaucheryLibrarian 54dbea659a Added missing image fallbacks to legacy Aziani scraper. 2023-08-04 21:43:57 +02:00
DebaucheryLibrarian 447c1d748a 1.231.16 2023-08-04 00:12:27 +02:00
DebaucheryLibrarian 4a10887e48 Fixed Aziani breaking on missing source. 2023-08-04 00:12:24 +02:00
DebaucheryLibrarian 48015a4c95 1.231.15 2023-08-03 23:35:14 +02:00
DebaucheryLibrarian abbfedf3f7 Added trailer support to legacy Aziani scraper. 2023-08-03 23:35:10 +02:00
DebaucheryLibrarian fa9153deb8 1.231.14 2023-08-03 23:24:26 +02:00
DebaucheryLibrarian b287f5c2db Fixed photo query in Aziana scraper. 2023-08-03 23:24:23 +02:00
DebaucheryLibrarian 2ebc2d441f 1.231.13 2023-08-03 00:31:09 +02:00
DebaucheryLibrarian 5f2c9eb5df Fixed place cache check. 2023-08-03 00:31:07 +02:00
DebaucheryLibrarian ce41e24434 1.231.12 2023-08-02 23:12:44 +02:00
DebaucheryLibrarian c5d81e94e5 Updated OSM API path, added redis caching. 2023-08-02 23:12:41 +02:00
DebaucheryLibrarian 0500bdee2b 1.231.11 2023-08-02 16:38:53 +02:00
DebaucheryLibrarian e9a1df9123 Improved Model Media scene code matching. 2023-08-02 16:38:50 +02:00
DebaucheryLibrarian 277a06c3de 1.231.10 2023-08-02 02:22:31 +02:00
DebaucheryLibrarian c064efc812 Fixed title curation disparity Tokyo Hot. 2023-08-02 02:22:26 +02:00
DebaucheryLibrarian 1408074ef4 1.231.9 2023-08-02 02:14:46 +02:00
DebaucheryLibrarian 8c1f1b69ff Splitting Han titles and actors in Model Media scraper. 2023-08-02 02:14:41 +02:00
DebaucheryLibrarian 5783507344 1.231.8 2023-07-31 23:41:35 +02:00
DebaucheryLibrarian ae64c5225f Added conditions to Tokyo Hot scraper to prevent total failure. 2023-07-31 23:41:32 +02:00
DebaucheryLibrarian d2f81d446b 1.231.7 2023-07-29 23:59:20 +02:00
DebaucheryLibrarian ab5b165c68 Preserving Jules Jordan base photos in deep scrape. 2023-07-29 23:59:17 +02:00
DebaucheryLibrarian c3d4bf0e62 Capitalized JAV tag. 2023-07-26 00:28:03 +02:00
DebaucheryLibrarian 60f594a948 1.231.6 2023-07-26 00:26:17 +02:00
DebaucheryLibrarian 7f74d227f0 Tracking iframe campaign clicks. 2023-07-26 00:26:15 +02:00
DebaucheryLibrarian f59429c30a 1.231.5 2023-07-25 20:45:50 +02:00
DebaucheryLibrarian 40276a11f9 Fixed Tokyo Hot deep scrape failing on missing trailer. 2023-07-25 20:45:46 +02:00
DebaucheryLibrarian 0e846bec3f 1.231.4 2023-07-25 05:17:33 +02:00
DebaucheryLibrarian ba376fa074 Getting last showcased batch for new label. 2023-07-25 05:17:30 +02:00
DebaucheryLibrarian d1b54dc2c5 1.231.3 2023-07-25 05:05:09 +02:00
DebaucheryLibrarian b9c3efa24e Tracking image campaign clicks in umami. 2023-07-25 05:05:05 +02:00
DebaucheryLibrarian 40e613ed8d 1.231.2 2023-07-25 04:23:13 +02:00
DebaucheryLibrarian d033def947 Using batch showcase flag to hide archival releases. 2023-07-25 04:23:10 +02:00
DebaucheryLibrarian 671e110d99 1.231.1 2023-07-25 03:22:26 +02:00
DebaucheryLibrarian b7a31b7933 Added showcase flag to batch table. 2023-07-25 03:22:24 +02:00
DebaucheryLibrarian 1082effc17 1.231.0 2023-07-25 03:03:45 +02:00
DebaucheryLibrarian 693983dc29 Added screen caps separate from photos. Added Tokyo Hot. Added hair type, shoe size and blood type actor fields. 2023-07-25 03:03:41 +02:00
DebaucheryLibrarian 6fe212796b 1.230.1 2023-07-24 22:21:09 +02:00
DebaucheryLibrarian bb1aa4aa55 Added Umami to pm2 ecosystem file. 2023-07-24 22:21:05 +02:00
DebaucheryLibrarian 7d77e0603b 1.230.0 2023-07-24 00:59:49 +02:00
DebaucheryLibrarian 9f727a0fa0 Added analytics configuration. 2023-07-24 00:59:47 +02:00
DebaucheryLibrarian 997914ec27 Improved Hush T1 profile scraper. 2023-07-23 01:05:25 +02:00
DebaucheryLibrarian 37f01b68e8 1.229.6 2023-07-23 01:02:20 +02:00
DebaucheryLibrarian ca695db3ba Storing actor socials, improved Hush profile scraper. 2023-07-23 01:02:18 +02:00
DebaucheryLibrarian 48acabac49 1.229.5 2023-07-22 23:43:49 +02:00
DebaucheryLibrarian d7ee278b02 Removed unnecessary actor details from releases query. 2023-07-22 23:43:44 +02:00
DebaucheryLibrarian 191a3628b5 1.229.4 2023-07-22 00:50:02 +02:00
DebaucheryLibrarian 80750b44dc Added Milfy to profile list, fixed Vixen not returning gracefully when profile is not found. 2023-07-22 00:49:56 +02:00
DebaucheryLibrarian 25f3dcf9a5 Fixed avatar data type in Vixen scraper. 2023-07-22 00:01:12 +02:00
DebaucheryLibrarian c17e44e9f9 1.229.3 2023-07-21 23:55:33 +02:00
DebaucheryLibrarian 0b101dde3c Updated Vixen model scraper. 2023-07-21 23:55:30 +02:00
DebaucheryLibrarian 4d20dae079 1.229.2 2023-07-21 21:58:52 +02:00
DebaucheryLibrarian 86e4fb7603 Fixed Team Skeet profiles. 2023-07-21 21:58:50 +02:00
DebaucheryLibrarian e8d081cc67 1.229.1 2023-07-21 01:07:08 +02:00
DebaucheryLibrarian dab38c8013 Added grey hair color, removed console log. 2023-07-21 01:07:06 +02:00
1193 changed files with 17794 additions and 747 deletions

View File

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

View File

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

View File

@ -3,13 +3,28 @@
title="Add alert" title="Add alert"
@close="$emit('close')" @close="$emit('close')"
> >
<div
v-if="error"
class="dialog-error"
>{{ error }}</div>
<form <form
class="dialog-body" class="dialog-body"
@submit.prevent="addAlert" @submit.prevent="addAlert"
> >
<div class="dialog-section"> <div class="dialog-section">
<h3 class="dialog-heading"> <h3 class="dialog-heading">
When<span class="dialog-description">All to appear in the same scene</span> 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>
</h3> </h3>
<div class="alert-section"> <div class="alert-section">
@ -29,7 +44,10 @@
:key="`actor-${actor.id}`" :key="`actor-${actor.id}`"
class="actor" class="actor"
> >
<ActorPreview :actor="actor" /> <ActorPreview
:actor="actor"
target="_blank"
/>
<Icon <Icon
icon="cross3" icon="cross3"
@ -104,10 +122,15 @@
<div class="entities"> <div class="entities">
<div <div
v-if="entity" v-for="(entity, index) in entities"
:key="`entity-${entity.id}`"
:class="{ invalid: all && index > 0 }"
class="entity" class="entity"
> >
<Entity :entity="entity" /> <Entity
:entity="entity"
target="_blank"
/>
<Icon <Icon
icon="cross3" icon="cross3"
@ -116,7 +139,7 @@
/> />
</div> </div>
<Tooltip v-if="!entity"> <Tooltip v-if="entities.length < 1 || !all">
<div class="entity placeholder"> <div class="entity placeholder">
Any channel Any channel
@ -136,6 +159,72 @@
</Tooltip> </Tooltip>
</div> </div>
</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="!entity"
@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>
<div class="dialog-section"> <div class="dialog-section">
@ -194,7 +283,7 @@
<div class="dialog-actions right"> <div class="dialog-actions right">
<button <button
:disabled="actors.length === 0 && tags.length === 0 && !entity" :disabled="actors.length === 0 && tags.length === 0 && !entity && matches.length === 0"
type="submit" type="submit"
class="button button-primary" class="button button-primary"
>Add alert</button> >Add alert</button>
@ -207,19 +296,28 @@
import ActorPreview from '../actors/preview.vue'; import ActorPreview from '../actors/preview.vue';
import Entity from '../entities/tile.vue'; import Entity from '../entities/tile.vue';
import Checkbox from '../form/checkbox.vue'; import Checkbox from '../form/checkbox.vue';
import Toggle from '../form/toggle.vue';
import Search from './search.vue'; import Search from './search.vue';
async function addAlert() { async function addAlert() {
await this.$store.dispatch('addAlert', { this.error = null;
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),
});
this.$emit('close', true); 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;
}
} }
function addActor(actor) { function addActor(actor) {
@ -231,7 +329,7 @@ function addActor(actor) {
} }
function addEntity(entity) { function addEntity(entity) {
this.entity = entity; this.entities = this.entities.concat(entity);
this.events.emit('blur'); this.events.emit('blur');
} }
@ -247,14 +345,34 @@ function removeActor(actor) {
this.actors = this.actors.filter((listedActor) => listedActor.id !== actor.id); this.actors = this.actors.filter((listedActor) => listedActor.id !== actor.id);
} }
function removeEntity() { function removeEntity(entity) {
this.entity = null; this.entities = this.entities.filter((alertEntity) => alertEntity.id !== entity.id);
} }
function removeTag(tag) { function removeTag(tag) {
this.tags = this.tags.filter((listedTag) => listedTag.id !== tag.id); 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) { function addStash(stash) {
if (!this.stashes.some((selectedStash) => selectedStash.id === stash.id)) { if (!this.stashes.some((selectedStash) => selectedStash.id === stash.id)) {
this.stashes = this.stashes.concat(stash); this.stashes = this.stashes.concat(stash);
@ -273,13 +391,19 @@ export default {
Checkbox, Checkbox,
Entity, Entity,
Search, Search,
Toggle,
}, },
emits: ['close'], emits: ['close'],
data() { data() {
return { return {
error: null,
actors: [], actors: [],
tags: [], tags: [],
entity: null, all: true,
entities: [],
matches: [],
matchProperty: 'title',
matchExpression: null,
notify: true, notify: true,
email: false, email: false,
stashes: [], stashes: [],
@ -290,10 +414,12 @@ export default {
addActor, addActor,
addAlert, addAlert,
addEntity, addEntity,
addMatch,
addTag, addTag,
addStash, addStash,
removeActor, removeActor,
removeEntity, removeEntity,
removeMatch,
removeTag, removeTag,
removeStash, removeStash,
}, },
@ -320,9 +446,24 @@ export default {
} }
.dialog-description { .dialog-description {
display: flex;
align-items: center;
color: var(--shadow); color: var(--shadow);
font-size: .9rem; font-size: .9rem;
font-weight: normal; 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 { .alert-heading {
@ -338,6 +479,34 @@ export default {
font-size: 0; 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, .actors > .actor,
.entity, .entity,
.tag, .tag,
@ -347,6 +516,11 @@ export default {
margin: 0 .5rem .5rem 0; margin: 0 .5rem .5rem 0;
} }
.entity.invalid {
opacity: .5;
pointer-events: none;
}
.entity .tile { .entity .tile {
width: 10rem; width: 10rem;
height: 2.5rem; height: 2.5rem;
@ -366,6 +540,14 @@ export default {
color: var(--text); color: var(--text);
} }
.pattern-tooltip {
display: flex;
gap: .5rem;
position: relative;
padding: .5rem;
overflow: hidden;
}
.remove { .remove {
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;

View File

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

View File

@ -96,17 +96,29 @@ function scrollToTop() {
this.$refs.content.scrollTop = 0; 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() { function mounted() {
document.addEventListener('click', this.blur); document.addEventListener('click', this.blur);
window.addEventListener('resize', this.resize); window.addEventListener('resize', this.resize);
this.events.on('toggleSettings', this.toggleSettings); this.events.on('toggleSettings', this.toggleSettings);
this.events.on('toggleSidebar', this.toggleSidebar); this.events.on('toggleSidebar', this.toggleSidebar);
window.addEventListener('blur', this.trackIframeCampaign);
} }
function beforeUnmount() { function beforeUnmount() {
document.removeEventListener('click', this.blur); document.removeEventListener('click', this.blur);
window.removeEventListener('resize', this.resize); window.removeEventListener('resize', this.resize);
window.removeEventListener('blur', this.trackIframeCampaign);
} }
export default { export default {
@ -129,10 +141,11 @@ export default {
mounted, mounted,
beforeUnmount, beforeUnmount,
methods: { methods: {
setConsent,
toggleSidebar, toggleSidebar,
toggleFilters, toggleFilters,
toggleSettings, toggleSettings,
setConsent, trackIframeCampaign,
blur, blur,
resize, resize,
scroll, scroll,

View File

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

View File

@ -99,7 +99,7 @@
<Icon <Icon
v-if="notification.alert" v-if="notification.alert"
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>`" 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>`"
icon="question5" icon="question5"
@click.prevent.stop @click.prevent.stop
/> />
@ -145,12 +145,12 @@ export default {
default: 0, default: 0,
}, },
}, },
emits: ['addAlert'],
data() { data() {
return { return {
showAddAlert: false, showAddAlert: false,
}; };
}, },
emits: ['addAlert'],
methods: { methods: {
checkNotifications, checkNotifications,
checkNotification, checkNotification,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -89,21 +89,34 @@ function initEntitiesActions(store, router) {
offset: $offset offset: $offset
orderBy: $orderBy orderBy: $orderBy
filter: { filter: {
not: { tags: { overlaps: $exclude } }
effectiveDate: { lessThan: $before, greaterThan: $after } effectiveDate: { lessThan: $before, greaterThan: $after }
showcased: { equalTo: true } showcased: { equalTo: true }
or: [ and: [
{ {
channelSlug: { equalTo: $entitySlug } or: [
channelType: { equalTo: $entityType } {
not: { tags: { overlaps: $exclude } }
}
{
tags: { isNull: true }
}
]
} }
{ {
networkSlug: { equalTo: $entitySlug } or: [
networkType: { equalTo: $entityType } {
} channelSlug: { equalTo: $entitySlug }
{ channelType: { equalTo: $entityType }
parentNetworkSlug: { equalTo: $entitySlug } }
parentNetworkType: { equalTo: $entityType } {
networkSlug: { equalTo: $entitySlug }
networkType: { equalTo: $entityType }
}
{
parentNetworkSlug: { equalTo: $entitySlug }
parentNetworkType: { equalTo: $entityType }
}
]
} }
] ]
} }

View File

@ -97,6 +97,13 @@ const actorFields = `
${actorStashesFields} ${actorStashesFields}
`; `;
const basicActorFields = `
id
name
slug
gender
`;
const movieFields = ` const movieFields = `
id id
title title
@ -240,6 +247,14 @@ const releaseActorsFragment = `
} }
`; `;
const releaseBasicActorsFragment = `
actors: releasesActors(orderBy: ACTOR_BY_ACTOR_ID__GENDER_ASC) {
actor {
${basicActorFields}
}
}
`;
const releaseDirectorFragment = ` const releaseDirectorFragment = `
directors: releasesDirectors(orderBy: ACTOR_BY_DIRECTOR_ID__NAME_ASC) { directors: releasesDirectors(orderBy: ACTOR_BY_DIRECTOR_ID__NAME_ASC) {
director { director {
@ -339,6 +354,31 @@ 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 = ` const releaseTrailerFragment = `
trailer: releasesTrailer { trailer: releasesTrailer {
media { media {
@ -379,11 +419,11 @@ const releaseFields = `
createdAt createdAt
url url
createdBatchId createdBatchId
${releaseActorsFragment} ${releaseBasicActorsFragment}
${releaseTagsFragment} ${releaseTagsFragment}
${releasePosterFragment} ${releasePosterFragment}
${releaseCoversFragment}
${releasePhotosFragment} ${releasePhotosFragment}
${releaseCapsFragment}
${siteFragment} ${siteFragment}
studio { studio {
id id
@ -456,9 +496,17 @@ const releasesFragment = `
offset: $offset offset: $offset
orderBy: $orderBy orderBy: $orderBy
filter: { filter: {
not: { tags: { overlaps: $exclude } } or: [
{
not: { tags: { overlaps: $exclude } }
}
{
tags: { isNull: true }
}
]
effectiveDate: { lessThan: $before, greaterThan: $after } effectiveDate: { lessThan: $before, greaterThan: $after }
showcased: { equalTo: true } showcased: { equalTo: true }
batchShowcased: { in: $batchShowcased }
} }
) { ) {
releases: nodes { releases: nodes {
@ -497,6 +545,7 @@ const releaseFragment = `
release(id: $releaseId) { release(id: $releaseId) {
id id
title title
altTitles
description description
date date
datePrecision datePrecision
@ -504,6 +553,7 @@ const releaseFragment = `
createdAt createdAt
shootId shootId
qualities qualities
photoCount
productionDate productionDate
createdBatchId createdBatchId
productionLocation productionLocation
@ -521,6 +571,7 @@ const releaseFragment = `
${releaseTagsFragment} ${releaseTagsFragment}
${releasePosterFragment} ${releasePosterFragment}
${releasePhotosFragment} ${releasePhotosFragment}
${releaseCapsFragment}
${releaseCoversFragment} ${releaseCoversFragment}
${releaseTrailerFragment} ${releaseTrailerFragment}
${releaseTeaserFragment} ${releaseTeaserFragment}
@ -624,7 +675,11 @@ const releaseFragment = `
`; `;
const batchFragment = ` const batchFragment = `
batches(first: 1, orderBy: CREATED_AT_DESC) { batches(
first: 1,
orderBy: CREATED_AT_DESC,
filter: { showcased: { equalTo: true } }
) {
id id
} }
`; `;

View File

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

View File

@ -161,7 +161,14 @@ function initTagsActions(store, _router) {
offset: $offset offset: $offset
orderBy: $orderBy orderBy: $orderBy
filter: { filter: {
not: { tags: { overlaps: $exclude } } or: [
{
not: { tags: { overlaps: $exclude } }
}
{
tags: { isNull: true }
}
]
tags: { anyEqualTo: $tagSlug } tags: { anyEqualTo: $tagSlug }
effectiveDate: { lessThan: $before, greaterThan: $after } effectiveDate: { lessThan: $before, greaterThan: $after }
showcased: { equalTo: true } showcased: { equalTo: true }

View File

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

View File

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

View File

@ -30,6 +30,20 @@ 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: { s3: {
enabled: false, enabled: false,
bucket: 'traxxx', bucket: 'traxxx',
@ -57,6 +71,7 @@ module.exports = {
'amberathome', 'amberathome',
'marycarey', 'marycarey',
'racqueldevonshire', 'racqueldevonshire',
'aziani',
// blowpass // blowpass
'sunlustxxx', 'sunlustxxx',
// ddfnetwork // ddfnetwork
@ -360,7 +375,7 @@ module.exports = {
thumbnailQuality: 100, thumbnailQuality: 100,
lazySize: 90, lazySize: 90,
lazyQuality: 90, lazyQuality: 90,
trailerQuality: [480, 540, 360, 720, 960, 1080, 320, 1440, 1600, 1920, 2160, 270, 240, 180], trailerQuality: [540, 720, 480, 360, 960, 1080, 320, 1440, 1600, 1920, 2160, 270, 240, 180],
limit: 25, // max number of photos per release limit: 25, // max number of photos per release
attempts: 2, attempts: 2,
fetchStreams: true, fetchStreams: true,

View File

@ -1,4 +1,4 @@
// const config = require('config'); const config = require('config');
module.exports = { module.exports = {
apps: [ apps: [
@ -14,5 +14,15 @@ module.exports = {
NODE_ENV: 'production', 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

@ -15,9 +15,10 @@ exports.up = async (knex) => {
AND (channels.showcased IS NOT false OR COALESCE(studios.showcased, false) = true) 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) AND (networks.showcased IS NOT false OR COALESCE(channels.showcased, false) = true OR COALESCE(studios.showcased, false) = true)
AS showcased, AS showcased,
batches.showcased AS batch_showcased,
releases.effective_date, releases.effective_date,
releases.created_at, releases.created_at,
array_agg(tags.slug) FILTER (WHERE tags.slug IS NOT NULL) AS tags array_agg(tags.slug ORDER BY tags.priority DESC) FILTER (WHERE tags.slug IS NOT NULL) AS tags
FROM releases FROM releases
LEFT JOIN releases_tags ON releases_tags.release_id = releases.id LEFT JOIN releases_tags ON releases_tags.release_id = releases.id
LEFT JOIN tags ON tags.id = releases_tags.tag_id LEFT JOIN tags ON tags.id = releases_tags.tag_id
@ -25,14 +26,15 @@ exports.up = async (knex) => {
LEFT JOIN entities AS studios ON studios.id = releases.studio_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 networks ON networks.id = channels.parent_id
LEFT JOIN entities AS parent_networks ON parent_networks.id = networks.parent_id LEFT JOIN entities AS parent_networks ON parent_networks.id = networks.parent_id
GROUP BY releases.id, studios.showcased, LEFT JOIN batches ON batches.id = releases.updated_batch_id
GROUP BY releases.id, studios.showcased, batches.showcased,
channels.showcased, channels.slug, channels.type, channels.showcased, channels.slug, channels.type,
networks.showcased, networks.slug, networks.type, networks.showcased, networks.slug, networks.type,
parent_networks.slug, parent_networks.type parent_networks.slug, parent_networks.type
); );
COMMENT ON MATERIALIZED VIEW releases_summaries IS E'@foreignKey (release_id) references releases (id)'; COMMENT ON MATERIALIZED VIEW releases_summaries IS E'@foreignKey (release_id) references releases (id)';
GRANT ALL ON ALL TABLES IN SCHEMA public TO :visitor; GRANT ALL ON releases_summaries TO :visitor;
`, { `, {
visitor: knex.raw(config.database.query.user), visitor: knex.raw(config.database.query.user),
}); });

View File

@ -0,0 +1,27 @@
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

@ -0,0 +1,24 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,13 @@
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

@ -0,0 +1,27 @@
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

@ -0,0 +1,36 @@
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

@ -0,0 +1,19 @@
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

@ -0,0 +1,42 @@
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');
};

289
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "traxxx", "name": "traxxx",
"version": "1.229.0", "version": "1.233.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "traxxx", "name": "traxxx",
"version": "1.229.0", "version": "1.233.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@casl/ability": "^5.2.2", "@casl/ability": "^5.2.2",
@ -36,6 +36,7 @@
"dayjs": "^1.8.21", "dayjs": "^1.8.21",
"dompurify": "^2.0.11", "dompurify": "^2.0.11",
"ejs": "^3.0.1", "ejs": "^3.0.1",
"escape-string-regexp": "^4.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-promise-router": "^4.1.0", "express-promise-router": "^4.1.0",
"express-react-views": "^0.11.0", "express-react-views": "^0.11.0",
@ -71,6 +72,7 @@
"puppeteer": "^20.5.0", "puppeteer": "^20.5.0",
"puppeteer-extra": "^3.3.6", "puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2", "puppeteer-extra-plugin-stealth": "^2.11.2",
"redis": "^4.6.7",
"sharp": "^0.29.2", "sharp": "^0.29.2",
"showdown": "^1.9.1", "showdown": "^1.9.1",
"source-map-support": "^0.5.16", "source-map-support": "^0.5.16",
@ -80,7 +82,7 @@
"tunnel": "0.0.6", "tunnel": "0.0.6",
"ua-parser-js": "^1.0.32", "ua-parser-js": "^1.0.32",
"undici": "^4.13.0", "undici": "^4.13.0",
"unprint": "^0.10.1", "unprint": "^0.10.11",
"url-pattern": "^1.0.3", "url-pattern": "^1.0.3",
"v-tooltip": "^2.0.3", "v-tooltip": "^2.0.3",
"video.js": "^7.11.4", "video.js": "^7.11.4",
@ -3228,6 +3230,64 @@
} }
} }
}, },
"node_modules/@redis/bloom": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/client": {
"version": "1.5.8",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz",
"integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==",
"dependencies": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@redis/client/node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/@redis/graph": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz",
"integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/json": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz",
"integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/search": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz",
"integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@redis/time-series": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz",
"integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==",
"peerDependencies": {
"@redis/client": "^1.0.0"
}
},
"node_modules/@tensorflow/tfjs-core": { "node_modules/@tensorflow/tfjs-core": {
"version": "1.7.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-1.7.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-1.7.0.tgz",
@ -5146,6 +5206,14 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/chalk/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/chardet": { "node_modules/chardet": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
@ -5412,6 +5480,14 @@
"request": "^2.88.0" "request": "^2.88.0"
} }
}, },
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/cmake-js": { "node_modules/cmake-js": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-6.1.0.tgz", "resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-6.1.0.tgz",
@ -7010,11 +7086,14 @@
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
}, },
"node_modules/escape-string-regexp": { "node_modules/escape-string-regexp": {
"version": "1.0.5", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/escodegen": { "node_modules/escodegen": {
@ -7624,17 +7703,6 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}, },
"node_modules/eslint/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/eslint/node_modules/eslint-scope": { "node_modules/eslint/node_modules/eslint-scope": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz",
@ -8384,6 +8452,14 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/figures/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@ -9112,6 +9188,14 @@
"node": ">= 4.0.0" "node": ">= 4.0.0"
} }
}, },
"node_modules/generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==",
"engines": {
"node": ">= 4"
}
},
"node_modules/gensync": { "node_modules/gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@ -11524,17 +11608,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/matcher/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -12504,6 +12577,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/node-sass/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/node-sass/node_modules/gauge": { "node_modules/node-sass/node_modules/gauge": {
"version": "2.7.4", "version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@ -14804,6 +14886,19 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/redis": {
"version": "4.6.7",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz",
"integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==",
"dependencies": {
"@redis/bloom": "1.2.0",
"@redis/client": "1.5.8",
"@redis/graph": "1.1.0",
"@redis/json": "1.0.4",
"@redis/search": "1.1.3",
"@redis/time-series": "1.0.4"
}
},
"node_modules/regenerate": { "node_modules/regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -17538,9 +17633,9 @@
} }
}, },
"node_modules/unprint": { "node_modules/unprint": {
"version": "0.10.1", "version": "0.10.11",
"resolved": "https://registry.npmjs.org/unprint/-/unprint-0.10.1.tgz", "resolved": "https://registry.npmjs.org/unprint/-/unprint-0.10.11.tgz",
"integrity": "sha512-2KtzIQKlOzXyDDyrCQQQXWuljC6kHjAhYZT1NRiDT2Lr1GgnwR+R9iVqbq6iz1Z1Oflt7ngpYW1MGHy3xDnduw==", "integrity": "sha512-+OL+8BFF9SYvayp57l8ifq77I6ok2ilPCidBVka7VbMALJgqHxkHqrqkCupw2RKX2tNfPT/TGa+NJsYGboFnRQ==",
"dependencies": { "dependencies": {
"axios": "^0.27.2", "axios": "^0.27.2",
"bottleneck": "^2.19.5", "bottleneck": "^2.19.5",
@ -17646,17 +17741,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/unprint/node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/unprint/node_modules/eslint": { "node_modules/unprint/node_modules/eslint": {
"version": "8.26.0", "version": "8.26.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
@ -21448,6 +21532,53 @@
} }
} }
}, },
"@redis/bloom": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz",
"integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==",
"requires": {}
},
"@redis/client": {
"version": "1.5.8",
"resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz",
"integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==",
"requires": {
"cluster-key-slot": "1.1.2",
"generic-pool": "3.9.0",
"yallist": "4.0.0"
},
"dependencies": {
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"@redis/graph": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz",
"integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==",
"requires": {}
},
"@redis/json": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz",
"integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==",
"requires": {}
},
"@redis/search": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz",
"integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==",
"requires": {}
},
"@redis/time-series": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz",
"integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==",
"requires": {}
},
"@tensorflow/tfjs-core": { "@tensorflow/tfjs-core": {
"version": "1.7.0", "version": "1.7.0",
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-1.7.0.tgz", "resolved": "https://registry.npmjs.org/@tensorflow/tfjs-core/-/tfjs-core-1.7.0.tgz",
@ -23017,6 +23148,13 @@
"ansi-styles": "^3.2.1", "ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0" "supports-color": "^5.3.0"
},
"dependencies": {
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
}
} }
}, },
"chardet": { "chardet": {
@ -23213,6 +23351,11 @@
"request-promise": "^4.2.4" "request-promise": "^4.2.4"
} }
}, },
"cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="
},
"cmake-js": { "cmake-js": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-6.1.0.tgz", "resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-6.1.0.tgz",
@ -24465,9 +24608,9 @@
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
}, },
"escape-string-regexp": { "escape-string-regexp": {
"version": "1.0.5", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
}, },
"escodegen": { "escodegen": {
"version": "2.0.0", "version": "2.0.0",
@ -24599,11 +24742,6 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}, },
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
},
"eslint-scope": { "eslint-scope": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz",
@ -25487,6 +25625,13 @@
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
"requires": { "requires": {
"escape-string-regexp": "^1.0.5" "escape-string-regexp": "^1.0.5"
},
"dependencies": {
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
}
} }
}, },
"file-entry-cache": { "file-entry-cache": {
@ -26051,6 +26196,11 @@
"globule": "^1.0.0" "globule": "^1.0.0"
} }
}, },
"generic-pool": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz",
"integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g=="
},
"gensync": { "gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@ -27857,13 +28007,6 @@
"integrity": "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==", "integrity": "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==",
"requires": { "requires": {
"escape-string-regexp": "^4.0.0" "escape-string-regexp": "^4.0.0"
},
"dependencies": {
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
}
} }
}, },
"media-typer": { "media-typer": {
@ -28618,6 +28761,12 @@
"supports-color": "^2.0.0" "supports-color": "^2.0.0"
} }
}, },
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true
},
"gauge": { "gauge": {
"version": "2.7.4", "version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@ -30274,6 +30423,19 @@
"strip-indent": "^3.0.0" "strip-indent": "^3.0.0"
} }
}, },
"redis": {
"version": "4.6.7",
"resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz",
"integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==",
"requires": {
"@redis/bloom": "1.2.0",
"@redis/client": "1.5.8",
"@redis/graph": "1.1.0",
"@redis/json": "1.0.4",
"@redis/search": "1.1.3",
"@redis/time-series": "1.0.4"
}
},
"regenerate": { "regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@ -32378,9 +32540,9 @@
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
}, },
"unprint": { "unprint": {
"version": "0.10.1", "version": "0.10.11",
"resolved": "https://registry.npmjs.org/unprint/-/unprint-0.10.1.tgz", "resolved": "https://registry.npmjs.org/unprint/-/unprint-0.10.11.tgz",
"integrity": "sha512-2KtzIQKlOzXyDDyrCQQQXWuljC6kHjAhYZT1NRiDT2Lr1GgnwR+R9iVqbq6iz1Z1Oflt7ngpYW1MGHy3xDnduw==", "integrity": "sha512-+OL+8BFF9SYvayp57l8ifq77I6ok2ilPCidBVka7VbMALJgqHxkHqrqkCupw2RKX2tNfPT/TGa+NJsYGboFnRQ==",
"requires": { "requires": {
"axios": "^0.27.2", "axios": "^0.27.2",
"bottleneck": "^2.19.5", "bottleneck": "^2.19.5",
@ -32461,11 +32623,6 @@
} }
} }
}, },
"escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
},
"eslint": { "eslint": {
"version": "8.26.0", "version": "8.26.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "traxxx", "name": "traxxx",
"version": "1.229.0", "version": "1.233.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": {
@ -95,6 +95,7 @@
"dayjs": "^1.8.21", "dayjs": "^1.8.21",
"dompurify": "^2.0.11", "dompurify": "^2.0.11",
"ejs": "^3.0.1", "ejs": "^3.0.1",
"escape-string-regexp": "^4.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-promise-router": "^4.1.0", "express-promise-router": "^4.1.0",
"express-react-views": "^0.11.0", "express-react-views": "^0.11.0",
@ -130,6 +131,7 @@
"puppeteer": "^20.5.0", "puppeteer": "^20.5.0",
"puppeteer-extra": "^3.3.6", "puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2", "puppeteer-extra-plugin-stealth": "^2.11.2",
"redis": "^4.6.7",
"sharp": "^0.29.2", "sharp": "^0.29.2",
"showdown": "^1.9.1", "showdown": "^1.9.1",
"source-map-support": "^0.5.16", "source-map-support": "^0.5.16",
@ -139,7 +141,7 @@
"tunnel": "0.0.6", "tunnel": "0.0.6",
"ua-parser-js": "^1.0.32", "ua-parser-js": "^1.0.32",
"undici": "^4.13.0", "undici": "^4.13.0",
"unprint": "^0.10.1", "unprint": "^0.10.11",
"url-pattern": "^1.0.3", "url-pattern": "^1.0.3",
"v-tooltip": "^2.0.3", "v-tooltip": "^2.0.3",
"video.js": "^7.11.4", "video.js": "^7.11.4",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
public/img/logos/analvids/lazy/favicon.png Executable file → Normal 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 Executable file → Normal 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 Executable file → Normal 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 Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 29 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
public/img/logos/analvids/thumbs/favicon.png Executable file → Normal 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 Executable file → Normal 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 Executable file → Normal 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 Executable file → Normal 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 Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

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