Agency-Phone تخزين الوسائط
الآن مع AgencyOS27: تحديث مجاني لكل من يملك الهاتف بالفعل.

أين تُخزَّن الصور ومقاطع الفيديو والرسائل الصوتية
كل صورة ومقطع فيديو وتسجيل شاشة ورسالة صوتية من Agency Phone يحفظها السكربت نفسه، بدءًا من الإصدار 27.1.1. أنت تختار مكان الحفظ:
| التخزين | الإعداد | مناسب لـ |
|---|---|---|
| محلي (الافتراضي) | لا يحتاج إلى شيء. يعمل مباشرة بعد التثبيت. | كل الخوادم. تبقى الملفات على خادمك، داخل قاعدة بياناتك. |
| Cloudflare R2 | حوالي 10 دقائق، مرة واحدة. مجاني حتى 10 جيجابايت. | الخوادم التي تضم الكثير من مقاطع الفيديو، أو عددًا كبيرًا جدًا من اللاعبين. |
لم يعد Fivemanage وDiscord يُستخدمان للتخزين. أما webhooks الخاصة بـ Discord فما زالت متاحة للسجلات.
التخزين المحلي (الافتراضي)
لا يوجد شيء لإعداده. ينشئ السكربت جدولين في قاعدة بياناتك عند أول تشغيل (agency_media وagency_media_parts) ويحفظ الملفات فيهما. كل ما تحتاجه هو oxmysql، وهو مطلوب للسكربت على أي حال.
ماذا يعني هذا لك:
- لا حساب ولا مفتاح API ولا resource إضافي. لا يعمل أي شيء خارج خادمك.
- التحديثات آمنة. الملفات موجودة في قاعدة البيانات وليس في مجلد الـ resource، لذلك فاستبدال المجلد عند التحديث يحافظ على كل الصور.
- النسخ الاحتياطية لقاعدة بياناتك تشمل الوسائط. تكبر قاعدة البيانات بنحو الثلث زيادة على حجم الملفات نفسها. تبلغ الصورة الواحدة حوالي 150 كيلوبايت.
- يتشارك Agency Phone وAgency Pad التخزين نفسه. الصورة الملتقطة بأحدهما تظهر في الآخر، بما في ذلك الصور المزامنة مع Agency Cloud.
- يعرضها تطبيق Agency Companion أيضًا، على iOS وAndroid وتطبيق الويب. ولا يحتاج هذا إلى أي إعداد كذلك.
السرعة
تنتقل الملفات عبر اتصال FiveM نفسه، دون أن توقف اللعبة. يحدّ FiveM من سرعة إرسال اللاعب للبيانات إلى الخادم (حوالي 165 كيلوبايت في الثانية)، وبناءً على ذلك:
| النوع | يستغرق الحفظ حوالي |
|---|---|
| صورة | ثانية واحدة |
| رسالة صوتية | أقل من ثانية |
| مقطع فيديو مدته 15 ثانية | 20 ثانية (تعرض الكاميرا التقدم بالنسبة المئوية) |
عرض الملف للاعبين الآخرين سريع، فالمقطع كاملًا يصل خلال بضع ثوانٍ. إذا كان خادمك يسجل الكثير من الفيديو، فإن Cloudflare R2 يحفظ المقاطع تقريبًا فورًا.
الإعدادات في config.lua
AgencyConfig.MediaStorage = {
Provider = 'local', -- 'محلي' أو 'cloudflare': 'local' or 'cloudflare'
MaxFileMegabytes = 10, -- أكبر حجم لملف واحد (المقاطع، التسجيلات)
TransferKilobytesPerSecond = 1000, -- 'local': سرعة إرسال الملفات إلى اللاعبين
Local = {
RetentionDays = 30, -- حذف الملفات الأقدم من هذه المدة (0 = الاحتفاظ بها دائمًا)
MaxStorageGigabytes = 10, -- حذف الأقدم أولًا عند تجاوز هذا الحجم (0 = بلا حد)
},
}
| الإعداد | وظيفته |
|---|---|
RetentionDays | تُحذف الملفات الأقدم من هذه المدة تلقائيًا مرة كل ساعة. تظهر الصورة المحذوفة في المعرض كعنصر بديل صغير. اضبطه على 0 للاحتفاظ بكل شيء. |
MaxStorageGigabytes | عندما يتجاوز حجم كل الملفات معًا هذا الحد، تُحذف الأقدم أولًا. اضبطه على 0 لإلغاء الحد. |
MaxFileMegabytes | تُرفض الملفات الأكبر من هذا الحجم. ويحدّ أيضًا من مقاطع الفيديو وتسجيلات الشاشة. |
TransferKilobytesPerSecond | السرعة لكل لاعب عند إرسال الملفات إلى اللاعبين. تبقى الأولوية دائمًا للعبة. |
Cloudflare R2 خطوة بخطوة
Cloudflare R2 مجاني حتى 10 جيجابايت من التخزين ومليون عملية رفع و10 ملايين عملية تنزيل شهريًا، ولا تكلّف عمليات التنزيل أي شيء أبدًا. تطلب Cloudflare وسيلة دفع عند تفعيل R2 حتى للخطة المجانية. لن تدفع إلا إذا تجاوزت الحدود المجانية.
1. تفعيل R2
- سجّل الدخول عبر dash.cloudflare.com (يكفي حساب مجاني).
- من القائمة على اليسار افتح Storage & databases ثم R2 Object Storage.
- أضف اشتراك R2. تعرض الصفحة أن المبلغ المستحق الآن هو $0.00. وافق على الشروط ثم اضغط Activate.
2. إنشاء bucket
- اضغط Create bucket.
- سمِّه مثلًا
myserver-media. لا يمكن تغيير الاسم لاحقًا. - اترك الموقع على Automatic وفئة التخزين على Standard.
- اضغط Create bucket.
3. جعل الملفات قابلة للعرض
- افتح الـ bucket الخاص بك وانتقل إلى Settings.
- ضمن Public Development URL اضغط Enable، واكتب
allowثم أكّد. - انسخ العنوان الذي يظهر، ويبدو مثل
https://pub-1a2b3c….r2.dev. هذا هو PublicUrl الخاص بك.
تضع Cloudflare حدودًا على عنوان r2.dev للخوادم كثيرة الازدحام. إذا كان لديك نطاق خاص بك على Cloudflare، فيمكنك إضافته ضمن Custom Domains في المكان نفسه واستخدام ذلك العنوان بدلًا من ذلك كـ PublicUrl.
4. السماح بالرفع من داخل اللعبة
- ما زلت في Settings، ابحث عن CORS Policy واضغط Add.
- احذف كل ما في حقل النص، والصق ما يلي ثم اضغط Save:
[
{
"AllowedOrigins": ["https://cfx-nui-agency-phone", "https://cfx-nui-agency-pad"],
"AllowedMethods": ["PUT", "GET"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
]
بدون هذه الخطوة لا تستطيع اللعبة الرفع، وتفشل عملية حفظ الصور. إذا غيّرت اسم مجلد الـ resource، فضع اسم مجلدك بعد cfx-nui-.
5. إنشاء مفتاح
- ارجع إلى R2 Object Storage واضغط Manage API tokens.
- اضغط Create API token (يكفي account token).
- الصلاحيات: Object Read & Write.
- عند اختيار الـ bucket، اختر الـ bucket الخاص بك فقط.
- اضغط Create. تعرض Cloudflare قيمتي Access Key ID وSecret Access Key مرة واحدة فقط، فانسخهما الآن.
- يظهر Account ID الخاص بك في نظرة R2 العامة، وهو أيضًا الجزء الأول من عنوان S3 (
https://<Account ID>.r2.cloudflarestorage.com).
6. إدخال البيانات في السكربت
تُوضع المفاتيح في config_server.lua. يقرأ هذا الملف الخادم فقط ولا يُرسَل أبدًا إلى اللاعبين. لا تضعها في config.lua: فهذا الملف يُرسَل إلى كل لاعب.
-- config_server.lua
AgencyServerConfig.Cloudflare = {
AccountId = 'your account id',
Bucket = 'myserver-media',
AccessKeyId = 'your access key id',
SecretAccessKey = 'your secret access key',
PublicUrl = 'https://pub-1a2b3c....r2.dev',
}
ثم اضبط الـ provider في config.lua وأعد تشغيل الـ resource:
AgencyConfig.MediaStorage = {
Provider = 'cloudflare',
...
}
تعرض وحدة تحكم الخادم الآن Media: storage: Cloudflare R2, bucket myserver-media. إذا كان شيء ناقصًا، تذكر وحدة التحكم ما هو، ويواصل السكربت الحفظ محليًا إلى أن يُصلَح الأمر، فلا تتوقف الكاميرا عن العمل أبدًا.
هل تستخدم Agency Phone وAgency Pad معًا؟ يمكن للاثنين استخدام الـ bucket نفسه والمفتاح نفسه، ويحتفظ كل منهما بملفاته في مجلد خاص به.
التحقق من أن كل شيء يعمل
نفّذ هذا في وحدة تحكم الخادم (أو كمشرف داخل اللعبة)، مع ID لاعب متصل حاليًا:
phonemediatest 1
يحفظ Agency Phone الخاص باللاعب صورة اختبار صغيرة، ويحمّلها مجددًا بالطريقة نفسها التي يفعلها أي لاعب آخر، ويعرضها، ثم يشغّل رسالة صوتية قصيرة. تجيب وحدة التحكم:
Media test passed for player 1 in 1361 ms: upload ok, download ok, shown as picture ok, app markup and backgrounds ok, voice message plays ok
أضف big لاختبار مقطع فيديو بحجم 6 ميجابايت أيضًا: phonemediatest 1 big.
المشكلات وحلولها
| ما تراه | الحل |
|---|---|
could not create the media tables في وحدة التحكم | oxmysql لا يعمل أو لا يستطيع الوصول إلى قاعدة البيانات. شغّل oxmysql قبل agency-phone. |
Provider is 'cloudflare', but config_server.lua is missing ... | إحدى القيم الخمس فارغة، أو أن PublicUrl لا يبدأ بـ https://. راجع الخطوة 6. |
تفشل الصور مع Cloudflare HTTP 403 | المفتاح لا يملك صلاحية الكتابة على هذا الـ bucket، أو أن اسم الـ bucket خاطئ. راجع الخطوة 5. |
تفشل الصور مع Failed to fetch على Cloudflare | سياسة CORS من الخطوة 4 غير موجودة أو تحمل اسم resource مختلفًا. |
| الصور المحفوظة لا تظهر على Cloudflare | خيار Public Development URL من الخطوة 3 غير مفعّل، أو أن PublicUrl يشير إلى bucket آخر. |
| يستغرق حفظ الفيديو وقتًا طويلًا | هذا طبيعي مع التخزين المحلي، راجع قسم السرعة أعلاه. استخدم Cloudflare R2 للحصول على مقاطع فورية. |
| اختفت الصور القديمة | حذفتها RetentionDays. ارفع قيمتها أو اضبطها على 0. |
إذا كنت قادمًا من Fivemanage أو Discord
لا شيء يحتاج إلى نقل. الصور المحفوظة سابقًا تحتفظ بروابطها القديمة وتبقى ظاهرة ما دامت تلك الخدمة لا تزال تقدمها. كل ما هو جديد يذهب إلى التخزين الذي اخترته. الإعدادات القديمة MediaStorageProvider وFiveManageApiUrl وFiveManageApiKey وScreenshotWebhook يتم تجاهلها ويمكن حذفها من ملف الإعدادات.
الأمان
- لا يستطيع الرفع إلا اللاعبون المتصلون بخادمك. يُعلَن عن كل عملية رفع أولًا ويُتحقق من نوع الملف وحجمه.
- يُفحَص المحتوى من خلال أولى بايتاته. لا يمكن أبدًا تخزين صفحة ويب أو سكربت متنكرًا في هيئة صورة.
- أسماء الملفات عشوائية بطول 128 بت، ولا يمكن تخمينها أو سرد قائمة بها.
- عمليات الرفع والتنزيل محدودة لكل لاعب.
- مع Cloudflare، تحصل كل عملية رفع على رابطها الخاص الصالح لمدة 5 دقائق، لملف واحد بالضبط من نوع واحد وبحجم واحد. ولا يغادر المفتاح السري خادمك أبدًا.