···352352 type=click.Path(file_okay=True, dir_okay=False, allow_dash=False),
353353 required=True,
354354)
355355-@click.argument("follow", type=str, required=True, nargs=-1)
356356-@click.option("--verbose", is_flag=True, help="Verbose mode: display every tweet")
355355+@add_identifier_options
356356+@click.option("--ids", is_flag=True, help="Treat input as user IDs, not screen names")
357357@click.option(
358358 "-a",
359359 "--auth",
···361361 default="auth.json",
362362 help="Path to auth.json token file",
363363)
364364-def follow(db_path, follow, auth, verbose):
364364+@click.option("--verbose", is_flag=True, help="Verbose mode: display every tweet")
365365+def follow(db_path, identifiers, attach, sql, ids, auth, verbose):
365366 "Experimental: Follow these Twitter users (numeric user IDs required) and save tweets in real-time"
366367 auth = json.load(open(auth))
367368 session = utils.session_for_auth(auth)
368369 db = sqlite_utils.Database(db_path)
370370+ identifiers = utils.resolve_identifiers(db, identifiers, attach, sql)
371371+ # Make sure we have saved these users to the database
372372+ for batch in utils.fetch_user_batches(session, identifiers, ids):
373373+ utils.save_users(db, batch)
374374+ # Ensure we have user IDs, not screen names
375375+ if ids:
376376+ follow = identifiers
377377+ else:
378378+ follow = utils.user_ids_for_screen_names(db, identifiers)
379379+ # Start streaming:
369380 for tweet in utils.stream_filter(session, follow=follow):
370381 if verbose:
371382 print(json.dumps(tweet, indent=2))
+9
twitter_to_sqlite/utils.py
···385385 fix_streaming_tweet(tweet["retweeted_status"])
386386 if "quoted_status" in tweet:
387387 fix_streaming_tweet(tweet["quoted_status"])
388388+389389+390390+def user_ids_for_screen_names(db, screen_names):
391391+ sql = "select id from users where lower(screen_name) in ({})".format(
392392+ ", ".join(["?"] * len(screen_names))
393393+ )
394394+ return [
395395+ r[0] for r in db.conn.execute(sql, [s.lower() for s in screen_names]).fetchall()
396396+ ]