-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmedium_publisher.py
More file actions
137 lines (109 loc) · 4.16 KB
/
medium_publisher.py
File metadata and controls
137 lines (109 loc) · 4.16 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import json
import os
import subprocess
from dotenv import load_dotenv
class MediumPublisher:
def __init__(self, token=None):
# Load token from environment or use provided token
load_dotenv()
self.token = token or os.getenv("MEDIUM_TOKEN")
if not self.token:
raise ValueError(
"Medium API token is required. Set MEDIUM_TOKEN environment variable or pass token to constructor."
)
self.base_url = "https://api.medium.com/v1"
def _make_curl_request(self, method, endpoint, data=None):
"""Make API request using curl to bypass Cloudflare protection"""
url = f"{self.base_url}{endpoint}"
cmd = [
"curl",
"-s",
"-H",
f"Authorization: Bearer {self.token}",
"-H",
"Content-Type: application/json",
"-X",
method.upper(),
]
if data:
cmd.extend(["-d", json.dumps(data)])
cmd.append(url)
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if result.returncode != 0:
raise Exception(f"Curl request failed: {result.stderr}")
response_data = json.loads(result.stdout)
return response_data
except subprocess.TimeoutExpired:
raise Exception("Request timed out")
except json.JSONDecodeError:
raise Exception(f"Invalid JSON response: {result.stdout}")
except Exception as e:
raise Exception(f"Request failed: {str(e)}")
def get_user_id(self):
"""Get the authenticated user's ID"""
try:
response = self._make_curl_request("GET", "/me")
return response["data"]["id"]
except Exception as e:
raise Exception(f"Failed to get user ID: {str(e)}")
def publish_article(self, title, content, tags=None, publish_status="draft"):
"""
Publish an article to Medium
Args:
title (str): Article title
content (str): Article content in markdown format
tags (list): List of tags for the article
publish_status (str): Either 'draft', 'public', or 'unlisted'
"""
if not title or not content:
raise ValueError("Title and content are required")
if publish_status not in ["draft", "public", "unlisted"]:
raise ValueError("publish_status must be 'draft', 'public', or 'unlisted'")
try:
user_id = self.get_user_id()
data = {
"title": title,
"contentFormat": "markdown",
"content": content,
"publishStatus": publish_status,
}
if tags:
data["tags"] = tags
response = self._make_curl_request("POST", f"/users/{user_id}/posts", data)
return response
except Exception as e:
raise Exception(f"Failed to publish article: {str(e)}")
def get_user_articles(self):
"""Get all articles for the authenticated user"""
try:
user_id = self.get_user_id()
response = self._make_curl_request("GET", f"/users/{user_id}/publications")
return response
except Exception as e:
raise Exception(f"Failed to get articles: {str(e)}")
# Example usage
if __name__ == "__main__":
# Test the API connection
try:
publisher = MediumPublisher()
user_id = publisher.get_user_id()
print(f"Successfully connected to Medium API. User ID: {user_id}")
# Test with a sample article
sample_content = """# Test Article
This is a test article created via the Medium API.
## Features
- Markdown support
- API integration
- Easy publishing
*This is a test article.*"""
response = publisher.publish_article(
title="API Test Article",
content=sample_content,
tags=["test", "api", "python"],
publish_status="draft",
)
print("Article published successfully!")
print(json.dumps(response, indent=2))
except Exception as e:
print(f"Error: {e}")