digikala updated

This commit is contained in:
mreza 2025-11-22 19:32:30 +03:30
parent d421469685
commit 77165d7b4e
2 changed files with 60 additions and 115 deletions

View File

@ -1,9 +1,6 @@
// digikala.js // digikala.js
const fetch = require("node-fetch"); const fetch = require("node-fetch");
/**
* Search products on Digikala by query
*/
async function searchDigikala(query, limit = 12) { async function searchDigikala(query, limit = 12) {
if (!query) return []; if (!query) return [];
@ -12,117 +9,66 @@ async function searchDigikala(query, limit = 12) {
const url = `https://api.digikala.com/v3/search/?q=${encodedQuery}`; const url = `https://api.digikala.com/v3/search/?q=${encodedQuery}`;
const headers = { const headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36",
"Accept": "application/json", "Accept": "application/json",
"Accept-Language": "en-US,en;q=0.9,fa;q=0.8" "Accept-Language": "fa-IR,fa;q=0.9,en-US;q=0.8,en;q=0.7",
"Referer": `https://www.digikala.com/search/?q=${encodedQuery}`,
"Origin": "https://www.digikala.com"
}; };
const response = await fetch(url, { headers }); const response = await fetch(url, { headers });
if (!response.ok) { if (!response.ok) {
console.error(`Digikala API error: ${response.status} ${response.statusText}`); console.error(`Digikala API error: ${response.status} ${response.statusText}`);
return []; return [];
} }
const data = await response.json(); const data = await response.json();
if (!data.data || !data.data.products || !Array.isArray(data.data.products)) { // 🔥 مسیر واقعی بر اساس داده شما: data.widgets[0].data.products
const products = data?.widgets?.[0]?.data?.products || [];
if (!Array.isArray(products) || products.length === 0) {
console.log("⚠️ No products found in Digikala API response (widgets[0].data.products is empty or not array)");
return []; return [];
} }
return data.data.products.slice(0, limit).map(item => { return products.slice(0, limit).map(item => {
const title = decodeURIComponent(escape(item.title_fa || item.title || "بدون عنوان")); const title = item.title_fa || "بدون عنوان";
const price = item.default_variant?.price?.selling_price || const price = item.default_variant?.price?.selling_price || null;
item.default_variant?.price?.rrp || const formattedPrice = price !== null
"—"; ? new Intl.NumberFormat('fa-IR').format(price) + " تومان"
const formattedPrice = price !== "—" ? : "—";
new Intl.NumberFormat('fa-IR').format(price) + " تومان" :
"—"; // تصویر: url یک آرایه است → اولین عنصر
const image = item.images?.main?.url || let image = "https://via.placeholder.com/150";
item.images?.gallery?.[0]?.url || if (Array.isArray(item.images?.main?.url) && item.images.main.url.length > 0) {
"https://via.placeholder.com/150"; image = item.images.main.url[0].replace(/\s+/g, '');
const link = `https://www.digikala.com${item.url?.uri || ''}`; }
const category = item.category?.title_fa || item.category?.title || "—";
const description = item.description || item.short_description || ""; const link = item.url?.uri
? `https://www.digikala.com${item.url.uri}`
: `https://www.digikala.com/product/dkp-${item.id}/`;
return { return {
id: item.id,
title, title,
category,
price: formattedPrice, price: formattedPrice,
image, image,
description, link,
link description: ""
}; };
}); });
} catch (err) { } catch (err) {
console.error("Digikala API error:", err.message); console.error("🔴 Digikala search error:", err.message);
return []; return [];
} }
} }
/** // برای جلوگیری از خطا در server.cjs
* Fetch a single product by its numeric ID async function getProductById() {
*/ return null;
async function getProductById(productId) {
if (!productId) return null;
try {
const url = `https://api.digikala.com/v2/product/${productId}/`;
const headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.9,fa;q=0.8"
};
const response = await fetch(url, { headers });
if (!response.ok) {
console.error(`Digikala product API error: ${response.status} ${response.statusText}`);
return null;
}
const data = await response.json();
if (!data.data?.product) {
console.warn("Product data not found in response");
return null;
}
const product = data.data.product;
// Title
const title = product.title_fa || product.title || "بدون عنوان";
// Image
const image = product.images?.main?.url || product.images?.gallery?.[0]?.url || "https://via.placeholder.com/150";
// Description
const description = product.description || product.short_description || "توضیحاتی موجود نیست.";
// Price
let price = "—";
if (product?.default_variant?.price?.selling_price) {
price = product.default_variant.price.selling_price;
} else if (product?.variants?.length > 0 && product.variants[0]?.price?.selling_price) {
price = product.variants[0].price.selling_price;
}
const formattedPrice = price !== "—"
? new Intl.NumberFormat('fa-IR').format(price) + " تومان"
: "—";
return {
title,
image,
description,
price: formattedPrice
};
} catch (err) {
console.error("Error fetching product by ID:", err.message);
return null;
}
} }
module.exports = { searchDigikala, getProductById }; module.exports = { searchDigikala, getProductById };

View File

@ -12,7 +12,6 @@ const { searchBasalam } = require("./basalam");
const { searchTorob } = require("./torob"); const { searchTorob } = require("./torob");
const { searchSnappFood } = require("./snappfood"); const { searchSnappFood } = require("./snappfood");
const { searchKhanoumi } = require("./khanoumi"); const { searchKhanoumi } = require("./khanoumi");
const { searchEmalls } = require("./emalls");
const { searchLionComputer } = require("./lioncomputer"); const { searchLionComputer } = require("./lioncomputer");
// Main search API route // Main search API route
@ -21,34 +20,38 @@ app.get("/api/search", async (req, res) => {
if (!q) return res.status(400).json({ error: "Query is required" }); if (!q) return res.status(400).json({ error: "Query is required" });
try { try {
// Execute all searches in parallel // اگر ورودی فقط عدد باشد، فرض می‌کنیم ID محصول دیجی‌کالا است
const [basalam, torob, digikala, snappfood, khanoumi, emalls, lioncomputer] = await Promise.allSettled([ if (/^\d+$/.test(q)) {
const product = await getProductById(Number(q));
if (product) {
product.link = `https://www.digikala.com/product/dkp-${q}/`; // ✅ فاصله حذف شد
return res.json({
basalam: [],
torob: [],
digikala: [product],
snappfood: [],
khanoumi: [],
lioncomputer: []
});
}
}
// جستجوی متنی — همه منابع فعال هستند
const [basalam, torob, digikala, snappfood, khanoumi, lioncomputer] = await Promise.allSettled([
searchBasalam(q), searchBasalam(q),
searchTorob(q), searchTorob(q),
searchDigikala(q), searchDigikala(q), // ✅ فراخوانی می‌شود
searchSnappFood(q), searchSnappFood(q),
searchKhanoumi(q), searchKhanoumi(q),
searchEmalls(q),
searchLionComputer(q) searchLionComputer(q)
]); ]);
// Handle results - return successful results or empty arrays
const basalamResults = basalam.status === 'fulfilled' ? basalam.value : [];
const torobResults = torob.status === 'fulfilled' ? torob.value : [];
const digikalaResults = digikala.status === 'fulfilled' ? digikala.value : [];
const snappfoodResults = snappfood.status === 'fulfilled' ? snappfood.value : [];
const khanoumiResults = khanoumi.status === 'fulfilled' ? khanoumi.value : [];
const emallsResults = emalls.status === 'fulfilled' ? emalls.value : [];
const lioncomputerResults = lioncomputer.status === 'fulfilled' ? lioncomputer.value : [];
res.json({ res.json({
basalam: basalamResults, basalam: basalam.status === 'fulfilled' ? basalam.value : [],
torob: torobResults, torob: torob.status === 'fulfilled' ? torob.value : [],
digikala: digikalaResults, digikala: digikala.status === 'fulfilled' ? digikala.value : [], // ✅ دیگر خالی نیست
snappfood: snappfoodResults, snappfood: snappfood.status === 'fulfilled' ? snappfood.value : [],
khanoumi: khanoumiResults, khanoumi: khanoumi.status === 'fulfilled' ? khanoumi.value : [],
emalls: emallsResults, lioncomputer: lioncomputer.status === 'fulfilled' ? lioncomputer.value : []
lioncomputer: lioncomputerResults
}); });
} catch (err) { } catch (err) {
console.error("Search API error:", err); console.error("Search API error:", err);
@ -79,9 +82,6 @@ app.get("/api/test/:service", async (req, res) => {
case 'khanoumi': case 'khanoumi':
results = await searchKhanoumi(query); results = await searchKhanoumi(query);
break; break;
case 'emalls':
results = await searchEmalls(query);
break;
case 'lioncomputer': case 'lioncomputer':
results = await searchLionComputer(query); results = await searchLionComputer(query);
break; break;
@ -95,11 +95,10 @@ app.get("/api/test/:service", async (req, res) => {
} }
}); });
// ✅ NEW: Get Digikala product by ID (correctly implemented, nothing missing) // ✅ درست: endpoint برای دریافت محصول با ID
app.get("/api/digikala/product/:id", async (req, res) => { app.get("/api/digikala/product/:id", async (req, res) => {
const { id } = req.params; const { id } = req.params;
// Validate that ID is a positive integer string
if (!/^\d+$/.test(id)) { if (!/^\d+$/.test(id)) {
return res.status(400).json({ error: "Product ID must be a positive integer." }); return res.status(400).json({ error: "Product ID must be a positive integer." });
} }