digikala updated
This commit is contained in:
parent
d421469685
commit
77165d7b4e
122
digikala.js
122
digikala.js
|
|
@ -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 };
|
||||||
53
server.cjs
53
server.cjs
|
|
@ -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." });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue