import type { DanbooruPost } from '../types.js';
const API_BASE = 'https://danbooru.donmai.us';
const HEADERS = {
'User-Agent': 'DanbooruCollector/1.0'
};
export class DanbooruService {
/**
* Fetch posts from Danbooru API with pagination
*/
async fetchPosts(
tag: string,
page: number = 1,
limit: number = 200
): Promise<DanbooruPost[]> {
const url = `${API_BASE}/posts.json`;
const params = new URLSearchParams({
tags: tag,
limit: limit.toString(),
page: page.toString()
});
try {
const response = await fetch(`${url}?${params}`, {
headers: HEADERS,
signal: AbortSignal.timeout(15000)
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const data = await response.json();
return data as DanbooruPost[];
} catch (error) {
console.error(`Danbooru API error: ${error}`);
throw error;
}
}
/**
* Collect all posts for a tag with pagination
*/
async collectAllPosts(
tag: string,
maxPosts?: number,
startPage: number = 1
): Promise<DanbooruPost[]> {
const allPosts: DanbooruPost[] = [];
let page = startPage;
while (true) {
const posts = await this.fetchPosts(tag, page, 200);
if (!posts || posts.length === 0) {
break;
}
allPosts.push(...posts);
// Check if we reached max posts
if (maxPosts && allPosts.length >= maxPosts) {
return allPosts.slice(0, maxPosts);
}
// Last page check (less than 200 posts)
if (posts.length < 200) {
break;
}
page++;
// Rate limiting: wait 1 second between requests
await new Promise(resolve => setTimeout(resolve, 1000));
}
return allPosts;
}
}