diff --git a/assets/components/header/filter-bar.vue b/assets/components/header/filter-bar.vue
index 5f73c972..20709932 100644
--- a/assets/components/header/filter-bar.vue
+++ b/assets/components/header/filter-bar.vue
@@ -3,47 +3,80 @@
Upcoming
All
+
+
+
+ All
+
+
+
+
+ New
+
+
+
@@ -82,6 +115,10 @@ function range(state) {
return state.ui.range;
}
+function batch(state) {
+ return state.ui.batch;
+}
+
async function setFilter(newFilter) {
this.$store.dispatch('setFilter', newFilter);
@@ -94,6 +131,12 @@ async function setRange(newRange) {
await this.fetchReleases();
}
+async function setBatch(newBatch) {
+ this.$store.dispatch('setBatch', newBatch);
+
+ await this.fetchReleases();
+}
+
export default {
components: {
Filters,
@@ -108,11 +151,13 @@ export default {
...mapState({
filter,
range,
+ batch,
}),
},
methods: {
setFilter,
setRange,
+ setBatch,
},
};
diff --git a/assets/components/tile/release.vue b/assets/components/tile/release.vue
index 97a6a630..bf716026 100644
--- a/assets/components/tile/release.vue
+++ b/assets/components/tile/release.vue
@@ -44,7 +44,7 @@
v-tooltip.bottom="release.url && `View scene on ${release.site.name}`"
:title="release.url && `View scene on ${release.site.name}`"
:href="release.url"
- :class="{ upcoming: isAfter(release.date, new Date()) }"
+ :class="{ upcoming: isAfter(release.date, new Date()), new: release.isNew }"
target="_blank"
rel="noopener noreferrer"
class="date"
@@ -53,7 +53,7 @@
({
+ latest: () => ({
after: '1900-01-01',
before: dayjs(new Date()).add(1, 'day').format('YYYY-MM-DD'),
}),
@@ -27,8 +27,13 @@ function after(state) {
return dateRanges[state.range]().after;
}
+function isNew(state) {
+ return state.batch === 'new' ? [true] : [true, false];
+}
+
export default {
rangeDates,
before,
after,
+ isNew,
};
diff --git a/assets/js/ui/mutations.js b/assets/js/ui/mutations.js
index 56fb11b5..85b7ce6a 100644
--- a/assets/js/ui/mutations.js
+++ b/assets/js/ui/mutations.js
@@ -6,7 +6,12 @@ function setRange(state, range) {
state.range = range;
}
+function setBatch(state, batch) {
+ state.batch = batch;
+}
+
export default {
setFilter,
setRange,
+ setBatch,
};
diff --git a/assets/js/ui/state.js b/assets/js/ui/state.js
index 318904b2..88922f43 100644
--- a/assets/js/ui/state.js
+++ b/assets/js/ui/state.js
@@ -1,7 +1,9 @@
const storedFilter = localStorage.getItem('filter');
const storedRange = localStorage.getItem('range');
+const storedBatch = localStorage.getItem('batch');
export default {
filter: storedFilter ? storedFilter.split(',') : ['gay', 'transsexual'],
- range: storedRange || 'new',
+ range: storedRange || 'latest',
+ batch: storedBatch || 'all',
};
diff --git a/migrations/20190325001339_releases.js b/migrations/20190325001339_releases.js
index 4e9cd188..14348a50 100644
--- a/migrations/20190325001339_releases.js
+++ b/migrations/20190325001339_releases.js
@@ -327,6 +327,13 @@ exports.up = knex => Promise.resolve()
table.datetime('created_at')
.defaultTo(knex.fn.now());
}))
+ .then(() => knex.schema.createTable('batches', (table) => {
+ table.increments('id', 12);
+ table.text('comment');
+
+ table.datetime('created_at')
+ .defaultTo(knex.fn.now());
+ }))
.then(() => knex.schema.createTable('releases', (table) => {
table.increments('id', 16);
@@ -362,7 +369,14 @@ exports.up = knex => Promise.resolve()
table.boolean('deep');
table.string('deep_url', 1000);
- table.string('batch');
+ table.integer('created_batch_id', 12)
+ .references('id')
+ .inTable('batches');
+
+ table.integer('updated_batch_id', 12)
+ .references('id')
+ .inTable('batches');
+
table.datetime('created_at')
.defaultTo(knex.fn.now());
}))
@@ -508,6 +522,10 @@ exports.up = knex => Promise.resolve()
url ILIKE ('%' || search || '%')
$$ LANGUAGE SQL STABLE;
+ CREATE FUNCTION releases_is_new(release releases) RETURNS boolean AS $$
+ SELECT NOT EXISTS(SELECT true FROM batches WHERE batches.id = release.created_batch_id + 1 LIMIT 1);
+ $$ LANGUAGE sql STABLE;
+
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';
`));
@@ -527,6 +545,7 @@ exports.down = knex => knex.raw(`
DROP TABLE IF EXISTS releases_teasers CASCADE;
DROP TABLE IF EXISTS releases_tags CASCADE;
DROP TABLE IF EXISTS releases_search CASCADE;
+ DROP TABLE IF EXISTS batches CASCADE;
DROP TABLE IF EXISTS actors_avatars CASCADE;
DROP TABLE IF EXISTS actors_photos CASCADE;
DROP TABLE IF EXISTS actors_social CASCADE;
diff --git a/src/media.js b/src/media.js
index c321139a..e510a623 100644
--- a/src/media.js
+++ b/src/media.js
@@ -271,7 +271,7 @@ function groupItems(items) {
}
async function storeMedia(sources, domain, role, { entropyFilter = 2.5 } = {}) {
- const presentSources = sources.filter(Boolean);
+ const presentSources = sources.filter(source => typeof source === 'string' || Array.isArray(source) || (source && source.src));
if (presentSources.length === 0) {
return {};
diff --git a/src/releases.js b/src/releases.js
index 93f72a34..a2ab4d63 100644
--- a/src/releases.js
+++ b/src/releases.js
@@ -202,7 +202,7 @@ async function attachStudio(release) {
};
}
-async function curateReleaseEntry(release) {
+async function curateReleaseEntry(release, batchId, existingRelease) {
const slug = slugify(release.title, {
encode: true,
limit: config.titleSlugLength,
@@ -227,6 +227,8 @@ async function curateReleaseEntry(release) {
// rating: release.rating && release.rating.stars && Math.floor(release.rating.stars),
deep: typeof release.deep === 'boolean' ? release.deep : false,
deep_url: release.deepUrl,
+ updated_batch_id: batchId,
+ ...(!existingRelease && { created_batch_id: batchId }),
};
return curatedRelease;
@@ -380,6 +382,7 @@ async function updateReleasesSearch(releaseIds) {
sites.slug || ' ' ||
networks.name || ' ' ||
networks.slug || ' ' ||
+ releases.shoot_id || ' ' ||
EXTRACT(YEAR FROM releases.date) || ' ' ||
CAST(EXTRACT(MONTH FROM releases.date) AS VARCHAR) || ' ' ||
CAST(EXTRACT(DAY FROM releases.date) AS VARCHAR) || ' ' ||
@@ -408,7 +411,7 @@ async function updateReleasesSearch(releaseIds) {
}
}
-async function storeRelease(release) {
+async function storeRelease(release, batchId) {
const existingRelease = await knex('releases')
.where({
entry_id: release.entryId,
@@ -416,7 +419,7 @@ async function storeRelease(release) {
})
.first();
- const curatedRelease = await curateReleaseEntry(release);
+ const curatedRelease = await curateReleaseEntry(release, batchId, existingRelease);
if (existingRelease && !argv.redownload) {
return existingRelease;
@@ -453,11 +456,13 @@ async function storeRelease(release) {
}
async function storeReleases(releases) {
+ const [batchId] = await knex('batches').insert({ comment: null }).returning('id');
+
const storedReleases = await Promise.map(releases, async (release) => {
try {
const releaseWithChannelSite = await attachChannelSite(release);
const releaseWithStudio = await attachStudio(releaseWithChannelSite);
- const { id, slug } = await storeRelease(releaseWithStudio);
+ const { id, slug } = await storeRelease(releaseWithStudio, batchId);
return {
id,
diff --git a/src/scrapers/private.js b/src/scrapers/private.js
index ba5dcb26..502aad72 100644
--- a/src/scrapers/private.js
+++ b/src/scrapers/private.js
@@ -84,12 +84,12 @@ async function scrapeScene(html, url, site) {
release.likes = Number($('.content-desc #social-actions #likes').text());
const posterScript = $('script:contains(poster)').html();
- const posterLink = posterScript.slice(posterScript.indexOf('https://'), posterScript.indexOf('.jpg') + 4);
- release.poster = $('meta[property="og:image"]').attr('content') || posterLink;
+ const posterLink = posterScript?.slice(posterScript.indexOf('https://'), posterScript.indexOf('.jpg') + 4);
+ release.poster = $('meta[property="og:image"]').attr('content') || posterLink || $('#trailer_player_finished img').attr('src');
- release.trailer = {
- src: $('meta[property="og:video"]').attr('content') || $('#videojs-trailer source').attr('src'),
- };
+ const trailer = $('meta[property="og:video"]').attr('content') || $('#videojs-trailer source').attr('src');
+
+ if (trailer) release.trailer = { src: trailer };
release.photos = await getPhotos(release.entryId, site);
release.movie = $('a[data-track="FULL MOVIE"]').attr('href');
diff --git a/src/web/plugins/releases.js b/src/web/plugins/releases.js
index 109f2d95..ec0bf68a 100644
--- a/src/web/plugins/releases.js
+++ b/src/web/plugins/releases.js
@@ -4,8 +4,14 @@ const { makeExtendSchemaPlugin, gql } = require('graphile-utils');
const schemaExtender = makeExtendSchemaPlugin(_build => ({
typeDefs: gql`
+ extend type Release {}
`,
resolvers: {
+ Release: {
+ async foo(_parent, _args, _context, _info) {
+ // template
+ },
+ },
},
}));