Compare commits
19 Commits
8fd792b85c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 244dc4fff6 | |||
| 4b39f787c9 | |||
| fb92b9c973 | |||
| 181358db7d | |||
| 3790567d44 | |||
| b3af993236 | |||
| 7ae2bb7635 | |||
| a75f0662ad | |||
| ffd68d5037 | |||
| adf9e2334c | |||
| 4125811017 | |||
| 4e8356b072 | |||
| bad116cdc0 | |||
| 9eac6871a4 | |||
| 3b694689f3 | |||
| 1604ddaa78 | |||
| 16181923b6 | |||
| 62dcaba875 | |||
| f67c05f034 |
4
assets/img/icons/at-sign.svg
Executable file
4
assets/img/icons/at-sign.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path d="M13.657 2.343c-1.511-1.511-3.52-2.343-5.657-2.343s-4.146 0.832-5.657 2.343c-1.511 1.511-2.343 3.52-2.343 5.657s0.832 4.146 2.343 5.657c1.511 1.511 3.52 2.343 5.657 2.343 1.199 0 2.353-0.259 3.429-0.77 0.499-0.237 0.711-0.834 0.474-1.332s-0.834-0.711-1.332-0.474c-0.806 0.383-1.671 0.577-2.571 0.577-3.308 0-6-2.692-6-6s2.692-6 6-6 6 2.692 6 6v1c0 0.551-0.449 1-1 1s-1-0.449-1-1v-4c0-0.552-0.448-1-1-1-0.406 0-0.755 0.242-0.912 0.59-0.608-0.374-1.323-0.59-2.088-0.59-2.206 0-4 1.794-4 4s1.794 4 4 4c1.045 0 1.998-0.403 2.712-1.062 0.551 0.649 1.372 1.062 2.288 1.062 1.654 0 3-1.346 3-3v-1c0-2.137-0.832-4.146-2.343-5.657zM8 10c-1.103 0-2-0.897-2-2s0.897-2 2-2c1.103 0 2 0.897 2 2s-0.897 2-2 2z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 850 B |
@@ -20,6 +20,15 @@
|
||||
</div>
|
||||
|
||||
<ul class="bio nolist">
|
||||
<li
|
||||
v-if="aliases.length > 0"
|
||||
class="bio-item"
|
||||
>
|
||||
<dfn class="bio-label"><Icon icon="at-sign" />Aliases</dfn>
|
||||
|
||||
<span class="orientation">{{ aliases.join(', ') }}</span>
|
||||
</li>
|
||||
|
||||
<li
|
||||
v-if="actor.dateOfBirth"
|
||||
class="bio-item"
|
||||
@@ -528,6 +537,15 @@ const socials = props.actor.socials.slice(0, 10).map((social) => ({
|
||||
: social.handle,
|
||||
}));
|
||||
|
||||
const aliases = Object
|
||||
.entries(props.actor.aliases.reduce((acc, alias) => {
|
||||
acc[alias.name] = (props.actor[alias.name] || 0) + 1;
|
||||
return acc;
|
||||
}, {}))
|
||||
.toSorted(([, countA], [, countB]) => countB - countA)
|
||||
.map(([alias]) => alias)
|
||||
.filter((alias) => alias !== props.actor.name);
|
||||
|
||||
const showMergeDialog = ref(false);
|
||||
</script>
|
||||
|
||||
|
||||
@@ -82,6 +82,13 @@
|
||||
:src="`/logos/${actor.entity.slug}/favicon_dark.png`"
|
||||
class="favicon"
|
||||
>
|
||||
|
||||
<Icon
|
||||
v-if="actor.alias && actor.alias.name !== actor.name"
|
||||
v-tooltip="`Credited as '${actor.alias.name}'`"
|
||||
icon="at-sign"
|
||||
class="alias"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -258,4 +265,11 @@ const favorited = ref(props.actor.stashes.some((actorStash) => actorStash.id ===
|
||||
height: .75rem;
|
||||
margin-left: .25rem;
|
||||
}
|
||||
|
||||
.alias {
|
||||
height: 100%;
|
||||
fill: var(--glass-weak-20);
|
||||
padding: 0 .25rem;
|
||||
cursor: help;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,10 +19,16 @@
|
||||
>{{ avatar.sharpness.toFixed(2) }}</span>
|
||||
</span>
|
||||
|
||||
<span
|
||||
:title="`Added ${format(avatar.createdAt, 'yyyy-MM-dd')}, may not reflect photo age`"
|
||||
class="avatar-date"
|
||||
>{{ format(avatar.createdAt, '\'\'yy-MM') }}</span>
|
||||
|
||||
<a
|
||||
:href="getPath(avatar)"
|
||||
target="_blank"
|
||||
class="avatar-zoom"
|
||||
@click.stop
|
||||
>
|
||||
<Icon
|
||||
icon="search"
|
||||
@@ -32,6 +38,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { format } from 'date-fns';
|
||||
import getPath from '#/src/get-path.js';
|
||||
|
||||
defineProps({
|
||||
@@ -89,7 +96,8 @@ defineProps({
|
||||
}
|
||||
|
||||
.avatar-meta,
|
||||
.avatar-credit {
|
||||
.avatar-credit,
|
||||
.avatar-date {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
box-sizing: border-box;
|
||||
@@ -112,4 +120,10 @@ defineProps({
|
||||
bottom: .75rem;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.avatar-date {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "traxxx-web",
|
||||
"version": "0.50.12",
|
||||
"version": "0.50.21",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "0.50.12",
|
||||
"version": "0.50.21",
|
||||
"dependencies": {
|
||||
"@brillout/json-serializer": "^0.5.8",
|
||||
"@dicebear/collection": "^7.0.5",
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
"overrides": {
|
||||
"vite": "$vite"
|
||||
},
|
||||
"version": "0.50.12",
|
||||
"version": "0.50.21",
|
||||
"imports": {
|
||||
"#/*": "./*.js"
|
||||
}
|
||||
|
||||
@@ -11,20 +11,6 @@
|
||||
/>
|
||||
</h2>
|
||||
|
||||
<li
|
||||
v-if="actor.aliases?.length"
|
||||
class="bio-item"
|
||||
>
|
||||
<dfn class="bio-label">Also known as</dfn>
|
||||
<span class="bio-value">
|
||||
<span
|
||||
v-for="alias in actor.aliases"
|
||||
:key="`alias-${alias.id}`"
|
||||
class="alias"
|
||||
>{{ alias.name }}</span>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
<Heart
|
||||
domain="actors"
|
||||
:item="actor"
|
||||
@@ -108,7 +94,7 @@ const photos = actor.photos.filter((photo) => photo.entropy > 5.5 && !badCredits
|
||||
.actor-header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
@@ -466,18 +466,18 @@ const fields = computed(() => [
|
||||
type: 'augmentation',
|
||||
note: 'Provide explicit evidence, such as social media posts, visible scarring, or before/after. Avoid "it\'s obvious".',
|
||||
value: {
|
||||
naturalBoobs: actor.value?.naturalBoobs || null,
|
||||
naturalBoobs: actor.value?.naturalBoobs ?? null,
|
||||
boobsVolume: actor.value?.boobsVolume || null,
|
||||
boobsImplant: actor.value?.boobsImplant || null,
|
||||
boobsPlacement: actor.value?.boobsPlacement || null,
|
||||
boobsIncision: actor.value?.boobsIncision || null,
|
||||
boobsSurgeon: actor.value?.boobsSurgeon || null,
|
||||
naturalButt: actor.value?.naturalButt || null,
|
||||
naturalButt: actor.value?.naturalButt ?? null,
|
||||
buttVolume: actor.value?.buttVolume || null,
|
||||
buttImplant: actor.value?.buttImplant || null,
|
||||
naturalLips: actor.value?.naturalLips || null,
|
||||
naturalLips: actor.value?.naturalLips ?? null,
|
||||
lipsVolume: actor.value?.lipsVolume || null,
|
||||
naturalLabia: actor.value?.naturalLabia || null,
|
||||
naturalLabia: actor.value?.naturalLabia ?? null,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -45,7 +45,13 @@
|
||||
:key="`actor-${actor.id}`"
|
||||
class="actor"
|
||||
>
|
||||
<td class="actor-id ellipsis">{{ actor.id }}</td>
|
||||
<td class="actor-id ellipsis">
|
||||
<a
|
||||
:href="`/actor/${actor.id}/${actor.slug}`"
|
||||
target="_blank"
|
||||
class="nolink"
|
||||
>{{ actor.id }}</a>
|
||||
</td>
|
||||
|
||||
<td
|
||||
v-tooltip="actor.entity?.name || 'Global'"
|
||||
|
||||
@@ -62,10 +62,22 @@ const keyMap = {
|
||||
const socialsOrder = ['onlyfans', 'fansly', 'twitter', 'instagram', 'loyalfans', 'manyvids', 'pornhub', 'linktree', null];
|
||||
|
||||
export function curateActor(actor, context = {}) {
|
||||
if (!actor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
id: actor.id,
|
||||
slug: actor.slug,
|
||||
name: actor.name,
|
||||
aliases: actor.aliases || [], // used for profile pages
|
||||
alias: actor.alias
|
||||
? {
|
||||
id: actor.alias.id,
|
||||
slug: actor.alias.slug,
|
||||
name: actor.alias.name,
|
||||
}
|
||||
: null,
|
||||
gender: actor.gender,
|
||||
age: actor.age,
|
||||
ethnicity: actor.ethnicity,
|
||||
@@ -233,8 +245,10 @@ export async function fetchActorsById(actorIds, options = {}, reqUser) {
|
||||
knex.raw('COALESCE(residence_countries.alias, residence_countries.name) as residence_country_name'),
|
||||
knex.raw('row_to_json(entities) as entity'),
|
||||
knex.raw('row_to_json(sfw_media) as sfw_avatar'),
|
||||
knex.raw('json_agg(aliases) filter (where aliases.id is not null) as aliases'),
|
||||
)
|
||||
.leftJoin('actors_meta', 'actors_meta.actor_id', 'actors.id')
|
||||
.leftJoin('actors as aliases', 'aliases.alias_for', 'actors.id')
|
||||
.leftJoin('countries as birth_countries', 'birth_countries.alpha2', 'actors.birth_country_alpha2')
|
||||
.leftJoin('countries as residence_countries', 'residence_countries.alpha2', 'actors.residence_country_alpha2')
|
||||
.leftJoin('media as avatars', 'avatars.id', 'actors.avatar_media_id')
|
||||
@@ -595,8 +609,11 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) {
|
||||
|
||||
const trx = await knex.transaction();
|
||||
|
||||
let mergedProfiles;
|
||||
let mergedScenes;
|
||||
let mergedProfiles = [];
|
||||
let mergedSceneActors = [];
|
||||
let existingSceneActors = [];
|
||||
let duplicateSourceActors = [];
|
||||
let mergedActorStashes = [];
|
||||
|
||||
try {
|
||||
const [existingProfiles] = await Promise.all([
|
||||
@@ -610,19 +627,42 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) {
|
||||
trx('actors_avatars')
|
||||
.update('actor_id', targetActorId)
|
||||
.whereIn('actor_id', sourceActorIds),
|
||||
trx('stashes_actors')
|
||||
.update('actor_id', targetActorId)
|
||||
.whereIn('actor_id', sourceActorIds)
|
||||
.returning('id'),
|
||||
]);
|
||||
|
||||
// assign source actor profiles to target actor, unless a profile for that entity is already present
|
||||
mergedProfiles = await trx('actors_profiles')
|
||||
.update('actor_id', targetActorId)
|
||||
.whereIn('actor_id', sourceActorIds)
|
||||
.whereNotIn('entity_id', existingProfiles.map((profile) => profile.entity_id))
|
||||
.returning('id');
|
||||
|
||||
mergedScenes = await trx('releases_actors')
|
||||
// find releases that have more than one source actor assigned
|
||||
duplicateSourceActors = await trx('releases_actors')
|
||||
.select('release_id', knex.raw('array_agg(actor_id) as actor_ids'))
|
||||
.whereIn('actor_id', sourceActorIds)
|
||||
.groupBy('release_id')
|
||||
.having(trx.raw('COUNT(DISTINCT actor_id) > 1'));
|
||||
|
||||
if (duplicateSourceActors.length > 0) {
|
||||
// some scenes have multiple source actors assigned, which will cause a conflict after merging; we will need to remove all but one
|
||||
await trx('releases_actors')
|
||||
.whereIn('release_id', duplicateSourceActors.map((sceneActor) => sceneActor.release_id))
|
||||
.whereIn('actor_id', duplicateSourceActors.flatMap((sceneActor) => sceneActor.actor_ids.slice(1)))
|
||||
.delete();
|
||||
}
|
||||
|
||||
// find scenes that already have target actor assigned
|
||||
existingSceneActors = await trx('releases_actors')
|
||||
.where('actor_id', targetActorId);
|
||||
|
||||
// delete release source actors for scenes that already have the target actor assigned
|
||||
await trx('releases_actors')
|
||||
.whereIn('release_id', existingSceneActors.map((sceneActor) => sceneActor.release_id))
|
||||
.whereIn('actor_id', sourceActorIds)
|
||||
.delete();
|
||||
|
||||
// alias release source actors to target actors
|
||||
mergedSceneActors = await trx('releases_actors')
|
||||
.update({
|
||||
actor_id: targetActorId,
|
||||
alias_id: knex.raw('actor_id'),
|
||||
@@ -630,6 +670,40 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) {
|
||||
.whereIn('actor_id', sourceActorIds)
|
||||
.returning('release_id');
|
||||
|
||||
const [targetActorStashes, sourceActorStashes] = await Promise.all([
|
||||
trx('stashes_actors')
|
||||
.where('actor_id', targetActorId),
|
||||
trx('stashes_actors')
|
||||
.whereIn('actor_id', sourceActorIds),
|
||||
]);
|
||||
|
||||
// remove source actors from stashes that already contain target actor
|
||||
await trx('stashes_actors')
|
||||
.whereIn('stash_id', targetActorStashes.map((stash) => stash.stash_id))
|
||||
.whereIn('actor_id', sourceActorIds)
|
||||
.delete();
|
||||
|
||||
// find stashes that have more than one source actor assigned
|
||||
const duplicateStashActors = await trx('stashes_actors')
|
||||
.select('stash_id', knex.raw('array_agg(actor_id order by created_at) as actor_ids'))
|
||||
.whereIn('actor_id', sourceActorStashes.map((actorStash) => actorStash.actor_id))
|
||||
.groupBy('stash_id')
|
||||
.having(trx.raw('COUNT(DISTINCT actor_id) > 1'));
|
||||
|
||||
if (duplicateStashActors.length > 0) {
|
||||
// some stashes have multiple source actors assigned, which will cause a conflict after merging; we will need to remove all but one
|
||||
await trx('stashes_actors')
|
||||
.whereIn('stash_id', duplicateStashActors.map((actorStash) => actorStash.stash_id))
|
||||
.whereIn('actor_id', duplicateStashActors.flatMap((actorStash) => actorStash.actor_ids.slice(1)))
|
||||
.delete();
|
||||
}
|
||||
|
||||
// we update an existing entry instead of creating a new one, so the original stash date is preserved
|
||||
mergedActorStashes = await trx('stashes_actors')
|
||||
.update('actor_id', targetActorId)
|
||||
.whereIn('actor_id', sourceActorIds)
|
||||
.returning('stash_id');
|
||||
|
||||
await trx.commit();
|
||||
} catch (error) {
|
||||
await trx.rollback();
|
||||
@@ -646,14 +720,19 @@ export async function mergeActors(targetActorId, sourceActorIds, reqUser) {
|
||||
}, { refreshView: false });
|
||||
|
||||
await Promise.all([
|
||||
syncScenes(mergedScenes.map((scene) => scene.release_id)),
|
||||
syncScenes([
|
||||
...mergedSceneActors.map((sceneActor) => sceneActor.release_id),
|
||||
...existingSceneActors.map((sceneActor) => sceneActor.release_id),
|
||||
...duplicateSourceActors.map((sceneActor) => sceneActor.release_id),
|
||||
]),
|
||||
syncActors([targetActorId, ...sourceActorIds]),
|
||||
syncStashes('actor', [targetActorId, ...sourceActorIds]),
|
||||
]);
|
||||
|
||||
return {
|
||||
scenes: mergedScenes.length,
|
||||
scenes: mergedSceneActors.length,
|
||||
profiles: mergedProfiles.length,
|
||||
stashes: mergedActorStashes.length,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import initServer from './web/server.js';
|
||||
import { initCaches } from './cache.js';
|
||||
import { initSyncCron } from './sync.js';
|
||||
|
||||
async function init() {
|
||||
await initCaches();
|
||||
|
||||
initServer();
|
||||
initSyncCron();
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
@@ -32,5 +32,6 @@ export function curateMedia(media, context = {}) {
|
||||
type: context.type || null,
|
||||
sfw: curateMedia(media.sfw_media),
|
||||
isRestricted: context.isRestricted,
|
||||
createdAt: media.created_at,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -209,16 +209,19 @@ export async function fetchScenesById(sceneIds, { reqUser, ...context } = {}) {
|
||||
'actors.*',
|
||||
knex.raw('row_to_json(avatars) as avatar'),
|
||||
knex.raw('row_to_json(sfw_media) as sfw_avatar'),
|
||||
knex.raw('row_to_json(aliases) as alias'),
|
||||
knex.raw('case when aliases.id is not null then json_build_object(\'id\', aliases.id, \'name\', aliases.name, \'slug\', aliases.slug) end as alias'),
|
||||
'countries.name as birth_country_name',
|
||||
'countries.alias as birth_country_alias',
|
||||
'releases_actors.release_id',
|
||||
)
|
||||
.leftJoin('actors', 'actors.id', 'releases_actors.actor_id')
|
||||
.leftJoin('actors as aliases', 'aliases.id', 'releases_actors.alias_id')
|
||||
.leftJoin('media as avatars', 'avatars.id', 'actors.avatar_media_id')
|
||||
.leftJoin('media as sfw_media', 'sfw_media.id', 'avatars.sfw_media_id')
|
||||
.leftJoin('countries', 'countries.alpha2', 'actors.birth_country_alpha2')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.groupBy('actors.id', 'releases_actors.release_id', 'avatars.id', 'countries.name', 'countries.alias', 'sfw_media.id'),
|
||||
.groupBy('actors.id', 'aliases.id', 'releases_actors.release_id', 'avatars.id', 'countries.name', 'countries.alias', 'sfw_media.id'),
|
||||
directors: knex('releases_directors')
|
||||
.whereIn('release_id', sceneIds)
|
||||
.leftJoin('actors as directors', 'directors.id', 'releases_directors.director_id'),
|
||||
|
||||
26
src/sync.js
26
src/sync.js
@@ -114,6 +114,7 @@ export async function syncManticoreScenes(sceneIds) {
|
||||
studios.name as studio_name,
|
||||
grandparents.id as parent_network_id,
|
||||
COALESCE(JSON_AGG(DISTINCT (actors.id, actors.name)) FILTER (WHERE actors.id IS NOT NULL), '[]') as actors,
|
||||
COALESCE(JSON_AGG(DISTINCT (actors_aliases.id, actors_aliases.name)) FILTER (WHERE actors_aliases.id IS NOT NULL), '[]') as actors_aliases,
|
||||
COALESCE(JSON_AGG(DISTINCT (tags.id, tags.name, tags.priority, tags_aliases.name)) FILTER (WHERE tags.id IS NOT NULL), '[]') as tags,
|
||||
COALESCE(JSON_AGG(DISTINCT (movies.id, movies.title)) FILTER (WHERE movies.id IS NOT NULL), '[]') as movies,
|
||||
COALESCE(JSON_AGG(DISTINCT (series.id, series.title)) FILTER (WHERE series.id IS NOT NULL), '[]') as series,
|
||||
@@ -135,6 +136,7 @@ export async function syncManticoreScenes(sceneIds) {
|
||||
LEFT JOIN releases_tags AS local_tags ON local_tags.release_id = releases.id
|
||||
LEFT JOIN actors ON local_actors.actor_id = actors.id
|
||||
LEFT JOIN actors AS directors ON local_directors.director_id = directors.id
|
||||
LEFT JOIN actors AS actors_aliases ON actors_aliases.id = local_actors.alias_id
|
||||
LEFT JOIN tags ON local_tags.tag_id = tags.id
|
||||
LEFT JOIN tags as tags_aliases ON local_tags.tag_id = tags_aliases.alias_for AND tags_aliases.secondary = true
|
||||
LEFT JOIN movies_scenes ON movies_scenes.scene_id = releases.id
|
||||
@@ -185,6 +187,8 @@ export async function syncManticoreScenes(sceneIds) {
|
||||
const flatTags = scene.tags.filter((tag) => tag.f3 > 6).flatMap((tag) => [tag.f2].concat(tag.f4)).filter(Boolean); // only make top tags searchable to minimize cluttered results
|
||||
const filteredTitle = filterTitle(scene.title, [...flatActors, ...flatTags]);
|
||||
|
||||
// TODO: reconsider how direct vs indirect tags are stored and searched
|
||||
|
||||
return {
|
||||
replace: {
|
||||
index: 'scenes',
|
||||
@@ -207,8 +211,8 @@ export async function syncManticoreScenes(sceneIds) {
|
||||
studio_slug: scene.studio_slug || undefined,
|
||||
studio_name: scene.studio_name || undefined,
|
||||
entity_ids: [scene.channel_id, scene.network_id, scene.parent_network_id, scene.studio_id].filter(Boolean), // manticore does not support OR, this allows IN
|
||||
actor_ids: scene.actors.map((actor) => actor.f1),
|
||||
actors: scene.actors.map((actor) => actor.f2).join(),
|
||||
actor_ids: scene.actors.map((actor) => actor.f1), // don't include aliases in ID or they would show up in filters
|
||||
actors: Array.from(new Set([...scene.actors.map((actor) => actor.f2), ...scene.actors_aliases.map((actor) => actor.f2)])).join(),
|
||||
tag_ids: scene.tags.map((tag) => tag.f1),
|
||||
tags: flatTags.join(' '), // only make top tags searchable to minimize cluttered results
|
||||
movie_ids: scene.movies.map((movie) => movie.f1),
|
||||
@@ -470,11 +474,13 @@ export async function syncQueue() {
|
||||
logger[process.tasks > 0 ? 'info' : 'verbose'](`Processed ${tasks.length} sync items`);
|
||||
}
|
||||
|
||||
CronJob.from({
|
||||
cronTime: config.sync.crontab,
|
||||
async onTick() {
|
||||
syncQueue();
|
||||
},
|
||||
start: config.sync.enabled,
|
||||
runOnInit: true,
|
||||
});
|
||||
export function initSyncCron() {
|
||||
CronJob.from({
|
||||
cronTime: config.sync.crontab,
|
||||
async onTick() {
|
||||
syncQueue();
|
||||
},
|
||||
start: config.sync.enabled,
|
||||
runOnInit: true,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user