-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Expand file tree
/
Copy pathscheduler.py
More file actions
112 lines (98 loc) · 3.55 KB
/
scheduler.py
File metadata and controls
112 lines (98 loc) · 3.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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