كيف أقوم بجدولة منشورات Bluesky بدون استخدام SaaS

أقوم بجدولة ثلاثة منشورات Bluesky يومياً باستخدام GitHub Actions وملف JSONL. أنا لا أستخدم أي خدمة جدولة خارجية.

يعمل النظام باستخدام ملف واحد فقط: content/bluesky-queue.jsonl.

كل سطر في هذا الملف هو كائن JSON.

  • الأسطر التي لم تُنشر تحتوي على نص فقط.
  • الأسطر المنشورة تتضمن طابعاً زمنياً (timestamp) ومعرف URI للمنشور.

يقرأ السكربت الملف من الأعلى إلى الأسفل. يبحث عن أول سطر لا يحتوي على طابع زمني، ثم ينشره، وبعد ذلك يقوم بتحديث ذلك السطر.

لماذا أستخدم JSONL بدلاً من قاعدة بيانات:

  • من السهل تتبع التغييرات في Git.
  • يمكن لأي وظيفة CI إضافة سطر جديد إلى الملف.
  • يبقي الإعداد بسيطاً ومجانياً.

التعامل مع متطلبات Bluesky API

تتطلب Bluesky ما يسمى بـ "facets" للروابط والوسوم (hashtags). لا يمكنك مجرد إرسال نص؛ بل يجب عليك توفير مواقع البايت (byte positions) الدقيقة لهذه العناصر.

أستخدم سكربت لحساب هذه المواقع. أستخدم TextEncoder للحصول على إزاحات بايت UTF-8. هذا يمنع حدوث أخطاء عند استخدام الرموز التعبيرية (emojis)، حيث إن الحروف والبايتات ليست شيئاً واحداً.

تحسين GitHub Actions

غالباً ما يتأخر تشغيل GitHub Actions إذا قمت بجدولة المهام في بداية الساعة تماماً. ولحل هذه المشكلة، أستخدم إزاحة بالدقائق (off-minute offset). فبدلاً من الساعة 00:00، أستخدم الساعة 23:37، مما يقلل من التأخير.

أقوم أيضاً بإضافة تأخير عشوائي يتراوح بين 0 و5 دقائق قبل النشر. هذا يجعل نمط النشر يبدو أكثر بشرية، ويتجنب التوقيت الآلي الدقيق الذي قد تقلل بعض الخوارزميات من أهميته.

منع الحلقات اللانهائية

عندما يقوم السكربت بتحديث قائمة الانتظار (queue)، فإنه يقوم بعمل commit للتغيير وإعادته إلى المستودع (repository). قد يؤدي هذا إلى تشغيل سير العمل (workflow) مرة أخرى.

أحل هذه المشكلة باستخدام حارس لرسالة الـ commit:

  • يضيف السكربت [skip bluesky-queue] إلى رسالة الـ commit.
  • يتحقق سير العمل (workflow) من وجود هذا الوسم.
  • إذا وجد الوسم، فلا يتم تشغيل سير العمل.

هذا النظام هو جزء من تجربة طويلة الأمد مع المواقع التي يتم تنسيقها بواسطة الذكاء الاصطناعي (AI-curated sites). إنه يظل نظاماً رشيقاً، رخيصاً، وموثوقاً.

المصدر: https://dev.to/morinaga/how-i-schedule-three-daily-bluesky-posts-from-a-jsonl-queue-without-an-external-service-mno