feat: add quote depth option for quoted tweets
This commit is contained in:
+33
-9
@@ -99,6 +99,7 @@ type BirdConfig = {
|
||||
firefoxProfile?: string;
|
||||
cookieSource?: CookieSource | CookieSource[];
|
||||
timeoutMs?: number;
|
||||
quoteDepth?: number;
|
||||
};
|
||||
|
||||
function readConfigFile(path: string): Partial<BirdConfig> {
|
||||
@@ -180,6 +181,7 @@ program
|
||||
.option('--media <path>', 'Attach media file (repeatable, up to 4 images or 1 video)', collect, [])
|
||||
.option('--alt <text>', 'Alt text for the corresponding --media (repeatable)', collect, [])
|
||||
.option('--timeout <ms>', 'Request timeout in milliseconds')
|
||||
.option('--quote-depth <depth>', 'Max quoted tweet depth (default: 1; 0 disables)')
|
||||
.option('--plain', 'Plain output (stable, no emoji, no color)')
|
||||
.option('--no-emoji', 'Disable emoji output')
|
||||
.option('--no-color', 'Disable ANSI colors (or set NO_COLOR)');
|
||||
@@ -224,6 +226,19 @@ function resolveTimeoutFromOptions(options: { timeout?: string | number }): numb
|
||||
return resolveTimeoutMs(options.timeout, config.timeoutMs, process.env.BIRD_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
function resolveQuoteDepth(...values: Array<string | number | undefined | null>): number | undefined {
|
||||
for (const value of values) {
|
||||
if (value === undefined || value === null || value === '') continue;
|
||||
const parsed = typeof value === 'number' ? value : Number.parseInt(value, 10);
|
||||
if (Number.isFinite(parsed) && parsed >= 0) return Math.floor(parsed);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function resolveQuoteDepthFromOptions(options: { quoteDepth?: string | number }): number | undefined {
|
||||
return resolveQuoteDepth(options.quoteDepth, config.quoteDepth, process.env.BIRD_QUOTE_DEPTH);
|
||||
}
|
||||
|
||||
function detectMime(path: string): string | null {
|
||||
const ext = path.toLowerCase();
|
||||
if (ext.endsWith('.jpg') || ext.endsWith('.jpeg')) return 'image/jpeg';
|
||||
@@ -364,6 +379,7 @@ program
|
||||
.action(async (text: string) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
let media: MediaSpec[] = [];
|
||||
try {
|
||||
media = loadMedia({ media: opts.media ?? [], alts: opts.alt ?? [] });
|
||||
@@ -387,7 +403,7 @@ program
|
||||
console.error(`${l('source')}${cookies.source}`);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
let mediaIds: string[] | undefined;
|
||||
if (media.length > 0) {
|
||||
const uploaded: string[] = [];
|
||||
@@ -422,6 +438,7 @@ program
|
||||
.action(async (tweetIdOrUrl: string, text: string) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
let media: MediaSpec[] = [];
|
||||
try {
|
||||
media = loadMedia({ media: opts.media ?? [], alts: opts.alt ?? [] });
|
||||
@@ -448,7 +465,7 @@ program
|
||||
|
||||
console.error(`${p('info')}Replying to tweet: ${tweetId}`);
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
let mediaIds: string[] | undefined;
|
||||
if (media.length > 0) {
|
||||
const uploaded: string[] = [];
|
||||
@@ -483,6 +500,7 @@ program
|
||||
.action(async (tweetIdOrUrl: string, cmdOpts: { json?: boolean }) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
|
||||
const tweetId = extractTweetId(tweetIdOrUrl);
|
||||
|
||||
@@ -497,7 +515,7 @@ program
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
const result = await client.getTweet(tweetId);
|
||||
|
||||
if (result.success && result.tweet) {
|
||||
@@ -526,6 +544,7 @@ program
|
||||
.action(async (tweetIdOrUrl: string, cmdOpts: { json?: boolean }) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
const tweetId = extractTweetId(tweetIdOrUrl);
|
||||
|
||||
const { cookies, warnings } = await resolveCredentialsFromOptions(opts);
|
||||
@@ -539,7 +558,7 @@ program
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
const result = await client.getReplies(tweetId);
|
||||
|
||||
if (result.success && result.tweets) {
|
||||
@@ -559,6 +578,7 @@ program
|
||||
.action(async (tweetIdOrUrl: string, cmdOpts: { json?: boolean }) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
const tweetId = extractTweetId(tweetIdOrUrl);
|
||||
|
||||
const { cookies, warnings } = await resolveCredentialsFromOptions(opts);
|
||||
@@ -572,7 +592,7 @@ program
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
const result = await client.getThread(tweetId);
|
||||
|
||||
if (result.success && result.tweets) {
|
||||
@@ -593,6 +613,7 @@ program
|
||||
.action(async (query: string, cmdOpts: { count?: string; json?: boolean }) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
const count = Number.parseInt(cmdOpts.count || '10', 10);
|
||||
|
||||
const { cookies, warnings } = await resolveCredentialsFromOptions(opts);
|
||||
@@ -606,7 +627,7 @@ program
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
const result = await client.search(query, count);
|
||||
|
||||
if (result.success && result.tweets) {
|
||||
@@ -627,6 +648,7 @@ program
|
||||
.action(async (cmdOpts: { user?: string; count?: string; json?: boolean }) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
const count = Number.parseInt(cmdOpts.count || '10', 10);
|
||||
|
||||
const fromUserOpt = mentionsQueryFromUserOption(cmdOpts.user);
|
||||
@@ -648,7 +670,7 @@ program
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
|
||||
if (!query) {
|
||||
const who = await client.getCurrentUser();
|
||||
@@ -682,6 +704,7 @@ program
|
||||
.action(async (cmdOpts: { count?: string; json?: boolean }) => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
const count = Number.parseInt(cmdOpts.count || '20', 10);
|
||||
|
||||
const { cookies, warnings } = await resolveCredentialsFromOptions(opts);
|
||||
@@ -695,7 +718,7 @@ program
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
const result = await client.getBookmarks(count);
|
||||
|
||||
if (result.success && result.tweets) {
|
||||
@@ -713,6 +736,7 @@ program
|
||||
.action(async () => {
|
||||
const opts = program.opts();
|
||||
const timeoutMs = resolveTimeoutFromOptions(opts);
|
||||
const quoteDepth = resolveQuoteDepthFromOptions(opts);
|
||||
|
||||
const { cookies, warnings } = await resolveCredentialsFromOptions(opts);
|
||||
|
||||
@@ -729,7 +753,7 @@ program
|
||||
console.error(`${l('source')}${cookies.source}`);
|
||||
}
|
||||
|
||||
const client = new TwitterClient({ cookies, timeoutMs });
|
||||
const client = new TwitterClient({ cookies, timeoutMs, quoteDepth });
|
||||
const result = await client.getCurrentUser();
|
||||
|
||||
const credentialSource = cookies.source ?? 'env/auto-detected cookies';
|
||||
|
||||
Reference in New Issue
Block a user