| import chromadb |
| import re |
| import time |
| from mastodon import Mastodon |
| from datetime import datetime |
| from pathlib import Path |
| import json |
|
|
| |
| |
| MASTODON_SERVER_URL = r"https://mastodon.social" |
| MASTODON_ACCESS_TOKEN = json.load(open(r"D:\cs452\TopicBuzz\secrets.json"))["token"] |
| USER_LIST_FILE = "usersAll.txt" |
| DB_PATH = "./my_mastodon_db" |
| COLLECTION_NAME = "mastodon_posts" |
| POSTS_TO_FETCH = 100 |
| |
|
|
| |
| def strip_html(text): |
| return re.sub(r'<[^<]+?>', '', text) |
|
|
| |
| def polite_request(api_call, *args, **kwargs): |
| """ |
| Makes an API call and then waits 1 second. |
| This respects the default 300 requests / 5 min (1 req/sec) limit. |
| """ |
| response = api_call(*args, **kwargs) |
| time.sleep(1) |
| return response |
|
|
| def main(): |
| print("--- Mastodon Post Fetcher ---") |
|
|
| |
| try: |
| |
| mastodon = Mastodon( |
| access_token=MASTODON_ACCESS_TOKEN, |
| api_base_url=MASTODON_SERVER_URL |
| ) |
| print(f"Mastodon client connected to {MASTODON_SERVER_URL}") |
|
|
| |
| client = chromadb.PersistentClient(path=DB_PATH) |
| collection = client.get_or_create_collection(name=COLLECTION_NAME) |
| print(f"ChromaDB client connected to {DB_PATH}") |
|
|
| except Exception as e: |
| print(f"Error during initialization: {e}") |
| return |
|
|
| |
| user_file = Path(USER_LIST_FILE) |
| if not user_file.exists(): |
| print(f"Error: User file not found at {USER_LIST_FILE}") |
| return |
|
|
| with open(user_file, 'r') as f: |
| usernames = [line.strip() for line in f if line.strip()] |
| |
| print(f"Found {len(usernames)} users to track.") |
|
|
| |
| for username in usernames: |
| print(f"\nFetching posts for user: {username}") |
| try: |
| |
| account = polite_request(mastodon.account_lookup, username) |
| if not account: |
| print(f"Could not find user {username}. Skipping.") |
| continue |
| |
| user_id = account['id'] |
|
|
| |
| |
| |
| |
| page1 = polite_request(mastodon.account_statuses, id=user_id, limit=40) |
| |
| |
| page2 = polite_request(mastodon.fetch_next, page1) if page1 else [] |
| |
| |
| page3 = polite_request(mastodon.fetch_next, page2) if page2 else [] |
|
|
| |
| |
| all_posts = (page1 or []) + (page2 or []) + (page3 or []) |
| recent_posts = all_posts[:POSTS_TO_FETCH] |
|
|
| if not recent_posts: |
| print(f"No posts found for {username}. Skipping.") |
| continue |
|
|
| |
| ids_batch = [] |
| docs_batch = [] |
| meta_batch = [] |
|
|
| for post in recent_posts: |
| |
| doc_content = "" |
| doc_id = str(post['id']) |
| doc_meta = {} |
|
|
| if post['reblog']: |
| |
| original_post = post['reblog'] |
| |
| |
| doc_content = strip_html(original_post['content']) |
| |
| doc_meta = { |
| "type": "reblog", |
| "reblogger_user_id": str(post['account']['id']), |
| "reblog_timestamp": int(post['created_at'].timestamp()), |
| "original_post_id": str(original_post['id']), |
| "original_author_id": str(original_post['account']['id']), |
| "language": str(original_post.get('language')) |
| } |
| else: |
| |
| doc_content = strip_html(post['content']) |
| |
| doc_meta = { |
| "type": "original", |
| "author_user_id": str(post['account']['id']), |
| "author_handle": str(post['account']['acct']), |
| "post_timestamp": int(post['created_at'].timestamp()), |
| "language": str(post.get('language')) |
| } |
|
|
| |
| if doc_content: |
| ids_batch.append(doc_id) |
| docs_batch.append(doc_content) |
| meta_batch.append(doc_meta) |
|
|
| |
| if ids_batch: |
| collection.upsert( |
| ids=ids_batch, |
| documents=docs_batch, |
| metadatas=meta_batch |
| ) |
| print(f"Successfully added/updated {len(ids_batch)} posts for {username}.") |
| else: |
| print(f"No new original posts found for {username}.") |
|
|
| except Exception as e: |
| print(f"An error occurred while processing {username}: {e}") |
| |
| pass |
|
|
| print("\n--- All users processed. ---") |
|
|
| if __name__ == "__main__": |
| main() |