-
Notifications
You must be signed in to change notification settings - Fork 9.6k
feat(route): add rule34video latest updates #21621
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
base: master
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,169 @@ | ||||||||
| import type { Context } from 'hono'; | ||||||||
Check failureCode scanning / oxlint simple-import-sort(imports) Error
Run autofix to sort these imports!
|
||||||||
| import { load } from 'cheerio'; | ||||||||
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show fixed
Hide fixed
|
||||||||
|
|
||||||||
| import type { Route } from '@/types'; | ||||||||
| import got from '@/utils/got'; | ||||||||
|
|
||||||||
| export const route: Route = { | ||||||||
| path: '/latest', | ||||||||
| categories: ['multimedia'], | ||||||||
| example: '/rule34video/latest', | ||||||||
| description: 'Latest updates from Rule34 Video', | ||||||||
| features: { | ||||||||
| requireConfig: false, | ||||||||
| requirePuppeteer: false, | ||||||||
| antiCrawler: false, | ||||||||
| supportBT: false, | ||||||||
| supportPodcast: false, | ||||||||
| supportScihub: false, | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| }, | ||||||||
| radar: [ | ||||||||
| { | ||||||||
| source: ['rule34video.com/latest-updates'], | ||||||||
| target: '/latest', | ||||||||
| }, | ||||||||
| ], | ||||||||
| name: 'Latest Updates', | ||||||||
| maintainers: ['Dgama'], | ||||||||
| handler, | ||||||||
| }; | ||||||||
|
|
||||||||
| interface VideoItem { | ||||||||
| title: string; | ||||||||
| link: string; | ||||||||
| preview?: string; | ||||||||
| duration?: string; | ||||||||
| added?: string; | ||||||||
| rating?: string; | ||||||||
| views?: string; | ||||||||
| hasSound: boolean; | ||||||||
| isHD: boolean; | ||||||||
| videoId?: string; | ||||||||
| } | ||||||||
|
|
||||||||
| async function handler(ctx: Context) { | ||||||||
Check failureCode scanning / oxlint eslint(no-unused-vars) Error
Parameter 'ctx' is declared but never used. Unused parameters should start with a '_'.
Consider removing this parameter. |
||||||||
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show fixed
Hide fixed
|
||||||||
| const response = await got({ | ||||||||
| method: 'get', | ||||||||
| url: 'https://www.rule34video.com/latest-updates', | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use the redirected URL instead. |
||||||||
| headers: { | ||||||||
| Referer: 'https://www.rule34video.com', | ||||||||
| }, | ||||||||
| }); | ||||||||
|
|
||||||||
| const $ = load(response.data); | ||||||||
| const items = $('a.th.js-open-popup') | ||||||||
| .toArray() | ||||||||
| .map((element) => { | ||||||||
| const $el = $(element); | ||||||||
| const title = $el.attr('title')?.trim() || $el.find('.thumb_title').text().trim(); | ||||||||
| const link = $el.attr('href')?.trim() || ''; | ||||||||
| const preview = | ||||||||
| $el.find('img.thumb.lazy-load').attr('data-original') || | ||||||||
| $el.find('img.thumb.lazy-load').attr('src') || | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not |
||||||||
| undefined; | ||||||||
| const duration = $el.find('.time').text().trim() || undefined; | ||||||||
| const added = $el.find('.added').text().replace(/\s+/g, ' ').trim() || undefined; | ||||||||
Check failureCode scanning / oxlint eslint-plugin-unicorn(prefer-string-replace-all) Error
Prefer String#replaceAll() over String#replace() when using a regex with the global flag.
Replace replace with replaceAll. |
||||||||
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Show fixed
Hide fixed
|
||||||||
| const rating = $el.find('.rating').text().trim() || undefined; | ||||||||
| const views = $el.find('.views').text().trim() || undefined; | ||||||||
| const hasSound = $el.find('.sound').length > 0; | ||||||||
| const isHD = $el.find('.quality').length > 0; | ||||||||
| const videoId = link.match(/\/video\/(\d+)\//)?.[1]; | ||||||||
|
|
||||||||
| return { | ||||||||
| title, | ||||||||
| link, | ||||||||
| preview, | ||||||||
| duration, | ||||||||
| added, | ||||||||
| rating, | ||||||||
| views, | ||||||||
| hasSound, | ||||||||
| isHD, | ||||||||
| videoId, | ||||||||
| } as VideoItem; | ||||||||
| }) | ||||||||
| .filter((item) => item.title && item.link); | ||||||||
|
|
||||||||
| return { | ||||||||
| allowEmpty: true, | ||||||||
| title: 'Rule34 Video Latest Updates', | ||||||||
| link: 'https://www.rule34video.com/latest-updates', | ||||||||
| description: 'Latest updates from Rule34 Video', | ||||||||
| item: items.map((item) => buildDataItem(item)), | ||||||||
| }; | ||||||||
| } | ||||||||
|
|
||||||||
| function buildDataItem(item: VideoItem) { | ||||||||
| const descriptionParts: string[] = []; | ||||||||
|
|
||||||||
| if (item.title) { | ||||||||
| descriptionParts.push(item.title); | ||||||||
| } | ||||||||
| if (item.duration) { | ||||||||
| descriptionParts.push(`Duration: ${item.duration}`); | ||||||||
| } | ||||||||
| if (item.views) { | ||||||||
| descriptionParts.push(`Views: ${item.views}`); | ||||||||
| } | ||||||||
| if (item.rating) { | ||||||||
| descriptionParts.push(`Rating: ${item.rating}`); | ||||||||
| } | ||||||||
|
|
||||||||
| const qualities: string[] = []; | ||||||||
| if (item.isHD) { | ||||||||
| qualities.push('HD'); | ||||||||
| } | ||||||||
| if (item.hasSound) { | ||||||||
| qualities.push('Has Sound'); | ||||||||
| } | ||||||||
| if (qualities.length > 0) { | ||||||||
| descriptionParts.push(`Quality: ${qualities.join(', ')}`); | ||||||||
| } | ||||||||
|
|
||||||||
| if (item.preview) { | ||||||||
| descriptionParts.push(`Image: ${item.preview}`); | ||||||||
| } | ||||||||
|
|
||||||||
| const description = descriptionParts.join(' | '); | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not use |
||||||||
| const pubDate = item.added ? parseRelativeDate(item.added) : new Date(); | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No fake date. |
||||||||
|
|
||||||||
| return { | ||||||||
| title: item.title, | ||||||||
| link: item.link, | ||||||||
| description, | ||||||||
| image: item.preview, | ||||||||
| pubDate: pubDate.toISOString(), | ||||||||
| guid: item.videoId ? `rule34video:${item.videoId}` : item.link, | ||||||||
| category: item.isHD ? ['HD'] : [], | ||||||||
| }; | ||||||||
| } | ||||||||
|
|
||||||||
| function parseRelativeDate(text: string) { | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not reinvent the wheels. |
||||||||
| const match = text.match(/(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago/i); | ||||||||
| if (!match) { | ||||||||
| return new Date(); | ||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No fake date. |
||||||||
| } | ||||||||
|
|
||||||||
| const value = Number(match[1]); | ||||||||
| const unit = match[2].toLowerCase(); | ||||||||
| const now = new Date(); | ||||||||
|
|
||||||||
| switch (unit) { | ||||||||
| case 'second': | ||||||||
| return new Date(now.getTime() - value * 1000); | ||||||||
| case 'minute': | ||||||||
| return new Date(now.getTime() - value * 60 * 1000); | ||||||||
| case 'hour': | ||||||||
| return new Date(now.getTime() - value * 60 * 60 * 1000); | ||||||||
| case 'day': | ||||||||
| return new Date(now.getTime() - value * 24 * 60 * 60 * 1000); | ||||||||
| case 'week': | ||||||||
| return new Date(now.getTime() - value * 7 * 24 * 60 * 60 * 1000); | ||||||||
| case 'month': | ||||||||
| return new Date(now.getTime() - value * 30 * 24 * 60 * 60 * 1000); | ||||||||
| case 'year': | ||||||||
| return new Date(now.getTime() - value * 365 * 24 * 60 * 60 * 1000); | ||||||||
| default: | ||||||||
| return now; | ||||||||
| } | ||||||||
| } | ||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| import type { Namespace } from '@/types'; | ||
|
|
||
| export const namespace: Namespace = { | ||
| name: 'Rule34Video', | ||
| url: 'rule34video.com', | ||
| lang: 'en', | ||
| }; |
Uh oh!
There was an error while loading. Please reload this page.