- Add moltbook_post.py script for posting to Moltbook - Add MOLTBOOK_POST.md documentation - Update SKILL.md with Moltbook section - Update README.md with Moltbook integration - Support posting from files or direct text - Handle rate limits gracefully
147 lines
4.0 KiB
Python
Executable File
147 lines
4.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Moltbook Post Tool - Post to Moltbook from the RAG skill
|
|
|
|
Usage:
|
|
python3 moltbook_post.py "Title" "Content"
|
|
python3 moltbook_post.py --file post.md
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import requests
|
|
from pathlib import Path
|
|
|
|
# Configuration
|
|
API_BASE = "https://www.moltbook.com/api/v1"
|
|
CONFIG_PATH = os.path.expanduser("~/.config/moltbook/credentials.json")
|
|
|
|
|
|
def load_api_key():
|
|
"""Load API key from config file or environment variable"""
|
|
# Try config file first
|
|
if os.path.exists(CONFIG_PATH):
|
|
with open(CONFIG_PATH, 'r') as f:
|
|
config = json.load(f)
|
|
return config.get('api_key')
|
|
|
|
# Try environment variable
|
|
api_key = os.environ.get('MOLTBOOK_API_KEY')
|
|
if api_key:
|
|
return api_key
|
|
|
|
# Default to known key (for this installation)
|
|
return "moltbook_sk_u6nkaLKRMNoJkWrT7iuUe-bJDD7wUZ1x"
|
|
|
|
|
|
def create_post(title, content, submolt="general", url=None):
|
|
"""Create a post to Moltbook"""
|
|
api_key = load_api_key()
|
|
|
|
if not api_key:
|
|
print("❌ Error: No Moltbook API key found")
|
|
print(f" Set environment variable MOLTBOOK_API_KEY or create {CONFIG_PATH}")
|
|
return False
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {api_key}",
|
|
"Content-Type": "application/json"
|
|
}
|
|
|
|
data = {
|
|
"submolt": submolt,
|
|
"title": title,
|
|
"content": content
|
|
}
|
|
|
|
if url:
|
|
data["url"] = url
|
|
|
|
try:
|
|
response = requests.post(
|
|
f"{API_BASE}/posts",
|
|
headers=headers,
|
|
json=data,
|
|
timeout=10
|
|
)
|
|
|
|
if response.status_code == 201:
|
|
result = response.json()
|
|
post_id = result.get('data', {}).get('id')
|
|
|
|
print(f"✅ Post created successfully!")
|
|
print(f" Post ID: {post_id}")
|
|
print(f" URL: https://moltbook.com/posts/{post_id}")
|
|
|
|
if 'data' in result and 'author' in result['data']:
|
|
print(f" Author: {result['data']['author']['name']}")
|
|
|
|
return True
|
|
elif response.status_code == 429:
|
|
error = response.json()
|
|
retry = error.get('hint', {}).get('retry_after_minutes', 'unknown')
|
|
print(f"⏸️ Rate limited. Wait {retry} minutes before posting again.")
|
|
return False
|
|
else:
|
|
print(f"❌ Error: {response.status_code}")
|
|
print(f" {response.text}")
|
|
return False
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"❌ Network error: {e}")
|
|
return False
|
|
|
|
|
|
def post_from_file(file_path, submolt="general"):
|
|
"""Read post from markdown file and publish"""
|
|
path = Path(file_path)
|
|
|
|
if not path.exists():
|
|
print(f"❌ File not found: {file_path}")
|
|
return False
|
|
|
|
content = path.read_text()
|
|
|
|
# Extract title from first heading or use filename
|
|
lines = content.split('\n')
|
|
title = "RAG Skill Announcement"
|
|
|
|
for line in lines:
|
|
if line.startswith('#'):
|
|
title = line.lstrip('#').strip()
|
|
break
|
|
|
|
# Remove title from content
|
|
if content.startswith('#'):
|
|
parts = content.split('\n', 1)
|
|
if len(parts) > 1:
|
|
content = parts[1].strip()
|
|
|
|
return create_post(title, content, submolt)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage:")
|
|
print(" python3 moltbook_post.py \"Title\" \"Content\"")
|
|
print(" python3 moltbook_post.py --file post.md")
|
|
print(" python3 moltbook_post.py --file post.md --submolt general")
|
|
sys.exit(1)
|
|
|
|
# Check for file mode
|
|
if sys.argv[1] == '--file':
|
|
file_path = sys.argv[2]
|
|
submolt = sys.argv[3] if len(sys.argv) > 3 else 'general'
|
|
success = post_from_file(file_path, submolt)
|
|
else:
|
|
title = sys.argv[1]
|
|
content = sys.argv[2] if len(sys.argv) > 2 else ""
|
|
submolt = sys.argv[3] if len(sys.argv) > 3 else 'general'
|
|
success = create_post(title, content, submolt)
|
|
|
|
sys.exit(0 if success else 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |