I hate how good AI is at doing menial straightforward tasks.
This commit is contained in:
commit
7c49de7e55
5 changed files with 168 additions and 0 deletions
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
.zuliprc
|
||||||
|
.mypy_cache/**
|
||||||
|
.venv/**
|
||||||
|
__pycache__/**
|
||||||
|
build/**
|
||||||
|
dist/**
|
||||||
|
*.md
|
||||||
4
.zuliprc.template
Normal file
4
.zuliprc.template
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
[api]
|
||||||
|
email=me@example.com
|
||||||
|
key=some_api_key
|
||||||
|
site=https://zulip.example.com
|
||||||
10
requirements.txt
Normal file
10
requirements.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
certifi==2026.5.20
|
||||||
|
charset-normalizer==3.4.7
|
||||||
|
click==8.4.1
|
||||||
|
colorama==0.4.6
|
||||||
|
distro==1.9.0
|
||||||
|
idna==3.18
|
||||||
|
requests==2.34.2
|
||||||
|
typing_extensions==4.15.0
|
||||||
|
urllib3==2.7.0
|
||||||
|
zulip==0.9.1
|
||||||
102
topic-export.py
Normal file
102
topic-export.py
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
import datetime
|
||||||
|
import zulip
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Check if running as a PyInstaller bundle or raw python script
|
||||||
|
if getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS"):
|
||||||
|
# Path inside the temporary binary folder
|
||||||
|
base_path = sys._MEIPASS # type: ignore
|
||||||
|
else:
|
||||||
|
# Path in your standard local workspace folder
|
||||||
|
base_path = os.path.abspath(".")
|
||||||
|
|
||||||
|
CONFIG_PATH = os.path.join(base_path, ".zuliprc")
|
||||||
|
CHANNEL_NAME = "wifey-time"
|
||||||
|
TOPIC_NAME = "Mutual Enjoyment"
|
||||||
|
OUTPUT_FILE = (
|
||||||
|
f"{datetime.date.today().isoformat()}_Mutual_Enjoyment.md" # Saved directly as .md
|
||||||
|
)
|
||||||
|
|
||||||
|
# Initialize client using the embedded configuration
|
||||||
|
client = zulip.Client(config_file=CONFIG_PATH)
|
||||||
|
|
||||||
|
narrow_filter = [
|
||||||
|
{"operator": "channel", "operand": CHANNEL_NAME},
|
||||||
|
{"operator": "topic", "operand": TOPIC_NAME},
|
||||||
|
]
|
||||||
|
|
||||||
|
anchor = "oldest"
|
||||||
|
all_messages = []
|
||||||
|
batch_count = 0
|
||||||
|
|
||||||
|
print(f"Starting export for '{CHANNEL_NAME}' > '{TOPIC_NAME}'...")
|
||||||
|
|
||||||
|
# Step 1: Automatic Pagination Loop
|
||||||
|
while True:
|
||||||
|
batch_count += 1
|
||||||
|
|
||||||
|
request_params = {
|
||||||
|
"anchor": anchor,
|
||||||
|
"num_before": 0,
|
||||||
|
"num_after": 1000,
|
||||||
|
"narrow": narrow_filter,
|
||||||
|
"apply_markdown": False, # This ensures Zulip gives us raw markdown strings
|
||||||
|
}
|
||||||
|
|
||||||
|
response = client.call_endpoint(
|
||||||
|
url="messages",
|
||||||
|
method="GET",
|
||||||
|
request=request_params,
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.get("result") != "success":
|
||||||
|
print(f"Error fetching data: {response.get('msg')}")
|
||||||
|
break
|
||||||
|
|
||||||
|
messages = response.get("messages", [])
|
||||||
|
if not messages:
|
||||||
|
break
|
||||||
|
|
||||||
|
if anchor == "oldest":
|
||||||
|
all_messages.extend(messages)
|
||||||
|
else:
|
||||||
|
all_messages.extend(messages[1:])
|
||||||
|
if len(messages) <= 1:
|
||||||
|
break
|
||||||
|
|
||||||
|
anchor = messages[-1]["id"]
|
||||||
|
print(f" Batch {batch_count}: Downloaded {len(messages)} messages...")
|
||||||
|
|
||||||
|
# Step 2: Format Data into a Valid Markdown File
|
||||||
|
if all_messages:
|
||||||
|
with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
|
||||||
|
# Markdown File Header
|
||||||
|
f.write(f"# Chat Export: {CHANNEL_NAME} > {TOPIC_NAME}\n")
|
||||||
|
f.write(f"**Total Messages:** {len(all_messages)} \n")
|
||||||
|
f.write(f"**Export Date:** {datetime.date.today().isoformat()} \n")
|
||||||
|
f.write("\n---\n\n")
|
||||||
|
|
||||||
|
# Process each individual message payload
|
||||||
|
for msg in all_messages:
|
||||||
|
sender = msg.get("sender_full_name", "Unknown User")
|
||||||
|
content = msg.get("content", "")
|
||||||
|
|
||||||
|
# Convert Unix timestamp to a friendly readable format
|
||||||
|
timestamp = msg.get("timestamp", 0)
|
||||||
|
formatted_time = datetime.datetime.fromtimestamp(timestamp).strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write metadata as a markdown bold header line
|
||||||
|
f.write(f"**[{formatted_time}] {sender}:**\n\n")
|
||||||
|
|
||||||
|
# Print the raw markdown content exactly as typed in Zulip
|
||||||
|
f.write(f"{content}\n\n")
|
||||||
|
|
||||||
|
# Add a clean markdown line break rule between chat entries
|
||||||
|
f.write(" \n")
|
||||||
|
|
||||||
|
print(f"\nSuccess! Exported {len(all_messages)} messages to: '{OUTPUT_FILE}'.")
|
||||||
|
else:
|
||||||
|
print("\nNo messages discovered matching this specific channel and topic criteria.")
|
||||||
45
topic-export.spec
Normal file
45
topic-export.spec
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
block_cipher = None
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['topic-export.py'],
|
||||||
|
pathex=[],
|
||||||
|
binaries=[],
|
||||||
|
datas=[('.zuliprc', '.')],
|
||||||
|
hiddenimports=[],
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
pyz = PYZ(
|
||||||
|
a.pure,
|
||||||
|
a.zipped_data,
|
||||||
|
cipher=block_cipher
|
||||||
|
)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.zipfiles,
|
||||||
|
a.datas,
|
||||||
|
[],
|
||||||
|
name="export_mutual_enjoyment",
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=True,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
)
|
||||||
Loading…
Reference in a new issue