Refactored alerts to use application code, added regex. Updated Jules Jordan for the Ass Factory relaunch.
|
@ -3,6 +3,11 @@
|
|||
title="Add alert"
|
||||
@close="$emit('close')"
|
||||
>
|
||||
<div
|
||||
v-if="error"
|
||||
class="dialog-error"
|
||||
>{{ error }}</div>
|
||||
|
||||
<form
|
||||
class="dialog-body"
|
||||
@submit.prevent="addAlert"
|
||||
|
@ -136,6 +141,72 @@
|
|||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert-section">
|
||||
<h4 class="alert-heading">Matching</h4>
|
||||
|
||||
<ul class="matches nolist">
|
||||
<li
|
||||
v-for="(match, index) in matches"
|
||||
:key="`match-${index}`"
|
||||
class="match"
|
||||
>
|
||||
<span class="match-property">{{ match.property }}: </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 class="dialog-section">
|
||||
|
@ -194,7 +265,7 @@
|
|||
|
||||
<div class="dialog-actions right">
|
||||
<button
|
||||
:disabled="actors.length === 0 && tags.length === 0 && !entity"
|
||||
:disabled="actors.length === 0 && tags.length === 0 && !entity && matches.length === 0"
|
||||
type="submit"
|
||||
class="button button-primary"
|
||||
>Add alert</button>
|
||||
|
@ -210,16 +281,23 @@ import Checkbox from '../form/checkbox.vue';
|
|||
import Search from './search.vue';
|
||||
|
||||
async function addAlert() {
|
||||
await this.$store.dispatch('addAlert', {
|
||||
actors: this.actors.map((actor) => actor.id),
|
||||
tags: this.tags.map((tag) => tag.id),
|
||||
entity: this.entity?.id,
|
||||
notify: this.notify,
|
||||
email: this.email,
|
||||
stashes: this.stashes.map((stash) => stash.id),
|
||||
});
|
||||
this.error = null;
|
||||
|
||||
this.$emit('close', true);
|
||||
try {
|
||||
await this.$store.dispatch('addAlert', {
|
||||
actors: this.actors.map((actor) => actor.id),
|
||||
tags: this.tags.map((tag) => tag.id),
|
||||
matches: this.matches,
|
||||
entity: this.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) {
|
||||
|
@ -255,6 +333,26 @@ function removeTag(tag) {
|
|||
this.tags = this.tags.filter((listedTag) => listedTag.id !== tag.id);
|
||||
}
|
||||
|
||||
function addMatch() {
|
||||
if (!this.matchExpression) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.matches = this.matches.concat({
|
||||
property: this.matchProperty,
|
||||
expression: this.matchExpression,
|
||||
});
|
||||
|
||||
this.matchProperty = 'title';
|
||||
this.matchExpression = null;
|
||||
|
||||
this.events.emit('blur');
|
||||
}
|
||||
|
||||
function removeMatch(removeIndex) {
|
||||
this.matches = this.matches.filter((match, matchIndex) => matchIndex !== removeIndex);
|
||||
}
|
||||
|
||||
function addStash(stash) {
|
||||
if (!this.stashes.some((selectedStash) => selectedStash.id === stash.id)) {
|
||||
this.stashes = this.stashes.concat(stash);
|
||||
|
@ -277,9 +375,13 @@ export default {
|
|||
emits: ['close'],
|
||||
data() {
|
||||
return {
|
||||
error: null,
|
||||
actors: [],
|
||||
tags: [],
|
||||
entity: null,
|
||||
matches: [],
|
||||
matchProperty: 'title',
|
||||
matchExpression: null,
|
||||
notify: true,
|
||||
email: false,
|
||||
stashes: [],
|
||||
|
@ -290,10 +392,12 @@ export default {
|
|||
addActor,
|
||||
addAlert,
|
||||
addEntity,
|
||||
addMatch,
|
||||
addTag,
|
||||
addStash,
|
||||
removeActor,
|
||||
removeEntity,
|
||||
removeMatch,
|
||||
removeTag,
|
||||
removeStash,
|
||||
},
|
||||
|
@ -325,6 +429,15 @@ export default {
|
|||
font-weight: normal;
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
background: var(--error);
|
||||
color: var(--text-light);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.alert-heading {
|
||||
margin: .75rem 0 .25rem 0;
|
||||
}
|
||||
|
@ -338,6 +451,34 @@ export default {
|
|||
font-size: 0;
|
||||
}
|
||||
|
||||
.match {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .25rem 0;
|
||||
font-family: inherit;
|
||||
|
||||
.remove {
|
||||
position: relative;
|
||||
top: -.1rem;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.match-property {
|
||||
text-transform: capitalize;
|
||||
color: var(--shadow);
|
||||
}
|
||||
|
||||
.match-expression {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.match-slash {
|
||||
padding: 0 .1rem;
|
||||
color: var(--primary);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.actors > .actor,
|
||||
.entity,
|
||||
.tag,
|
||||
|
@ -366,6 +507,14 @@ export default {
|
|||
color: var(--text);
|
||||
}
|
||||
|
||||
.pattern-tooltip {
|
||||
display: flex;
|
||||
gap: .5rem;
|
||||
position: relative;
|
||||
padding: .5rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.remove {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
|
||||
<Icon
|
||||
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 <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> 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(', ') || 'anything'}</strong>`"
|
||||
icon="question5"
|
||||
@click.prevent.stop
|
||||
/>
|
||||
|
@ -145,12 +145,12 @@ export default {
|
|||
default: 0,
|
||||
},
|
||||
},
|
||||
emits: ['addAlert'],
|
||||
data() {
|
||||
return {
|
||||
showAddAlert: false,
|
||||
};
|
||||
},
|
||||
emits: ['addAlert'],
|
||||
methods: {
|
||||
checkNotifications,
|
||||
checkNotification,
|
||||
|
|
|
@ -125,6 +125,7 @@ function mounted() {
|
|||
}
|
||||
|
||||
export default {
|
||||
emits: ['open', 'close'],
|
||||
data() {
|
||||
return {
|
||||
opened: false,
|
||||
|
@ -133,7 +134,6 @@ export default {
|
|||
arrowOffset: 0,
|
||||
};
|
||||
},
|
||||
emits: ['open', 'close'],
|
||||
mounted,
|
||||
methods: {
|
||||
calculate,
|
||||
|
|
|
@ -93,17 +93,43 @@
|
|||
</div>
|
||||
|
||||
<div
|
||||
v-if="alert.entity"
|
||||
v-if="alert.entities.length > 0"
|
||||
class="alert-section alert-trigger"
|
||||
>
|
||||
<h4 class="alert-heading">Channel</h4>
|
||||
<h4 class="alert-heading">{{ alert.entities.length > 1 ? 'Channels' : 'Channel' }}</h4>
|
||||
|
||||
<Entity
|
||||
v-if="alert.entity"
|
||||
:entity="alert.entity"
|
||||
v-for="entity in alert.entities"
|
||||
:key="`${alert.id}${entity.id}`"
|
||||
:entity="entity"
|
||||
class="entity"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="alert.matches.length > 0"
|
||||
class="alert-section alert-trigger"
|
||||
>
|
||||
<h4 class="alert-heading">Matches</h4>
|
||||
|
||||
<ul class="alert-matches nolist">
|
||||
<li
|
||||
v-for="match in alert.matches"
|
||||
:key="`match-${match.id}`"
|
||||
class="match"
|
||||
>
|
||||
<span
|
||||
v-if="match.expression.slice(0, 1) === '/' && match.expression.slice(-1) === '/'"
|
||||
class="match-expression"
|
||||
><span class="match-slash">/</span>{{ match.expression.slice(1, -1) }}<span class="match-slash">/</span></span>
|
||||
|
||||
<span
|
||||
v-else
|
||||
class="match-expression"
|
||||
>{{ match.expression }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -227,26 +253,34 @@ export default {
|
|||
}
|
||||
|
||||
.alert-actors,
|
||||
.alert-tags {
|
||||
.alert-tags,
|
||||
.alert-matches {
|
||||
display: flex;
|
||||
grid-gap: .5rem;
|
||||
}
|
||||
|
||||
.tag {
|
||||
.tag,
|
||||
.match {
|
||||
color: var(--shadow-strong);
|
||||
padding: .5rem;
|
||||
border: solid 1px var(--shadow-hint);
|
||||
font-size: .9rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
border: solid 1px var(--primary);
|
||||
}
|
||||
.tag:hover {
|
||||
cursor: pointer;
|
||||
border: solid 1px var(--primary);
|
||||
}
|
||||
|
||||
.entity {
|
||||
width: 10rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.match-slash {
|
||||
padding: 0 .1rem;
|
||||
color: var(--primary);
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -191,6 +191,10 @@ function curateAlert(alert) {
|
|||
curatedAlert.entity = curateEntity(alert.entity.entity || alert.entity);
|
||||
}
|
||||
|
||||
if (alert.entities) {
|
||||
curatedAlert.entities = alert.entities.map((entity) => curateEntity(entity.entity || entity));
|
||||
}
|
||||
|
||||
if (alert.stashes) {
|
||||
curatedAlert.stashes = alert.stashes.map((stash) => curateStash(stash.stash || stash));
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ function initUiActions(store, _router) {
|
|||
slug
|
||||
}
|
||||
}
|
||||
entity: alertsEntity {
|
||||
entities: alertsEntities {
|
||||
entity {
|
||||
id
|
||||
name
|
||||
|
@ -90,6 +90,10 @@ function initUiActions(store, _router) {
|
|||
independent
|
||||
}
|
||||
}
|
||||
matches: alertsMatches {
|
||||
property
|
||||
expression
|
||||
}
|
||||
}
|
||||
}
|
||||
totalCount
|
||||
|
|
|
@ -85,12 +85,17 @@ function initUsersActions(store, _router) {
|
|||
slug
|
||||
}
|
||||
}
|
||||
matches: alertsMatches {
|
||||
id
|
||||
property
|
||||
expression
|
||||
}
|
||||
actors: alertsActors {
|
||||
actor {
|
||||
${actorFields}
|
||||
}
|
||||
}
|
||||
entity: alertsEntity {
|
||||
entities: alertsEntities {
|
||||
entity {
|
||||
id
|
||||
name
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
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.dropTable('alerts_matches');
|
||||
};
|
|
@ -36,6 +36,7 @@
|
|||
"dayjs": "^1.8.21",
|
||||
"dompurify": "^2.0.11",
|
||||
"ejs": "^3.0.1",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"express-react-views": "^0.11.0",
|
||||
|
@ -5205,6 +5206,14 @@
|
|||
"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": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||
|
@ -7077,11 +7086,14 @@
|
|||
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||
},
|
||||
"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": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen": {
|
||||
|
@ -7691,17 +7703,6 @@
|
|||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"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": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz",
|
||||
|
@ -8451,6 +8452,14 @@
|
|||
"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": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
|
@ -11599,17 +11608,6 @@
|
|||
"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": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
|
@ -12579,6 +12577,15 @@
|
|||
"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": {
|
||||
"version": "2.7.4",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
|
||||
|
@ -17734,17 +17741,6 @@
|
|||
"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": {
|
||||
"version": "8.26.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
|
||||
|
@ -23152,6 +23148,13 @@
|
|||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"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": {
|
||||
|
@ -24605,9 +24608,9 @@
|
|||
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
|
||||
},
|
||||
"escodegen": {
|
||||
"version": "2.0.0",
|
||||
|
@ -24739,11 +24742,6 @@
|
|||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"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": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz",
|
||||
|
@ -25627,6 +25625,13 @@
|
|||
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
|
||||
"requires": {
|
||||
"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": {
|
||||
|
@ -28002,13 +28007,6 @@
|
|||
"integrity": "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==",
|
||||
"requires": {
|
||||
"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": {
|
||||
|
@ -28763,6 +28761,12 @@
|
|||
"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": {
|
||||
"version": "2.7.4",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
|
||||
|
@ -32619,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": {
|
||||
"version": "8.26.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.26.0.tgz",
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
"dayjs": "^1.8.21",
|
||||
"dompurify": "^2.0.11",
|
||||
"ejs": "^3.0.1",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"express": "^4.17.1",
|
||||
"express-promise-router": "^4.1.0",
|
||||
"express-react-views": "^0.11.0",
|
||||
|
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 709 B After Width: | Height: | Size: 745 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 925 B After Width: | Height: | Size: 961 B |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 6.4 MiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
@ -676,6 +676,7 @@ const tagMedia = [
|
|||
['blowbang', 'zaawaadi_roccosiffredi_1', 'Zaawaadi in "My Name Is Zaawaadi"', 'roccosiffredi'],
|
||||
['blowbang', 1, 'Nicole Black in GIO1680', 'analvids'],
|
||||
['blowbang', 'gina_gerson_assholefever', 'Gina Gerson in "Oppa Gangbang Style"', 'assholefever'],
|
||||
['blowjob', 'lily_lou_julesjordan', 'Lily Lou in "Lily Lou Has Her Ass Explored"', 'julesjordan'],
|
||||
['blowjob', 'clanddi_jinkcego_ddfbusty_1', 'Clanddi Jinkcego', 'ddfbusty'],
|
||||
['blowjob', 'juelz_ventura_babygotboobs', 'Juelz Ventura in "A Deep DP For Dessert"', 'babygotboobs'],
|
||||
['blowjob', 4, 'Chloe Cherry in "Chloe\'s Big Anal"', 'darkx'],
|
||||
|
|
216
src/alerts.js
|
@ -1,5 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const escapeRegexp = require('escape-string-regexp');
|
||||
|
||||
const knex = require('./knex');
|
||||
const bulkInsert = require('./utils/bulk-insert');
|
||||
const { HttpError } = require('./errors');
|
||||
|
@ -9,10 +11,14 @@ async function addAlert(alert, sessionUser) {
|
|||
throw new HttpError('You are not authenthicated', 401);
|
||||
}
|
||||
|
||||
if (!alert.actors?.length > 0 && !alert.tags?.length > 0 && !alert.entity) {
|
||||
if (!alert.actors?.length > 0 && !alert.tags?.length > 0 && !alert.entity && !alert.matches?.length > 0) {
|
||||
throw new HttpError('Alert must contain at least one actor, tag or entity', 400);
|
||||
}
|
||||
|
||||
if (alert.matches?.some((match) => !match.property || !match.expression)) {
|
||||
throw new HttpError('Match must define a property and an expression', 400);
|
||||
}
|
||||
|
||||
const [alertId] = await knex('alerts')
|
||||
.insert({
|
||||
user_id: sessionUser.id,
|
||||
|
@ -30,6 +36,11 @@ async function addAlert(alert, sessionUser) {
|
|||
alert_id: alertId,
|
||||
tag_id: tagId,
|
||||
})), false),
|
||||
alert.matches?.length > 0 && bulkInsert('alerts_matches', alert.matches.map((match) => ({
|
||||
alert_id: alertId,
|
||||
property: match.property,
|
||||
expression: match.expression,
|
||||
})), false),
|
||||
alert.stashes?.length > 0 && bulkInsert('alerts_stashes', alert.stashes.map((stashId) => ({
|
||||
alert_id: alertId,
|
||||
stash_id: stashId,
|
||||
|
@ -48,88 +59,153 @@ async function removeAlert(alertId) {
|
|||
}
|
||||
|
||||
async function notify(scenes) {
|
||||
const releases = await knex.raw(`
|
||||
SELECT alerts.id as alert_id, alerts.notify, alerts.email, releases.id as scene_id, users.id as user_id, COALESCE(json_agg(alerts_stashes.stash_id) FILTER (WHERE alerts_stashes.stash_id IS NOT NULL), '[]') as stashes
|
||||
FROM releases
|
||||
CROSS JOIN alerts
|
||||
LEFT JOIN users ON users.id = alerts.user_id
|
||||
LEFT JOIN alerts_stashes ON alerts_stashes.alert_id = alerts.id
|
||||
/* match updated IDs from input */
|
||||
WHERE (releases.id = ANY(:sceneIds))
|
||||
/* match tags */
|
||||
AND (NOT EXISTS (SELECT alerts_tags.alert_id
|
||||
FROM alerts_tags
|
||||
WHERE alerts_tags.alert_id = alerts.id)
|
||||
OR (SELECT array_agg(releases_tags.tag_id)
|
||||
FROM releases_tags
|
||||
WHERE releases_tags.release_id = releases.id
|
||||
GROUP BY releases_tags.release_id)
|
||||
@> (SELECT array_agg(alerts_tags.tag_id)
|
||||
FROM alerts_tags
|
||||
WHERE alerts_tags.alert_id = alerts.id
|
||||
GROUP BY alerts_tags.alert_id))
|
||||
/* match actors */
|
||||
AND (NOT EXISTS (SELECT alerts_actors.alert_id
|
||||
FROM alerts_actors
|
||||
WHERE alerts_actors.alert_id = alerts.id)
|
||||
OR (SELECT array_agg(releases_actors.actor_id)
|
||||
FROM releases_actors
|
||||
WHERE releases_actors.release_id = releases.id
|
||||
GROUP BY releases_actors.release_id)
|
||||
@> (SELECT array_agg(alerts_actors.actor_id)
|
||||
FROM alerts_actors
|
||||
WHERE alerts_actors.alert_id = alerts.id
|
||||
GROUP BY alerts_actors.alert_id))
|
||||
/* match entity */
|
||||
AND ((NOT EXISTS (SELECT alerts_entities.entity_id
|
||||
FROM alerts_entities
|
||||
WHERE alerts_entities.alert_id = alerts.id))
|
||||
OR (releases.entity_id
|
||||
= ANY(array(
|
||||
/* include children of entities */
|
||||
WITH RECURSIVE included AS (
|
||||
SELECT entities.*
|
||||
FROM alerts_entities
|
||||
LEFT JOIN entities ON entities.id = alerts_entities.entity_id
|
||||
WHERE alerts_entities.alert_id = alerts.id
|
||||
const sceneIds = scenes.map((scene) => scene.id);
|
||||
|
||||
UNION ALL
|
||||
const [
|
||||
releasesActors,
|
||||
releasesTags,
|
||||
rawAlerts,
|
||||
alertsActors,
|
||||
alertsTags,
|
||||
alertsEntities,
|
||||
alertsMatches,
|
||||
alertsStashes,
|
||||
] = await Promise.all([
|
||||
knex('releases_actors').whereIn('release_id', sceneIds),
|
||||
knex('releases_tags').whereIn('release_id', sceneIds),
|
||||
knex('alerts'),
|
||||
knex('alerts_actors'),
|
||||
knex('alerts_tags'),
|
||||
knex('alerts_entities'),
|
||||
knex('alerts_matches'),
|
||||
knex('alerts_stashes'),
|
||||
]);
|
||||
|
||||
SELECT entities.*
|
||||
FROM entities
|
||||
INNER JOIN included ON included.id = entities.parent_id
|
||||
)
|
||||
const actorIdsByReleaseId = releasesActors.reduce((acc, releaseActor) => {
|
||||
if (!acc[releaseActor.release_id]) {
|
||||
acc[releaseActor.release_id] = [];
|
||||
}
|
||||
|
||||
SELECT included.id
|
||||
FROM included
|
||||
GROUP BY included.id
|
||||
))))
|
||||
GROUP BY releases.id, users.id, alerts.id;
|
||||
`, {
|
||||
sceneIds: scenes.map((scene) => scene.id),
|
||||
acc[releaseActor.release_id].push(releaseActor.actor_id);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const tagIdsByReleaseId = releasesTags.reduce((acc, releaseTag) => {
|
||||
if (!acc[releaseTag.release_id]) {
|
||||
acc[releaseTag.release_id] = [];
|
||||
}
|
||||
|
||||
acc[releaseTag.release_id].push(releaseTag.tag_id);
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const alertsActorsByAlertId = alertsActors.reduce((acc, alertActor) => { if (!acc[alertActor.alert_id]) { acc[alertActor.alert_id] = []; } acc[alertActor.alert_id].push(alertActor.actor_id); return acc; }, {});
|
||||
const alertsTagsByAlertId = alertsTags.reduce((acc, alertTag) => { if (!acc[alertTag.alert_id]) { acc[alertTag.alert_id] = []; } acc[alertTag.alert_id].push(alertTag.tag_id); return acc; }, {});
|
||||
const alertsEntitiesByAlertId = alertsEntities.reduce((acc, alertEntity) => { if (!acc[alertEntity.alert_id]) { acc[alertEntity.alert_id] = []; } acc[alertEntity.alert_id].push(alertEntity.entity_id); return acc; }, {});
|
||||
const alertsStashesByAlertId = alertsStashes.reduce((acc, alertStash) => { if (!acc[alertStash.alert_id]) { acc[alertStash.alert_id] = []; } acc[alertStash.alert_id].push(alertStash.stash_id); return acc; }, {});
|
||||
|
||||
const alertsMatchesByAlertId = alertsMatches.reduce((acc, alertMatch) => {
|
||||
if (!acc[alertMatch.alert_id]) {
|
||||
acc[alertMatch.alert_id] = [];
|
||||
}
|
||||
|
||||
acc[alertMatch.alert_id].push({
|
||||
property: alertMatch.property,
|
||||
expression: /\/.*\//.test(alertMatch.expression)
|
||||
? new RegExp(alertMatch.expression.slice(1, -1), 'ui')
|
||||
: new RegExp(escapeRegexp(alertMatch.expression), 'ui'),
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
console.log(alertsStashesByAlertId);
|
||||
|
||||
const alerts = rawAlerts.map((alert) => ({
|
||||
id: alert.id,
|
||||
userId: alert.user_id,
|
||||
notify: alert.notify,
|
||||
email: alert.email,
|
||||
all: alert.all,
|
||||
actors: alertsActorsByAlertId[alert.id] || [],
|
||||
tags: alertsTagsByAlertId[alert.id] || [],
|
||||
entities: alertsEntitiesByAlertId[alert.id] || [],
|
||||
matches: alertsMatchesByAlertId[alert.id] || [],
|
||||
stashes: alertsStashesByAlertId[alert.id] || [],
|
||||
}));
|
||||
|
||||
const curatedScenes = scenes.map((scene) => ({
|
||||
id: scene.id,
|
||||
title: scene.title,
|
||||
description: scene.description,
|
||||
actorIds: actorIdsByReleaseId[scene.id] || [],
|
||||
tagIds: tagIdsByReleaseId[scene.id] || [],
|
||||
entityId: scene.entity.id,
|
||||
parentEntityId: scene.entity.parent?.id,
|
||||
}));
|
||||
|
||||
const triggers = alerts.flatMap((alert) => {
|
||||
const alertScenes = curatedScenes.filter((scene) => {
|
||||
console.log(scene.title, alert.tags, scene.tagIds);
|
||||
|
||||
if (alert.actors.length > 0 && !alert.actors.every((actorId) => scene.actorIds.includes(actorId))) {
|
||||
console.log('THROW ACTORS');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alert.tags.length > 0 && !alert.tags.every((tagId) => scene.tagIds.includes(tagId))) {
|
||||
console.log('THROW TAGS');
|
||||
return false;
|
||||
}
|
||||
|
||||
// multiple entities can only be matched in OR mode
|
||||
if (alert.entities.length > 0 && !alert.entities.some((alertEntityId) => alertEntityId === scene.entityId || alertEntityId === scene.parentEntityId)) {
|
||||
console.log('THROW ENTITIES');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alert.matches.length > 0 && !alert.matches.every((match) => match.expression.test(scene[match.property]))) {
|
||||
console.log('THROW MATCHES');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('OK');
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return alertScenes.map((scene) => ({
|
||||
sceneId: scene.id,
|
||||
alert,
|
||||
}));
|
||||
});
|
||||
|
||||
const notifications = releases.rows
|
||||
.filter((alert) => alert.notify)
|
||||
.map((notification) => ({
|
||||
user_id: notification.user_id,
|
||||
alert_id: notification.alert_id,
|
||||
scene_id: notification.scene_id,
|
||||
const notifications = Object.values(Object.fromEntries(triggers // prevent multiple notifications for the same scene
|
||||
.filter((trigger) => trigger.alert.notify)
|
||||
.map((trigger) => [`${trigger.alert.userId}:${trigger.sceneId}`, trigger])))
|
||||
.map((trigger) => ({
|
||||
user_id: trigger.alert.userId,
|
||||
alert_id: trigger.alert.id,
|
||||
scene_id: trigger.sceneId,
|
||||
}));
|
||||
|
||||
const stashes = releases.rows
|
||||
.filter((release) => release.stashes.length > 0)
|
||||
.flatMap((release) => release.stashes.map((stash) => ({
|
||||
scene_id: release.scene_id,
|
||||
stash_id: stash,
|
||||
})));
|
||||
console.log('triggers', triggers);
|
||||
|
||||
const stashes = Object.values(Object.fromEntries(triggers.flatMap((trigger) => trigger.alert.stashes.map((stashId) => ({
|
||||
scene_id: trigger.sceneId,
|
||||
stash_id: stashId,
|
||||
}))).map((stash) => [`${stash.stash_id}:${stash.scene_id}`, stash])));
|
||||
|
||||
console.log('stashes', stashes);
|
||||
|
||||
await Promise.all([
|
||||
bulkInsert('notifications', notifications, false),
|
||||
bulkInsert('stashes_scenes', stashes, false),
|
||||
]);
|
||||
|
||||
return releases.rows;
|
||||
return triggers;
|
||||
}
|
||||
|
||||
async function updateNotification(notificationId, notification, sessionUser) {
|
||||
|
|
|
@ -32,7 +32,7 @@ function scrapeAll(scenes, site, entryIdFromTitle) {
|
|||
|
||||
release.title = title?.slice(0, title.match(/starring:/i)?.index || Infinity).trim();
|
||||
release.url = query.url('.content_img a, .dvd_info > a, a.update_title, a[title]');
|
||||
release.date = query.date('.update_date', 'MM/DD/YYYY');
|
||||
release.date = query.date('.update_date', ['MM/DD/YYYY', 'YYYY-MM-DD']);
|
||||
|
||||
release.entryId = (entryIdFromTitle && slugify(release.title)) || element.dataset.setid || query.element('.rating_box')?.dataset.id || query.attribute('a img', 'id')?.match(/set-target-(\d+)/)?.[1];
|
||||
|
||||
|
@ -81,7 +81,7 @@ function scrapeUpcoming(scenes, channel) {
|
|||
const release = {};
|
||||
|
||||
release.title = query.text('.overlay-text', { join: false })?.[0];
|
||||
release.date = query.date('.overlay-text', 'MM/DD/YYYY');
|
||||
release.date = query.date('.overlay-text', ['MM/DD/YYYY', 'YYYY-MM-DD']);
|
||||
|
||||
release.actors = query.all('.update_models a').map((actorEl) => ({
|
||||
name: unprint.query.content(actorEl),
|
||||
|
@ -159,7 +159,7 @@ async function scrapeScene({ html, query }, context) {
|
|||
release.description = query.content('.update_description') || query.text('//div[./span[contains(text(), "Description")]]');
|
||||
release.entryId = context.entity.parameters?.entryIdFromTitle ? slugify(release.title) : getEntryId(html);
|
||||
|
||||
release.date = query.date(['.update_date', '//div[./span[contains(text(), "Date")]]'], 'MM/DD/YYYY');
|
||||
release.date = query.date(['.update_date', '//div[./span[contains(text(), "Date")]]'], ['MM/DD/YYYY', 'YYYY-MM-DD']);
|
||||
|
||||
release.actors = query.all('.backgroundcolor_info > .update_models a, .item .update_models a, .player-scene-description .update_models a').map((actorEl) => ({
|
||||
name: unprint.query.content(actorEl),
|
||||
|
|