Add account browsing simulation
This commit is contained in:
1 parent
e2d7dc4b82
commit
27012399ec
31 files changed
+1476
-28
No files matched your search
@@ -125,6 +125,23 @@ export interface RedditPost {
|
||||
pinned?: boolean;
|
||||
distinguished?: string | null;
|
||||
removed_by_category?: string | null;
|
||||
score?: number;
|
||||
}
|
||||
|
||||
/** Typed Reddit content used only by the simulation-only browsing reader. */
|
||||
export interface BrowsingThing {
|
||||
fullname: string;
|
||||
kind: 'post' | 'comment';
|
||||
subreddit: string;
|
||||
author: string;
|
||||
permalink: string;
|
||||
createdAt: number;
|
||||
score: number | null;
|
||||
text: string;
|
||||
nsfw: boolean;
|
||||
parentPostId: string;
|
||||
distinguished: string | null;
|
||||
removed: boolean;
|
||||
}
|
||||
|
||||
interface RedditListingChild {
|
||||
@@ -478,6 +495,58 @@ export class RedditApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Typed top-level comments for browsing simulation. This is intentionally
|
||||
* separate from `getThreadTopComments()`, whose string-only contract belongs
|
||||
* to comment generation.
|
||||
*/
|
||||
async getBrowsingComments(
|
||||
subreddit: string,
|
||||
postId: string,
|
||||
limit = 25,
|
||||
): Promise<BrowsingThing[]> {
|
||||
const cookieHeader = await this.getCookieHeader();
|
||||
const headers: Record<string, string> = {};
|
||||
if (cookieHeader) headers.Cookie = cookieHeader;
|
||||
|
||||
try {
|
||||
const response = await this.scheduleRequest(() => this.client.get(
|
||||
`/r/${subreddit}/comments/${postId}.json`,
|
||||
{ params: { limit, depth: 1, sort: 'hot', raw_json: 1 }, headers },
|
||||
));
|
||||
const listings = Array.isArray(response.data) ? response.data : [];
|
||||
const children = (listings[1] as { data?: { children?: unknown } } | undefined)?.data?.children;
|
||||
if (!Array.isArray(children)) return [];
|
||||
return children.flatMap((child): BrowsingThing[] => {
|
||||
const data = (child as { data?: Record<string, unknown> })?.data;
|
||||
if (!data || typeof data.name !== 'string' || !data.name.startsWith('t1_')) return [];
|
||||
const author = typeof data.author === 'string' ? data.author : '[deleted]';
|
||||
const body = typeof data.body === 'string' ? data.body : '';
|
||||
return [{
|
||||
fullname: data.name,
|
||||
kind: 'comment',
|
||||
subreddit: typeof data.subreddit === 'string' ? data.subreddit : subreddit,
|
||||
author,
|
||||
permalink: typeof data.permalink === 'string'
|
||||
? data.permalink
|
||||
: `/r/${subreddit}/comments/${postId}/_/${data.name.slice(3)}/`,
|
||||
createdAt: typeof data.created_utc === 'number' ? Math.round(data.created_utc * 1_000) : 0,
|
||||
score: typeof data.score === 'number' ? data.score : null,
|
||||
text: body,
|
||||
nsfw: data.over_18 === true,
|
||||
parentPostId: postId,
|
||||
distinguished: typeof data.distinguished === 'string' ? data.distinguished : null,
|
||||
removed: body === '[removed]' || body === '[deleted]' || data.removed === true,
|
||||
}];
|
||||
}).slice(0, limit);
|
||||
} catch (error) {
|
||||
const rateLimitError = this.toRateLimitError(error);
|
||||
if (rateLimitError) throw rateLimitError;
|
||||
this.logger.warn(`Failed to read browsing comments for ${postId}:`, error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private isValidPost(post: RedditPost, type: 'image' | 'chat' = 'image'): boolean {
|
||||
// Skip deleted/removed authors
|
||||
if (post.author === '[deleted]' || post.author === 'AutoModerator') return false;
|
||||
|
||||
Reference in new issue
Block a user