diff --git a/src/tools/gamma_banners.js b/src/tools/gamma_banners.js new file mode 100644 index 00000000..b8aa212f --- /dev/null +++ b/src/tools/gamma_banners.js @@ -0,0 +1,119 @@ +'use strict'; + +const unprint = require('unprint'); +const fs = require('fs'); +const { Readable } = require('stream'); +const { pipeline } = require('stream/promises'); + +const knex = require('../knex'); +const argv = require('../argv'); +const slugify = require('../utils/slugify'); + +const apiUrl = 'https://vjoc5ygk89-dsn.algolia.net/1/indexes/*/queries?x-algolia-agent=Algolia%20for%20JavaScript%20(3.33.0)%3B%20Browser%20(lite)%3B%20react%20(16.8.6)%3B%20react-instantsearch%20(5.7.0)%3B%20JS%20Helper%20(2.28.1)&x-algolia-application-id=VJOC5YGK89&x-algolia-api-key=c5546bdfb4d3f31daf49ed3bb1463561'; + +async function fetchBanners() { + const res = await unprint.post( + apiUrl, + { + requests: [ + { + indexName: 'creatives', + params: new URLSearchParams({ + hitsPerPage: 1000, + maxValuesPerFacet: 100, + page: 0, + filters: '(ProgramType:Legacy OR ProgramType:Internal) AND NOT OverlayActive:false', + facets: '["SceneActors","SceneCategories","ProgramName","Size","Niche","MediaExt","SiteTag","OverlayName"]', + facetFilters: `[["SiteTag:${argv.site}"],["MediaExt:jpg", "MediaExt:png", "MediaExt:gif"],["ProgramName:${argv.program || 'Fame'}"]]`, + }).toString(), + }, + ], + }, + { + headers: { + 'content-type': 'application/x-www-form-urlencoded', + referer: 'https://creatives.gammae.com/', + }, + }, + ); + + if (res.ok && res.data.results[0]) { + return res.data.results[0].hits; + } + + console.error(`Failed API request (${res.status}): ${res.body}`); + + return null; +} + +async function matchTags(rawTags) { + if (!rawTags) { + return []; + } + + const tags = rawTags + .map((tag) => tag?.trim().match(/[a-z0-9()]+/ig)?.join(' ').toLowerCase()) + .filter(Boolean); + + const tagEntries = await knex('tags') + .select('tags.slug', 'aliases.slug as alias_slug') + .whereIn(knex.raw('lower(tags.name)'), tags) + .leftJoin('tags as aliases', 'aliases.id', 'tags.alias_for') + .orderByRaw('CASE WHEN tags.alias_for IS NOT NULL THEN aliases.priority ELSE tags.priority END DESC'); + + return tagEntries.map((tagEntry) => tagEntry.alias_slug || tagEntry.slug); +} + +async function init() { + const banners = await fetchBanners(); + + if (!banners) { + return; + } + + await banners.reduce(async (chain, banner) => { + await chain; + + const channel = slugify(banner.SiteTag, ''); + const url = `https://cdn.banhq.com${banner.MediaLocation}`; + + const tags = await matchTags([ + ...banner.Tags?.map((tag) => tag.Value) || [], + ...banner.SceneCategories || [], + banner.Niche, + ].filter(Boolean)); + + const fileTags = tags.slice(0, 4).join('_'); + const fileActors = banner.SceneActors?.slice(0, 2).map((actor) => slugify(actor, '_')).join('_'); + + const filename = `${channel}_${banner.Width}_${banner.Height}_${fileActors || banner.MediaID}${fileTags ? `-${fileTags}` : ''}.${banner.MediaExt}`; + const filepath = `/tmp/gamma/${channel}/${filename}`; + + if (argv.inspect) { + console.log(banner); + } + + if (argv.preview) { + console.log(`Preview ${url}: ${filepath}`); + return; + } + + await fs.promises.mkdir(`/tmp/gamma/${channel}`, { recursive: true }); + + const res = await fetch(url); + + if (res.ok && res.body) { + const writer = fs.createWriteStream(filepath); + + await pipeline(Readable.fromWeb(res.body), writer); + + console.log(`Saved ${url} to ${filepath}`); + } else { + console.log(`Failed to fetch ${url}`); + } + }, Promise.resolve()); + + await knex.destroy(); +} + +init();