feat(route): wellcee (#15433)

This commit is contained in:
Tony
2024-05-02 03:44:06 +08:00
committed by GitHub
parent 39e234f427
commit 0a506a9e67
7 changed files with 257 additions and 2 deletions
+2 -2
View File
@@ -4,13 +4,13 @@ import { parseDate } from '@/utils/parse-date';
export const route: Route = {
path: '/',
example: '/weekendhk',
radar: [
{
source: ['weekendhk.com/'],
target: '',
},
],
name: 'Unknown',
name: '最新文章',
maintainers: ['TonyRL'],
handler,
url: 'weekendhk.com/',
+7
View File
@@ -0,0 +1,7 @@
import type { Namespace } from '@/types';
export const namespace: Namespace = {
name: 'Wellcee 唯心所寓',
url: 'wellcee.com',
categories: ['other'],
};
+81
View File
@@ -0,0 +1,81 @@
import { Route } from '@/types';
import type { Context } from 'hono';
import { District, House } from './types';
import ofetch from '@/utils/ofetch';
import { parseDate } from '@/utils/parse-date';
import { baseUrl, getCitys, getDistricts } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { art } from '@/utils/render';
import path from 'path';
import { getCurrentPath } from '@/utils/helpers';
const __dirname = getCurrentPath(import.meta.url);
const render = (data) => art(path.join(__dirname, 'templates', 'house.art'), data);
export const route: Route = {
path: '/rent/:city/:district?',
example: '/wellcee/rent/北京',
parameters: {
city: '城市',
district: '地区',
},
name: '租房信息',
maintainers: ['TonyRL'],
handler,
url: 'www.wellcee.com',
description: '支持的城市可以通过 [/wellcee/support-city](https://rsshub.app/wellcee/support-city) 获取',
};
async function handler(ctx: Context) {
const { city, district = '' } = ctx.req.param();
const citys = await getCitys();
const cityInfo = citys.find((item) => item.chCityName === city);
if (!cityInfo) {
throw new InvalidParameterError('Invalid city');
}
let districtInfo: District | undefined;
if (district) {
const districts = await getDistricts(cityInfo.id);
const d = districts.find((item) => item.name === district);
if (!d) {
throw new InvalidParameterError('Invalid district');
}
districtInfo = d;
}
const response = await ofetch(`${baseUrl}/api/house/filter`, {
method: 'POST',
body: {
districtIds: districtInfo?.id ? [districtInfo.id] : [],
subways: [],
rentTypeIds: [],
timeTypeIds: [],
price: [],
tagTypeIds: [],
cityId: cityInfo.id,
lang: 1,
pn: 1,
},
});
const items = (response.data.list as House[]).map((item) => ({
title: item.address,
link: `${baseUrl}/rent-apartment/${item.id}`,
description: render({ item }),
pubDate: parseDate(item.loginTime, 'X'),
author: item.userInfo.name,
category: [...item.tags, ...item.typeTags],
}));
return {
title: `${city}${districtInfo?.name ?? ''}租房信息 - Wellcee`,
description: `${cityInfo.statics.online_text} ${cityInfo.statics.total_text}`,
image: cityInfo.icon,
icon: cityInfo.icon,
logo: cityInfo.icon,
link: `${baseUrl}/rent-apartment/${cityInfo.cityName}/list?cityId=${cityInfo.id}&lang=zh${district ? `#districtIds=${districtInfo?.id}` : ''}`,
item: items,
};
}
+46
View File
@@ -0,0 +1,46 @@
import { Route } from '@/types';
import type { Context } from 'hono';
import { baseUrl, getCitys, getDistricts } from './utils';
export const route: Route = {
path: '/support-city',
example: '/wellcee/support-city',
name: '支持的城市',
maintainers: ['TonyRL'],
radar: [
{
source: ['www.wellcee.com'],
},
],
handler,
url: 'www.wellcee.com',
};
async function handler(ctx: Context) {
const citys = await getCitys();
const list = await Promise.all(
citys.map(async (city) => ({
...city,
district: await getDistricts(city.id),
}))
);
const requestHost = new URL(ctx.req.url).host;
const items = list.flatMap((city) =>
city.district.map((district) => ({
title: `${city.chCityName} - ${district.name}`,
description: `${city.chCityName} - ${district.name}`,
link: `https://${requestHost}/wellcee/rent/${city.chCityName}/${district.name}`,
}))
);
return {
title: '支持的城市 - Wellcee',
description:
'上海国际化租房平台|北京合租&找室友|香港留学生租房|深圳无中介租房|广州外国人租房 |杭州高品质租房|成都房东直租;同志友好&宠物友好;Wellcee 的生活方式:社交|活动|交友|美食|宠物领养|音乐&艺术;Wellcee 的二手市集:家居|电子|奢侈品|时尚。',
link: baseUrl,
item: items,
};
}
+18
View File
@@ -0,0 +1,18 @@
租金: {{ item.rent }}<br>
{{ if item.dailyRent }}
日租: {{ item.dailyRent }}<br>
{{ /if }}
<br>
{{ if item.video }}
<video controls preload="metadata" poster="{{ item.video }}?vframe/png/offset/0">
<source src="{{ item.video }}" type="video/mp4">
</video>
<br>
{{ /if }}
{{ if item.imgs }}
{{ each item.imgs img }}
<img src="{{ img }}"><br>
{{ /each }}
{{ /if }}
+58
View File
@@ -0,0 +1,58 @@
export interface City {
id: string;
icon: string;
city: string;
enCityName: string;
cityName: string;
chCityName: string;
twCityName: string;
statics: {
total_text: string;
online_text: string;
total_count: number;
online_count: number;
};
district: District[];
}
export interface District {
id: string;
longitude: number;
latitude: number;
name: string;
business: {
id: string;
name: string;
}[];
}
export interface House {
id: string;
imgs: string[];
ev: number;
city: string;
district: string;
tagsText: string;
tags: string[];
typeTags: string[];
rent: string;
video: string;
personalDesc: string;
address: string;
longitude: number;
latitude: number;
collectNum: number;
isCollect: boolean;
userInfo: {
id: string;
name: string;
gender: number;
avatar: string;
language: string[];
loginTime: string;
tenant_status: number;
landlord_status: number;
};
loginTime: number;
dailyRent: string;
}
+45
View File
@@ -0,0 +1,45 @@
import { City, District } from './types';
import ofetch from '@/utils/ofetch';
import cache from '@/utils/cache';
import { config } from '@/config';
export const baseUrl = 'https://www.wellcee.com';
export const getCitys = () =>
cache.tryGet(
'wellcee:citys',
async () => {
const response = await ofetch(`${baseUrl}/api/home/index`, {
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
lang: '1',
userId: '',
type: '1',
}).toString(),
});
return response.data.citys;
},
config.cache.routeExpire,
false
) as Promise<City[]>;
export const getDistricts = (cityId: string) =>
cache.tryGet(
`wellcee:city:${cityId}`,
async () => {
const response = await ofetch(`${baseUrl}/api/house/filterType`, {
query: {
cityId,
lang: '1',
},
});
return response.data.district;
},
config.cache.routeExpire,
false
) as Promise<District[]>;