diff --git a/migrations/20260520044355_actors_unique.js b/migrations/20260520044355_actors_unique.js index c00ee10d..aa488603 100644 --- a/migrations/20260520044355_actors_unique.js +++ b/migrations/20260520044355_actors_unique.js @@ -8,6 +8,19 @@ exports.up = async function(knex) { table.boolean('allow_global_match'); table.text('comment'); }); + + await knex('users_roles') + .update('abilities', JSON.stringify([ + { subject: 'scene', action: 'create' }, + { subject: 'scene', action: 'update' }, + { subject: 'scene', action: 'delete' }, + { subject: 'actor', action: 'create' }, + { subject: 'actor', action: 'update' }, + { subject: 'actor', action: 'delete' }, + { subject: 'actor', action: 'merge' }, + { plainUrls: true }, + ])) + .where('role', 'admin'); }; exports.down = async function(knex) { @@ -31,4 +44,16 @@ exports.down = async function(knex) { table.dropColumn('allow_global_match'); table.dropColumn('comment'); }); + + await knex('users_roles') + .update('abilities', JSON.stringify([ + { subject: 'scene', action: 'create' }, + { subject: 'scene', action: 'update' }, + { subject: 'scene', action: 'delete' }, + { subject: 'actor', action: 'create' }, + { subject: 'actor', action: 'update' }, + { subject: 'actor', action: 'delete' }, + { plainUrls: true }, + ])) + .where('role', 'admin'); }; diff --git a/src/scrapers/julesjordan.js b/src/scrapers/julesjordan.js index ba0d8bfb..70b37ce5 100755 --- a/src/scrapers/julesjordan.js +++ b/src/scrapers/julesjordan.js @@ -256,13 +256,15 @@ async function scrapeScene({ html, query }, context) { }))); } - if (query.exists('.player-scene-description a[href*="/dvd"]')) { + const movieQuery = '//div[@class="meta-item"][div[@class="lbl" and text()="Movie"]]/div[@class="val"]/a'; + + if (query.exists(movieQuery)) { release.movie = { - url: query.url('.player-scene-description a[href*="/dvd"]'), - title: query.content('.player-scene-description a[href*="/dvd"]'), + url: query.url(movieQuery), + title: query.content(movieQuery), }; - release.movie.entryId = new URL(release.movie.url).pathname.split('/').slice(-1)[0]?.replace('.html', '').toLowerCase(); + release.movie.entryId = new URL(release.movie.url).pathname.match(/\/dvds\/(.*?).html/)?.[1]; } release.stars = query.number('.avg_rating'); @@ -275,32 +277,35 @@ async function scrapeScene({ html, query }, context) { function scrapeMovie({ query }, { url }) { const movie = {}; - movie.entryId = new URL(url).pathname.split('/').slice(-1)[0]?.replace('.html', '').toLowerCase(); - movie.title = query.attribute('meta[property="og:title"]', 'content'); + movie.entryId = new URL(url).pathname.match(/\/dvds\/(.*?).html/)?.[1]; + movie.title = query.attribute('meta[property="og:title"]', 'content')?.replace(/\s*-\s*jules jordan/i, ''); movie.covers = [query.img('img.dvd_box')]; // -2x etc is likely upscaled - const sceneTitles = query.contents('.title-heading-content-black-dvd'); + const descriptionDate = query.content('meta[name="description"]', { attribute: 'content' })?.match(/released (\w+ \d{4})/i)?.[1]; - const scenes = query.all('.grid-container-scene').map((sceneEl, index) => { + if (descriptionDate) { + movie.date = unprint.extractDate(descriptionDate, 'MMMM YYYY', { match: null }); + movie.datePrecision = 'month'; + } + + const scenes = query.all('.dvd-scene').map((sceneEl) => { const scene = {}; - scene.url = unprint.query.url(sceneEl, 'a[href*="/scenes"]'); - scene.title = sceneTitles[index]; - - scene.date = unprint.query.date(sceneEl, '//span[contains(@class, "dvd-scene-description") and span[contains(text(), "Date")]]', 'MM/DD/YYYY'); - scene.actors = unprint.query.contents(sceneEl, '.update_models a'); - + scene.url = unprint.query.url(sceneEl, '.dvd-watch-btn'); scene.entryId = getEntryId(scene.url); + scene.title = unprint.query.content(sceneEl, '.dvd-hero-title'); + scene.date = unprint.query.date(sceneEl, '.dvd-hero-date', 'MM/DD/YYYY'); + scene.actors = unprint.query.contents(sceneEl, '.dvd-hero .update_models a'); + + scene.photos = unprint.query.imgs(sceneEl, '.dvd-img-strip img'); + return scene; }); movie.scenes = scenes?.sort((sceneA, sceneB) => sceneA.date - sceneB.date); - movie.date = movie.scenes?.[0]?.date; - movie.datePrecision = 'month'; - return movie; } diff --git a/src/store-releases.js b/src/store-releases.js index a2141a2d..3cca2084 100755 --- a/src/store-releases.js +++ b/src/store-releases.js @@ -344,6 +344,8 @@ async function associateMovieScenes(movies, movieScenes) { .filter(Boolean); await bulkInsert('movies_scenes', associations, false); + + await updateSceneSearch(movieScenes.map((scene) => scene.id)); } async function associateSerieScenes(series, serieScenes) { diff --git a/src/tools/manticore-actors.js b/src/tools/manticore-actors.js index 2ab9a10d..13bfb2df 100644 --- a/src/tools/manticore-actors.js +++ b/src/tools/manticore-actors.js @@ -38,6 +38,7 @@ async function init() { id int, name text, slug string, + entity_id int, gender string, date_of_birth timestamp, country string, @@ -59,6 +60,7 @@ async function init() { index: 'actors', id: actor.id, doc: { + entity_id: actor.entity_id, name: actor.name, slug: actor.slug, gender: actor.gender || undefined,