2021-03-09 20:28:52 +01:00
|
|
|
const { getFiles } = require('./../file-utils');
|
2021-03-05 14:08:10 +01:00
|
|
|
const fs = require('fs').promises;
|
2021-07-01 13:49:30 +02:00
|
|
|
const got = require("got");
|
2021-03-05 14:08:10 +01:00
|
|
|
const {promisify} = require('util');
|
|
|
|
const frontMatterParser = require('parser-front-matter');
|
|
|
|
|
|
|
|
const parse = promisify(frontMatterParser.parse.bind(frontMatterParser));
|
2022-07-26 12:02:19 +02:00
|
|
|
const exec = promisify(require('child_process').exec);
|
2021-03-05 14:08:10 +01:00
|
|
|
|
2021-07-01 13:49:30 +02:00
|
|
|
const stream = require('stream');
|
|
|
|
const pipeline = promisify(stream.pipeline);
|
|
|
|
const { createWriteStream } = require("fs");
|
2021-03-05 14:08:10 +01:00
|
|
|
|
|
|
|
async function loadPostsWithFrontMatter(postsDirectoryPath) {
|
|
|
|
const postNames = await getFiles(postsDirectoryPath);
|
|
|
|
const posts = await Promise.all(
|
|
|
|
// could be .DS_Store stuff found using recursive function above...
|
|
|
|
postNames.filter(name => name.endsWith('.md')).map(async fileName => {
|
|
|
|
const fileContent = await fs.readFile(fileName, 'utf8');
|
|
|
|
const {content, data} = await parse(fileContent);
|
|
|
|
return {
|
|
|
|
game: data.game_name,
|
|
|
|
howlongtobeat_id: data.howlongtobeat_id,
|
|
|
|
file: fileName
|
|
|
|
}
|
|
|
|
})
|
|
|
|
);
|
|
|
|
return posts;
|
|
|
|
}
|
|
|
|
|
2021-07-01 13:49:30 +02:00
|
|
|
async function downloadThumbnail(url, id, dir) {
|
2022-09-15 09:37:24 +02:00
|
|
|
if(url.indexOf('howlongtobeat.com') == -1) {
|
|
|
|
url = `https://howlongtobeat.com/games/${url}`
|
2021-07-01 14:22:33 +02:00
|
|
|
}
|
2021-07-01 13:49:30 +02:00
|
|
|
console.log(` --- downloading thumbnail ${url} of id ${id}...`)
|
|
|
|
await pipeline(
|
|
|
|
got.stream(url),
|
|
|
|
createWriteStream(`${dir}/${id}.jpg`)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-09-15 09:37:24 +02:00
|
|
|
// I'm doing this myself, getting tired of HLTB's API breakages.
|
|
|
|
// See https://github.com/ckatzorke/howlongtobeat/issues/40
|
|
|
|
async function howLongToBeatSearch(game) {
|
|
|
|
const params = {
|
|
|
|
"searchType": "games",
|
|
|
|
"searchTerms": game.split(" "),
|
|
|
|
"searchPage": 1,
|
|
|
|
"size": 20,
|
|
|
|
"searchOptions": {
|
|
|
|
"games": {
|
|
|
|
"userId": 0,
|
|
|
|
"platform": "",
|
|
|
|
"sortCategory": "popular",
|
|
|
|
"rangeCategory": "main",
|
|
|
|
"rangeTime": {
|
|
|
|
"min": 0,
|
|
|
|
"max": 0
|
|
|
|
},
|
|
|
|
"gameplay": {
|
|
|
|
"perspective": "",
|
|
|
|
"flow": "",
|
|
|
|
"genre": ""
|
|
|
|
},
|
|
|
|
"modifier": ""
|
|
|
|
},
|
|
|
|
"users": {
|
|
|
|
"sortCategory": "postcount"
|
|
|
|
},
|
|
|
|
"filter": "",
|
|
|
|
"sort": 0,
|
|
|
|
"randomizer": 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const results = await got.post("https://www.howlongtobeat.com/api/search", {
|
|
|
|
json: params,
|
|
|
|
headers: {
|
|
|
|
'Content-Type': "application/json",
|
|
|
|
'Referer': 'https://howlongtobeat.com/',
|
|
|
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:90.0) Gecko/20100101 Firefox/90.0"
|
|
|
|
}
|
|
|
|
}).json()
|
|
|
|
console.log(results)
|
|
|
|
return results.data.map(item => {
|
|
|
|
return {
|
|
|
|
'id': item.game_id,
|
|
|
|
'name': item.game_name,
|
|
|
|
'imageUrl': item.game_image,
|
|
|
|
'howlong': (item.comp_main / 60 / 60).toFixed(1)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-01 13:49:30 +02:00
|
|
|
async function fillInHowLongToBeat(posts, downloadDir) {
|
2021-03-05 14:08:10 +01:00
|
|
|
for(post of posts) {
|
2022-09-15 09:37:24 +02:00
|
|
|
const results = await howLongToBeatSearch(post.game)
|
2021-03-05 14:08:10 +01:00
|
|
|
|
|
|
|
if(results.length > 0) {
|
2021-07-01 13:49:30 +02:00
|
|
|
const game = results[0]
|
2022-09-15 09:37:24 +02:00
|
|
|
post.howlongtobeat = game.howlong
|
2021-07-01 13:49:30 +02:00
|
|
|
post.howlongtobeat_id = game.id
|
|
|
|
|
|
|
|
if(downloadDir) {
|
|
|
|
await downloadThumbnail(game.imageUrl, game.id, downloadDir)
|
2022-07-26 12:02:19 +02:00
|
|
|
const { stdout, stderr } = await exec(`mogrify -sampling-factor 4:2:0 -strip -quality 85 -interlace JPEG -format jpg -colorspace sRGB ${downloadDir}/${game.id}.jpg`)
|
|
|
|
if(stderr) {
|
|
|
|
console.log(`-- WARN: unable to mogrify downloaded JPG: ${stderr}`)
|
|
|
|
}
|
2021-07-01 13:49:30 +02:00
|
|
|
}
|
|
|
|
}
|
2021-03-05 14:08:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-01 13:49:30 +02:00
|
|
|
async function run(options) {
|
|
|
|
const { postDir, downloadDir } = options
|
|
|
|
|
2021-07-01 14:22:33 +02:00
|
|
|
console.log(`-- SCANNING posts in ${postDir} for "game_name" key... --`)
|
2021-07-01 13:49:30 +02:00
|
|
|
let posts = await loadPostsWithFrontMatter(postDir)
|
2021-07-01 14:22:33 +02:00
|
|
|
console.log(` >> Found ${posts.length}`)
|
2021-03-05 14:08:10 +01:00
|
|
|
posts = posts.filter(post => post.game && !post.howlongtobeat_id)
|
2021-07-01 14:22:33 +02:00
|
|
|
console.log(` >> ToProcess: ${posts.length}`)
|
2021-07-01 13:49:30 +02:00
|
|
|
await fillInHowLongToBeat(posts, downloadDir)
|
2021-03-05 14:08:10 +01:00
|
|
|
|
|
|
|
for(post of posts) {
|
|
|
|
let data = await fs.readFile(post.file, 'utf8')
|
2021-07-01 14:22:33 +02:00
|
|
|
|
|
|
|
// just in case it's there, do not duplicate keys!
|
|
|
|
data = data.replace(/howlongtobeat_id:(.*)\n/, '')
|
|
|
|
data = data.replace(/nhowlongtobeat_hrs:(.*)\n/, '')
|
|
|
|
|
2021-03-05 14:08:10 +01:00
|
|
|
data = data.replace(/game_name:/, `howlongtobeat_id: ${post.howlongtobeat_id}\nhowlongtobeat_hrs: ${post.howlongtobeat}\ngame_name:`)
|
|
|
|
console.log(`\tFound game ${post.game}, how long filling in: ${post.howlongtobeat} (id #${post.howlongtobeat_id})`)
|
|
|
|
await fs.writeFile(post.file, data, 'utf8')
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log("-- DONE modifying files --")
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
howlong: run
|
|
|
|
}
|