Files
crates/server/src/discogs.ts
T
2022-08-01 00:05:55 +10:00

95 lines
3.1 KiB
TypeScript

import fs from 'fs/promises';
import axios from 'axios';
import cheerio from 'cheerio';
import Bluebird from 'bluebird';
import type Log from 'bunyan';
import type { PrismaClient, Want, User, Listing } from '@prisma/client';
import { logAxiosError } from './utils';
import { Pg } from './pg';
export default function discogs(log: Log, pg: Pg) {
const TOKEN = 'wRTXuYZGOPsIQgKRGKCAkUkidGtvpSfQgPWkYIpD';
const apiBase = 'https://api.discogs.com'
const discogsBase = 'https://www.discogs.com'
const api = axios.create({
headers: {
'Authorization': TOKEN,
// discogs only returns the first page without a desktop u/a
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0',
},
});
async function handleApiError(e) {
logAxiosError(e);
if (e.response.status === 429) {
throw new Error('rate limited');
}
return null;
}
async function user(discogs: string) {
const user = await pg.userFindName(discogs);
if (user) return user;
log.debug('fetching user', discogs);
const res = await api.get(`${apiBase}/users/${discogs}`);
return pg.userUpsert(res.data);
}
async function wantlist(user: User): Promise<Want[]> {
const stored = await pg.userWants(user);
if (stored.length) return stored;
return wantlistLatest(user);
}
async function wantlistLatest(user: User): Promise<Want[]> {
const { username } = user.data as { username: string };
const { data: { wants, pagination }} = await api.get(`${apiBase}/users/${username}/wants`);
return Bluebird.mapSeries(wants, async r => pg.wantUpsert(r, user));
}
async function inventory(user: string) {
const res = await api.get(`${apiBase}/users/${user}/inventory`);
return res.data.listings;
}
async function listings(want: Want) {
const res = await api.get(`https://www.discogs.com/sell/release/${want.release}?limit=250`);
const $ = cheerio.load(res.data);
const ids = $('.item_description_title[href]')
.map(function getListingId() {
const id = Number.parseInt(this.attribs.href.replace('/sell/item/', ''), 10);
return id;
})
.get();
const unlisted = await pg.listingRmUnlisted(want, ids);
if (unlisted) log.info({ wantId: want.id, unlisted: unlisted }, 'missing listings removed');
return Bluebird.mapSeries(ids, async id => listing(id, want));
}
async function listing(id, want) {
const listing = await pg.listingFind(id);
if (listing) return listing;
try {
log.debug('fetching listing', id);
const res = await api.get(`${apiBase}/marketplace/listings/${id}`);
return pg.listingUpsert(res.data, want);
} catch (e) {
return handleApiError(e);
}
}
return {
user,
wantlist,
wantlistLatest,
inventory,
listings,
listing,
};
}