fix: improve show command cache design and reliability
- Merge get_tweet_id_by_index + get_cache_size into resolve_cached_tweet to eliminate redundant file IO on cache miss - Move save_tweet_cache before emit_structured so --json/--yaml modes also persist the cache for subsequent show commands - Extract _print_show_hint helper to reduce duplication - Add trailing newline to cache.py
This commit is contained in:
@@ -6,7 +6,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional
|
from typing import List, Optional, Tuple
|
||||||
|
|
||||||
from .models import Tweet
|
from .models import Tweet
|
||||||
|
|
||||||
@@ -50,19 +50,17 @@ def _load_cache() -> Optional[List[dict]]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_tweet_id_by_index(index: int) -> Optional[str]:
|
def resolve_cached_tweet(index: int) -> Tuple[Optional[str], int]:
|
||||||
"""Return tweet ID at *index* (1-based), or None if not found."""
|
"""Resolve a 1-based index to a tweet ID, returning (tweet_id, cache_size).
|
||||||
|
|
||||||
|
Returns (tweet_id, cache_size) where tweet_id is None if the index
|
||||||
|
cannot be resolved (empty/expired cache or out-of-range index).
|
||||||
|
"""
|
||||||
entries = _load_cache()
|
entries = _load_cache()
|
||||||
if entries is None:
|
if entries is None:
|
||||||
return None
|
return None, 0
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
if entry.get("index") == index:
|
if entry.get("index") == index:
|
||||||
tweet_id = entry.get("id")
|
tweet_id = entry.get("id")
|
||||||
return str(tweet_id) if tweet_id is not None else None
|
return (str(tweet_id) if tweet_id is not None else None), len(entries)
|
||||||
return None
|
return None, len(entries)
|
||||||
|
|
||||||
|
|
||||||
def get_cache_size() -> int:
|
|
||||||
"""Return number of tweets in the current cache (0 if unavailable)."""
|
|
||||||
entries = _load_cache()
|
|
||||||
return len(entries) if entries is not None else 0
|
|
||||||
@@ -45,7 +45,7 @@ from rich.console import Console
|
|||||||
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from .auth import get_cookies
|
from .auth import get_cookies
|
||||||
from .cache import get_cache_size, get_tweet_id_by_index, save_tweet_cache
|
from .cache import resolve_cached_tweet, save_tweet_cache
|
||||||
from .client import TwitterClient
|
from .client import TwitterClient
|
||||||
from .config import load_config
|
from .config import load_config
|
||||||
from .filter import filter_tweets
|
from .filter import filter_tweets
|
||||||
@@ -349,17 +349,18 @@ def _fetch_and_display(fetch_fn, label, emoji, max_count, as_json, as_yaml, outp
|
|||||||
click.echo(tweets_to_compact_json(filtered))
|
click.echo(tweets_to_compact_json(filtered))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
save_tweet_cache(filtered)
|
||||||
|
|
||||||
if emit_structured(tweets_to_data(filtered), as_json=as_json, as_yaml=as_yaml):
|
if emit_structured(tweets_to_data(filtered), as_json=as_json, as_yaml=as_yaml):
|
||||||
return
|
return
|
||||||
|
|
||||||
save_tweet_cache(filtered)
|
|
||||||
print_tweet_table(
|
print_tweet_table(
|
||||||
filtered,
|
filtered,
|
||||||
console,
|
console,
|
||||||
title="%s %s — %d tweets" % (emoji, label, len(filtered)),
|
title="%s %s — %d tweets" % (emoji, label, len(filtered)),
|
||||||
full_text=full_text,
|
full_text=full_text,
|
||||||
)
|
)
|
||||||
console.print("[dim]💡 Use `twitter show <N>` to view tweet #N from this list.[/dim]")
|
_print_show_hint()
|
||||||
console.print()
|
console.print()
|
||||||
|
|
||||||
|
|
||||||
@@ -443,14 +444,15 @@ def feed(ctx, feed_type, max_count, as_json, as_yaml, input_file, output_file, d
|
|||||||
click.echo(tweets_to_compact_json(filtered))
|
click.echo(tweets_to_compact_json(filtered))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
save_tweet_cache(filtered)
|
||||||
|
|
||||||
if emit_structured(tweets_to_data(filtered), as_json=as_json, as_yaml=as_yaml):
|
if emit_structured(tweets_to_data(filtered), as_json=as_json, as_yaml=as_yaml):
|
||||||
return
|
return
|
||||||
|
|
||||||
title = "👥 Following" if feed_type == "following" else "📱 Twitter"
|
title = "👥 Following" if feed_type == "following" else "📱 Twitter"
|
||||||
title += " — %d tweets" % len(filtered)
|
title += " — %d tweets" % len(filtered)
|
||||||
save_tweet_cache(filtered)
|
|
||||||
print_tweet_table(filtered, console, title=title, full_text=full_text)
|
print_tweet_table(filtered, console, title=title, full_text=full_text)
|
||||||
console.print("[dim]💡 Use `twitter show <N>` to view tweet #N from this list.[/dim]")
|
_print_show_hint()
|
||||||
console.print()
|
console.print()
|
||||||
|
|
||||||
|
|
||||||
@@ -725,6 +727,12 @@ def _emit_tweet_detail(tweets, compact, as_json, as_yaml, full_text):
|
|||||||
console.print()
|
console.print()
|
||||||
|
|
||||||
|
|
||||||
|
def _print_show_hint():
|
||||||
|
# type: () -> None
|
||||||
|
"""Print a hint about the `show` command."""
|
||||||
|
console.print("[dim]💡 Use `twitter show <N>` to view tweet #N from this list.[/dim]")
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("index", type=click.IntRange(1))
|
@click.argument("index", type=click.IntRange(1))
|
||||||
@click.option("--max", "-n", "max_count", type=int, default=None, help="Max replies to fetch.")
|
@click.option("--max", "-n", "max_count", type=int, default=None, help="Max replies to fetch.")
|
||||||
@@ -736,9 +744,8 @@ def show(ctx, index, max_count, full_text, as_json, as_yaml):
|
|||||||
"""View tweet #INDEX from the last feed/search results."""
|
"""View tweet #INDEX from the last feed/search results."""
|
||||||
compact = ctx.obj.get("compact", False)
|
compact = ctx.obj.get("compact", False)
|
||||||
|
|
||||||
tweet_id = get_tweet_id_by_index(index)
|
tweet_id, cache_size = resolve_cached_tweet(index)
|
||||||
if tweet_id is None:
|
if tweet_id is None:
|
||||||
cache_size = get_cache_size()
|
|
||||||
if cache_size == 0:
|
if cache_size == 0:
|
||||||
raise click.UsageError(
|
raise click.UsageError(
|
||||||
"No cached results found. Run `twitter feed`, `twitter search`, "
|
"No cached results found. Run `twitter feed`, `twitter search`, "
|
||||||
|
|||||||
Reference in New Issue
Block a user