112 lines
3.6 KiB
Python
112 lines
3.6 KiB
Python
import os
|
|
import json
|
|
import requests
|
|
import datetime
|
|
from typing import Optional, Dict, Any
|
|
from pydantic import BaseModel
|
|
|
|
# Constants
|
|
API_URL = "https://api.typefully.com/v1/drafts/"
|
|
API_KEY = os.getenv("TYPEFULLY_API_KEY")
|
|
HEADERS = {
|
|
"X-API-KEY": f"Bearer {API_KEY}"
|
|
}
|
|
|
|
def json_to_typefully_content(thread_json: Dict[str, Any]) -> str:
|
|
"""Convert JSON thread format to Typefully's format with 4 newlines between tweets."""
|
|
tweets = thread_json['tweets']
|
|
formatted_tweets = []
|
|
for tweet in tweets:
|
|
tweet_text = tweet['content']
|
|
if 'media_urls' in tweet and tweet['media_urls']:
|
|
tweet_text += f"\n{tweet['media_urls'][0]}"
|
|
formatted_tweets.append(tweet_text)
|
|
|
|
return '\n\n\n\n'.join(formatted_tweets)
|
|
|
|
def json_to_linkedin_content(thread_json: Dict[str, Any]) -> str:
|
|
"""Convert JSON thread format to Typefully's format."""
|
|
content = thread_json['content']
|
|
if 'url' in thread_json and thread_json['url']:
|
|
content += f"\n{thread_json['url']}"
|
|
return content
|
|
|
|
def schedule_thread(
|
|
content: str,
|
|
schedule_date: str = "next-free-slot",
|
|
threadify: bool = False,
|
|
share: bool = False,
|
|
auto_retweet_enabled: bool = False,
|
|
auto_plug_enabled: bool = False
|
|
) -> Optional[Dict[str, Any]]:
|
|
"""Schedule a thread on Typefully."""
|
|
payload = {
|
|
"content": content,
|
|
"schedule-date": schedule_date,
|
|
"threadify": threadify,
|
|
"share": share,
|
|
"auto_retweet_enabled": auto_retweet_enabled,
|
|
"auto_plug_enabled": auto_plug_enabled
|
|
}
|
|
|
|
payload = {key: value for key, value in payload.items() if value is not None}
|
|
|
|
try:
|
|
response = requests.post(API_URL, json=payload, headers=HEADERS)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"Error: {e}")
|
|
return None
|
|
|
|
def schedule(
|
|
thread_model: BaseModel,
|
|
hours_from_now: int = 1,
|
|
threadify: bool = False,
|
|
share: bool = True,
|
|
post_type: str = "twitter"
|
|
) -> Optional[Dict[str, Any]]:
|
|
"""
|
|
Schedule a thread from a Pydantic model.
|
|
|
|
Args:
|
|
thread_model: Pydantic model containing thread data
|
|
hours_from_now: Hours from now to schedule the thread (default: 1)
|
|
threadify: Whether to let Typefully split the content (default: False)
|
|
share: Whether to get a share URL in response (default: True)
|
|
|
|
Returns:
|
|
API response dictionary or None if failed
|
|
"""
|
|
try:
|
|
# Convert Pydantic model to dict
|
|
thread_json = thread_model.pydantic.model_dump()
|
|
print("######## Thread JSON: ", thread_json)
|
|
# Convert to Typefully format
|
|
if post_type == "twitter":
|
|
thread_content = json_to_typefully_content(thread_json)
|
|
elif post_type == "linkedin":
|
|
thread_content = json_to_linkedin_content(thread_json)
|
|
|
|
# Calculate schedule time
|
|
schedule_date = (datetime.datetime.utcnow() +
|
|
datetime.timedelta(hours=hours_from_now)).isoformat() + "Z"
|
|
|
|
# Schedule the thread
|
|
response = schedule_thread(
|
|
content=thread_content,
|
|
schedule_date=schedule_date,
|
|
threadify=threadify,
|
|
share=share
|
|
)
|
|
|
|
if response:
|
|
print("Thread scheduled successfully!")
|
|
return response
|
|
else:
|
|
print("Failed to schedule the thread.")
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"Error: {str(e)}")
|
|
return None |