GitHub Action commited on
Commit
ce09a51
·
1 Parent(s): aebb950

Sync from GitHub with Git LFS

Browse files
Files changed (1) hide show
  1. scripts/publish_to_blogger.py +95 -94
scripts/publish_to_blogger.py CHANGED
@@ -1,99 +1,100 @@
1
- import json
2
  import os
 
3
  import hashlib
4
- import markdown2
5
  from googleapiclient.discovery import build
6
  from google.oauth2.credentials import Credentials
7
- from googleapiclient.errors import HttpError
8
- import pickle
9
- import time
10
-
11
- # Файлы
12
- SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
13
- JSON_FILE = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "published_posts.json"))
14
-
15
- # Загружаем токен
16
- TOKEN_FILE = os.environ.get('TOKEN_FILE', 'token.pkl')
17
- with open(TOKEN_FILE, 'rb') as f:
18
- creds = pickle.load(f)
19
-
20
- service = build('blogger', 'v3', credentials=creds)
21
- BLOG_ID = os.environ['BLOG_ID']
22
-
23
- # Загружаем список опубликованных постов
24
- if os.path.exists(JSON_FILE):
25
- try:
26
- with open(JSON_FILE, 'r', encoding='utf-8') as f:
27
- published = json.load(f)
28
- print(f"✅ Загружен список опубликованных постов: {list(published.keys())}")
29
- except json.JSONDecodeError:
30
- print("⚠ published_posts.json пустой или поврежден — начинаем с нуля.")
31
- published = {}
32
- else:
33
- published = {}
34
  print("⚠ published_posts.json не найден — начинаем с нуля.")
35
-
36
- # Обход markdown файлов
37
- md_files = []
38
- for root, _, files in os.walk("docs"):
39
- for filename in files:
40
- if filename.endswith(".md"):
41
- md_files.append(os.path.join(root, filename))
42
-
43
- # Сортируем для последовательной публикации
44
- md_files.sort()
45
-
46
- for path in md_files:
47
- title = os.path.splitext(os.path.basename(path))[0]
48
-
49
- with open(path, 'r', encoding='utf-8') as f:
50
- md_content = f.read()
51
-
52
- html_content = markdown2.markdown(md_content)
53
- content_hash = hashlib.md5(md_content.encode('utf-8')).hexdigest()
54
-
55
- # Пропускаем если ничего не изменилось
56
- if title in published and published[title]['hash'] == content_hash:
57
- print(f"⏭ Без изменений: {title}")
58
- continue
59
-
60
- print(f"📝 Новый или изменённый пост: {title}")
61
-
62
- post = {
63
- "kind": "blogger#post",
64
- "title": title,
65
- "content": html_content
66
- }
67
-
68
- try:
69
- if title in published:
70
- # обновляем
71
- post_id = published[title]['id']
72
- updated_post = service.posts().update(
73
- blogId=BLOG_ID, postId=post_id, body=post
74
- ).execute()
75
- print(f"♻️ Пост обновлён: {updated_post['url']}")
76
- published[title] = {"id": post_id, "hash": content_hash}
77
- else:
78
- # публикуем новый
79
- new_post = service.posts().insert(
80
- blogId=BLOG_ID, body=post, isDraft=False
81
- ).execute()
82
- print(f"🆕 Пост опубликован: {new_post['url']}")
83
- published[title] = {"id": new_post['id'], "hash": content_hash}
84
-
85
- # 💾 сохраняем прогресс после каждого поста
86
- with open(JSON_FILE, 'w', encoding='utf-8') as f:
87
- json.dump(published, f, ensure_ascii=False, indent=2)
88
-
89
- print("⏱ Пауза 1 минута перед следующим постом...")
90
- time.sleep(60)
91
-
92
- except HttpError as e:
93
- if e.resp.status == 403 and "quotaExceeded" in str(e):
94
- print("⚠ Достигнут лимит Blogger API. Попробуйте снова позже.")
95
- break
96
- else:
97
- raise
98
-
99
- print("🎉 Все посты обработаны.")
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
  import os
3
+ import json
4
  import hashlib
5
+ import time
6
  from googleapiclient.discovery import build
7
  from google.oauth2.credentials import Credentials
8
+ import argparse
9
+
10
+ # === Настройки ===
11
+ SITE_DIR = "site" # HTML-файлы после mkdocs build
12
+ PUBLISHED_FILE = "published_posts.json"
13
+ SLEEP_BETWEEN_POSTS = 60 # секунд
14
+ BLOG_ID = os.environ.get("BLOG_ID")
15
+ TOKEN_FILE = os.environ.get("TOKEN_FILE", "token.pkl")
16
+
17
+ # === Утилиты ===
18
+ def md5sum(path):
19
+ with open(path, "rb") as f:
20
+ return hashlib.md5(f.read()).hexdigest()
21
+
22
+ def load_published():
23
+ if os.path.exists(PUBLISHED_FILE):
24
+ with open(PUBLISHED_FILE, "r", encoding="utf-8") as f:
25
+ return json.load(f)
 
 
 
 
 
 
 
 
 
26
  print("⚠ published_posts.json не найден — начинаем с нуля.")
27
+ return {}
28
+
29
+ def save_published(data):
30
+ with open(PUBLISHED_FILE, "w", encoding="utf-8") as f:
31
+ json.dump(data, f, ensure_ascii=False, indent=2)
32
+
33
+ def get_service():
34
+ creds = Credentials.from_authorized_user_file(TOKEN_FILE)
35
+ return build("blogger", "v3", credentials=creds)
36
+
37
+ # === Основная логика ===
38
+ def publish_site():
39
+ service = get_service()
40
+ published = load_published()
41
+
42
+ # собираем все html-файлы
43
+ html_files = []
44
+ for root, _, files in os.walk(SITE_DIR):
45
+ for name in files:
46
+ if name.endswith(".html"):
47
+ path = os.path.join(root, name)
48
+ rel_path = os.path.relpath(path, SITE_DIR) # ключ
49
+ html_files.append((rel_path, path))
50
+
51
+ for rel_path, path in html_files:
52
+ content_hash = md5sum(path)
53
+ post_meta = published.get(rel_path)
54
+
55
+ # читаем содержимое html
56
+ with open(path, "r", encoding="utf-8") as f:
57
+ html_content = f.read()
58
+
59
+ if post_meta and post_meta["hash"] == content_hash:
60
+ print(f"⏭ Пропускаем {rel_path} — без изменений")
61
+ continue
62
+
63
+ title = os.path.splitext(os.path.basename(rel_path))[0]
64
+
65
+ if post_meta: # обновление поста
66
+ post_id = post_meta["id"]
67
+ print(f"🔄 Обновляем пост {rel_path}")
68
+ post = (
69
+ service.posts()
70
+ .update(
71
+ blogId=BLOG_ID,
72
+ postId=post_id,
73
+ body={"title": title, "content": html_content},
74
+ )
75
+ .execute()
76
+ )
77
+ else: # новый пост
78
+ print(f"🆕 Публикуем новый пост {rel_path}")
79
+ post = (
80
+ service.posts()
81
+ .insert(
82
+ blogId=BLOG_ID,
83
+ body={"title": title, "content": html_content},
84
+ )
85
+ .execute()
86
+ )
87
+
88
+ url = post.get("url")
89
+ post_id = post.get("id")
90
+ print(f"✅ {rel_path} → {url}")
91
+
92
+ # сохраняем метаданные
93
+ published[rel_path] = {"id": post_id, "hash": content_hash}
94
+ save_published(published)
95
+
96
+ print(f"⏱ Пауза {SLEEP_BETWEEN_POSTS} секунд перед следующим постом…")
97
+ time.sleep(SLEEP_BETWEEN_POSTS)
98
+
99
+ if __name__ == "__main__":
100
+ publish_site()