Compare commits

..

No commits in common. "6fef87b0f1ec1139b07b803bce5081efdef48396" and "7c7b38e8699c6ae9e9a5e5d23322f08b5cb3be3f" have entirely different histories.

177 changed files with 183 additions and 1798 deletions

View File

@ -33,20 +33,6 @@
:actor="actor"
class="header-social"
/>
<Icon
v-show="me && isStashed"
icon="heart7"
class="stash stashed noselect"
@click="unstashActor"
/>
<Icon
v-show="me && !isStashed"
icon="heart8"
class="stash unstashed noselect"
@click="stashActor"
/>
</div>
<div class="content-inner actor-inner">
@ -68,6 +54,13 @@
>
</a>
<Expand
v-if="bioExpanded"
:expanded="bioExpanded"
class="expand expand-light"
@expand="(state) => bioExpanded = state"
/>
<ul class="bio nolist">
<li
v-if="actor.realName"
@ -391,7 +384,7 @@ import Scroll from '../scroll/scroll.vue';
import Gender from './gender.vue';
import Social from './social.vue';
async function fetchActor(scroll = true) {
async function fetchActor() {
const { actor, releases, totalCount } = await this.$store.dispatch('fetchActorById', {
actorId: Number(this.$route.params.actorId),
limit: this.limit,
@ -403,37 +396,11 @@ async function fetchActor(scroll = true) {
this.releases = releases;
this.totalCount = totalCount;
if (this.$refs.filter && scroll) {
if (this.$refs.filter) {
this.$refs.filter.$el.scrollIntoView();
}
}
async function stashActor() {
this.$store.dispatch('stashActor', {
actorId: this.actor.id,
stashId: this.$store.getters.favorites.id,
});
this.fetchActor(false);
}
async function unstashActor() {
this.$store.dispatch('unstashActor', {
actorId: this.actor.id,
stashId: this.$store.getters.favorites.id,
});
this.fetchActor(false);
}
function me() {
return this.$store.state.auth.user;
}
function isStashed() {
return this.actor.stashes?.length > 0;
}
function sfw() {
return this.$store.state.ui.sfw;
}
@ -480,8 +447,6 @@ export default {
};
},
computed: {
isStashed,
me,
sfw,
showAlbum,
},
@ -492,8 +457,6 @@ export default {
mounted,
methods: {
fetchActor,
stashActor,
unstashActor,
},
};
</script>
@ -514,10 +477,11 @@ export default {
align-items: center;
color: var(--lighten-extreme);
background: var(--profile);
padding: .5rem 1rem;
}
.header-name {
padding: .5rem 1rem;
padding: 0;
margin: 0;
display: inline-flex;
justify-content: space-between;
@ -527,7 +491,7 @@ export default {
.header-gender {
display: inline-block;
margin: 0 0 0 .5rem;
transform: translate(0, .125rem);
transform: translate(0, .1rem);
}
.header-social {
@ -767,22 +731,6 @@ export default {
border-bottom: solid 1px var(--shadow-hint);
}
.stash.icon {
width: 1.5rem;
height: 1.5rem;
padding: 0 1rem;
fill: var(--lighten);
&.stashed {
fill: var(--primary);
}
&:hover {
fill: var(--primary);
cursor: pointer;
}
}
@media(max-width: $breakpoint4) {
.descriptions-container {
display: none;
@ -847,16 +795,8 @@ export default {
}
.header-name {
flex-grow: 1;
flex-grow: 1;
font-size: 1.3rem;
padding: .5rem .5rem .5rem 1rem;
}
.stash.icon {
width: 1.25rem;
height: 1.25rem;
padding: 0 1rem 0 .25rem;
transform: translate(0, -.1rem);
}
}
</style>

View File

@ -81,8 +81,8 @@
@input="(range) => updateValue('age', range, false)"
@change="(range) => updateValue('age', range, true)"
>
<template v-slot:start><Icon icon="leaf" /></template>
<template v-slot:end><Icon icon="tree3" /></template>
<template v-slot:start><Icon icon="flower" /></template>
<template v-slot:end><Icon icon="pipe" /></template>
</RangeFilter>
<div class="filter-section">

View File

@ -27,9 +27,6 @@
>
<img
:src="getPath(item, 'thumbnail', { local })"
:style="{ 'background-image': `url('${getPath(item, 'lazy', { local })}')` }"
:width="item.width"
:height="item.height"
:title="item.title"
loading="lazy"
class="item image"
@ -186,9 +183,6 @@ export default {
.item {
max-width: 100%;
max-height: 100%;
height: auto;
background-size: cover;
background-position: center;
}
.item-comment {

View File

@ -1,123 +0,0 @@
<template>
<form
class="login"
@submit.prevent="login"
>
<div
v-if="error"
class="feedback error"
>{{ error }}</div>
<div
v-if="success"
class="feedback success"
>Login successful, redirecting</div>
<template v-else>
<input
v-model="username"
placeholder="Username or e-mail"
type="text"
class="input"
required
>
<input
v-model="password"
placeholder="Password"
type="password"
class="input"
required
>
<button
type="submit"
class="button button-primary"
>Log in</button>
<router-link
:to="{ name: 'signup', query: { ref: $route.query.ref } }"
class="link link-external signup"
>Sign up</router-link>
</template>
</form>
</template>
<script>
async function login() {
this.error = null;
this.success = false;
try {
const user = await this.$store.dispatch('login', {
username: this.username,
password: this.password,
});
this.success = true;
setTimeout(() => {
this.$router.replace(this.$route.query.ref || { name: 'user', params: { username: user.username } });
}, 1000);
} catch (error) {
this.error = error.message;
}
}
function mounted() {
if (!this.$store.state.auth.enabled) {
this.$router.replace({ name: 'not-found' });
}
}
export default {
data() {
return {
username: null,
password: null,
success: false,
error: null,
};
},
mounted,
methods: {
login,
},
};
</script>
<style lang="scss" scoped>
.login {
width: 20rem;
display: flex;
flex-direction: column;
margin: auto;
}
.input {
margin: 0 0 .5rem 0;
}
.feedback {
padding: 1rem;
text-align: center;
font-weight: bold;
}
.error {
color: var(--error);
}
.success {
color: var(--shadow-strong);
}
.button {
margin: 0 0 .25rem 0;
}
.signup {
padding: .5rem;
text-align: center;
}
</style>

View File

@ -1,133 +0,0 @@
<template>
<form
class="signup"
@submit.prevent="signup"
>
<div
v-if="error"
class="feedback error"
>{{ error }}</div>
<div
v-if="success"
class="feedback success"
>Signup successful, redirecting</div>
<template v-else>
<input
v-model="username"
placeholder="Username"
type="text"
class="input"
required
>
<input
v-model="email"
placeholder="E-mail"
type="email"
class="input"
required
>
<input
v-model="password"
placeholder="Password"
type="password"
class="input"
required
>
<button
type="submit"
class="button button-primary"
>Sign up</button>
<router-link
:to="{ name: 'login', query: { ref: $route.query.ref } }"
class="link link-external login"
>Log in</router-link>
</template>
</form>
</template>
<script>
async function signup() {
this.error = null;
this.success = false;
try {
await this.$store.dispatch('signup', {
username: this.username,
email: this.email,
password: this.password,
});
this.success = true;
setTimeout(() => {
this.$router.replace(this.$route.query.ref || { name: 'home' });
}, 1000);
} catch (error) {
this.error = error.message;
}
}
function mounted() {
if (!this.$store.state.auth.enabled) {
this.$router.replace({ name: 'not-found' });
}
}
export default {
data() {
return {
username: null,
email: null,
password: null,
success: false,
error: null,
};
},
mounted,
methods: {
signup,
},
};
</script>
<style lang="scss" scoped>
.signup {
width: 20rem;
display: flex;
flex-direction: column;
margin: auto;
}
.input {
margin: 0 0 .5rem 0;
}
.feedback {
padding: 1rem;
text-align: center;
font-weight: bold;
}
.error {
color: var(--error);
}
.success {
color: var(--shadow-strong);
}
.button {
margin: 0 0 .25rem 0;
}
.login {
padding: .5rem;
text-align: center;
}
</style>

View File

@ -93,7 +93,67 @@
</div>
<template v-slot:tooltip>
<Menu />
<div class="menu">
<ul class="menu-items noselect">
<li
class="menu-item disabled"
@click.stop
>
<Icon icon="enter2" />Sign in
</li>
<li
v-show="!sfw"
class="menu-item"
@click.stop="setSfw(true)"
>
<Icon
icon="flower"
class="toggle noselect"
/>Safe mode
</li>
<li
v-show="sfw"
class="menu-item"
@click.stop="setSfw(false)"
>
<Icon
icon="fire"
class="toggle noselect"
/>Filth mode
</li>
<li
v-show="theme === 'light'"
class="menu-item"
@click.stop="setTheme('dark')"
>
<Icon
icon="moon"
class="toggle noselect"
/>Dark theme
</li>
<li
v-show="theme === 'dark'"
class="menu-item"
@click.stop="setTheme('light')"
>
<Icon
icon="sun"
class="toggle noselect"
/>Light theme
</li>
<li
class="menu-item"
@click="$emit('showFilters', true)"
>
<Icon icon="filter" />Filters
</li>
</ul>
</div>
</template>
</Tooltip>
@ -126,14 +186,30 @@
</template>
<script>
import Menu from './menu.vue';
import { mapState } from 'vuex';
import Search from './search.vue';
import logo from '../../img/logo.svg';
function sfw(state) {
return state.ui.sfw;
}
function theme(state) {
return state.ui.theme;
}
function setTheme(newTheme) {
this.$store.dispatch('setTheme', newTheme);
}
function setSfw(enabled) {
this.$store.dispatch('setSfw', enabled);
}
export default {
components: {
Menu,
Search,
},
emits: ['toggleSidebar', 'showFilters'],
@ -144,6 +220,16 @@ export default {
showFilters: false,
};
},
computed: {
...mapState({
sfw,
theme,
}),
},
methods: {
setSfw,
setTheme,
},
};
</script>
@ -308,6 +394,40 @@ export default {
}
}
.menu-items {
list-style: none;
padding: 0;
margin: 0;
}
.menu-item {
display: flex;
padding: .75rem 1rem .75rem .75rem;
.icon {
fill: var(--darken);
margin: 0 1rem 0 0;
}
&.disabled {
color: var(--darken-weak);
cursor: default;
.icon {
fill: var(--darken-weak);
}
}
&:hover:not(.disabled) {
cursor: pointer;
color: var(--primary);
.icon {
fill: var(--primary);
}
}
}
.search-compact {
display: none;
height: 100%;

View File

@ -1,173 +0,0 @@
<template>
<div class="menu">
<ul class="menu-items noselect">
<router-link
v-if="auth && me"
:to="{ name: 'user', params: { username: me.username } }"
class="menu-username"
>{{ me.username }}</router-link>
<router-link
v-else-if="auth"
:to="{ name: 'login', query: { ref: $route.path } }"
class="menu-item"
@click.stop
>
<Icon icon="enter2" />Log in
</router-link>
<li
v-if="auth && me"
class="menu-item"
@click.stop="$store.dispatch('logout')"
>
<Icon icon="enter2" />Log out
</li>
<li
v-show="!sfw"
class="menu-item"
@click.stop="setSfw(true)"
>
<Icon
icon="flower"
class="toggle noselect"
/>Safe mode
</li>
<li
v-show="sfw"
class="menu-item"
@click.stop="setSfw(false)"
>
<Icon
icon="fire"
class="toggle noselect"
/>Filth mode
</li>
<li
v-show="theme === 'light'"
class="menu-item"
@click.stop="setTheme('dark')"
>
<Icon
icon="moon"
class="toggle noselect"
/>Dark theme
</li>
<li
v-show="theme === 'dark'"
class="menu-item"
@click.stop="setTheme('light')"
>
<Icon
icon="sun"
class="toggle noselect"
/>Light theme
</li>
<li
class="menu-item"
@click="$emit('showFilters', true)"
>
<Icon icon="filter" />Filters
</li>
</ul>
</div>
</template>
<script>
import { mapState } from 'vuex';
function sfw(state) {
return state.ui.sfw;
}
function theme(state) {
return state.ui.theme;
}
function auth(state) {
return state.auth.enabled;
}
function me(state) {
return state.auth.user;
}
function setTheme(newTheme) {
this.$store.dispatch('setTheme', newTheme);
}
function setSfw(enabled) {
this.$store.dispatch('setSfw', enabled);
}
export default {
computed: {
...mapState({
auth,
sfw,
theme,
me,
}),
},
methods: {
setSfw,
setTheme,
},
};
</script>
<style lang="scss" scoped>
@import 'breakpoints';
.menu-items {
list-style: none;
padding: 0;
margin: 0;
}
.menu-item {
display: flex;
padding: .75rem 1rem .75rem .75rem;
color: inherit;
text-decoration: none;
.icon {
fill: var(--darken);
margin: 0 1rem 0 0;
}
&.disabled {
color: var(--darken-weak);
cursor: default;
.icon {
fill: var(--darken-weak);
}
}
&:hover:not(.disabled) {
cursor: pointer;
color: var(--primary);
.icon {
fill: var(--primary);
}
}
}
.menu-username {
display: block;
font-weight: bold;
color: var(--shadow-strong);
font-size: .9rem;
padding: .75rem 1rem;
border-bottom: solid 1px var(--shadow-hint);
text-align: center;
text-decoration: none;
}
</style>

View File

@ -21,10 +21,8 @@
<script>
async function search() {
if (this.query) {
this.$router.push({ name: 'search', query: { q: this.query } });
this.$emit('search');
}
this.$router.push({ name: 'search', query: { q: this.query } });
this.$emit('search');
}
function searching(to) {

View File

@ -33,8 +33,6 @@
v-else-if="release.teaser && /^image\//.test(release.teaser.mime)"
:src="getPath(release.teaser, 'thumbnail', { original: true })"
:alt="release.title"
:width="photo.width"
:height="photo.height"
loading="lazy"
class="item trailer"
>
@ -68,8 +66,6 @@
<img
:src="getPath(cover, 'thumbnail')"
:style="{ 'background-image': getBgPath(cover, 'lazy') }"
:width="photo.width"
:height="photo.height"
class="item cover"
loading="lazy"
@load="$emit('load', $event)"
@ -91,10 +87,8 @@
>
<img
:src="getPath(photo, 'thumbnail')"
:style="{ 'background-image': `url('${getPath(photo, 'lazy')}` }"
:style="{ 'background-image': getPath(photo, 'lazy') }"
:alt="`Photo ${photo.index + 1}`"
:width="photo.width"
:height="photo.height"
loading="lazy"
class="item"
@load="$emit('load', $event)"
@ -279,7 +273,6 @@ export default {
.item {
max-width: 100%;
width: auto;
height: 18rem;
box-shadow: 0 0 3px var(--shadow-weak);
background-size: cover;

View File

@ -1,26 +1,5 @@
<template>
<div
v-if="timeline"
class="timeline"
>
<ul class="timeline-items nolist">
<li
v-for="chapter in timeline"
:key="`chapter-${chapter.id}`"
:style="{ left: `${(chapter.time / duration) * 100}%` }"
:title="formatDuration(chapter.time)"
class="timeline-item"
><router-link
:to="`/tag/${chapter.tags[0].slug}`"
class="link"
>{{ chapter.tags[0]?.name || '&nbsp;' }}</router-link></li>
</ul>
</div>
<ul
v-else
class="chapters nolist"
>
<ul class="chapters nolist">
<li
v-for="chapter in chapters"
:key="`chapter-${chapter.id}`"
@ -76,14 +55,6 @@
<script>
import Tags from './tags.vue';
function timeline() {
if (this.chapters.every(chapter => chapter.time)) {
return this.chapters.filter(chapter => chapter.tags?.length > 0);
}
return null;
}
export default {
components: {
Tags,
@ -94,16 +65,6 @@ export default {
default: () => [],
},
},
data() {
const lastChapter = this.chapters[this.chapters.length - 1];
return {
duration: lastChapter.time + lastChapter.duration,
};
},
computed: {
timeline,
},
};
</script>
@ -192,41 +153,6 @@ export default {
line-height: 1.5;
}
.timeline-items {
position: relative;
height: 5rem;
border-bottom: solid 1px var(--shadow-weak);
}
.timeline-item {
position: absolute;
bottom: -.25rem;
padding: .1rem .5rem;
border-radius: .6rem;
color: var(--primary);
background: var(--background);
transform: rotate(-60deg);
transform-origin: 0 50%;
box-shadow: 0 0 3px var(--shadow-weak);
font-size: .8rem;
font-weight: bold;
.link {
color: inherit;
}
&:before {
content: '';
display: inline-block;
width: 1rem;
height: 2px;
position: absolute;
left: calc(-1rem + 1px);
margin: .3rem .5rem 0 0;
background: var(--primary);
}
}
@media(max-width: $breakpoint-micro) {
.chapters {
grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));

View File

@ -73,10 +73,7 @@
>{{ release.entity.name }}</h3>
</a>
<span
v-if="release.actors?.length > 0"
class="row"
>
<span class="row">
<ul
class="actors nolist"
:title="release.actors.map(actor => actor.name).join(', ')"
@ -109,7 +106,7 @@
>{{ release.shootId }}</span>
<ul
v-if="release.tags?.length > 0"
v-if="release.tags.length > 0"
:title="release.tags.map(tag => tag.name).join(', ')"
class="tags nolist"
>

View File

@ -4,7 +4,7 @@
:class="{ new: release.isNew }"
>
<span
v-if="release.entity && release.entity.type !== 'network' && !release.entity.independent && release.entity.parent"
v-if="release.entity.type !== 'network' && !release.entity.independent && release.entity.parent"
class="site"
>
<router-link
@ -33,7 +33,7 @@
</span>
<router-link
v-else-if="release.entity"
v-else
:to="`/${release.entity.type}/${release.entity.slug}`"
class="site site-link"
>

View File

@ -1,132 +0,0 @@
<template>
<div
v-if="user"
class="user"
>
<div class="header">
<h2 class="username">{{ user.username }}</h2>
</div>
<section
v-if="user.stashes?.length > 0"
class="section"
>
<h3 class="heading">Stashes</h3>
<ul class="stashes nolist">
<li
v-for="stash in user.stashes"
:key="stash.id"
class="stash"
>
<h4 class="stash-name">{{ stash.name }}</h4>
<ul
v-if="stash.scenes?.length > 0"
class="stash-section stash-scenes nolist"
>
<li
v-for="item in stash.scenes"
:key="item.id"
><Scene :release="item.scene" /></li>
</ul>
<ul
v-if="stash.actors?.length > 0"
class="stash-section stash-actors nolist"
>
<li
v-for="item in stash.actors"
:key="item.id"
><Actor :actor="item.actor" /></li>
</ul>
</li>
</ul>
</section>
</div>
</template>
<script>
import Actor from '../actors/tile.vue';
import Scene from '../releases/scene-tile.vue';
async function mounted() {
this.user = await this.$store.dispatch('fetchUser', this.$route.params.username);
this.pageTitle = this.user?.username;
}
export default {
components: {
Actor,
Scene,
},
data() {
return {
user: this.$route.params.username === this.$store.state.auth.user?.username
? this.$store.state.auth.user
: null,
pageTitle: null,
};
},
mounted,
};
</script>
<style lang="scss" scoped>
.header {
padding: .5rem 1rem;
background: var(--profile);
}
.username {
margin: 0;
font-size: 1.5rem;
color: var(--text-light);
}
.section {
padding: 1rem;
margin: 0 0 1rem 0;
}
.heading {
color: var(--primary);
}
.stash {
width: 100%;
background: var(--background);
margin: 0 0 1rem 0;
box-shadow: 0 0 3px var(--shadow-weak);
}
.stash-name {
color: var(--shadow-strong);
padding: 1rem .5rem 0 .5rem;
margin: 0;
}
.stash-section {
padding: 1rem .5rem;
&:not(:last-child) {
border-bottom: solid 1px var(--shadow-hint);
}
}
.stash-actors,
.stash-scenes {
display: grid;
flex-grow: 1;
grid-gap: .5rem;
box-sizing: border-box;
}
.stash-actors {
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
}
.stash-scenes {
grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
}
</style>

View File

@ -1,15 +1,10 @@
.input {
box-sizing: border-box;
padding: .5rem;
border: solid 1px var(--shadow-hint);
border: solid 1px var(--shadow-weak);
color: var(--shadow-strong);
background: var(--background);
font-size: 1rem;
font-family: inherit;
&:focus {
border: solid 1px var(--primary);
}
&::-webkit-calendar-picker-indicator {
opacity: .5;
@ -25,35 +20,6 @@
cursor: pointer;
}
.button {
border: none;
background: none;
padding: .5rem;
font-weight: bold;
&:hover {
cursor: pointer;
}
}
.button-primary {
color: var(--text-light);
background: var(--primary);
&:hover {
background: var(--primary-strong);
}
}
.button-secondary {
color: var(--primary);
&:hover {
color: var(--highlight-strong);
background: var(--primary);
}
}
.album-toggle {
height: fit-content;
display: inline-flex;

View File

@ -5,14 +5,10 @@ $breakpoint3: 1200px;
$breakpoint4: 1500px;
:root {
/*
/* --primary: #ff886c; */
--primary: #ff6c88;
--primary-strong: #ff4166;
--primary-faded: #ffdfee;
*/
--primary: #f28;
--primary-strong: #f90071;
--primary-faded: #ffcce4;
--text-dark: #222;
--text-light: #fff;
@ -40,7 +36,6 @@ $breakpoint4: 1500px;
--female: #f0a;
--alert: #f00;
--error: #f00;
--warn: #fa0;
--success: #5c2;
@ -63,7 +58,6 @@ $breakpoint4: 1500px;
--tile: #2a2a2a;
--link: #dd6688;
--link-external: #48f;
--empty: #333;
--crease: #eaeaea;

View File

@ -44,12 +44,3 @@ body {
fill: var(--primary);
}
}
.link {
color: var(--link);
text-decoration: none;
}
.link-external {
color: var(--link-external);
}

View File

@ -1,5 +0,0 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>leaf2</title>
<path d="M15.802 2.102c-1.73-1.311-4.393-2.094-7.124-2.094-3.377 0-6.129 1.179-7.549 3.235-0.667 0.965-1.036 2.109-1.097 3.398-0.065 1.375 0.225 2.925 0.859 4.606-0.586 1.428-0.904 2.898-0.904 4.254 0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5c0-1.198 0.293-2.535 0.818-3.835 1.472 0.272 2.712 0.405 3.776 0.405 1.839 0 3.146-0.398 4.115-1.252 0.868-0.765 1.347-1.794 1.854-2.882 0.774-1.663 1.651-3.547 4.198-5.002 0.146-0.083 0.24-0.234 0.251-0.402s-0.063-0.329-0.197-0.431zM10.644 7.515c-0.481 1.034-0.897 1.927-1.608 2.554-0.776 0.684-1.873 1.002-3.454 1.002-0.945 0-2.047-0.113-3.351-0.345 0.238-0.476 0.507-0.941 0.804-1.386 0.692-1.036 1.505-1.931 2.417-2.661 0.984-0.788 2.059-1.36 3.193-1.7 0.264-0.079 0.415-0.358 0.335-0.623s-0.358-0.415-0.623-0.335c-1.257 0.377-2.445 1.009-3.53 1.878-0.991 0.794-1.874 1.765-2.623 2.886-0.252 0.378-0.485 0.767-0.698 1.163-0.36-1.185-0.52-2.279-0.474-3.261 0.052-1.099 0.361-2.067 0.921-2.876 0.636-0.92 1.583-1.633 2.816-2.119 1.134-0.447 2.487-0.684 3.911-0.684 2.172 0 4.357 0.555 5.9 1.475-2.314 1.551-3.206 3.467-3.935 5.032z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,5 +0,0 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>tree2</title>
<path d="M13.887 13.182l-2.387-3.182h1c0 0 0.001 0 0.001 0 0.276 0 0.5-0.224 0.5-0.5 0-0.121-0.043-0.231-0.114-0.318l-2.387-3.182h1c0.192 0 0.367-0.11 0.451-0.283s0.060-0.379-0.060-0.529l-4-5c-0.095-0.119-0.239-0.188-0.39-0.188s-0.296 0.069-0.39 0.188l-4 5c-0.12 0.15-0.143 0.356-0.060 0.529s0.258 0.283 0.451 0.283h1l-2.4 3.2c-0.114 0.152-0.132 0.354-0.047 0.524s0.258 0.276 0.447 0.276h1l-2.4 3.2c-0.114 0.152-0.132 0.354-0.047 0.524s0.258 0.276 0.447 0.276h4.5v1.5c0 0.276 0.224 0.5 0.5 0.5h2c0.276 0 0.5-0.224 0.5-0.5v-1.5h4.5c0 0 0 0 0.001 0 0.276 0 0.5-0.224 0.5-0.5 0-0.121-0.043-0.231-0.114-0.318zM8 15h-1v-1h1v1zM2.5 13l2.4-3.2c0.114-0.152 0.132-0.354 0.047-0.524s-0.258-0.276-0.447-0.276h-1l2.4-3.2c0.114-0.152 0.132-0.354 0.047-0.524s-0.258-0.276-0.447-0.276h-0.96l2.96-3.7 2.96 3.7h-0.96c-0.189 0-0.363 0.107-0.447 0.276s-0.066 0.372 0.047 0.524l2.4 3.2h-1c-0.189 0-0.363 0.107-0.447 0.276s-0.066 0.372 0.047 0.524l2.4 3.2h-10z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,5 +0,0 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>tree3</title>
<path d="M11.852 3.354c-0.508-1.928-2.266-3.354-4.352-3.354s-3.844 1.426-4.352 3.354c-1.891 0.754-3.148 2.596-3.148 4.646 0 2.757 2.243 5 5 5 0.34 0 0.674-0.035 1-0.101v2.601c0 0.276 0.224 0.5 0.5 0.5h2c0.276 0 0.5-0.224 0.5-0.5v-2.601c0.327 0.066 0.661 0.101 1 0.101 2.757 0 5-2.243 5-5 0-2.060-1.254-3.892-3.148-4.646z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 489 B

View File

@ -1,5 +0,0 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<title>tree4</title>
<path d="M11.852 3.354c-0.508-1.928-2.266-3.354-4.352-3.354s-3.844 1.426-4.352 3.354c-1.891 0.754-3.148 2.596-3.148 4.646 0 2.757 2.243 5 5 5h1v2.5c0 0.276 0.224 0.5 0.5 0.5h2c0.276 0 0.5-0.224 0.5-0.5v-2.5h1c2.757 0 5-2.243 5-5 0-2.060-1.254-3.892-3.148-4.646zM8 15h-1v-2h1v2zM10 12h-5c-2.206 0-4-1.794-4-4 0-1.444 0.781-2.76 2.001-3.465 0.003 0.369 0.050 0.735 0.141 1.090 0.058 0.226 0.261 0.375 0.484 0.375 0.041 0 0.083-0.005 0.125-0.016 0.267-0.069 0.428-0.341 0.36-0.609-0.073-0.284-0.11-0.579-0.11-0.875 0-1.93 1.57-3.5 3.5-3.5s3.5 1.57 3.5 3.5c0 0.297-0.037 0.591-0.11 0.875-0.069 0.267 0.092 0.54 0.36 0.609s0.54-0.092 0.609-0.36c0.091-0.355 0.139-0.722 0.141-1.091 1.222 0.704 2.001 2.014 2.001 3.466 0 2.206-1.794 4-4 4z"></path>
</svg>

Before

Width:  |  Height:  |  Size: 901 B

View File

@ -24,8 +24,6 @@ function initActorActions(store, router) {
const { actor } = await graphql(`
query Actor(
$actorId: Int!
$userId: Int,
$hasAuth: Boolean!,
$limit:Int = 10,
$offset:Int = 0,
$after:Datetime = "1900-01-01",
@ -238,21 +236,6 @@ function initActorActions(store, router) {
}
totalCount
}
stashes: stashesActors(
filter: {
stash: {
userId: {
equalTo: $userId
}
}
}
) @include(if: $hasAuth) {
stash {
id
name
slug
}
}
}
}
`, {
@ -270,8 +253,6 @@ function initActorActions(store, router) {
includedEntities: getIncludedEntities(router),
includedActors: getIncludedActors(router),
mode,
hasAuth: !!store.state.auth.user,
userId: store.state.auth.user?.id,
});
if (!actor) {

View File

@ -10,14 +10,8 @@ async function get(endpoint, query = {}) {
credentials: 'same-origin',
});
const contentTypes = res.headers.get('content-type');
if (res.ok && contentTypes?.includes('application/json')) {
return res.json();
}
if (res.ok) {
return null;
return res.json();
}
const errorMsg = await res.text();
@ -36,32 +30,10 @@ async function post(endpoint, data) {
body: JSON.stringify(data),
});
const contentTypes = res.headers.get('content-type');
if (res.ok && contentTypes?.includes('application/json')) {
if (res.ok) {
return res.json();
}
if (res.ok) {
return null;
}
const errorMsg = await res.text();
throw new Error(errorMsg);
}
async function del(endpoint) {
const res = await fetch(`${config.api.url}${endpoint}`, {
method: 'DELETE',
mode: 'cors',
credentials: 'same-origin',
});
if (res.ok) {
return true;
}
const errorMsg = await res.text();
throw new Error(errorMsg);
@ -95,6 +67,5 @@ async function graphql(query, variables = null) {
export {
get,
post,
del,
graphql,
};

View File

@ -1,47 +1,3 @@
import { get, post, del } from '../api';
function initAuthActions(_store, _router) {
async function fetchMe({ commit }) {
try {
const user = await get('/session');
commit('setUser', user);
return user;
} catch (error) {
// continue as guest
return null;
}
}
async function login({ commit }, credentials) {
const user = await post('/session', credentials);
commit('setUser', user);
return user;
}
async function signup({ commit }, credentials) {
const user = await post('/users', credentials);
commit('setUser', user);
return user;
}
async function logout({ commit }) {
await del('/session');
commit('setUser', null);
}
return {
fetchMe,
login,
logout,
signup,
};
}
function initAuthActions(_store, _router) {}
export default initAuthActions;

View File

@ -1,13 +1,11 @@
import state from './state';
import mutations from './mutations';
import getters from './getters';
import actions from './actions';
function initAuthStore(store, router) {
return {
state,
mutations,
getters,
actions: actions(store, router),
};
}

View File

@ -1,8 +0,0 @@
function favoritesStash(state) {
return state.user.stashes.find(stash => stash.slug === 'favorites');
}
module.exports = {
favoritesStash,
favorites: favoritesStash,
};

View File

@ -1,7 +1 @@
function setUser(state, user) {
state.user = user;
}
export default {
setUser,
};
export default {};

View File

@ -1,5 +0,0 @@
async function initAuthObserver(store, _router) {
await store.dispatch('fetchMe');
}
export default initAuthObserver;

View File

@ -1,4 +1,4 @@
export default {
enabled: window.env.auth,
authenticated: false,
user: null,
};

View File

@ -56,8 +56,6 @@ function curateActor(actor, release) {
curatedActor.aliasFor = curateActor(curatedActor.aliasFor);
}
curatedActor.stashes = actor.stashes?.map(stash => stash.stash || stash) || [];
return curatedActor;
}
@ -127,41 +125,9 @@ function curateTag(tag) {
return curatedTag;
}
function curateStash(stash) {
const curatedStash = stash;
if (stash.scenes) {
curatedStash.scenes = stash.scenes.map(item => ({
...item,
scene: curateRelease(item.scene),
}));
}
if (stash.actors) {
curatedStash.actors = stash.actors.map(item => ({
...item,
actor: curateActor(item.actor),
}));
}
return curatedStash;
}
function curateUser(user) {
const curatedUser = user;
if (user.stashes) {
curatedUser.stashes = user.stashes.map(stash => curateStash(stash));
}
return curatedUser;
}
export {
curateActor,
curateEntity,
curateRelease,
curateTag,
curateStash,
curateUser,
};

View File

@ -108,8 +108,6 @@ const releasePosterFragment = `
index
path
thumbnail
width
height
lazy
isS3
comment
@ -131,8 +129,6 @@ const releaseCoversFragment = `
index
path
thumbnail
width
height
lazy
isS3
comment
@ -154,8 +150,6 @@ const releasePhotosFragment = `
index
path
thumbnail
width
height
lazy
isS3
comment

View File

@ -6,7 +6,6 @@ import mitt from 'mitt';
import router from './router';
import initStore from './store';
import initUiObservers from './ui/observers';
import initAuthObservers from './auth/observers';
import { formatDate, formatDuration } from './format';
@ -64,8 +63,7 @@ async function init() {
return `${path}/${filename}`;
}
await initAuthObservers(store, router);
await initUiObservers(store, router);
initUiObservers(store, router);
if (window.env.sfw) {
store.dispatch('setSfw', true);

View File

@ -1,9 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../components/home/home.vue';
import Login from '../components/auth/login.vue';
import Signup from '../components/auth/signup.vue';
import User from '../components/users/user.vue';
import Release from '../components/releases/release.vue';
import Entity from '../components/entities/entity.vue';
import Networks from '../components/networks/networks.vue';
@ -19,7 +16,6 @@ import NotFound from '../components/errors/404.vue';
const routes = [
{
path: '/',
name: 'home',
redirect: {
name: 'updates',
params: {
@ -29,21 +25,6 @@ const routes = [
},
},
},
{
path: '/login',
name: 'login',
component: Login,
},
{
path: '/signup',
name: 'signup',
component: Signup,
},
{
path: '/user/:username',
name: 'user',
component: User,
},
{
path: '/updates',
redirect: {

View File

@ -1,18 +0,0 @@
import { post, del } from '../api';
function initStashesActions(_store, _router) {
async function stashActor(context, { actorId, stashId }) {
await post(`/stashes/${stashId}/actors`, { actorId });
}
async function unstashActor(context, { actorId, stashId }) {
await del(`/stashes/${stashId}/actors/${actorId}`);
}
return {
stashActor,
unstashActor,
};
}
export default initStashesActions;

View File

@ -1 +0,0 @@
export default {};

View File

@ -1,13 +0,0 @@
import state from './state';
import mutations from './mutations';
import actions from './actions';
function initStashesStore(store, router) {
return {
state,
mutations,
actions: actions(store, router),
};
}
export default initStashesStore;

View File

@ -1 +0,0 @@
export default {};

View File

@ -2,24 +2,20 @@ import Vuex from 'vuex';
import initUiStore from './ui/ui';
import initAuthStore from './auth/auth';
import initUsersStore from './users/users';
import initReleasesStore from './releases/releases';
import initEntitiesStore from './entities/entities';
import initActorsStore from './actors/actors';
import initTagsStore from './tags/tags';
import initStashesStore from './stashes/stashes';
function initStore(router) {
const store = new Vuex.Store();
store.registerModule('ui', initUiStore(store, router));
store.registerModule('auth', initAuthStore(store, router));
store.registerModule('users', initUsersStore(store, router));
store.registerModule('releases', initReleasesStore(store, router));
store.registerModule('entities', initEntitiesStore(store, router));
store.registerModule('actors', initActorsStore(store, router));
store.registerModule('tags', initTagsStore(store, router));
store.registerModule('stashes', initStashesStore(store, router));
return store;
}

View File

@ -1,102 +0,0 @@
import { graphql } from '../api';
function initUsersActions(_store, _router) {
async function fetchUser(context, username) {
const { user } = await graphql(`
query User(
$username: String!
) {
user: userByUsername(username: $username) {
id
role
username
stashes {
id
name
slug
public
actors: stashesActors {
comment
actor {
id
name
slug
gender
age
ageFromBirth
dateOfBirth
birthCity
birthState
birthCountry: countryByBirthCountryAlpha2 {
alpha2
name
alias
}
avatar: avatarMedia {
id
path
thumbnail
lazy
}
}
}
scenes: stashesScenes {
comment
scene {
id
title
slug
url
date
actors: releasesActors {
actor {
id
name
slug
}
}
tags: releasesTags {
tag {
id
name
slug
}
}
entity {
id
name
slug
independent
parent {
id
name
slug
independent
}
}
poster: releasesPosterByReleaseId {
media {
path
thumbnail
lazy
isS3
}
}
}
}
}
}
}
`, {
username,
});
return user;
}
return {
fetchUser,
};
}
export default initUsersActions;

View File

@ -1 +0,0 @@
export default {};

View File

@ -1 +0,0 @@
export default {};

View File

@ -1,13 +0,0 @@
import state from './state';
import mutations from './mutations';
import actions from './actions';
function initUsersStore(store, router) {
return {
state,
mutations,
actions: actions(store, router),
};
}
export default initUsersStore;

View File

@ -33,9 +33,6 @@ module.exports = {
accessKey: 'ABCDEFGHIJ1234567890',
secretKey: 'abcdefghijklmnopqrstuvwxyz1234567890ABCD',
},
auth: {
enabled: true,
},
exclude: {
channels: [
// 21sextreme, no longer updated

View File

@ -1,5 +1,3 @@
const config = require('config');
exports.up = knex => Promise.resolve()
.then(() => knex.schema.createTable('countries', (table) => {
table.text('alpha2', 2)
@ -107,10 +105,6 @@ exports.up = knex => Promise.resolve()
.inTable('entities')
.onDelete('cascade');
table.date('date');
table.enum('date_precision', ['year', 'month', 'day', 'hour', 'minute', 'second'])
.defaultTo('year');
table.text('comment');
table.text('group');
@ -986,125 +980,12 @@ exports.up = knex => Promise.resolve()
table.unique(['tag_id', 'chapter_id']);
}))
.then(() => knex.schema.createTable('users_roles', (table) => {
table.string('role')
.primary();
table.json('abilities');
}))
.then(() => knex('users_roles').insert([
{
role: 'admin',
abilities: JSON.stringify([ // serialization necessary to avoid array being interpreted as a PG array
{ subject: 'scene', action: 'create' },
{ subject: 'scene', action: 'update' },
{ subject: 'scene', action: 'delete' },
{ subject: 'actor', action: 'create' },
{ subject: 'actor', action: 'update' },
{ subject: 'actor', action: 'delete' },
]),
},
{
role: 'editor',
abilities: JSON.stringify([ // serialization necessary to avoid array being interpreted as a PG array
{ subject: 'scene', action: 'update' },
{ subject: 'actor', action: 'update' },
]),
},
{
role: 'user',
},
]))
.then(() => knex.schema.createTable('users', (table) => {
table.increments('id');
table.text('username')
.unique()
.notNullable();
table.text('email')
.unique()
.notNullable();
table.text('password')
.notNullable();
table.string('role')
.references('role')
.inTable('users_roles')
.defaultTo('user')
.notNullable();
table.json('abilities');
table.boolean('email_verified')
.notNullable()
.defaultTo(false);
table.boolean('identity_verified')
.notNullable()
.defaultTo(false);
table.datetime('created_at')
.notNullable()
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('stashes', (table) => {
table.increments('id');
table.integer('user_id')
.references('id')
.inTable('users');
table.string('name')
.notNullable();
table.string('slug')
.notNullable();
table.boolean('public')
.notNullable()
.defaultTo(false);
table.datetime('created_at')
.notNullable()
.defaultTo(knex.fn.now());
}))
.then(() => knex.schema.createTable('stashes_scenes', (table) => {
table.integer('stash_id')
.notNullable()
.references('id')
.inTable('stashes');
table.integer('scene_id')
.notNullable()
.references('id')
.inTable('releases');
table.unique(['stash_id', 'scene_id']);
table.string('comment');
}))
.then(() => knex.schema.createTable('stashes_actors', (table) => {
table.integer('stash_id')
.notNullable()
.references('id')
.inTable('stashes');
table.integer('actor_id')
.notNullable()
.references('id')
.inTable('actors');
table.unique(['stash_id', 'actor_id']);
table.string('comment');
}))
// SEARCH
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
ALTER TABLE releases_search ADD COLUMN document tsvector;
ALTER TABLE releases_search
ADD COLUMN document tsvector;
`);
})
// INDEXES
@ -1122,10 +1003,6 @@ exports.up = knex => Promise.resolve()
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
CREATE FUNCTION current_user_id() RETURNS INTEGER AS $$
SELECT current_setting('user.id', true)::integer;
$$ LANGUAGE SQL STABLE;
/* We need both the release entries and their search ranking, and PostGraphile does not seem to allow virtual foreign keys on function results.
* Using a table as a proxy for the search results allows us to get both a reference to the releases table, and the ranking.
* A composite type does not seem to be compatible with PostGraphile's @sortable, and a view does not allow for many native constraints */
@ -1292,54 +1169,10 @@ exports.up = knex => Promise.resolve()
$$ LANGUAGE sql STABLE;
`);
})
// POLICIES
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
GRANT ALL ON ALL TABLES IN SCHEMA public TO :visitor;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO :visitor;
REVOKE ALL ON users FROM :visitor;
GRANT SELECT (id, username, role, identity_verified, created_at) ON users TO :visitor;
ALTER TABLE stashes ENABLE ROW LEVEL SECURITY;
ALTER TABLE stashes_scenes ENABLE ROW LEVEL SECURITY;
ALTER TABLE stashes_actors ENABLE ROW LEVEL SECURITY;
CREATE POLICY stashes_policy_select ON stashes FOR SELECT USING (stashes.public OR stashes.user_id = current_user_id());
CREATE POLICY stashes_policy_update ON stashes FOR UPDATE USING (stashes.public OR stashes.user_id = current_user_id());
CREATE POLICY stashes_policy_delete ON stashes FOR DELETE USING (stashes.public OR stashes.user_id = current_user_id());
CREATE POLICY stashes_policy_insert ON stashes FOR INSERT WITH CHECK (true);
CREATE POLICY stashes_policy ON stashes_scenes
USING (EXISTS (
SELECT *
FROM stashes
WHERE stashes.id = stashes_scenes.stash_id
AND (stashes.user_id = current_user_id() OR stashes.public)
));
CREATE POLICY stashes_policy ON stashes_actors
USING (EXISTS (
SELECT *
FROM stashes
WHERE stashes.id = stashes_actors.stash_id
AND (stashes.user_id = current_user_id() OR stashes.public)
));
`, {
visitor: knex.raw(config.database.query.user),
password: knex.raw(config.database.query.password),
});
})
// VIEWS AND COMMENTS
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
COMMENT ON COLUMN users.password IS E'@omit';
COMMENT ON COLUMN users.email IS E'@omit';
COMMENT ON COLUMN users.email_verified IS E'@omit';
COMMENT ON COLUMN users.abilities IS E'@omit';
COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many';
COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many';
COMMENT ON COLUMN actors.penis_length IS E'@omit read,update,create,delete,all,many';
@ -1416,13 +1249,6 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
DROP TABLE IF EXISTS entities_types CASCADE;
DROP TABLE IF EXISTS entities CASCADE;
DROP TABLE IF EXISTS stashes_scenes CASCADE;
DROP TABLE IF EXISTS stashes_actors CASCADE;
DROP TABLE IF EXISTS stashes CASCADE;
DROP TABLE IF EXISTS users CASCADE;
DROP TABLE IF EXISTS users_roles CASCADE;
DROP FUNCTION IF EXISTS search_releases;
DROP FUNCTION IF EXISTS search_sites;
DROP FUNCTION IF EXISTS search_entities;
@ -1439,12 +1265,6 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
DROP FUNCTION IF EXISTS movies_tags;
DROP FUNCTION IF EXISTS movies_photos;
DROP POLICY IF EXISTS stashes_policy ON stashes;
DROP POLICY IF EXISTS stashes_policy ON stashes_scenes;
DROP POLICY IF EXISTS stashes_policy ON stashes_actors;
DROP FUNCTION IF EXISTS current_user_id;
DROP TABLE IF EXISTS releases_search_results;
`);
};

86
package-lock.json generated
View File

@ -1,14 +1,13 @@
{
"name": "traxxx",
"version": "1.185.0",
"version": "1.184.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.185.0",
"version": "1.184.2",
"license": "ISC",
"dependencies": {
"@casl/ability": "^5.2.2",
"@graphile-contrib/pg-order-by-related": "^1.0.0-beta.6",
"@graphile-contrib/pg-simplify-inflector": "^5.0.0-beta.1",
"acorn": "^8.0.4",
@ -1263,17 +1262,6 @@
"to-fast-properties": "^2.0.0"
}
},
"node_modules/@casl/ability": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@casl/ability/-/ability-5.2.2.tgz",
"integrity": "sha512-A0GTDWojP72Z4HSgS0pfbtGnhQWbquhn9luAr4Uc/HnqWWib0NvmpXC4//7gsiMUiVYCoFozQ+nG1oeZuhT7Jg==",
"dependencies": {
"@ucast/mongo2js": "^1.3.0"
},
"funding": {
"url": "https://github.com/stalniy/casl/blob/master/BACKERS.md"
}
},
"node_modules/@eslint/eslintrc": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
@ -1504,37 +1492,6 @@
"@types/node": "*"
}
},
"node_modules/@ucast/core": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@ucast/core/-/core-1.8.2.tgz",
"integrity": "sha512-pc+XGjJmZkfypJIIRo38el/FUDtBXBlGQbXafWwRwInocXVwNbJ56efECKLgAQSyI7OCJFSaEeqpf3SrR3D6cw=="
},
"node_modules/@ucast/js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@ucast/js/-/js-3.0.1.tgz",
"integrity": "sha512-sabiuYsM5VUg4EaCwlDxnqcrHPFvbZcXvBu+P/o4pqK2q046RLTdo0bM7iVCn5Ro4HpCiRv3QzxtW8epcluY1g==",
"dependencies": {
"@ucast/core": "^1.0.0"
}
},
"node_modules/@ucast/mongo": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@ucast/mongo/-/mongo-2.4.1.tgz",
"integrity": "sha512-l/hc3TxjWO9inBrgM5iMCAcsIeV2DToppRlabQa5xB/6uHYtCXfm3TPaJgr8TU1OFxqPlaXEnNQhaV0sVHGsoQ==",
"dependencies": {
"@ucast/core": "^1.4.1"
}
},
"node_modules/@ucast/mongo2js": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@ucast/mongo2js/-/mongo2js-1.3.2.tgz",
"integrity": "sha512-KNOEs61wxo4VJkVGqwP2a03TKuLx9fLMQgW5HD8Th/mrcuP1SspS4W+kUQD+wB1AA5pOn65hzlHUw5wZBwme0Q==",
"dependencies": {
"@ucast/core": "^1.6.1",
"@ucast/js": "^3.0.0",
"@ucast/mongo": "^2.4.0"
}
},
"node_modules/@videojs/http-streaming": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.2.4.tgz",
@ -16646,14 +16603,6 @@
"to-fast-properties": "^2.0.0"
}
},
"@casl/ability": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@casl/ability/-/ability-5.2.2.tgz",
"integrity": "sha512-A0GTDWojP72Z4HSgS0pfbtGnhQWbquhn9luAr4Uc/HnqWWib0NvmpXC4//7gsiMUiVYCoFozQ+nG1oeZuhT7Jg==",
"requires": {
"@ucast/mongo2js": "^1.3.0"
}
},
"@eslint/eslintrc": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
@ -16856,37 +16805,6 @@
"@types/node": "*"
}
},
"@ucast/core": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/@ucast/core/-/core-1.8.2.tgz",
"integrity": "sha512-pc+XGjJmZkfypJIIRo38el/FUDtBXBlGQbXafWwRwInocXVwNbJ56efECKLgAQSyI7OCJFSaEeqpf3SrR3D6cw=="
},
"@ucast/js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@ucast/js/-/js-3.0.1.tgz",
"integrity": "sha512-sabiuYsM5VUg4EaCwlDxnqcrHPFvbZcXvBu+P/o4pqK2q046RLTdo0bM7iVCn5Ro4HpCiRv3QzxtW8epcluY1g==",
"requires": {
"@ucast/core": "^1.0.0"
}
},
"@ucast/mongo": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/@ucast/mongo/-/mongo-2.4.1.tgz",
"integrity": "sha512-l/hc3TxjWO9inBrgM5iMCAcsIeV2DToppRlabQa5xB/6uHYtCXfm3TPaJgr8TU1OFxqPlaXEnNQhaV0sVHGsoQ==",
"requires": {
"@ucast/core": "^1.4.1"
}
},
"@ucast/mongo2js": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@ucast/mongo2js/-/mongo2js-1.3.2.tgz",
"integrity": "sha512-KNOEs61wxo4VJkVGqwP2a03TKuLx9fLMQgW5HD8Th/mrcuP1SspS4W+kUQD+wB1AA5pOn65hzlHUw5wZBwme0Q==",
"requires": {
"@ucast/core": "^1.6.1",
"@ucast/js": "^3.0.0",
"@ucast/mongo": "^2.4.0"
}
},
"@videojs/http-streaming": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.2.4.tgz",

View File

@ -1,6 +1,6 @@
{
"name": "traxxx",
"version": "1.185.0",
"version": "1.184.2",
"description": "All the latest porn releases in one place",
"main": "src/app.js",
"scripts": {
@ -69,7 +69,6 @@
"webpack-cli": "^3.3.11"
},
"dependencies": {
"@casl/ability": "^5.2.2",
"@graphile-contrib/pg-order-by-related": "^1.0.0-beta.6",
"@graphile-contrib/pg-simplify-inflector": "^5.0.0-beta.1",
"acorn": "^8.0.4",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 781 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 692 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

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