File size: 4,969 Bytes
12ac8ff 2c5aea5 12ac8ff 2c5aea5 12ac8ff afcd954 12ac8ff 2c5aea5 12ac8ff 2c5aea5 12ac8ff 2c5aea5 afcd954 12ac8ff 2c5aea5 12ac8ff afcd954 12ac8ff 2c5aea5 ecf2c66 12ac8ff ecf2c66 2c5aea5 12ac8ff 2c5aea5 ecf2c66 12ac8ff 2c5aea5 ec8c142 12ac8ff ec8c142 12ac8ff 15e2717 ec8c142 15e2717 ec8c142 12ac8ff 15e2717 e2c8dd5 6440d27 afcd954 e2c8dd5 6440d27 e2c8dd5 2c5aea5 12ac8ff afcd954 38cf376 2c5aea5 12ac8ff afcd954 12ac8ff afcd954 2f8f693 12ac8ff afcd954 2c5aea5 ecf2c66 12ac8ff afcd954 ecf2c66 12ac8ff 2c5aea5 afcd954 12ac8ff 2c5aea5 12ac8ff afcd954 12ac8ff 2c5aea5 12ac8ff 2c5aea5 12ac8ff |
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 138 139 140 141 142 143 |
import os
import json
import hashlib
import time
import re
from pathlib import Path
import requests
PUBLISHED_FILE = "published_posts.json"
GH_PAGES_BASE = "https://kagvi13.github.io/HMP/"
HASHNODE_TOKEN = os.environ["HASHNODE_TOKEN"]
HASHNODE_PUBLICATION_ID = os.environ["HASHNODE_PUBLICATION_ID"]
API_URL = "https://gql.hashnode.com"
def convert_md_links(md_text: str) -> str:
"""Конвертирует относительные ссылки (*.md) в абсолютные ссылки на GitHub Pages."""
def replacer(match):
text, link = match.groups()
if link.startswith("http://") or link.startswith("https://") or not link.endswith(".md"):
return match.group(0)
abs_link = GH_PAGES_BASE + link.replace(".md", "").lstrip("./")
return f"[{text}]({abs_link})"
return re.sub(r"\[([^\]]+)\]\(([^)]+)\)", replacer, md_text)
def load_published():
if Path(PUBLISHED_FILE).exists():
with open(PUBLISHED_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return {}
def save_published(data):
with open(PUBLISHED_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def file_hash(md_text: str):
return hashlib.md5(md_text.encode("utf-8")).hexdigest()
def graphql_request(query, variables):
headers = {"Authorization": f"Bearer {HASHNODE_TOKEN}", "Content-Type": "application/json"}
resp = requests.post(API_URL, json={"query": query, "variables": variables}, headers=headers)
data = resp.json()
if "errors" in data:
raise Exception(f"GraphQL errors: {data['errors']}")
return data
def create_post(title, slug, markdown_content):
query = """
mutation CreateDraft($input: CreateDraftInput!) {
createDraft(input: $input) { draft { id slug title } }
}
"""
variables = {
"input": {
"title": title,
"contentMarkdown": markdown_content,
"publicationId": HASHNODE_PUBLICATION_ID
}
}
return graphql_request(query, variables)["data"]["createDraft"]["draft"]
def update_post(post_id, title, markdown_content):
"""Обновляем уже опубликованный пост."""
query = """
mutation UpdatePost($input: UpdatePostInput!) {
updatePost(input: $input) { post { id slug title } }
}
"""
variables = {
"input": {
"id": post_id,
"title": title,
"contentMarkdown": markdown_content
}
}
return graphql_request(query, variables)["data"]["updatePost"]["post"]
def publish_draft(draft_id):
query = """
mutation PublishDraft($input: PublishDraftInput!) {
publishDraft(input: $input) { post { id slug url } }
}
"""
variables = {"input": {"draftId": draft_id}}
return graphql_request(query, variables)["data"]["publishDraft"]["post"]
def main(force=False):
published = load_published()
md_files = list(Path("docs").rglob("*.md"))
for md_file in md_files:
name = md_file.stem
title = name if len(name) >= 6 else name + "-HMP"
slug = re.sub(r'[^a-z0-9-]', '-', title.lower()).strip('-')[:250]
md_text = f"Источник: [ {md_file.name} ](https://github.com/kagvi13/HMP/blob/main/docs/{md_file.name})\n\n" \
+ md_file.read_text(encoding="utf-8")
md_text = convert_md_links(md_text)
h = file_hash(md_text)
if not force and name in published and published[name].get("hash") == h:
print(f"✅ Пост '{name}' без изменений — пропускаем.")
continue
try:
if name in published and "id" in published[name]:
post = update_post(published[name]["id"], title, md_text)
print(f"♻ Обновлён пост: https://hashnode.com/@yourusername/{post['slug']}")
else:
draft = create_post(title, slug, md_text)
post = publish_draft(draft["id"])
print(f"🆕 Пост опубликован: https://hashnode.com/@yourusername/{post['slug']}")
# Обновляем локальный JSON после публикации/обновления
published[name] = {"id": post["id"], "slug": post["slug"], "hash": h}
save_published(published)
print("⏱ Пауза 30 секунд перед следующим постом...")
time.sleep(30)
except Exception as e:
print(f"❌ Ошибка при публикации {name}: {e}")
save_published(published)
break
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--force", action="store_true", help="Обновить все посты, даже без изменений")
args = parser.parse_args()
main(force=args.force)
|