Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(route): wellcee #15433

Merged
merged 1 commit into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/routes/weekendhk/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/',
Expand Down
7 changes: 7 additions & 0 deletions lib/routes/wellcee/namespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { Namespace } from '@/types';

export const namespace: Namespace = {
name: 'Wellcee 唯心所寓',
url: 'wellcee.com',
categories: ['other'],
};
81 changes: 81 additions & 0 deletions lib/routes/wellcee/rent.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 46 additions & 0 deletions lib/routes/wellcee/support-city.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions lib/routes/wellcee/templates/house.art
Original file line number Diff line number Diff line change
@@ -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 changes: 58 additions & 0 deletions lib/routes/wellcee/types.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 45 additions & 0 deletions lib/routes/wellcee/utils.ts
Original file line number Diff line number Diff line change
@@ -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[]>;