rsshub
Version:
Make RSS Great Again!
176 lines (146 loc) • 5.48 kB
text/typescript
import { getSubPath } from '@/utils/common-utils';
import got from '@/utils/got';
import { load } from 'cheerio';
import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import dayjs from 'dayjs';
import path from 'node:path';
const rootUrl = 'https://www.dlsite.com';
const defaultFilters = {
show_type: 1,
show_layout: 1,
per_page: 100,
};
const formatDate = (date, format) => dayjs(date).format(format);
const addFilters = (url, filters) => {
const keys = Object.keys(filters);
const filterStr = keys.map((k) => `/${k}/${filters[k]}`).join('');
const newUrl = url.replaceAll(new RegExp(`(/${keys.join(String.raw`/\w+|/`)}/\\w+)`, 'g'), '');
return `${newUrl}${/=/.test(newUrl) ? '' : '/='}${filterStr}`;
};
const getPubDate = (raw) => {
const dateMatches = raw.match(/(\d{4}).*(\d{2}).*(\d{2})/);
if (dateMatches) {
return parseDate(`${dateMatches[1]}-${dateMatches[2]}-${dateMatches[3]}`, 'YYYY-MM-DD');
}
return parseDate(raw.split(':').pop().trim(), 'MMM/DD/YYYY');
};
const getDetails = async (works) => {
const apiUrl = `${rootUrl}/home-touch/product/info/ajax?product_id=${works}`;
const detailResponse = await got({
method: 'get',
url: apiUrl,
});
return detailResponse.data;
};
const ProcessItems = async (ctx) => {
art.defaults.imports.formatDate = formatDate;
const subPath = getSubPath(ctx) === '/' ? '/home/new' : getSubPath(ctx);
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 100;
const currentUrl = `${rootUrl}${addFilters(subPath, defaultFilters)}`;
const response = await got({
method: 'get',
url: currentUrl,
});
const $ = load(response.data);
const works = $('dt.work_name').slice(0, limit);
const updatedDate = $('.work_update').length === 0 ? undefined : getPubDate($('.work_update').text());
const details = await getDetails(
works
.toArray()
.map(
(item) =>
$(item)
.find('a')
.attr('href')
.match(/_id\/(.*?)\.html/)[1]
)
.join(',')
);
const items = works.toArray().map((item) => {
item = $(item).parentsUntil('tbody, ul');
const a = item.find('.work_name a');
const title = a.text();
const link = a.attr('href');
const guid = link.match(/_id\/(.*?)\.html/)[1];
const description = item.find('.work_text').text();
const authors = item
.find('.maker_name a')
.toArray()
.map((a) => ({
name: $(a).text(),
link: $(a).attr('href'),
}));
let images = item.find('div[data-samples]').length === 0 ? [] : JSON.parse(item.find('div[data-samples]').attr('data-samples').replaceAll("'", '"')).map((s) => s.thumb);
const workCategories = item
.find('.work_category')
.find('a')
.toArray()
.map((i) => ({
text: $(i).text(),
link: $(i).attr('href'),
}));
const workGenres = item
.find('.work_genre')
.find('span[title]')
.toArray()
.map((i) => ({
text: $(i).text(),
}));
const searchTags = item
.find('.search_tag')
.find('a')
.toArray()
.map((i) => ({
text: $(i).text(),
link: $(i).attr('href'),
}));
const nameTags = item
.find('.icon_wrap')
.find('span[title]')
.toArray()
.map((i) => ({
text: $(i).text(),
}));
const detail = details[guid];
const pubDate = timezone(parseDate(detail.regist_date), +9);
const discountRate = detail.discount_rate;
const discountEndDate = detail.discount_end_date ? timezone(parseDate(detail.discount_end_date, 'MM/DD HH:mm'), +9) : undefined;
images = images.length === 0 ? [detail.work_image] : images;
return {
title: `${
discountRate
? `${discountRate}% OFF
${` ${discountEndDate ? `${dayjs(discountEndDate).format('YYYY-MM-DD HH:mm')} まで` : ''}`}`
: ' '
}${title}`,
link,
pubDate,
author: authors.map((a) => a.name).join(' / '),
category: [...workCategories.map((i) => i.text), ...workGenres.map((i) => i.text), ...searchTags.map((i) => i.text), ...nameTags.map((i) => i.text)],
guid: `dlsite-${guid}`,
description: art(path.join(__dirname, 'templates/description.art'), {
detail,
images,
authors,
discountRate,
discountEndDate,
updatedDate,
pubDate,
workCategories,
workGenres,
searchTags,
description,
}),
};
});
return {
title: $('title').text(),
description: $('meta[name="description"]').attr('content'),
link: currentUrl,
item: items,
allowEmpty: true,
};
};
export { ProcessItems };