feat: parse Facebook marketplace item details and test exports
This commit is contained in:
104
src/facebook.ts
104
src/facebook.ts
@@ -830,6 +830,110 @@ function parseFacebookAds(ads: FacebookAdNode[]): ListingDetails[] {
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
Parse Facebook marketplace item details into ListingDetails format
|
||||
Updated for 2026 GroupCommerceProductItem structure
|
||||
*/
|
||||
function parseFacebookItem(item: FacebookMarketplaceItem): ListingDetails | null {
|
||||
try {
|
||||
const title = item.marketplace_listing_title || item.custom_title;
|
||||
if (!title) return null;
|
||||
|
||||
const url = `https://www.facebook.com/marketplace/item/${item.id}`;
|
||||
|
||||
// Extract price information
|
||||
let cents = 0;
|
||||
let currency = "CAD"; // Default
|
||||
let amountFormatted = item.formatted_price?.text || "FREE";
|
||||
|
||||
if (item.listing_price) {
|
||||
currency = item.listing_price.currency || "CAD";
|
||||
if (item.listing_price.amount && item.listing_price.amount !== "0.00") {
|
||||
const amount = parseFloat(item.listing_price.amount);
|
||||
if (!isNaN(amount)) {
|
||||
cents = Math.round(amount * 100);
|
||||
amountFormatted = item.formatted_price?.text || formatCentsToCurrency(cents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract description
|
||||
const description = item.redacted_description?.text;
|
||||
|
||||
// Extract location
|
||||
const address = item.location_text?.text || null;
|
||||
|
||||
// Extract seller information
|
||||
const seller = item.marketplace_listing_seller ? {
|
||||
name: item.marketplace_listing_seller.name,
|
||||
id: item.marketplace_listing_seller.id
|
||||
} : undefined;
|
||||
|
||||
// Determine listing status
|
||||
let listingStatus: string | undefined;
|
||||
if (item.is_sold) {
|
||||
listingStatus = "SOLD";
|
||||
} else if (item.is_pending) {
|
||||
listingStatus = "PENDING";
|
||||
} else if (item.is_live) {
|
||||
listingStatus = "ACTIVE";
|
||||
} else if (item.is_hidden) {
|
||||
listingStatus = "HIDDEN";
|
||||
}
|
||||
|
||||
// Format creation date
|
||||
const creationDate = item.creation_time
|
||||
? new Date(item.creation_time * 1000).toISOString()
|
||||
: undefined;
|
||||
|
||||
// Determine listing type based on category or vehicle data
|
||||
let listingType = "item";
|
||||
if (item.vehicle_make_display_name || item.vehicle_odometer_data) {
|
||||
listingType = "vehicle";
|
||||
} else if (item.marketplace_listing_category_id) {
|
||||
// Could map category IDs to types, but keeping simple for now
|
||||
listingType = "item";
|
||||
}
|
||||
|
||||
const listingDetails: ListingDetails = {
|
||||
url,
|
||||
title,
|
||||
description,
|
||||
listingPrice: {
|
||||
amountFormatted,
|
||||
cents,
|
||||
currency,
|
||||
},
|
||||
address,
|
||||
creationDate,
|
||||
listingType,
|
||||
listingStatus,
|
||||
categoryId: item.marketplace_listing_category_id,
|
||||
seller,
|
||||
deliveryTypes: item.delivery_types,
|
||||
};
|
||||
|
||||
return listingDetails;
|
||||
} catch (error) {
|
||||
console.warn(`Failed to parse Facebook item ${item.id}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------- Exports for Testing -----------------------------
|
||||
// Export internal functions for comprehensive testing
|
||||
export {
|
||||
extractFacebookItemData,
|
||||
extractFacebookMarketplaceData,
|
||||
parseFacebookItem,
|
||||
parseFacebookAds,
|
||||
formatCentsToCurrency,
|
||||
loadFacebookCookies,
|
||||
formatCookiesForHeader,
|
||||
parseFacebookCookieString,
|
||||
ensureFacebookCookies,
|
||||
};
|
||||
|
||||
// ----------------------------- Main -----------------------------
|
||||
|
||||
export default async function fetchFacebookItems(
|
||||
|
||||
Reference in New Issue
Block a user