mobygames API implementation
parent
71572a67c5
commit
d3d50847ff
|
@ -1,7 +1,9 @@
|
|||
|
||||
*.sublime-workspace
|
||||
|
||||
data/ac/*.png
|
||||
data/**/*.png
|
||||
data/**/*.jpg
|
||||
data/**/*.gif
|
||||
|
||||
src/config.js
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -10,7 +10,7 @@
|
|||
"main": "src/chat.js",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"jam": "node src/chat.js"
|
||||
"toot": "node src/chat.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest": "^26.6.3"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
const { collect } = require('./collector')
|
||||
const md5 = require('md5')
|
||||
|
||||
async function chat() {
|
||||
async function chat(buddyConfig) {
|
||||
/* format:
|
||||
{
|
||||
"href": "/wiki/Admiral",
|
||||
|
@ -22,7 +22,7 @@ async function chat() {
|
|||
.replace(/\n/g, "")
|
||||
return {
|
||||
"toot": `${record.name}: "${quote}"\n\n${birthday} is my birthday.\nhttps://animalcrossing.fandom.com${record.href}`,
|
||||
"attach": `data/ac/${md5(record.img)}.png`,
|
||||
"attach": [ `data/ac/${md5(record.img)}.png` ],
|
||||
"attachDescription": `Screenshot of Animal Crossing villager ${record.name}`
|
||||
}
|
||||
})
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
const { collect, collectScreenshotsFor } = require('./collector')
|
||||
|
||||
async function chat(buddyConfig) {
|
||||
const possibleGames = (await collect(buddyConfig)).games
|
||||
|
||||
const game = possibleGames[Math.floor(Math.random() * possibleGames.length)]
|
||||
|
||||
const screenshots = await collectScreenshotsFor(game, buddyConfig)
|
||||
|
||||
const release = game.platforms.find(pl => pl["platform_id"] === buddyConfig.platform)["first_release_date"]
|
||||
return {
|
||||
"toot": `${game.title} (${release})\n\n${game["moby_url"]}`,
|
||||
"attach": screenshots,
|
||||
"attachDescription": `Screenshots of Game Boy game ${game.title}`
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
chat
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
const axios = require('axios')
|
||||
const fsp = require('fs').promises
|
||||
const { existsSync, createWriteStream } = require('fs')
|
||||
|
||||
const endpoint = "https://api.mobygames.com/v1"
|
||||
|
||||
const delay = ms => new Promise(resolve => setTimeout(resolve, ms))
|
||||
|
||||
// TODO move AC code to axios, move this to utilities.js
|
||||
async function download(url, filename) {
|
||||
console.log(` -- mobygames: downloading file ${url}...`)
|
||||
const result = await axios({
|
||||
url,
|
||||
method: 'GET',
|
||||
responseType: 'stream'
|
||||
})
|
||||
await result.data.pipe(createWriteStream(filename))
|
||||
}
|
||||
|
||||
/**
|
||||
game example from cache:
|
||||
{
|
||||
"game_id": 138,
|
||||
"moby_url": "http://www.mobygames.com/game/pac-man",
|
||||
"title": "Pac-Man"
|
||||
}
|
||||
*/
|
||||
async function collectScreenshotsFor(game, buddyConfig) {
|
||||
const { platform, mobyGamesToken } = buddyConfig
|
||||
|
||||
const id = game['game_id']
|
||||
const ext = url => url.split(".").pop()
|
||||
|
||||
const screenshots = (await axios.get(`${endpoint}/games/${id}/platforms/${platform}/screenshots?api_key=${mobyGamesToken}`)).data.screenshots
|
||||
|
||||
const titleshots = screenshots.filter(s => s.caption?.toLowerCase()?.indexOf("title screen") >= 0)
|
||||
const titleshot = titleshots.length == 0 ? screenshots[0].image : titleshots[0].image
|
||||
const titleshotfile = `data/mobygames/title_${id}_1.${ext(titleshot)}`
|
||||
|
||||
// not sure if this is ok, we now take the SECOND LAST screenshot that doesn't contain 'title screen'
|
||||
// however, the screenshot could be a dull one, but taking something random isn't great either
|
||||
const gameshots = screenshots.filter(s => s.caption?.toLowerCase()?.indexOf("title screen") == -1)
|
||||
const gameshot = gameshots[gameshots.length < 2 ? 0 : gameshots.length - 2].image
|
||||
const gameshotfile = `data/mobygames/title_${id}_2.${ext(gameshot)}`
|
||||
|
||||
await download(titleshot, titleshotfile)
|
||||
await download(gameshot, gameshotfile)
|
||||
|
||||
return [ titleshotfile, gameshotfile ]
|
||||
}
|
||||
|
||||
// for the gameboy: 10, 688 - see https://www.mobygames.com/browse/games/gameboy/list-games/
|
||||
async function collect(buddyConfig) {
|
||||
const { platform, totalAmountOfGamesForPlatform, mobyGamesToken } = buddyConfig
|
||||
|
||||
const overviewFile = `data/mobygames/games_${platform}.json`
|
||||
if(existsSync(overviewFile)) {
|
||||
console.log(' -- mobygames: retrieving list from cache...')
|
||||
const fileData = await fsp.readFile(overviewFile)
|
||||
return JSON.parse(fileData)
|
||||
}
|
||||
|
||||
console.log(' -- mobygames: no overview json file found for platform, fetching...')
|
||||
const allGames = []
|
||||
for(let offset = 0; offset < totalAmountOfGamesForPlatform; offset += 100) {
|
||||
console.log(` -- mobygames: fetching platform ${platform} offset ${offset}...`)
|
||||
const result = await axios.get(`${endpoint}/games?platform=${platform}&api_key=${mobyGamesToken}&offset=${offset}`)
|
||||
allGames.push(result.data.games)
|
||||
|
||||
// there's a rate limit of 1 request per second.
|
||||
await delay(1200)
|
||||
}
|
||||
|
||||
const games = allGames.flat()
|
||||
await fsp.writeFile(overviewFile, JSON.stringify({ games }, null, 2))
|
||||
console.log(` -- mobygames: done collecting, result in games_${platform}.json!`)
|
||||
|
||||
return { games }
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
collect,
|
||||
collectScreenshotsFor
|
||||
}
|
11
src/chat.js
11
src/chat.js
|
@ -7,14 +7,15 @@ if(!buddies) throw "Did you seutp your config?"
|
|||
const { toot } = require('./toot');
|
||||
|
||||
(async function() {
|
||||
for await(buddy of buddies) {
|
||||
const { chat } = require(`./buddies/${buddy}/buddy`)
|
||||
for await(buddyConfig of buddies) {
|
||||
console.log(`bootstrapping chat for ${buddyConfig.name}...`)
|
||||
const { chat } = require(`./buddies/${buddyConfig.name}/buddy`)
|
||||
|
||||
// contains 'toot', and maybe 'attach' / 'attachDescription'
|
||||
const message = await chat()
|
||||
console.log(`buddy ${buddy} has this to say: ${JSON.stringify(message)}`)
|
||||
const message = await chat(buddyConfig)
|
||||
console.log(`buddy ${buddyConfig.name} has this to say: ${JSON.stringify(message)}`)
|
||||
|
||||
await toot(message)
|
||||
//await toot(message, buddyConfig)
|
||||
}
|
||||
|
||||
console.log('Done! for now... ')
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
// do NOT check this in.
|
||||
|
||||
// which ones are active?
|
||||
const buddies = [{
|
||||
name: "animalcrossing",
|
||||
instance: "https://mastodon.social",
|
||||
oauthToken: "my-token"
|
||||
}, {
|
||||
name: "mobygames",
|
||||
instance: "https://botsin.space",
|
||||
oauthToken: "my-token-for-botsin-space",
|
||||
|
||||
mobyGamesToken: "my-mobygames-api-token",
|
||||
platform: 10, // gameboy
|
||||
totalAmountOfGames: 688 // mobygames has a total of 688 GB games in their library
|
||||
}]
|
||||
|
||||
module.exports = {
|
||||
buddies
|
||||
}
|
12
src/toot.js
12
src/toot.js
|
@ -2,14 +2,16 @@ const axios = require('axios')
|
|||
const FormData = require('form-data')
|
||||
const { createReadStream } = require('fs')
|
||||
|
||||
const { instance, oauthToken } = require('./config')
|
||||
async function toot(data, opts) {
|
||||
const { instance, oauthToken } = opts
|
||||
|
||||
async function toot(data) {
|
||||
// contains 'toot', and maybe 'attach' / 'attachDescription'
|
||||
const media_ids = []
|
||||
if(data.attach) {
|
||||
const id = await uploadMedia(data.attach, data.attachDescription)
|
||||
media_ids.push(id)
|
||||
for await(file of data.attach) {
|
||||
const id = await uploadMedia(file, data.attachDescription, instance, oauthToken)
|
||||
media_ids.push(id)
|
||||
}
|
||||
}
|
||||
|
||||
// https://docs.joinmastodon.org/methods/statuses/
|
||||
|
@ -25,7 +27,7 @@ async function toot(data) {
|
|||
console.log(` toot: status result: ${result.status}`)
|
||||
}
|
||||
|
||||
async function uploadMedia(fileName, description) {
|
||||
async function uploadMedia(fileName, description, instance, oauthToken) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', createReadStream(fileName))
|
||||
formData.append('description', description)
|
||||
|
|
Loading…
Reference in New Issue