Storing image dimensions and file size to database. Added new site Filthy Femdom to Kink.
|
@ -26,8 +26,11 @@ exports.up = knex => Promise.resolve()
|
||||||
table.string('mime');
|
table.string('mime');
|
||||||
|
|
||||||
table.string('hash');
|
table.string('hash');
|
||||||
table.string('type');
|
|
||||||
table.string('quality', 6);
|
table.integer('size', 12);
|
||||||
|
table.integer('quality', 6);
|
||||||
|
table.integer('width', 6);
|
||||||
|
table.integer('height', 6);
|
||||||
table.float('entropy');
|
table.float('entropy');
|
||||||
|
|
||||||
table.text('comment');
|
table.text('comment');
|
||||||
|
|
Before ![]() (image error) Size: 30 KiB After ![]() (image error) Size: 31 KiB ![]() ![]() |
Before ![]() (image error) Size: 36 KiB After ![]() (image error) Size: 36 KiB ![]() ![]() |
Before ![]() (image error) Size: 26 KiB After ![]() (image error) Size: 26 KiB ![]() ![]() |
Before ![]() (image error) Size: 48 KiB After ![]() (image error) Size: 49 KiB ![]() ![]() |
Before ![]() (image error) Size: 60 KiB After ![]() (image error) Size: 60 KiB ![]() ![]() |
Before ![]() (image error) Size: 46 KiB After ![]() (image error) Size: 47 KiB ![]() ![]() |
Before ![]() (image error) Size: 46 KiB After ![]() (image error) Size: 47 KiB ![]() ![]() |
Before ![]() (image error) Size: 28 KiB After ![]() (image error) Size: 29 KiB ![]() ![]() |
Before ![]() (image error) Size: 25 KiB After ![]() (image error) Size: 26 KiB ![]() ![]() |
Before ![]() (image error) Size: 30 KiB After ![]() (image error) Size: 32 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.5 KiB After ![]() (image error) Size: 1.8 KiB ![]() ![]() |
After ![]() (image error) Size: 21 KiB |
Before ![]() (image error) Size: 7.4 KiB After ![]() (image error) Size: 6.5 KiB ![]() ![]() |
Before ![]() (image error) Size: 6.8 KiB After ![]() (image error) Size: 5.8 KiB ![]() ![]() |
Before ![]() (image error) Size: 18 KiB After ![]() (image error) Size: 19 KiB ![]() ![]() |
Before ![]() (image error) Size: 40 KiB After ![]() (image error) Size: 26 KiB ![]() ![]() |
Before ![]() (image error) Size: 43 KiB After ![]() (image error) Size: 44 KiB ![]() ![]() |
Before ![]() (image error) Size: 9.9 KiB After ![]() (image error) Size: 10 KiB ![]() ![]() |
Before ![]() (image error) Size: 37 KiB After ![]() (image error) Size: 38 KiB ![]() ![]() |
Before ![]() (image error) Size: 13 KiB After ![]() (image error) Size: 14 KiB ![]() ![]() |
Before ![]() (image error) Size: 14 KiB After ![]() (image error) Size: 15 KiB ![]() ![]() |
Before ![]() (image error) Size: 34 KiB After ![]() (image error) Size: 35 KiB ![]() ![]() |
Before ![]() (image error) Size: 36 KiB After ![]() (image error) Size: 37 KiB ![]() ![]() |
Before ![]() (image error) Size: 49 KiB After ![]() (image error) Size: 52 KiB ![]() ![]() |
Before ![]() (image error) Size: 32 KiB After ![]() (image error) Size: 34 KiB ![]() ![]() |
Before ![]() (image error) Size: 8.1 KiB After ![]() (image error) Size: 9.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 50 KiB After ![]() (image error) Size: 51 KiB ![]() ![]() |
Before ![]() (image error) Size: 5.6 KiB After ![]() (image error) Size: 3.6 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.8 KiB After ![]() (image error) Size: 4.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 20 KiB After ![]() (image error) Size: 21 KiB ![]() ![]() |
Before ![]() (image error) Size: 46 KiB After ![]() (image error) Size: 47 KiB ![]() ![]() |
Before ![]() (image error) Size: 36 KiB After ![]() (image error) Size: 20 KiB ![]() ![]() |
Before ![]() (image error) Size: 14 KiB After ![]() (image error) Size: 15 KiB ![]() ![]() |
Before ![]() (image error) Size: 31 KiB After ![]() (image error) Size: 32 KiB ![]() ![]() |
Before ![]() (image error) Size: 17 KiB After ![]() (image error) Size: 18 KiB ![]() ![]() |
Before ![]() (image error) Size: 8.7 KiB After ![]() (image error) Size: 7.6 KiB ![]() ![]() |
Before ![]() (image error) Size: 51 KiB After ![]() (image error) Size: 52 KiB ![]() ![]() |
|
@ -2169,7 +2169,7 @@ const sites = [
|
||||||
slug: 'boundgangbangs',
|
slug: 'boundgangbangs',
|
||||||
name: 'Bound Gangbangs',
|
name: 'Bound Gangbangs',
|
||||||
url: 'https://www.kink.com/channel/boundgangbangs',
|
url: 'https://www.kink.com/channel/boundgangbangs',
|
||||||
description: 'Poweless whores tied in bondage and stuffed with a cock in every hole. At BoundGangbangs women get surprise extreme gangbangs, blindfolds, deepthroat blowjobs, sex punishment, bondage, double penetration and interracial sex.',
|
description: 'Powerless whores tied in bondage and stuffed with a cock in every hole. At BoundGangbangs women get surprise extreme gangbangs, blindfolds, deepthroat blowjobs, sex punishment, bondage, double penetration and interracial sex.',
|
||||||
network: 'kink',
|
network: 'kink',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -2231,6 +2231,14 @@ const sites = [
|
||||||
description: 'Gaping Anal Holes Are Stuffed & Stretched To The Max. Anal Fisting, Enemas & Rimming Has Never Tasted So Good. EverythingButt.com explores the extreme limits of FemDom lesbian anal. Watch asses get destroyed by brutal fistings, huge insertions, double anal & more!',
|
description: 'Gaping Anal Holes Are Stuffed & Stretched To The Max. Anal Fisting, Enemas & Rimming Has Never Tasted So Good. EverythingButt.com explores the extreme limits of FemDom lesbian anal. Watch asses get destroyed by brutal fistings, huge insertions, double anal & more!',
|
||||||
network: 'kink',
|
network: 'kink',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
slug: 'filthyfemdom',
|
||||||
|
name: 'Filthy Femdom',
|
||||||
|
url: 'https://www.kink.com/channel/filthyfemdom',
|
||||||
|
description: 'Powerful women dominate your dirty dreams of sweet pain, seductive bondage, and sexual servitude.',
|
||||||
|
tags: ['femdom'],
|
||||||
|
network: 'kink',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
slug: 'familiestied',
|
slug: 'familiestied',
|
||||||
name: 'Families Tied',
|
name: 'Families Tied',
|
||||||
|
|
41
src/media.js
|
@ -62,11 +62,17 @@ function pickQuality(items) {
|
||||||
return item || items[0];
|
return item || items[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getEntropy(buffer) {
|
async function getMeta(buffer) {
|
||||||
try {
|
try {
|
||||||
const { entropy } = await sharp(buffer).stats();
|
const { entropy } = await sharp(buffer).stats();
|
||||||
|
const { width, height, size } = await sharp(buffer).metadata();
|
||||||
|
|
||||||
return entropy;
|
return {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
size,
|
||||||
|
entropy,
|
||||||
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(`Failed to retrieve image entropy, using 7.5: ${error.message}`);
|
logger.warn(`Failed to retrieve image entropy, using 7.5: ${error.message}`);
|
||||||
|
|
||||||
|
@ -125,7 +131,7 @@ async function fetchItem(source, index, existingItemsBySource, domain, role, att
|
||||||
const mimetype = mime.getType(pathname);
|
const mimetype = mime.getType(pathname);
|
||||||
const extension = mime.getExtension(mimetype);
|
const extension = mime.getExtension(mimetype);
|
||||||
const hash = getHash(res.body);
|
const hash = getHash(res.body);
|
||||||
const entropy = /image/.test(mimetype) ? await getEntropy(res.body) : null;
|
const { entropy, size, width, height } = /image/.test(mimetype) ? await getMeta(res.body) : {};
|
||||||
|
|
||||||
logger.verbose(`Fetched media item from ${source.src || source}`);
|
logger.verbose(`Fetched media item from ${source.src || source}`);
|
||||||
|
|
||||||
|
@ -135,6 +141,9 @@ async function fetchItem(source, index, existingItemsBySource, domain, role, att
|
||||||
extension,
|
extension,
|
||||||
hash,
|
hash,
|
||||||
entropy,
|
entropy,
|
||||||
|
size,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
quality: source.quality || null,
|
quality: source.quality || null,
|
||||||
source: originalSource?.src || originalSource || source.src || source,
|
source: originalSource?.src || originalSource || source.src || source,
|
||||||
scraper: source.scraper,
|
scraper: source.scraper,
|
||||||
|
@ -192,10 +201,13 @@ async function saveItems(items, domain, role) {
|
||||||
mimetype: item.mimetype,
|
mimetype: item.mimetype,
|
||||||
extension: item.extension,
|
extension: item.extension,
|
||||||
hash: item.hash,
|
hash: item.hash,
|
||||||
|
size: item.size,
|
||||||
|
width: item.width,
|
||||||
|
height: item.height,
|
||||||
|
quality: item.quality,
|
||||||
entropy: item.entropy,
|
entropy: item.entropy,
|
||||||
scraper: item.scraper,
|
scraper: item.scraper,
|
||||||
copyright: item.copyright,
|
copyright: item.copyright,
|
||||||
quality: item.quality,
|
|
||||||
source: item.source,
|
source: item.source,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -207,9 +219,12 @@ async function saveItems(items, domain, role) {
|
||||||
mimetype: item.mimetype,
|
mimetype: item.mimetype,
|
||||||
extension: item.extension,
|
extension: item.extension,
|
||||||
hash: item.hash,
|
hash: item.hash,
|
||||||
|
size: item.size,
|
||||||
|
width: item.width,
|
||||||
|
height: item.height,
|
||||||
|
quality: item.quality,
|
||||||
entropy: item.entropy,
|
entropy: item.entropy,
|
||||||
scraper: item.scraper,
|
scraper: item.scraper,
|
||||||
quality: item.quality,
|
|
||||||
copyright: item.copyright,
|
copyright: item.copyright,
|
||||||
source: item.source,
|
source: item.source,
|
||||||
};
|
};
|
||||||
|
@ -226,6 +241,10 @@ function curateItemEntries(items) {
|
||||||
thumbnail: item.thumbpath,
|
thumbnail: item.thumbpath,
|
||||||
mime: item.mimetype,
|
mime: item.mimetype,
|
||||||
hash: item.hash,
|
hash: item.hash,
|
||||||
|
size: item.size,
|
||||||
|
width: item.width,
|
||||||
|
height: item.height,
|
||||||
|
quality: item.quality,
|
||||||
entropy: item.entropy,
|
entropy: item.entropy,
|
||||||
source: item.source,
|
source: item.source,
|
||||||
scraper: item.scraper,
|
scraper: item.scraper,
|
||||||
|
@ -317,17 +336,21 @@ function associateTargetMedia(targetId, sources, mediaBySource, domain, role, pr
|
||||||
if (!sources) return { [role]: null, [primaryRole]: null };
|
if (!sources) return { [role]: null, [primaryRole]: null };
|
||||||
|
|
||||||
const mediaIds = sources
|
const mediaIds = sources
|
||||||
.filter(Boolean)
|
|
||||||
.map((source) => {
|
.map((source) => {
|
||||||
|
if (!source) return null;
|
||||||
|
|
||||||
const mediaItem = Array.isArray(source)
|
const mediaItem = Array.isArray(source)
|
||||||
? source.reduce((acc, sourceX) => acc || mediaBySource[sourceX.src || sourceX], null)
|
? source.reduce((acc, sourceX) => acc || mediaBySource[sourceX.src || sourceX], null)
|
||||||
: mediaBySource[source.src || source];
|
: mediaBySource[source.src || source];
|
||||||
|
|
||||||
// return mediaItem && { [`${domain}_id`]: targetId, media_id: mediaItem.id };
|
// return mediaItem && { [`${domain}_id`]: targetId, media_id: mediaItem.id };
|
||||||
return mediaItem && mediaItem.id;
|
return mediaItem;
|
||||||
});
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
// .sort((mediaItemA, mediaItemB) => mediaItemB.height - mediaItemA.height) // prefer high res images for primary item
|
||||||
|
.map(mediaItem => mediaItem.id);
|
||||||
|
|
||||||
const uniqueMediaIds = Array.from(new Set(mediaIds.filter(Boolean)));
|
const uniqueMediaIds = Array.from(new Set(mediaIds));
|
||||||
const associations = uniqueMediaIds.map(mediaId => ({ [`${domain}_id`]: targetId, media_id: mediaId }));
|
const associations = uniqueMediaIds.map(mediaId => ({ [`${domain}_id`]: targetId, media_id: mediaId }));
|
||||||
|
|
||||||
logger.silly(`Associating ${associations.length} ${role}s to ${domain} ${targetId}`);
|
logger.silly(`Associating ${associations.length} ${role}s to ${domain} ${targetId}`);
|
||||||
|
|