{"id":480859,"date":"2026-05-25T07:33:13","date_gmt":"2026-05-25T07:33:13","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=480859"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=480859","title":{"rendered":"\u0410\u0432\u0442\u043e\u043f\u043e\u0441\u0442\u0438\u043d\u0433 \u043d\u0430 8 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445: \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 waterfall, custom publisher&#8217;\u044b \u0438 API-\u043b\u043e\u0432\u0443\u0448\u043a\u0438"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u043e\u0441\u0442\u0440\u043e\u0438\u043b pipeline \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043d\u0430 8 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445. \u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u043b\u043e\u0441\u044c \u0441 50 \u043c\u0438\u043d\u0443\u0442 \u0434\u043e 90 \u0441\u0435\u043a\u0443\u043d\u0434. \u0420\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u044e, \u043f\u043e\u0447\u0435\u043c\u0443 waterfall \u043e\u0431\u0445\u043e\u0434\u0438\u0442 parallel, \u043a\u0430\u043a\u0438\u0435 API-\u043b\u043e\u0432\u0443\u0448\u043a\u0438 \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u043b\u0438\u0441\u044c, \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u0435\u0437 \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430 \u0432 \u0446\u0438\u043a\u043b\u0435 \u043d\u0435\u043b\u044c\u0437\u044f.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/62d\/2f2\/0eb\/62d2f20eb51129397159a5ec0aed0bd3.png\" width=\"1214\" height=\"1296\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/62d\/2f2\/0eb\/62d2f20eb51129397159a5ec0aed0bd3.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/62d\/2f2\/0eb\/62d2f20eb51129397159a5ec0aed0bd3.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h3>\u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438<\/h3>\n<p>\u041f\u0438\u0448\u0443 \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c. \u0414\u0432\u0430 \u0433\u043e\u0434\u0430 \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u043b\u0430\u0441\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e: \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432\u043e\u0441\u0435\u043c\u044c \u0432\u043a\u043b\u0430\u0434\u043e\u043a, \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c markdown, \u0443\u0431\u0440\u0430\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f Telegram, \u0441\u0436\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u043b\u044f Mastodon, \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u0443\u043a \u0434\u043b\u044f Bluesky (\u043b\u0438\u043c\u0438\u0442 300 \u0433\u0440\u0430\u0444\u0435\u043c), \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c URL \u0432 \u043a\u0430\u0436\u0434\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443, \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0443\u0434\u0430 \u0447\u0442\u043e \u0443\u0448\u043b\u043e. \u041f\u044f\u0442\u044c\u0434\u0435\u0441\u044f\u0442 \u043c\u0438\u043d\u0443\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b Buffer \u0438 Zapier. \u041e\u0431\u0430 \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0434\u0432\u0443\u043c \u043f\u0443\u043d\u043a\u0442\u0430\u043c: \u043d\u0435 \u0443\u043c\u0435\u044e\u0442 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c markdown \u0432 plaintext (Telegram \u0438 VK \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 `<strong>\u0436\u0438\u0440\u043d\u044b\u0439<\/strong> \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442, \u043d\u0435 \u043a\u0430\u043a \u0436\u0438\u0440\u043d\u044b\u0439), \u0438 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 AT Protocol Bluesky \u0438\u043b\u0438 GraphQL Paragraph. \u0414\u043b\u044f \u043d\u0438\u0448\u0435\u0432\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 publisher&#8217;\u044b \u2014 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043f\u0443\u0442\u044c.<\/p>\n<p>\u0417\u0430\u0434\u0430\u0447\u0430: \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0436\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u043a\u043d\u043e\u043f\u043a\u0443 \u2014 \u0438 \u0447\u0435\u0440\u0435\u0437 90 \u0441\u0435\u043a\u0443\u043d\u0434 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0431\u044b\u043b \u043d\u0430 \u0432\u0441\u0435\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445.<\/p>\n<hr\/>\n<h3>\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430: \u043f\u043e\u0447\u0435\u043c\u0443 waterfall, \u0430 \u043d\u0435 parallel<\/h3>\n<p>\u041f\u0435\u0440\u0432\u0430\u044f \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0431\u044b\u043b\u0430 \u043d\u0430\u0438\u0432\u043d\u043e\u0439: \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e. \u041f\u0440\u043e\u0432\u0430\u043b\u0438\u043b\u0430\u0441\u044c \u0441\u0440\u0430\u0437\u0443.<\/p>\n<p>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u2014 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439. \u0422\u0438\u0437\u0435\u0440\u044b Bluesky \u043d\u0443\u0436\u0434\u0430\u044e\u0442\u0441\u044f \u0432 URL WordPress, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c link cards. \u041d\u0435\u043b\u044c\u0437\u044f \u0437\u0430\u043f\u043e\u0441\u0442\u0438\u0442\u044c \u0442\u0438\u0437\u0435\u0440 \u0434\u043e \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438. <a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> \u0438 Paragraph \u0438\u043c\u0435\u044e\u0442 rate limits, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442 \u043a\u0430\u0441\u043a\u0430\u0434 429 \u043d\u0430 \u0432\u0441\u0435 publisher&#8217;\u044b. \u041e\u0434\u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043f\u043e\u0434\u0432\u0438\u0441\u0430\u0435\u0442 \u2014 \u0443\u0431\u0438\u0432\u0430\u0435\u0442 \u0432\u0435\u0441\u044c \u0437\u0430\u043f\u0443\u0441\u043a.<\/p>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435: waterfall \u0441 \u0438\u0437\u0431\u0438\u0440\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c\u044e. \u0427\u0435\u0442\u044b\u0440\u0435 \u0441\u0442\u0430\u0434\u0438\u0438, \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439.<\/p>\n<pre><code>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502  PIPELINE: WATERFALL \u0421 \u0418\u0417\u0411\u0418\u0420\u0410\u0422\u0415\u041b\u042c\u041d\u041e\u0419 \u041a\u041e\u041d\u041a\u0423\u0420\u0415\u041d\u0422\u041d\u041e\u0421\u0422\u042c\u042e                     \u2502\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 1: \u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 (\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e)                       \u2502\u2502    \u2192 \u041f\u0430\u0440\u0441\u0438\u043d\u0433 markdown-\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430                                     \u2502\u2502    \u2192 \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 Jinja2-\u0448\u0430\u0431\u043b\u043e\u043d\u044b                      \u2502\u2502    \u2192 \u0421\u0436\u0430\u0442\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043f\u043e\u0434 \u043b\u0438\u043c\u0438\u0442\u044b \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c (FFmpeg)                  \u2502\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 2: Primary Hub (\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0435)                  \u2502\u2502    \u2192 WordPress: \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2192 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e URL\u2502\u2502    \u2192 Dev.to: \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f markdown-\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u2192 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 dev.to URL      \u2502\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 3: \u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u0437\u0435\u0440\u044b (\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e, 4 \u043f\u043e\u0442\u043e\u043a\u0430)               \u2502\u2502    \u2192 Bluesky: 300 \u0433\u0440\u0430\u0444\u0435\u043c + \u0441\u0436\u0430\u0442\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 + \u0441\u0441\u044b\u043b\u043a\u0430               \u2502\u2502    \u2192 Mastodon: 500 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 + \u043c\u0435\u0434\u0438\u0430-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 + \u0441\u0441\u044b\u043b\u043a\u0430                \u2502\u2502    \u2192 Tumblr: \u0444\u043e\u0442\u043e-\u043f\u043e\u0441\u0442 + \u043f\u043e\u0434\u043f\u0438\u0441\u044c + \u0441\u0441\u044b\u043b\u043a\u0430                             \u2502\u2502    \u2192 Telegram: plaintext + \u0441\u0436\u0430\u0442\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 + \u0441\u0441\u044b\u043b\u043a\u0430                \u2502\u2502    \u2192 VK: plaintext + \u0444\u043e\u0442\u043e + \u0441\u0441\u044b\u043b\u043a\u0430                                    \u2502\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 4: \u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e)                            \u2502\u2502    \u2192 Git-\u043a\u043e\u043c\u043c\u0438\u0442 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 URL                          \u2502\u2502    \u2192 \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u0430 LLM-Wiki                                      \u2502\u2502    \u2192 \u0417\u0430\u043f\u0438\u0441\u044c execution log \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438                                 \u2502\u2502                                                                     \u2502\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0447\u0435\u043c\u0443 waterfall? \u041a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0430\u0434\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439. URL WordPress \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043f\u043e\u0441\u0442\u0438\u0442\u0441\u044f \u0441\u0438\u0440\u043e\u0442\u0441\u043a\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u0438\u0441\u0447\u0435\u0437\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 48 \u0447\u0430\u0441\u043e\u0432.<\/p>\n<hr\/>\n<h3>\u0421\u0442\u0430\u0434\u0438\u044f 1: \u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430<\/h3>\n<p>\u0417\u0434\u0435\u0441\u044c \u0443\u043c\u0438\u0440\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e pipeline&#8217;\u043e\u0432. \u041d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0441\u0442\u0438\u0442\u044c \u043e\u0434\u0438\u043d markdown \u0432 <a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a>, Telegram \u0438 Bluesky. <a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 <code>##<\/code> \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u043e. Telegram \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u044b\u0440\u043e\u0439 <code>#<\/code>. Bluesky \u0432\u044b\u0440\u0435\u0437\u0430\u0435\u0442 \u0432\u0435\u0441\u044c markdown \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 plaintext.<\/p>\n<p>\u041f\u043e\u0441\u0442\u0440\u043e\u0438\u043b \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0430 Jinja2 \u2014 \u043e\u0434\u0438\u043d \u0448\u0430\u0431\u043b\u043e\u043d \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443. \u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0434\u0438\u043d markdown-\u0444\u0430\u0439\u043b \u0432 vault LLM-Wiki. \u0410\u0434\u0430\u043f\u0442\u0435\u0440 \u0447\u0438\u0442\u0430\u0435\u0442 \u0435\u0433\u043e, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.<\/p>\n<pre><code class=\"python\"># scripts\/adaptation.pyimport refrom pathlib import Pathfrom jinja2 import Environment, FileSystemLoaderTEMPLATES_DIR = Path(__file__).parent.parent \/ \"templates\"env = Environment(loader=FileSystemLoader(TEMPLATES_DIR))def adapt_for_platform(source_md: str, platform: str) -&gt; str:    \"\"\"\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u043e\u0434 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0438\u0437 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e markdown.\"\"\"    template = env.get_template(f\"{platform}.j2\")        if platform in (\"telegram\", \"vk\"):        text = re.sub(r'\\*\\*(.*?)\\*\\*', r'\\1', source_md)   # \u0436\u0438\u0440\u043d\u044b\u0439        text = re.sub(r'\\*(.*?)\\*', r'\\1', text)             # \u043a\u0443\u0440\u0441\u0438\u0432        text = re.sub(r'__(.*?)__', r'\\1', text)            # \u043f\u043e\u0434\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435        text = re.sub(r'~~(.*?)~~', r'\\1', text)            # \u0437\u0430\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435        text = re.sub(r'\\[(.*?)\\]\\((.*?)\\)', r'\\2', text)   # \u0441\u0441\u044b\u043b\u043a\u0438 \u2192 \u0433\u043e\u043b\u044b\u0439 URL        text = re.sub(r'!\\[.*?\\]\\(.*?\\)', '', text)        # \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f        text = re.sub(r'#{1,6}\\s+', '', text)              # \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438        return template.render(content=text, has_images=False)        elif platform == \"bluesky\":        text = re.sub(r'#{1,6}\\s+', '', source_md)        text = re.sub(r'\\*\\*(.*?)\\*\\*', r'\\1', text)        text = re.sub(r'\\n+', ' ', text)        return text[:270].strip() + \"...\"  # \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u0441\u0442\u043e \u043f\u043e\u0434 URL        elif platform == \"devto\":        text = source_md.replace(\".svg)\", \".png)\")        return template.render(content=text, tags=extract_tags(source_md))        elif platform == \"wordpress\":        return template.render(content=markdown_to_html(source_md))        elif platform == \"mastodon\":        text = re.sub(r'\\*\\*(.*?)\\*\\*', r'\\1', source_md)        text = re.sub(r'\\n+', ' ', text)        return text[:470].strip() + \"...\"        elif platform == \"paragraph\":        return template.render(content=source_md, images_are_external=True)        return source_mddef extract_tags(md: str) -&gt; list:    \"\"\"\u0418\u0437\u0432\u043b\u0435\u0447\u044c \u0442\u0435\u0433\u0438 \u0438\u0437 YAML frontmatter, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0434\u043e 4 \u0434\u043b\u044f Dev.to.\"\"\"    match = re.search(r'^tags:\\s*(.+)', md, re.MULTILINE)    if match:        tags = [t.strip() for t in match.group(1).split(\",\")]        return tags[:4]    return [\"python\", \"automation\"]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c:<\/strong><\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430<\/p>\n<\/th>\n<th>\n<p align=\"left\">Markdown<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041b\u0438\u043c\u0438\u0442 \u0434\u043b\u0438\u043d\u044b<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>Telegram \/ VK<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u043b\u043d\u0430\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0422\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0432\u044c\u044e \u043f\u043e \u0433\u043e\u043b\u043e\u043c\u0443 URL<\/p>\n<\/td>\n<td>\n<p align=\"left\">~4000 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0413\u043e\u043b\u044b\u0435 URL \u0434\u043b\u044f \u043f\u0440\u0435\u0432\u044c\u044e, \u0431\u0435\u0437 markdown<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>Bluesky<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u043b\u043d\u0430\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">Blob-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 (2 \u041c\u0411 \u043c\u0430\u043a\u0441)<\/p>\n<\/td>\n<td>\n<p align=\"left\">300 \u0433\u0440\u0430\u0444\u0435\u043c<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u0434\u0441\u0447\u0451\u0442 \u0433\u0440\u0430\u0444\u0435\u043c, \u043d\u0435 \u0431\u0430\u0439\u0442\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>Mastodon<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u043b\u043d\u0430\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0432\u0443\u0445\u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">500 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>POST \/api\/v1\/media<\/code> \u2192 <code>id<\/code> \u2192 <code>POST \/api\/v1\/statuses<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\"><strong>Dev.to<\/strong><\/a><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0430\u0442\u0438\u0432\u043d\u044b\u0439<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0422\u043e\u043b\u044c\u043a\u043e PNG (SVG \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f)<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 4 \u0442\u0435\u0433\u0430, \u0440\u0435\u0436\u0438\u043c draft<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>WordPress<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">HTML<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0422\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0435 URL (free plan)<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">Scope <code>posts<\/code> \u0442\u043e\u043b\u044c\u043a\u043e, \u0431\u0435\u0437 <code>media<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>Paragraph<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0430\u0442\u0438\u0432\u043d\u044b\u0439<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0422\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0435 URL<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">GitHub raw URL \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442\u0441\u044f hotlink<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><strong>Habr<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0420\u0443\u0447\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0424\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0442\u043e\u043d, \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><a href=\"http:\/\/VC.ru\" rel=\"noopener noreferrer nofollow\"><strong>VC.ru<\/strong><\/a><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0420\u0443\u0447\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0443\u0433\u043e\u043b, \u0431\u0438\u0437\u043d\u0435\u0441-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>\u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 ~30 \u0441\u0435\u043a\u0443\u043d\u0434 \u2014 \u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0432\u0441\u0435\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c, \u043f\u0438\u0448\u0435\u0442 8 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432. \u041a\u0430\u0436\u0434\u044b\u0439 \u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 git.<\/p>\n<hr\/>\n<h3>\u0421\u0442\u0430\u0434\u0438\u044f 2: Primary Hub \u2014 WordPress \u0438 Dev.to<\/h3>\n<p>\u0414\u0432\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u043c\u0438. \u041e\u0431\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0442 URL, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 downstream-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u043c.<\/p>\n<h4>WordPress<\/h4>\n<p>WordPress \u2014 SEO-\u044f\u043a\u043e\u0440\u044c. \u0412\u0441\u0435 \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u0437\u0435\u0440\u044b \u0441\u0441\u044b\u043b\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043d\u0435\u0433\u043e \u043a\u0430\u043a \u043d\u0430 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a. \u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043d\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0443\u044e\u0442\u0441\u044f Google; WordPress \u2014 \u0434\u0430. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043f\u043e\u0441\u0442\u0438\u0442\u0441\u044f \u0441\u0438\u0440\u043e\u0442\u0441\u043a\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442.<\/p>\n<pre><code class=\"python\"># api\/publishers\/wordpress.pyimport osimport requestsACCESS_TOKEN = os.environ.get('WORDPRESS_ACCESS_TOKEN')BLOG_ID = os.environ.get('WORDPRESS_BLOG_ID')def publish_post(title: str, content: str, featured_image_url: str = None,                 categories: list = None, tags: str = \"\") -&gt; dict:    url = f\"https:\/\/public-api.wordpress.com\/rest\/v1.2\/sites\/{BLOG_ID}\/posts\/new\"    headers = {        \"Authorization\": f\"Bearer {ACCESS_TOKEN}\",        \"Content-Type\": \"application\/json\",    }    payload = {        \"title\": title,        \"content\": content,        \"status\": \"publish\",    }    if categories:        payload[\"categories\"] = categories    if tags:        payload[\"tags\"] = tags    if featured_image_url:        payload[\"featured_image\"] = featured_image_url        r = requests.post(url, headers=headers, json=payload, timeout=30)    data = r.json()        return {        \"success\": \"ID\" in data,        \"url\": data.get(\"URL\"),        \"id\": data.get(\"ID\")    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>\u041a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435:<\/strong> Free <a href=\"http:\/\/WordPress.com\" rel=\"noopener noreferrer nofollow\">WordPress.com<\/a> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e <code>posts<\/code> OAuth scope. Scope <code>media<\/code> \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e Business ($25\/\u043c\u0435\u0441). \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 API \u043d\u0430 free tier \u2014 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430. \u0420\u0435\u0448\u0435\u043d\u0438\u0435: \u0445\u043e\u0441\u0442\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435 \u0438 \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043f\u043e URL.<\/p>\n<h4>Dev.to<\/h4>\n<p><a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> \u2014 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0445\u0430\u0431. Markdown-\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439, code blocks \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442, frontmatter \u0442\u0435\u0433\u0438 \u0430\u0432\u0442\u043e-\u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0437\u0443\u044e\u0442. URL <a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u00ab\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u00bb.<\/p>\n<pre><code class=\"python\"># api\/publishers\/devto.pyimport osimport requestsAPI_KEY = os.environ.get('DEVTO_API_KEY')def publish_article(title: str, body: str, tags: list, published: bool = False) -&gt; dict:    url = \"https:\/\/dev.to\/api\/articles\"    headers = {        \"api-key\": API_KEY,        \"Content-Type\": \"application\/json\"    }        payload = {        \"article\": {            \"title\": title,            \"body_markdown\": body,            \"published\": published,            \"tags\": tags[:4]  # Hard limit Dev.to: \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 4 \u0442\u0435\u0433\u0430        }    }        r = requests.post(url, headers=headers, json=payload, timeout=30)    data = r.json()        if r.status_code == 201:        return {\"success\": True, \"url\": data.get(\"url\"), \"id\": data.get(\"id\")}    return {\"success\": False, \"error\": data.get(\"error\", f\"HTTP {r.status_code}\")}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>\u041d\u0435\u0432\u0438\u0434\u0438\u043c\u044b\u0435 \u043b\u0438\u043c\u0438\u0442\u044b:<\/strong><\/p>\n<ul>\n<li>\n<p>\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 4 \u0442\u0435\u0433\u0430. \u041f\u0440\u0438\u0441\u044b\u043b\u0430\u0442\u044c 5 \u2014 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c 422.<\/p>\n<\/li>\n<li>\n<p>SVG \u043d\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f. \u041d\u0443\u0436\u043d\u043e \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 PNG \u0447\u0435\u0440\u0435\u0437 FFmpeg \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u0436\u0438\u043c draft: <code>published: false<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a \u0432 \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u0431\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c\u0441\u044f \u0434\u043e \u0441\u0442\u0430\u0440\u0442\u0430 \u0421\u0442\u0430\u0434\u0438\u0438 3. \u0415\u0441\u043b\u0438 WordPress \u0443\u043f\u0430\u043b \u2014 pipeline \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f.<\/p>\n<hr\/>\n<h3>\u0421\u0442\u0430\u0434\u0438\u044f 3: \u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u0437\u0435\u0440\u044b \u2014 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f URL \u043e\u0442 WordPress \u0438 <a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> \u0448\u0435\u0441\u0442\u044c \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e.<\/p>\n<h4>Bluesky: AT Protocol<\/h4>\n<p>Bluesky \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 REST. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 AT Protocol \u2014 \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 blob-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0447\u0435\u0440\u0435\u0437 JSON-RPC, \u043b\u0438\u043c\u0438\u0442 blob 2 \u041c\u0411.<\/p>\n<pre><code class=\"python\"># api\/publishers\/bluesky.pyimport osimport requestsfrom datetime import datetime, timezoneHANDLE = os.environ.get('BLUESKY_HANDLE')APP_PASSWORD = os.environ.get('BLUESKY_APP_PASSWORD')BASE_URL = \"https:\/\/bsky.social\/xrpc\"def create_session() -&gt; dict:    r = requests.post(        f\"{BASE_URL}\/com.atproto.server.createSession\",        json={\"identifier\": HANDLE, \"password\": APP_PASSWORD},        timeout=30    )    data = r.json()    return {        \"success\": \"accessJwt\" in data,        \"accessJwt\": data.get(\"accessJwt\"),        \"did\": data.get(\"did\")    }def upload_blob(image_path: str, session: dict) -&gt; dict:    ext = image_path.lower().split(\".\")[-1]    mime = {\"jpg\": \"image\/jpeg\", \"jpeg\": \"image\/jpeg\",             \"png\": \"image\/png\", \"gif\": \"image\/gif\"}.get(ext, \"image\/png\")        with open(image_path, \"rb\") as f:        data = f.read()        r = requests.post(        f\"{BASE_URL}\/com.atproto.repo.uploadBlob\",        headers={            \"Authorization\": f\"Bearer {session['accessJwt']}\",            \"Content-Type\": mime        },        data=data,        timeout=120  # 1.5 \u041c\u0411 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438    )        blob = r.json().get(\"blob\")    return {\"success\": bool(blob), \"blob\": blob}def post(text: str, image_path: str = None) -&gt; dict:    session = create_session()    if not session[\"success\"]:        return session        now = datetime.now(timezone.utc).isoformat().replace(\"+00:00\", \"Z\")        record = {        \"$type\": \"app.bsky.feed.post\",        \"text\": text,        \"createdAt\": now,    }        if image_path and os.path.exists(image_path):        if os.path.getsize(image_path) &gt; 2_000_000:            compressed = image_path.replace(\".png\", \"-compressed.jpg\")            os.system(f\"ffmpeg -y -i {image_path} -q:v 2 {compressed}\")            image_path = compressed                blob = upload_blob(image_path, session)        if blob[\"success\"]:            record[\"embed\"] = {                \"$type\": \"app.bsky.embed.images\",                \"images\": [{\"alt\": \"\", \"image\": blob[\"blob\"]}]            }        r = requests.post(        f\"{BASE_URL}\/com.atproto.repo.createRecord\",        headers={\"Authorization\": f\"Bearer {session['accessJwt']}\"},        json={            \"repo\": session[\"did\"],            \"collection\": \"app.bsky.feed.post\",            \"record\": record        },        timeout=30    )        data = r.json()    if \"uri\" in data:        post_id = data[\"uri\"].split(\"\/\")[-1]        return {            \"success\": True,            \"url\": f\"https:\/\/bsky.app\/profile\/{HANDLE}\/post\/{post\\_id}\"        }    return {\"success\": False, \"error\": data}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>\u0422\u0440\u0438 \u043b\u043e\u0432\u0443\u0448\u043a\u0438:<\/strong><\/p>\n<ol>\n<li>\n<p><code>uploadBlob<\/code> \u043e\u0436\u0438\u0434\u0430\u0435\u0442 \u0441\u044b\u0440\u044b\u0435 \u0431\u0430\u0439\u0442\u044b \u0441 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c <code>Content-Type<\/code> \u2014 \u043d\u0435 multipart <code>files={...}<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0430\u0439\u043c\u0430\u0443\u0442 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e 30 \u0441\u0435\u043a\u0443\u043d\u0434 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 1.5 \u041c\u0411. \u0423\u0432\u0435\u043b\u0438\u0447\u0435\u043d \u0434\u043e 120 \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u043e\u0441\u043b\u0435 \u0442\u0440\u0451\u0445 \u043f\u043e\u0434\u0440\u044f\u0434 \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<\/li>\n<li>\n<p>\u041b\u0438\u043c\u0438\u0442 300 \u0433\u0440\u0430\u0444\u0435\u043c \u2014 hard. <code>len(text)<\/code> \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u043a\u043e\u0434\u043f\u043e\u0438\u043d\u0442\u044b; \u044f\u043f\u043e\u043d\u0441\u043a\u0438\u0435 emoji \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0433\u0440\u0430\u0444\u0435\u043c. \u041d\u0443\u0436\u0435\u043d <code>regex.findall(r'\\X', text)<\/code>.<\/p>\n<\/li>\n<\/ol>\n<h4>Mastodon: \u0434\u0432\u0443\u0445\u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u0430\u044f \u043c\u0435\u0434\u0438\u0430-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430<\/h4>\n<pre><code class=\"python\"># api\/publishers\/mastodon.pyimport osimport requestsBASE_URL = os.environ.get('MASTODON_URL')ACCESS_TOKEN = os.environ.get('MASTODON_ACCESS_TOKEN')def upload_media(image_path: str) -&gt; dict:    url = f\"{BASE_URL}\/api\/v1\/media\"    headers = {\"Authorization\": f\"Bearer {ACCESS_TOKEN}\"}        with open(image_path, \"rb\") as f:        files = {\"file\": (os.path.basename(image_path), f)}        r = requests.post(url, headers=headers, files=files, timeout=60)        data = r.json()    return {        \"success\": \"id\" in data,        \"id\": data.get(\"id\"),        \"url\": data.get(\"url\")    }def post_status(text: str, media_ids: list = None) -&gt; dict:    url = f\"{BASE_URL}\/api\/v1\/statuses\"    headers = {\"Authorization\": f\"Bearer {ACCESS_TOKEN}\"}    payload = {\"status\": text}    if media_ids:        payload[\"media_ids[]\"] = media_ids        r = requests.post(url, headers=headers, data=payload, timeout=30)    data = r.json()        return {        \"success\": \"id\" in data,        \"url\": data.get(\"url\")    }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0434\u043d\u0438\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 \u0441 \u0442\u0435\u043a\u0441\u0442\u043e\u043c \u0438 \u0444\u0430\u0439\u043b\u043e\u043c \u2014 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0414\u0432\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b.<\/p>\n<h4>Telegram: Bot API<\/h4>\n<pre><code class=\"python\"># api\/publishers\/telegram.pyimport osimport requestsBOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')CHAT_ID = os.environ.get('TELEGRAM_CHAT_ID')BASE_URL = f\"https:\/\/api.telegram.org\/bot{BOT\\_TOKEN}\"def send_message(text: str) -&gt; dict:    url = f\"{BASE_URL}\/sendMessage\"    payload = {        \"chat_id\": CHAT_ID,        \"text\": text,        \"parse_mode\": \"HTML\",        \"disable_web_page_preview\": False    }    r = requests.post(url, json=payload, timeout=30)    data = r.json()    return {\"success\": data.get(\"ok\"), \"message_id\": data.get(\"result\", {}).get(\"message_id\")}def send_photo(image_path: str, caption: str = \"\") -&gt; dict:    url = f\"{BASE_URL}\/sendPhoto\"        with open(image_path, \"rb\") as f:        files = {\"photo\": f}        payload = {\"chat_id\": CHAT_ID, \"caption\": caption, \"parse_mode\": \"HTML\"}        r = requests.post(url, data=payload, files=files, timeout=60)        data = r.json()    return {\"success\": data.get(\"ok\"), \"message_id\": data.get(\"result\", {}).get(\"message_id\")}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 Telegram:<\/strong><\/p>\n<ul>\n<li>\n<p><code>parse_mode: HTML<\/code> \u2014 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 <code>&lt;b&gt;<\/code>, <code>&lt;i&gt;<\/code>, <code>&lt;a&gt;<\/code>, \u043d\u043e \u043d\u0435 markdown.<\/p>\n<\/li>\n<li>\n<p><code>disable_web_page_preview: False<\/code> \u2014 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043f\u0440\u0435\u0432\u044c\u044e \u043f\u043e \u0433\u043e\u043b\u044b\u043c URL.<\/p>\n<\/li>\n<li>\n<p>\u0424\u043e\u0442\u043e-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430: multipart POST \u0441 \u0444\u0430\u0439\u043b\u043e\u043c, \u043d\u0435 base64.<\/p>\n<\/li>\n<li>\n<p>\u041b\u0438\u043c\u0438\u0442 caption: 1024 \u0441\u0438\u043c\u0432\u043e\u043b\u0430. \u0411\u043e\u043b\u044c\u0448\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442 \u0431\u0435\u0437 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438.<\/p>\n<\/li>\n<\/ul>\n<h4>VK: photos.upload + wall.post<\/h4>\n<p>VK API \u2014 \u0441\u0430\u043c\u044b\u0439 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0438\u0437 \u0432\u0441\u0435\u0445. \u0422\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u043e\u0442\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 VK, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f owner_id \u0438 photo_id, \u0437\u0430\u0442\u0435\u043c \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f \u043a \u0437\u0430\u043f\u0438\u0441\u0438 \u043d\u0430 \u0441\u0442\u0435\u043d\u0435.<\/p>\n<pre><code class=\"bash\"># \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c URL \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438VK_UPLOAD_URL=$(curl -s \"https:\/\/api.vk.com\/method\/photos.getWallUploadServer?access\\_token=${VK\\_TOKEN}&amp;v=5.199\" | jq -r '.response.upload_url')# \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u043e\u0442\u043e \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 VKUPLOAD_RESPONSE=$(curl -s -F \"photo=@${IMAGE_PATH}\" \"${VK_UPLOAD_URL}\")# \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0444\u043e\u0442\u043e \u043d\u0430 \u0441\u0442\u0435\u043d\u0435SAVE_RESPONSE=$(curl -s \"https:\/\/api.vk.com\/method\/photos.saveWallPhoto?server=${SERVER}&amp;photo=${PHOTO}&amp;hash=${HASH}&amp;access\\_token=${VK\\_TOKEN}&amp;v=5.199\")OWNER_ID=$(echo $SAVE_RESPONSE | jq -r '.response[0].owner_id')PHOTO_ID=$(echo $SAVE_RESPONSE | jq -r '.response[0].id')# \u041e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u044c \u0441 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u043b\u0451\u043d\u043d\u044b\u043c \u0444\u043e\u0442\u043ecurl -s \"https:\/\/api.vk.com\/method\/wall.post?owner\\_id=${OWNER\\_ID}&amp;message=${TEXT}&amp;attachments=photo${OWNER\\_ID}\\_${PHOTO\\_ID}&amp;access\\_token=${VK\\_TOKEN}&amp;v=5.199\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>\u0421\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 VK:<\/strong><\/p>\n<ul>\n<li>\n<p>\u0422\u043e\u043a\u0435\u043d <code>access_token<\/code> \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u0430\u0432 \u0447\u0435\u0440\u0435\u0437 OAuth \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u043e\u0442\u043e \u2014 \u0434\u0432\u0443\u0445\u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u0430\u044f: \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c upload_url \u2192 POST \u0444\u0430\u0439\u043b \u2192 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c server\/photo\/hash \u2192 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>photos.saveWallPhoto<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u0420\u0435\u043a\u043b\u0430\u043c\u043d\u044b\u0435 \u0431\u043b\u043e\u043a\u0438: \u0433\u0440\u0443\u043f\u043f\u044b \u0441 &gt;1000 \u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u043e\u0432 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u043f\u043e\u043c\u0435\u0442\u043a\u0443 \u043a\u0430\u043a \u0440\u0435\u043a\u043b\u0430\u043c\u0443. \u041b\u0438\u0447\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u2014 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442.<\/p>\n<\/li>\n<li>\n<p>Rate limit: 3 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0441\u0443\u0442\u043a\u0438 \u0434\u043b\u044f \u043b\u0438\u0447\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, 50 \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f\u044b.<\/p>\n<\/li>\n<\/ul>\n<h4>Tumblr \u0438 Paragraph<\/h4>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043f\u0430\u0442\u0442\u0435\u0440\u043d\u0430\u043c \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0434\u0438\u0430 \u043f\u0435\u0440\u0432\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c, \u0437\u0430\u0442\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u043e\u0441\u0442\u0430 \u0441 media IDs \u0438\u043b\u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438 URL.<\/p>\n<hr\/>\n<h3>\u0421\u0442\u0430\u0434\u0438\u044f 4: \u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440<\/h3>\n<p>Hermes Agent \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0438, \u043d\u043e \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 autopublishes \u0431\u0435\u0437 \u044f\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f.<\/p>\n<pre><code class=\"python\"># scripts\/orchestrator.pyimport sysfrom pathlib import Pathfrom concurrent.futures import ThreadPoolExecutorsys.path.insert(0, str(Path(__file__).parent.parent))from api.publishers.bluesky import post as publish_blueskyfrom api.publishers.wordpress import publish_post as publish_wordpressfrom api.publishers.devto import publish_article as publish_devtofrom api.publishers.mastodon import post_status as publish_mastodon, upload_media as upload_mastodon_mediafrom api.publishers.telegram import send_message as send_telegram, send_photo as send_telegram_photofrom api.publishers.paragraph import publish_post as publish_paragraphfrom scripts.adaptation import adapt_for_platformdef run_pipeline(article_path: str, image_path: str, dry_run: bool = True):    with open(article_path) as f:        full_text = f.read()        # \u0421\u0442\u0430\u0434\u0438\u044f 1: \u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f    variants = {        \"wordpress\": adapt_for_platform(full_text, \"wordpress\"),        \"devto\": adapt_for_platform(full_text, \"devto\"),        \"bluesky\": adapt_for_platform(full_text, \"bluesky\"),        \"mastodon\": adapt_for_platform(full_text, \"mastodon\"),        \"telegram\": adapt_for_platform(full_text, \"telegram\"),        \"vk\": adapt_for_platform(full_text, \"vk\"),        \"tumblr\": adapt_for_platform(full_text, \"tumblr\"),        \"paragraph\": adapt_for_platform(full_text, \"paragraph\"),    }        if dry_run:        print(\"[DRY RUN] \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b:\")        for platform, text in variants.items():            print(f\"  {platform}: {len(text)} \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432\")        return        # \u0421\u0442\u0430\u0434\u0438\u044f 2: Primary Hub (\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e)    wp = publish_wordpress({        \"title\": \"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438\",        \"content\": variants[\"wordpress\"],        \"status\": \"publish\",        \"categories\": [\"Productivity\", \"Tools\"],        \"tags\": \"automation, python, publishing\"    })    canonical_url = wp.get(\"url\")        dev = publish_devto({        \"title\": \"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438\",        \"body_markdown\": variants[\"devto\"],        \"published\": False,        \"tags\": [\"python\", \"automation\", \"publishing\"]    })        # \u0421\u0442\u0430\u0434\u0438\u044f 3: \u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u0437\u0435\u0440\u044b (\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e, 6 \u043f\u043e\u0442\u043e\u043a\u043e\u0432)    def publish_bluesky_trailer():        text = f\"{variants['bluesky']} \u2192 {canonical_url}\"        return publish_bluesky(text, image_path)        def publish_mastodon_trailer():        media = upload_mastodon_media(image_path)        text = f\"{variants['mastodon']} \u2192 {dev.get('url', canonical_url)}\"        return publish_mastodon(text, [media[\"id\"]] if media[\"success\"] else [])        def publish_tumblr_post():        return publish_tumblr(image_path, variants[\"tumblr\"], canonical_url)        def publish_paragraph_article():        return publish_paragraph(\"\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u044c\u0438\", variants[\"paragraph\"])        def publish_telegram_message():        return send_telegram_photo(image_path, variants[\"telegram\"])        def publish_vk_post():        return publish_vk(image_path, variants[\"vk\"], canonical_url)        with ThreadPoolExecutor(max_workers=6) as executor:        futures = {            \"bluesky\": executor.submit(publish_bluesky_trailer),            \"mastodon\": executor.submit(publish_mastodon_trailer),            \"tumblr\": executor.submit(publish_tumblr_post),            \"paragraph\": executor.submit(publish_paragraph_article),            \"telegram\": executor.submit(publish_telegram_message),            \"vk\": executor.submit(publish_vk_post),        }        social_results = {k: v.result() for k, v in futures.items()}        # \u0421\u0442\u0430\u0434\u0438\u044f 4: \u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435    log_publish_results(wp, dev, social_results)    git_commit_with_urls(wp, dev, social_results)    update_llm_wiki_index(wp, dev, social_results)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><strong>Human-in-the-loop:<\/strong><\/p>\n<ol>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u00ab\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0439 \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u044c\u044e\u00bb<\/p>\n<\/li>\n<li>\n<p>\u0410\u0433\u0435\u043d\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u0440\u0435\u0432\u044c\u044e<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 <a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> draft (\u0441\u0430\u043c\u044b\u0439 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442)<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0433\u043e\u0432\u043e\u0440\u0438\u0442 \u00ab\u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e\u00bb \u2014 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f API-\u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e \u00ab\u043e\u0439, \u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a\u00bb. \u041a\u0430\u0436\u0434\u044b\u0439 publisher \u0438\u043c\u0435\u0435\u0442 <code>dry_run=True<\/code> \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.<\/p>\n<hr\/>\n<h3>\u041a\u0440\u0430\u0435\u0432\u044b\u0435 \u0441\u043b\u0443\u0447\u0430\u0438: \u0440\u0435\u0430\u043b\u044c\u043d\u0430\u044f \u0443\u0447\u0435\u0431\u043d\u0430\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041a\u0440\u0430\u0435\u0432\u043e\u0439 \u0441\u043b\u0443\u0447\u0430\u0439<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041a\u0430\u043a \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043b<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Bluesky blob &gt; 2 \u041c\u0411<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0422\u0440\u0438 \u043f\u043e\u0434\u0440\u044f\u0434 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432\u0435\u0447\u0435\u0440\u043e\u043c \u0447\u0435\u0442\u0432\u0435\u0440\u0433\u0430, \u0432\u0441\u0435 400 \u0431\u0435\u0437 \u0442\u0435\u043b\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0436\u0430\u0442\u0438\u0435 FFmpeg: <code>ffmpeg -y -i input.png -q:v 2 output.jpg<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">WordPress free \u043f\u043b\u0430\u043d \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442 media upload<\/p>\n<\/td>\n<td>\n<p align=\"left\">403 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0425\u043e\u0441\u0442\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435, \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043f\u043e URL<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> SVG \u0441\u043b\u043e\u043c\u0430\u043d<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043d\u0435\u0434\u0435\u043b\u044e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0430\u0441\u044c \u043f\u0443\u0441\u0442\u044b\u043c \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u043e\u043c<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>ffmpeg -y -i diagram.svg diagram.png<\/code> \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><a href=\"http:\/\/Dev.to\" rel=\"noopener noreferrer nofollow\">Dev.to<\/a> 5-\u0439 \u0442\u0435\u0433 \u043e\u0442\u043a\u043b\u043e\u043d\u0451\u043d<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u043b\u0443\u0447\u0438\u043b 422, \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u043e\u0448\u0438\u0431\u043a\u0443<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0416\u0451\u0441\u0442\u043a\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 4 \u0442\u0435\u0433\u0430. \u0411\u0435\u0437 \u043f\u0435\u0440\u0435\u0433\u043e\u0432\u043e\u0440\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Mastodon \u0434\u0432\u0443\u0445\u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u0430\u044f \u043c\u0435\u0434\u0438\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0422\u0440\u0438 \u0440\u0430\u0437\u0430 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b \u0442\u0435\u043a\u0441\u0442 \u0431\u0435\u0437 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0432\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u0430: <code>POST \/api\/v1\/media<\/code> \u2192 <code>id<\/code> \u2192 <code>POST \/api\/v1\/statuses<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Bluesky 300 \u0433\u0440\u0430\u0444\u0435\u043c<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u0441\u0442 305 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u043f\u043e\u043b\u0443\u0447\u0438\u043b <code>\"record too large\"<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u0434\u0441\u0447\u0451\u0442 \u0433\u0440\u0430\u0444\u0435\u043c \u0447\u0435\u0440\u0435\u0437 <code>regex.findall(r'\\X', text)<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Paragraph hotlink-\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">GitHub raw URL \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u043a\u0430\u043a \u0431\u0438\u0442\u044b\u0435 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">VK CDN URL \u0438\u0437 <code>photos.getById<\/code> \u043f\u043e\u0441\u043b\u0435 VK-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">LinkedIn \u0442\u043e\u043a\u0435\u043d \u0438\u0441\u0442\u0435\u043a\u0430\u0435\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u0441\u0442\u044b \u043f\u0430\u0434\u0430\u043b\u0438 \u0441 401 \u0447\u0435\u0440\u0435\u0437 60 \u0434\u043d\u0435\u0439<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0420\u0443\u0447\u043d\u043e\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435. \u0414\u043b\u044f \u0435\u0436\u0435\u043c\u0435\u0441\u044f\u0447\u043d\u043e\u0439 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0442\u0440\u0430\u0442<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Telegram \u043b\u0438\u043c\u0438\u0442 caption<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0421\u0442\u0430\u0442\u044c\u044f 1200 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u043d\u0435 \u0432\u043b\u0435\u0437\u043b\u0430 \u0432 caption \u043a \u0444\u043e\u0442\u043e<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435: \u0444\u043e\u0442\u043e \u0441 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u043c caption + \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u043c<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">VK rate limit<\/p>\n<\/td>\n<td>\n<p align=\"left\">4-\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u0441\u0443\u0442\u043a\u0438 \u0432\u0435\u0440\u043d\u0443\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0443<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043b\u0438\u043c\u0438\u0442\u0430 \u043f\u0435\u0440\u0435\u0434 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0435\u0439, \u043e\u0442\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0434\u0435\u043d\u044c<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Markdown-\u0440\u0430\u0441\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">Telegram \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b <code><strong>\u0436\u0438\u0440\u043d\u044b\u0439<\/strong><\/code> \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041f\u043e\u043b\u043d\u0430\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0430 markdown \u0434\u043b\u044f Telegram\/VK \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">NotebookLM cookies \u0438\u0441\u0442\u0435\u043a\u0430\u044e\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">Cron \u0437\u0430\u0434\u0430\u043d\u0438\u0435 \u0432 11:00 \u043c\u043e\u043b\u0447\u0430 \u043f\u0430\u0434\u0430\u043b\u043e \u043d\u0430 auth<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0414\u0432\u0443\u0445\u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u044b\u0439 cron: 10:30 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u043d\u0438\u0435 \u2192 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 cookies \u2192 11:00 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<hr\/>\n<h3>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041c\u0435\u0442\u0440\u0438\u043a\u0430<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0414\u043e pipeline<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u041f\u043e\u0441\u043b\u0435 pipeline<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0412\u0440\u0435\u043c\u044f \u043d\u0430 \u0441\u0442\u0430\u0442\u044c\u044e<\/p>\n<\/td>\n<td>\n<p align=\"left\">50 \u043c\u0438\u043d\u0443\u0442 (8 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u00d7 ~6 \u043c\u0438\u043d)<\/p>\n<\/td>\n<td>\n<p align=\"left\">90 \u0441\u0435\u043a\u0443\u043d\u0434 (\u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044f) + 5 \u043c\u0438\u043d\u0443\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b<\/p>\n<\/td>\n<td>\n<p align=\"left\">3\u20134 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u044d\u043d\u0435\u0440\u0433\u0438\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">8 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043e + \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a\u0438 \u0434\u043b\u044f 10 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041d\u0435\u0443\u0434\u0430\u0447\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">~30% (\u0437\u0430\u0431\u044b\u043b \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0443, \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442, \u0438\u0441\u0442\u0451\u043a\u0448\u0438\u0439 \u0442\u043e\u043a\u0435\u043d)<\/p>\n<\/td>\n<td>\n<p align=\"left\">~5% (\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">SEO-\u0438\u043d\u0434\u0435\u043a\u0441\u0430\u0446\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442 \u2014 \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u044d\u0444\u0435\u043c\u0435\u0440\u0435\u043d<\/p>\n<\/td>\n<td>\n<p align=\"left\">WordPress \u043a\u0430\u043a \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a, \u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0443\u0435\u0442\u0441\u044f Google<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\">8 \u0432\u043a\u043b\u0430\u0434\u043e\u043a, 8 \u0440\u0430\u0437\u043d\u044b\u0445 UI, 8 copy-paste<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041e\u0434\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u043e\u0434\u043d\u043e \u043f\u0440\u0435\u0432\u044c\u044e, \u043e\u0434\u043d\u043e \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0412\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0442\u0435\u0439<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u041d\u0435\u0442 \u2014 \u0440\u0430\u0441\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u043a\u043e\u043f\u0438\u0438 \u0440\u0430\u0441\u0445\u043e\u0434\u0438\u043b\u0438\u0441\u044c<\/p>\n<\/td>\n<td>\n<p align=\"left\">Git \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442, \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443, URL<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1038884\/\">https:\/\/habr.com\/ru\/articles\/1038884\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u043e\u0441\u0442\u0440\u043e\u0438\u043b pipeline \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u043d\u0430 8 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445. \u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u043b\u043e\u0441\u044c \u0441 50 \u043c\u0438\u043d\u0443\u0442 \u0434\u043e 90 \u0441\u0435\u043a\u0443\u043d\u0434. \u0420\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u044e, \u043f\u043e\u0447\u0435\u043c\u0443 waterfall \u043e\u0431\u0445\u043e\u0434\u0438\u0442 parallel, \u043a\u0430\u043a\u0438\u0435 API-\u043b\u043e\u0432\u0443\u0448\u043a\u0438 \u0432\u0441\u0442\u0440\u0435\u0442\u0438\u043b\u0438\u0441\u044c, \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u0435\u0437 \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430 \u0432 \u0446\u0438\u043a\u043b\u0435 \u043d\u0435\u043b\u044c\u0437\u044f.\u041f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0438\u041f\u0438\u0448\u0443 \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c. \u0414\u0432\u0430 \u0433\u043e\u0434\u0430 \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u043b\u0430\u0441\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u043e: \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432\u043e\u0441\u0435\u043c\u044c \u0432\u043a\u043b\u0430\u0434\u043e\u043a, \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c markdown, \u0443\u0431\u0440\u0430\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f Telegram, \u0441\u0436\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438 \u0434\u043b\u044f Mastodon, \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0445\u0443\u043a \u0434\u043b\u044f Bluesky (\u043b\u0438\u043c\u0438\u0442 300 \u0433\u0440\u0430\u0444\u0435\u043c), \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c URL \u0432 \u043a\u0430\u0436\u0434\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443, \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0443\u0434\u0430 \u0447\u0442\u043e \u0443\u0448\u043b\u043e. \u041f\u044f\u0442\u044c\u0434\u0435\u0441\u044f\u0442 \u043c\u0438\u043d\u0443\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0432\u043e\u0440\u0447\u0435\u0441\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.\u041f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u043b Buffer \u0438 Zapier. \u041e\u0431\u0430 \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u043e \u0434\u0432\u0443\u043c \u043f\u0443\u043d\u043a\u0442\u0430\u043c: \u043d\u0435 \u0443\u043c\u0435\u044e\u0442 \u0430\u0434\u0430\u043f\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c markdown \u0432 plaintext (Telegram \u0438 VK \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 `\u0436\u0438\u0440\u043d\u044b\u0439 \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442, \u043d\u0435 \u043a\u0430\u043a \u0436\u0438\u0440\u043d\u044b\u0439), \u0438 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 AT Protocol Bluesky \u0438\u043b\u0438 GraphQL Paragraph. \u0414\u043b\u044f \u043d\u0438\u0448\u0435\u0432\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u044b\u0435 publisher&#8217;\u044b \u2014 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043f\u0443\u0442\u044c.\u0417\u0430\u0434\u0430\u0447\u0430: \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u0441\u0442\u0430\u0432\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0436\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u043a\u043d\u043e\u043f\u043a\u0443 \u2014 \u0438 \u0447\u0435\u0440\u0435\u0437 90 \u0441\u0435\u043a\u0443\u043d\u0434 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0431\u044b\u043b \u043d\u0430 \u0432\u0441\u0435\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u0445.\u0410\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430: \u043f\u043e\u0447\u0435\u043c\u0443 waterfall, \u0430 \u043d\u0435 parallel\u041f\u0435\u0440\u0432\u0430\u044f \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0431\u044b\u043b\u0430 \u043d\u0430\u0438\u0432\u043d\u043e\u0439: \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0432\u0441\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e. \u041f\u0440\u043e\u0432\u0430\u043b\u0438\u043b\u0430\u0441\u044c \u0441\u0440\u0430\u0437\u0443.\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u2014 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439. \u0422\u0438\u0437\u0435\u0440\u044b Bluesky \u043d\u0443\u0436\u0434\u0430\u044e\u0442\u0441\u044f \u0432 URL WordPress, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c link cards. \u041d\u0435\u043b\u044c\u0437\u044f \u0437\u0430\u043f\u043e\u0441\u0442\u0438\u0442\u044c \u0442\u0438\u0437\u0435\u0440 \u0434\u043e \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438. Dev.to \u0438 Paragraph \u0438\u043c\u0435\u044e\u0442 rate limits, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442 \u043a\u0430\u0441\u043a\u0430\u0434 429 \u043d\u0430 \u0432\u0441\u0435 publisher&#8217;\u044b. \u041e\u0434\u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430 \u043f\u043e\u0434\u0432\u0438\u0441\u0430\u0435\u0442 \u2014 \u0443\u0431\u0438\u0432\u0430\u0435\u0442 \u0432\u0435\u0441\u044c \u0437\u0430\u043f\u0443\u0441\u043a.\u0420\u0435\u0448\u0435\u043d\u0438\u0435: waterfall \u0441 \u0438\u0437\u0431\u0438\u0440\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043a\u043e\u043d\u043a\u0443\u0440\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c\u044e. \u0427\u0435\u0442\u044b\u0440\u0435 \u0441\u0442\u0430\u0434\u0438\u0438, \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439.\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\u2502  PIPELINE: WATERFALL \u0421 \u0418\u0417\u0411\u0418\u0420\u0410\u0422\u0415\u041b\u042c\u041d\u041e\u0419 \u041a\u041e\u041d\u041a\u0423\u0420\u0415\u041d\u0422\u041d\u041e\u0421\u0422\u042c\u042e                     \u2502\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 1: \u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 (\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e)                       \u2502\u2502    \u2192 \u041f\u0430\u0440\u0441\u0438\u043d\u0433 markdown-\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430                                     \u2502\u2502    \u2192 \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 Jinja2-\u0448\u0430\u0431\u043b\u043e\u043d\u044b                      \u2502\u2502    \u2192 \u0421\u0436\u0430\u0442\u0438\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u043f\u043e\u0434 \u043b\u0438\u043c\u0438\u0442\u044b \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c (FFmpeg)                  \u2502\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 2: Primary Hub (\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0435)                  \u2502\u2502    \u2192 WordPress: \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u2192 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e URL\u2502\u2502    \u2192 Dev.to: \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f markdown-\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u2192 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 dev.to URL      \u2502\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 3: \u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u0437\u0435\u0440\u044b (\u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e, 4 \u043f\u043e\u0442\u043e\u043a\u0430)               \u2502\u2502    \u2192 Bluesky: 300 \u0433\u0440\u0430\u0444\u0435\u043c + \u0441\u0436\u0430\u0442\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 + \u0441\u0441\u044b\u043b\u043a\u0430               \u2502\u2502    \u2192 Mastodon: 500 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 + \u043c\u0435\u0434\u0438\u0430-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 + \u0441\u0441\u044b\u043b\u043a\u0430                \u2502\u2502    \u2192 Tumblr: \u0444\u043e\u0442\u043e-\u043f\u043e\u0441\u0442 + \u043f\u043e\u0434\u043f\u0438\u0441\u044c + \u0441\u0441\u044b\u043b\u043a\u0430                             \u2502\u2502    \u2192 Telegram: plaintext + \u0441\u0436\u0430\u0442\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 + \u0441\u0441\u044b\u043b\u043a\u0430                \u2502\u2502    \u2192 VK: plaintext + \u0444\u043e\u0442\u043e + \u0441\u0441\u044b\u043b\u043a\u0430                                    \u2502\u2502                                                                     \u2502\u2502  \u0421\u0442\u0430\u0434\u0438\u044f 4: \u0410\u0440\u0445\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e)                            \u2502\u2502    \u2192 Git-\u043a\u043e\u043c\u043c\u0438\u0442 \u0441\u043e \u0432\u0441\u0435\u043c\u0438 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 URL                          \u2502\u2502    \u2192 \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u0430 LLM-Wiki                                      \u2502\u2502    \u2192 \u0417\u0430\u043f\u0438\u0441\u044c execution log \u0434\u043b\u044f \u043e\u0442\u043b\u0430\u0434\u043a\u0438                                 \u2502\u2502                                                                     \u2502\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\u041f\u043e\u0447\u0435\u043c\u0443 waterfall? \u041a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0430\u0434\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u044b \u0434\u043b\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439. URL WordPress \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043f\u043e\u0441\u0442\u0438\u0442\u0441\u044f \u0441\u0438\u0440\u043e\u0442\u0441\u043a\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442, \u0438\u0441\u0447\u0435\u0437\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 48 \u0447\u0430\u0441\u043e\u0432.\u0421\u0442\u0430\u0434\u0438\u044f 1: \u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430\u0417\u0434\u0435\u0441\u044c \u0443\u043c\u0438\u0440\u0430\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e pipeline&#8217;\u043e\u0432. \u041d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0441\u0442\u0438\u0442\u044c \u043e\u0434\u0438\u043d markdown \u0432 Dev.to, Telegram \u0438 Bluesky. Dev.to \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 ## \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043d\u0430\u0442\u0438\u0432\u043d\u043e. Telegram \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u044b\u0440\u043e\u0439 #. Bluesky \u0432\u044b\u0440\u0435\u0437\u0430\u0435\u0442 \u0432\u0435\u0441\u044c markdown \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 plaintext.\u041f\u043e\u0441\u0442\u0440\u043e\u0438\u043b \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0439 \u043d\u0430 Jinja2 \u2014 \u043e\u0434\u0438\u043d \u0448\u0430\u0431\u043b\u043e\u043d \u043d\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443. \u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0434\u0438\u043d markdown-\u0444\u0430\u0439\u043b \u0432 vault LLM-Wiki. \u0410\u0434\u0430\u043f\u0442\u0435\u0440 \u0447\u0438\u0442\u0430\u0435\u0442 \u0435\u0433\u043e, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442.# scripts\/adaptation.pyimport refrom pathlib import Pathfrom jinja2 import Environment, FileSystemLoaderTEMPLATES_DIR = Path(__file__).parent.parent \/ &#171;templates&#187;env = Environment(loader=FileSystemLoader(TEMPLATES_DIR))def adapt_for_platform(source_md: str, platform: str) -&gt; str:    &#171;&#187;&#187;\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043f\u043e\u0434 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0443 \u0438\u0437 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e markdown.&#187;&#187;&#187;    template = env.get_template(f&#187;{platform}.j2&#8243;)        if platform in (&#171;telegram&#187;, &#171;vk&#187;):        text = re.sub(r&#8217;\\*\\*(.*?)\\*\\*&#8217;, r&#8217;\\1&#8242;, source_md)   # \u0436\u0438\u0440\u043d\u044b\u0439        text = re.sub(r&#8217;\\*(.*?)\\*&#8217;, r&#8217;\\1&#8242;, text)             # \u043a\u0443\u0440\u0441\u0438\u0432        text = re.sub(r&#8217;__(.*?)__&#8217;, r&#8217;\\1&#8242;, text)            # \u043f\u043e\u0434\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435        text = re.sub(r&#8217;~~(.*?)~~&#8217;, r&#8217;\\1&#8242;, text)            # \u0437\u0430\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435        text = re.sub(r&#8217;\\[(.*?)\\]\\((.*?)\\)&#8217;, r&#8217;\\2&#8242;, text)   # \u0441\u0441\u044b\u043b\u043a\u0438 \u2192 \u0433\u043e\u043b\u044b\u0439 URL        text = re.sub(r&#8217;!\\[.*?\\]\\(.*?\\)&#8217;, &#187;, text)        # \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f        text = re.sub(r&#8217;#{1,6}\\s+&#8217;, &#187;, text)              # \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438        return template.render(content=text, has_images=False)        elif platform == &#171;bluesky&#187;:        text = re.sub(r&#8217;#{1,6}\\s+&#8217;, &#187;, source_md)        text = re.sub(r&#8217;\\*\\*(.*?)\\*\\*&#8217;, r&#8217;\\1&#8242;, text)        text = re.sub(r&#8217;\\n+&#8217;, &#8216; &#8216;, text)        return text[:270].strip() + &#171;&#8230;&#187;  # \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u0441\u0442\u043e \u043f\u043e\u0434 URL        elif platform == &#171;devto&#187;:        text = source_md.replace(&#171;.svg)&#187;, &#171;.png)&#187;)        return template.render(content=text, tags=extract_tags(source_md))        elif platform == &#171;wordpress&#187;:        return template.render(content=markdown_to_html(source_md))        elif platform == &#171;mastodon&#187;:        text = re.sub(r&#8217;\\*\\*(.*?)\\*\\*&#8217;, r&#8217;\\1&#8242;, source_md)        text = re.sub(r&#8217;\\n+&#8217;, &#8216; &#8216;, text)        return text[:470].strip() + &#171;&#8230;&#187;        elif platform == &#171;paragraph&#187;:        return template.render(content=source_md, images_are_external=True)        return source_mddef extract_tags(md: str) -&gt; list:    &#171;&#187;&#187;\u0418\u0437\u0432\u043b\u0435\u0447\u044c \u0442\u0435\u0433\u0438 \u0438\u0437 YAML frontmatter, \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0434\u043e 4 \u0434\u043b\u044f Dev.to.&#187;&#187;&#187;    match = re.search(r&#8217;^tags:\\s*(.+)&#8217;, md, re.MULTILINE)    if match:        tags = [t.strip() for t in match.group(1).split(&#171;,&#187;)]        return tags[:4]    return [&#171;python&#187;, &#171;automation&#187;]\u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c:\u041f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430Markdown\u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u041b\u0438\u043c\u0438\u0442 \u0434\u043b\u0438\u043d\u044b\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438Telegram \/ VK\u041f\u043e\u043b\u043d\u0430\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0430\u0422\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0432\u044c\u044e \u043f\u043e \u0433\u043e\u043b\u043e\u043c\u0443 URL~4000 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432\u0413\u043e\u043b\u044b\u0435 URL \u0434\u043b\u044f \u043f\u0440\u0435\u0432\u044c\u044e, \u0431\u0435\u0437 markdownBluesky\u041f\u043e\u043b\u043d\u0430\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0430Blob-\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 (2 \u041c\u0411 \u043c\u0430\u043a\u0441)300 \u0433\u0440\u0430\u0444\u0435\u043c\u041f\u043e\u0434\u0441\u0447\u0451\u0442 \u0433\u0440\u0430\u0444\u0435\u043c, \u043d\u0435 \u0431\u0430\u0439\u0442\u043e\u0432Mastodon\u041f\u043e\u043b\u043d\u0430\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0430\u0414\u0432\u0443\u0445\u0441\u0442\u0443\u043f\u0435\u043d\u0447\u0430\u0442\u0430\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430500 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432POST \/api\/v1\/media \u2192 id \u2192 POST \/api\/v1\/statusesDev.to\u041d\u0430\u0442\u0438\u0432\u043d\u044b\u0439\u0422\u043e\u043b\u044c\u043a\u043e PNG (SVG \u043b\u043e\u043c\u0430\u0435\u0442\u0441\u044f)\u041d\u0435\u0442\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 4 \u0442\u0435\u0433\u0430, \u0440\u0435\u0436\u0438\u043c draftWordPressHTML\u0422\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0435 URL (free plan)\u041d\u0435\u0442Scope posts \u0442\u043e\u043b\u044c\u043a\u043e, \u0431\u0435\u0437 mediaParagraph\u041d\u0430\u0442\u0438\u0432\u043d\u044b\u0439\u0422\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0435\u0448\u043d\u0438\u0435 URL\u041d\u0435\u0442GitHub raw URL \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442\u0441\u044f hotlinkHabr\u0420\u0443\u0447\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u041d\u0435\u0442\u0424\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0442\u043e\u043d, \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u0434\u0430VC.ru\u0420\u0443\u0447\u043d\u0430\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0430\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0447\u0435\u0440\u0435\u0437 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u041d\u0435\u0442\u0410\u043d\u0430\u043b\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0443\u0433\u043e\u043b, \u0431\u0438\u0437\u043d\u0435\u0441-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0410\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 ~30 \u0441\u0435\u043a\u0443\u043d\u0434 \u2014 \u0447\u0438\u0442\u0430\u0435\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0432\u0441\u0435\u0445 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c, \u043f\u0438\u0448\u0435\u0442 8 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432. \u041a\u0430\u0436\u0434\u044b\u0439 \u0432\u0435\u0440\u0441\u0438\u043e\u043d\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 git.\u0421\u0442\u0430\u0434\u0438\u044f 2: Primary Hub \u2014 WordPress \u0438 Dev.to\u0414\u0432\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u043c\u0438. \u041e\u0431\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0442 URL, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 downstream-\u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u043c.WordPressWordPress \u2014 SEO-\u044f\u043a\u043e\u0440\u044c. \u0412\u0441\u0435 \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u0437\u0435\u0440\u044b \u0441\u0441\u044b\u043b\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043d\u0435\u0433\u043e \u043a\u0430\u043a \u043d\u0430 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a. \u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u043d\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u0438\u0440\u0443\u044e\u0442\u0441\u044f Google; WordPress \u2014 \u0434\u0430. \u0411\u0435\u0437 \u043d\u0435\u0433\u043e \u043f\u043e\u0441\u0442\u0438\u0442\u0441\u044f \u0441\u0438\u0440\u043e\u0442\u0441\u043a\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442.# api\/publishers\/wordpress.pyimport osimport requestsACCESS_TOKEN = os.environ.get(&#8216;WORDPRESS_ACCESS_TOKEN&#8217;)BLOG_ID = os.environ.get(&#8216;WORDPRESS_BLOG_ID&#8217;)def publish_post(title: str, content: str, featured_image_url: str = None,                 categories: list = None, tags: str = &#171;&#187;) -&gt; dict:    url = f&#187;https:\/\/public-api.wordpress.com\/rest\/v1.2\/sites\/{BLOG_ID}\/posts\/new&#187;    headers = {        &#171;Authorization&#187;: f&#187;Bearer {ACCESS_TOKEN}&#187;,        &#171;Content-Type&#187;: &#171;application\/json&#187;,    }    payload = {        &#171;title&#187;: title,        &#171;content&#187;: content,        &#171;status&#187;: &#171;publish&#187;,    }    if categories:        payload[&#171;categories&#187;] = categories    if tags:        payload[&#171;tags&#187;] = tags    if featured_image_url:        payload[&#171;featured_image&#187;] = featured_image_url        r = requests.post(url, headers=headers, json=payload, timeout=30)    data = r.json()        return {        &#171;success&#187;: &#171;ID&#187; in data,        &#171;url&#187;: data.get(&#171;URL&#187;),        &#171;id&#187;: data.get(&#171;ID&#187;)    }\u041a\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435: Free WordPress.com \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e posts OAuth scope. Scope media \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u043b\u0430\u0442\u043d\u043e\u0433\u043e Business ($25\/\u043c\u0435\u0441). \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0447\u0435\u0440\u0435\u0437 API \u043d\u0430 free tier \u2014 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u0430. \u0420\u0435\u0448\u0435\u043d\u0438\u0435: \u0445\u043e\u0441\u0442\u0438\u0442\u044c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0435 \u0438 \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043f\u043e URL.Dev.toDev.to \u2014 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0445\u0430\u0431. Markdown-\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0439, code blocks \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442, frontmatter \u0442\u0435\u0433\u0438 \u0430\u0432\u0442\u043e-\u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0437\u0443\u044e\u0442. URL Dev.to \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u00ab\u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u00bb.# api\/publishers\/devto.pyimport osimport requestsAPI_KEY = os.environ.get(&#8216;DEVTO_API_KEY&#8217;)def publish_article(title: str, body: str, tags: list, published: bool = False) -&gt; dict:    url = &#171;https:\/\/dev.to\/api\/articles&#187;    headers = {        &#171;api-key&#187;: API_KEY,        &#171;Content-Type&#187;: &#171;application\/json&#187;    }        payload = {        &#171;article&#187;: {            &#171;title&#187;: title,            &#171;body_markdown&#187;: body,            &#171;published&#187;: published,            &#171;tags&#187;: tags[:4]  # Hard limit Dev.to: \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 4 \u0442\u0435\u0433\u0430        }    }        r = requests.post(url, headers=headers, json=payload, timeout=30)    data = r.json()        if r.status_code == 201:        return {&#171;success&#187;: True, &#171;url&#187;: data.get(&#171;url&#187;), &#171;id&#187;: data.get(&#171;id&#187;)}    return {&#171;success&#187;: False, &#171;error&#187;: data.get(&#171;error&#187;, f&#187;HTTP {r.status_code}&#187;)}\u041d\u0435\u0432\u0438\u0434\u0438\u043c\u044b\u0435 \u043b\u0438\u043c\u0438\u0442\u044b:\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c 4 \u0442\u0435\u0433\u0430. \u041f\u0440\u0438\u0441\u044b\u043b\u0430\u0442\u044c 5 \u2014 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c 422.SVG \u043d\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f. \u041d\u0443\u0436\u043d\u043e \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 PNG \u0447\u0435\u0440\u0435\u0437 FFmpeg \u043f\u0435\u0440\u0435\u0434 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u043e\u0439.\u0420\u0435\u0436\u0438\u043c draft: published: false \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0447\u0435\u0440\u043d\u043e\u0432\u0438\u043a \u0432 \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0435.\u041e\u0431\u0435 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c\u0441\u044f \u0434\u043e \u0441\u0442\u0430\u0440\u0442\u0430 \u0421\u0442\u0430\u0434\u0438\u0438 3. \u0415\u0441\u043b\u0438 WordPress \u0443\u043f\u0430\u043b \u2014 pipeline \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f.\u0421\u0442\u0430\u0434\u0438\u044f 3: \u0421\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u0437\u0435\u0440\u044b \u2014 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f URL \u043e\u0442&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-480859","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/480859","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=480859"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/480859\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=480859"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=480859"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=480859"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}