feat(route/rumble): add channel feed#21545
Conversation
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
|
I tested this route locally and it returns valid results there, but the GitHub Actions fails on the request to |
Auto ReviewNo clear rule violations found in the current diff. |
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
|
I realize, I should also clarify. The reason for no API usage is because Rumble doesn't seem to offer a web API for listing all the videos reliably. If it comes to my attention an area where it does I'd love to rewrite this since the site does often update their formatting. I'm happy to fix it if it does in the mean time though. |
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
Add a Rumble channel route so channel videos can be subscribed to through RSSHub. Use stable server-rendered selectors and normalized item URLs to keep feed entries consistent.
Add full Rumble video descriptions to channel feeds and expose an /embed route variant for readers that support iframe players. Keep the default route image-based while deriving stable embed URLs from each video page.
Match YouTube's optional embed parameter behavior so the default feed includes embedded players and any trailing path segment disables embedding. Keep full Rumble video descriptions in both output modes.
Use structured detail-page data for Rumble descriptions and fallback thumbnails while keeping the channel listing on stable server-rendered markup. Limit detail fetch concurrency so the route is less likely to trip anti-bot protections.
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |
| videoElements, | ||
| (element: Element) => { | ||
| const $video = $(element); | ||
| const $link = $video.find('.videostream__link[href]').first(); |
There was a problem hiding this comment.
Provide the URL where you do found multiple occurrences of .videostream__link[href] within a single .videostream.thumbnail__grid--item[data-video-id] which makes you used first().
| const url = new URL(href, rootUrl); | ||
| url.search = ''; | ||
|
|
||
| const $title = $video.find('.thumbnail__title').first(); |
There was a problem hiding this comment.
Provide the URL where you do found multiple occurrences of .thumbnail__title within a single .videostream.thumbnail__grid--item[data-video-id] which makes you used first().
| return null; | ||
| } | ||
|
|
||
| const imageRaw = $video.find('img.thumbnail__image, .thumbnail__thumb img').first().attr('src'); |
There was a problem hiding this comment.
Do not enumerate different combination of selectors of the same element. Beside that, provide the URL where you do found multiple occurrences of img.thumbnail__image or .thumbnail__thumb img within a single .videostream.thumbnail__grid--item[data-video-id] which makes you used first().
|
|
||
| const imageRaw = $video.find('img.thumbnail__image, .thumbnail__thumb img').first().attr('src'); | ||
| const listImage = imageRaw ? new URL(imageRaw, rootUrl).href : undefined; | ||
| const pubDateRaw = $video.find('time.videostream__time[datetime]').first().attr('datetime')?.trim(); |
There was a problem hiding this comment.
Provide the URL where you do found multiple occurrences of time.videostream__time[datetime] within a single .videostream.thumbnail__grid--item[data-video-id] which makes you used first().
| } | ||
|
|
||
| function parseStructuredVideoObject($: ReturnType<typeof load>): RumbleVideoObject | undefined { | ||
| const content = $('script[type="application/ld+json"]').first().text().trim(); |
There was a problem hiding this comment.
#21545 (comment) is marked as resolved so please provide the URL where you do found multiple occurrences of script[type="application/ld+json"] which makes you used .toArray() and first().
| return; | ||
| } | ||
|
|
||
| try { |
There was a problem hiding this comment.
#21545 (comment) is marked as resolved so please provide the URL where you do found a malformed JSON in script[type="application/ld+json"] that can't be parsed.
|
|
||
| try { | ||
| const parsed = JSON.parse(content); | ||
| const entries = Array.isArray(parsed) ? parsed : [parsed]; |
There was a problem hiding this comment.
Provide the URL where you didn’t find the JSON-LD as an array which requires [parsed].
| const videoObject = parseStructuredVideoObject($); | ||
| const image = listImage || parseImage($, videoObject); | ||
| const description = renderDescription(image, parseDescription($, videoObject?.description?.trim()), videoObject?.embedUrl, includeEmbed); | ||
| const author = videoObject?.author?.name || $('.channel-header--title').first().text().trim() || undefined; |
There was a problem hiding this comment.
#21545 (comment) is marked as resolved so please provide the URL where you do found multiple occurrences of .channel-header--title which makes you used first().
|
Successfully generated as following: http://localhost:1200/rumble/c/MikhailaPeterson - Failed ❌http://localhost:1200/rumble/c/MikhailaPeterson/noembed - Failed ❌ |



Involved Issue / 该 PR 相关 Issue
No issue involved. This was just something I wanted and thought others might like too.
Example for the Proposed Route(s) / 路由地址示例
New RSS Route Checklist / 新 RSS 路由检查表
PuppeteerNote / 说明
This adds a Rumble route that keeps the channel listing on server-rendered markup while using structured detail-page data for fallback descriptions and thumbnails. It also adds standard
imageoutput and limits detail-page fetch concurrency to reduce anti-bot risk.