mkdir -p zing-ultra-max/functions zing-ultra-max/public cd zing-ultra-max cat > firebase.json <<'EOF' { "functions":{"source":"functions"}, "database":{"rules":"database.rules.json"}, "hosting":{"public":"public","ignore":["firebase.json","**/.*","**/node_modules/**"]} } EOF cat > database.rules.json <<'EOF' { "rules":{ "posts":{".read":"auth != null",".write":"auth != null"}, "reels":{".read":"auth != null",".write":"auth != null"}, "messages":{".read":"auth != null",".write":"auth != null"}, "profiles":{"$uid":{".read":"auth != null",".write":"auth != null && auth.uid === $uid"}}, "aiNews":{".read":"auth != null",".write":false}, "agentStatus":{".read":"auth != null",".write":false} } } EOF cat > functions/package.json <<'EOF' { "name":"zing-ultra-max", "version":"1.0.0", "main":"index.js", "engines":{"node":"20"}, "dependencies":{ "firebase-admin":"^13.0.0", "firebase-functions":"^6.0.0" } } EOF cat > functions/index.js <<'EOF' const {onSchedule}=require("firebase-functions/v2/scheduler"); const {defineSecret,defineString}=require("firebase-functions/params"); const {setGlobalOptions}=require("firebase-functions/v2"); const admin=require("firebase-admin"); const GEMINI_API_KEY=defineSecret("GEMINI_API_KEY"); const DATABASE_URL=defineString("DATABASE_URL"); admin.initializeApp({databaseURL:DATABASE_URL.value()}); setGlobalOptions({region:"europe-west1",maxInstances:3}); const db=admin.database(); const MODEL="gemini-2.5-flash"; const FEEDS=[ {lang:"ar",q:"أخبار فلسطين"}, {lang:"ar",q:"أخبار العالم"}, {lang:"he",q:"חדשות ישראל"}, {lang:"he",q:"חדשות העולם"}, {lang:"en",q:"World news"}, {lang:"en",q:"Technology news"} ]; function clean(s=""){ return s.replace(//g,"") .replace(/<[^>]*>/g," ").replace(/&/g,"&") .replace(/"/g,'"').replace(/'/g,"'") .replace(/</g,"<").replace(/>/g,">") .replace(/\s+/g," ").trim(); } function tag(x,n){ const m=x.match(new RegExp("<"+n+"[^>]*>([\\s\\S]*?)","i")); return m?clean(m[1]):""; } async function getFeed(f){ const ceid={ar:"PS:ar",he:"IL:he",en:"US:en"}[f.lang]; const hl={ar:"ar",he:"he",en:"en"}[f.lang]; const url="https://news.google.com/rss/search?q="+ encodeURIComponent(f.q)+"&hl="+hl+"&gl="+ ({ar:"PS",he:"IL",en:"US"}[f.lang])+"&ceid="+ceid; const r=await fetch(url,{headers:{"User-Agent":"ZingUltraMax/1.0"}}); if(!r.ok)throw Error("RSS "+r.status); const xml=await r.text(); return [...xml.matchAll(/([\s\S]*?)<\/item>/gi)] .slice(0,15).map(m=>{ const x=m[1],link=tag(x,"link"); let source=tag(x,"source"); try{source=source||new URL(link).hostname}catch{} return {title:tag(x,"title"),link,source,lang:f.lang,published:tag(x,"pubDate")}; }).filter(x=>x.title&&x.link); } function normalize(s){ return s.toLowerCase().replace(/[^\p{L}\p{N}]/gu,"").slice(0,100); } async function reviewNews(items){ const prompt=`أنت محرر أخبار مهني. حلل الأخبار التالية واكتب JSON فقط: {"items":[{"title":"عنوان","summary":"ملخص محايد","category":"سياسة أو اقتصاد أو تقنية أو مجتمع أو رياضة أو عالم","importance":"high أو normal","language":"ar أو he أو en"}]} لا تخترع معلومات. لا تعتبر الخبر مؤكدا بسبب تكراره. الأخبار: ${JSON.stringify(items)}`; const url="https://generativelanguage.googleapis.com/v1beta/models/"+ MODEL+":generateContent?key="+GEMINI_API_KEY.value(); const r=await fetch(url,{ method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({ contents:[{parts:[{text:prompt}]}], generationConfig:{temperature:0.2,responseMimeType:"application/json"} }) }); if(!r.ok)throw Error("Gemini error "+r.status); const j=await r.json(); const t=j.candidates?.[0]?.content?.parts?.[0]?.text||"{}"; return JSON.parse(t.replace(/```json|```/g,"").trim()); } exports.collectNews=onSchedule({ schedule:"every 15 minutes", timeZone:"Asia/Jerusalem", secrets:[GEMINI_API_KEY], timeoutSeconds:120, memory:"512MiB" },async()=>{ const results=await Promise.allSettled(FEEDS.map(getFeed)); const all=results.filter(x=>x.status==="fulfilled").flatMap(x=>x.value); const groups=new Map(); for(const n of all){ const k=normalize(n.title); if(!groups.has(k))groups.set(k,[]); groups.get(k).push(n); } const items=[...groups.values()].map(group=>{ const n=group[0]; const sources=[...new Set(group.map(x=>x.source))]; return {...n,sources,sourceCount:sources.length}; }).sort((a,b)=>b.sourceCount-a.sourceCount).slice(0,35); if(!items.length){ await db.ref("agentStatus").set({status:"no_news",lastRun:Date.now()}); return; } let reviewed=[]; try{ const result=await reviewNews(items); reviewed=result.items||[]; }catch(e){console.error("AI review:",e);} const updates={},now=Date.now(); items.forEach((n,i)=>{ const a=reviewed[i]||{}; const id=db.ref("aiNews").push().key; updates[id]={ title:a.title||n.title, summary:a.summary||"الخبر قيد المراجعة التحريرية.", category:a.category||"عام", language:a.language||n.lang, importance:a.importance||"normal", sourceCount:n.sourceCount, sources:n.sources, verification:n.sourceCount>1?"multiple_sources":"single_source", link:n.link,published:n.published||"", createdAt:now,status:"published" }; }); await db.ref("aiNews").update(updates); await db.ref("agentStatus").set({ status:"ok",lastRun:now,itemsCollected:items.length, feedsSucceeded:results.filter(x=>x.status==="fulfilled").length }); }); EOF cat > public/index.html <<'EOF' Zing Ultra Max
جارٍ الاتصال...

شارك منشورًا

EOF cat > README-AR.txt <<'EOF' Zing Ultra Max 1. عدل firebaseConfig داخل public/index.html بقيم مشروع Firebase الحقيقي. 2. أنشئ Realtime Database وفعّل Anonymous Authentication. 3. أنشئ ملف functions/.env وضع: DATABASE_URL=https://YOUR_PROJECT-default-rtdb.firebaseio.com 4. ثبت Firebase CLI وسجل الدخول: npm install -g firebase-tools firebase login 5. ثبت التبعيات: cd functions npm install cd .. 6. أضف مفتاح Gemini كسر: firebase functions:secrets:set GEMINI_API_KEY 7. انشر: firebase deploy --only database,functions,hosting لا تضع مفتاح Gemini داخل HTML. EOF echo "تم إنشاء ملفات Zing Ultra Max داخل مجلد zing-ultra-max"