Skip to content

Commit d3ff772

Browse files
committed
updated ebay routes according to standard
1 parent cfc0cab commit d3ff772

3 files changed

Lines changed: 122 additions & 76 deletions

File tree

lib/routes/ebay/search.ts

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Route } from '@/types';
22
import { load } from 'cheerio';
33
import ofetch from '@/utils/ofetch';
4-
import { parseDate } from '@/utils/parse-date';
54
import logger from '@/utils/logger';
65

76
export const route: Route = {
@@ -17,52 +16,59 @@ export const route: Route = {
1716
supportPodcast: false,
1817
supportScihub: false,
1918
},
19+
radar: [
20+
{
21+
source: ['ebay.com/sch/i.html'],
22+
target: (params, url) => {
23+
const searchKeywords = new URL(url).searchParams.get('_nkw');
24+
return `/search/${searchKeywords}`;
25+
},
26+
},
27+
],
2028
name: 'Search Results',
2129
maintainers: ['phoeagon'],
22-
handler,
23-
};
24-
25-
async function handler(ctx) {
26-
const { keywords } = ctx.req.param();
27-
const url = `https://www.ebay.com/sch/i.html?_nkw=${encodeURIComponent(keywords)}&_sop=10&_ipg=240`;
30+
handler: async (ctx) => {
31+
const { keywords } = ctx.req.param();
32+
const url = `https://www.ebay.com/sch/i.html?_nkw=${encodeURIComponent(keywords)}&_sop=10&_ipg=240`;
2833

29-
logger.info(`Fetching eBay search results: ${url}`);
30-
const response = await ofetch(url);
31-
logger.info(`eBay response status: ${response instanceof Response ? response.status : 'unknown'}`);
32-
const $ = load(response);
34+
logger.info(`Fetching eBay search results: ${url}`);
35+
const response = await ofetch(url);
36+
logger.info(`eBay response status: ${response instanceof Response ? response.status : 'unknown'}`);
37+
const $ = load(response);
3338

34-
const items = $('.s-item, .s-card, .s-item__wrapper.clearfix')
35-
.toArray()
36-
.map((item) => {
37-
const $item = $(item);
38-
const titleElement = $item.find('.s-item__title, .s-card__title, .s-item__title--has-tags');
39-
const title = titleElement.text().replace(/^New Listing/i, '').trim();
40-
const link = $item.find('.s-item__link, .s-card__link').attr('href');
41-
const price = $item.find('.s-item__price, .s-card__price').text().trim();
42-
const image =
43-
$item.find('.s-item__image-img img, img.s-item__image-img').attr('src') ||
44-
$item.find('.s-item__image-wrapper img').attr('src') ||
45-
$item.find('.s-card__image-img img').attr('src') ||
46-
$item.find('.s-item__image img').attr('src');
39+
const items = $('.s-item, .s-card, .s-item__wrapper.clearfix')
40+
.toArray()
41+
.map((item) => {
42+
const $item = $(item);
43+
const titleElement = $item.find('.s-item__title, .s-card__title, .s-item__title--has-tags');
44+
const title = titleElement.text().replace(/^New Listing/i, '').trim();
45+
const link = $item.find('.s-item__link, .s-card__link').attr('href');
46+
const price = $item.find('.s-item__price, .s-card__price').text().trim();
47+
const image =
48+
$item.find('.s-item__image-img img, img.s-item__image-img').attr('src') ||
49+
$item.find('.s-item__image-wrapper img').attr('src') ||
50+
$item.find('.s-card__image-img img').attr('src') ||
51+
$item.find('.s-item__image img').attr('src');
4752

48-
if (!title || !link || title.toLowerCase().includes('shop on ebay') || price === '') {
49-
return null;
50-
}
53+
if (!title || !link || title.toLowerCase().includes('shop on ebay') || price === '') {
54+
return null;
55+
}
5156

52-
return {
53-
title: `${title} - ${price}`,
54-
link,
55-
description: `<img src="${image}"><br>Price: ${price}`,
56-
category: 'eBay Search',
57-
};
58-
})
59-
.filter(Boolean);
57+
return {
58+
title: `${title} - ${price}`,
59+
link,
60+
description: `<img src="${image}"><br>Price: ${price}`,
61+
category: 'eBay Search',
62+
};
63+
})
64+
.filter(Boolean);
6065

61-
logger.info(`Found ${items.length} items on eBay`);
66+
logger.info(`Found ${items.length} items on eBay`);
6267

63-
return {
64-
title: `eBay Search: ${keywords}`,
65-
link: url,
66-
item: items,
67-
};
68-
}
68+
return {
69+
title: `eBay Search: ${keywords}`,
70+
link: url,
71+
item: items,
72+
};
73+
},
74+
};

lib/routes/ebay/user.ts

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,47 @@ export const route: Route = {
1515
supportPodcast: false,
1616
supportScihub: false,
1717
},
18+
radar: [
19+
{
20+
source: ['ebay.com/usr/:username'],
21+
target: '/user/:username',
22+
},
23+
],
1824
name: 'User Listings',
1925
maintainers: ['phoeagon'],
20-
handler,
21-
};
22-
23-
async function handler(ctx) {
24-
const { username } = ctx.req.param();
25-
const url = `https://www.ebay.com/usr/${username}`;
26+
handler: async (ctx) => {
27+
const { username } = ctx.req.param();
28+
const url = `https://www.ebay.com/usr/${username}`;
2629

27-
const response = await ofetch(url);
28-
const $ = load(response);
29-
console.log(response);
30+
const response = await ofetch(url);
31+
const $ = load(response);
3032

31-
const items = $('article.str-item-card.StoreFrontItemCard')
32-
.toArray()
33-
.map((item) => {
34-
const $item = $(item);
35-
const title = $item.find('.str-card-title .str-text-span').first().text().trim();
36-
const link = $item.find('.str-item-card__link').attr('href');
37-
const price = $item.find('.str-item-card__property-displayPrice').text().trim();
38-
const image = $item.find('.str-image img').attr('src');
33+
const items = $('article.str-item-card.StoreFrontItemCard')
34+
.toArray()
35+
.map((item) => {
36+
const $item = $(item);
37+
const title = $item.find('.str-card-title .str-text-span').first().text().trim();
38+
const link = $item.find('.str-item-card__link').attr('href');
39+
const price = $item.find('.str-item-card__property-displayPrice').text().trim();
40+
const image = $item.find('.str-image img').attr('src');
3941

40-
if (!title || !link) {
41-
return null;
42-
}
42+
if (!title || !link) {
43+
return null;
44+
}
4345

44-
return {
45-
title: `${title} - ${price}`,
46-
link,
47-
description: `<img src="${image}"><br>Price: ${price}`,
48-
author: username,
49-
};
50-
})
51-
.filter(Boolean);
46+
return {
47+
title: `${title} - ${price}`,
48+
link,
49+
description: `<img src="${image}"><br>Price: ${price}`,
50+
author: username,
51+
};
52+
})
53+
.filter(Boolean);
5254

53-
return {
54-
title: `eBay User: ${username}`,
55-
link: url,
56-
item: items,
57-
};
58-
}
55+
return {
56+
title: `eBay User: ${username}`,
57+
link: url,
58+
item: items,
59+
};
60+
},
61+
};

lib/routes/ebay/utils.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { CheerioAPI, Element } from 'cheerio';
2+
3+
/**
4+
* Transforms an eBay image URL to prefer WebP format if it's a JPG/JPEG.
5+
* @param url The original image URL.
6+
* @returns The transformed URL.
7+
*/
8+
export const transformImage = (url?: string): string | undefined => {
9+
if (!url) {
10+
return undefined;
11+
}
12+
// eBay images often look like https://i.ebayimg.com/images/g/.../s-l500.jpg
13+
// Replacing .jpg with .webp usually works if s-lXXX is used.
14+
return url.replace(/\.jpe?g$/i, '.webp');
15+
};
16+
17+
/**
18+
* Common item structure for eBay routes.
19+
*/
20+
export interface eBayItem {
21+
title: string;
22+
link: string;
23+
description: string;
24+
category?: string;
25+
author?: string;
26+
}
27+
28+
/**
29+
* Helper to extract common data from an eBay item element.
30+
* Note: Since selectors vary, this might be less useful than specific logic in each route,
31+
* but let's provide a way to standardize the output.
32+
*/
33+
export const createItem = (title: string, price: string, link: string, image?: string): eBayItem => ({
34+
title: `${title} - ${price}`,
35+
link,
36+
description: `<img src="${transformImage(image)}"><br>Price: ${price}`,
37+
});

0 commit comments

Comments
 (0)