mirror of
https://github.com/d0zingcat/BroadcastChannel.git
synced 2026-05-13 23:16:46 +00:00
Merge branch 'main' of https://github.com/ccbikai/BroadcastChannel
This commit is contained in:
15
README.md
15
README.md
@@ -9,9 +9,9 @@ English | [简体中文](./README.zh-cn.md)
|
||||
## ✨ Features
|
||||
|
||||
- **Turn your Telegram Channel into a MicroBlog**
|
||||
- **SEO friendly**
|
||||
- **SEO friendly** `/sitemap.xml`
|
||||
- **0 JS on the browser side**
|
||||
- **RSS and RSS JSON**
|
||||
- **RSS and RSS JSON** `/rss.xml` `/rss.json`
|
||||
|
||||
## 🪧 Demo
|
||||
|
||||
@@ -61,7 +61,7 @@ For detailed tutorials, see [Deploy your Astro site](https://docs.astro.build/en
|
||||
## ⚒️ Configuration
|
||||
|
||||
```env
|
||||
## Telegram channel name, required
|
||||
## Telegram Channel Username, must be configured. The string of characters following t.me/
|
||||
CHANNEL=miantiao_me
|
||||
|
||||
## Language and timezone settings, language options see [dayjs](https://github.com/iamkun/dayjs/tree/dev/src/locale)
|
||||
@@ -97,6 +97,15 @@ HOST=telegram.dog
|
||||
STATIC_PROXY=
|
||||
```
|
||||
|
||||
## 🙋🏻 FAQs
|
||||
|
||||
1. Why is the content empty after deployment?
|
||||
- Check if the channel is public, it must be public
|
||||
- The channel username is a string, not a number
|
||||
- Turn off the "Restricting Saving Content" setting in the channel
|
||||
- Redeploy after modifying environment variables
|
||||
- Telegram blocks public display of some sensitive channels, you can verify by visiting `https://t.me/s/channelusername`.
|
||||
|
||||
## ☕ Sponsor
|
||||
|
||||
1. [Follow me on Telegram](https://t.me/miantiao_me)
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
## ✨ 特性
|
||||
|
||||
- **将 Telegram Channel 转为微博客**
|
||||
- **SEO 友好**
|
||||
- **SEO 友好** `/sitemap.xml`
|
||||
- **浏览器端 0 JS**
|
||||
- **提供 RSS 和 RSS JSON**
|
||||
- **提供 RSS 和 RSS JSON** `/rss.xml` `/rss.json`
|
||||
|
||||
## 🪧 演示
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
## ⚒️ 配置
|
||||
|
||||
```env
|
||||
## Telegram 频道名称,必须配置
|
||||
## Telegram 频道用户名,必须配置。 t.me/ 后面那串字符
|
||||
CHANNEL=miantiao_me
|
||||
|
||||
## 语言和时区设置,语言选项见[dayjs](https://github.com/iamkun/dayjs/tree/dev/src/locale)
|
||||
@@ -95,6 +95,15 @@ HOST=telegram.dog
|
||||
STATIC_PROXY=
|
||||
```
|
||||
|
||||
## 🙋🏻 常问问题
|
||||
|
||||
1. 为什么部署后内容为空?
|
||||
- 检查频道是否是公开的,必须是公开的
|
||||
- 频道用户名是字符串,不是数字
|
||||
- 关闭频道 Restricting Saving Content 设置项
|
||||
- 修改完环境变量后需要重新部署
|
||||
- Telegram 会屏蔽一些敏感频道的公开展示, 可以通过访问 `https://t.me/s/频道用户名` 确认
|
||||
|
||||
## ☕ 赞助
|
||||
|
||||
1. [在 Telegram 关注我](https://t.me/miantiao_me)
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"cheerio": "1.0.0-rc.12",
|
||||
"dayjs": "^1.11.12",
|
||||
"lru-cache": "^11.0.0",
|
||||
"ofetch": "^1.3.4"
|
||||
"ofetch": "^1.3.4",
|
||||
"sanitize-html": "^2.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/eslint-config": "^2.24.1",
|
||||
|
||||
36
pnpm-lock.yaml
generated
36
pnpm-lock.yaml
generated
@@ -32,6 +32,9 @@ importers:
|
||||
ofetch:
|
||||
specifier: ^1.3.4
|
||||
version: 1.3.4
|
||||
sanitize-html:
|
||||
specifier: ^2.13.0
|
||||
version: 2.13.0
|
||||
devDependencies:
|
||||
'@antfu/eslint-config':
|
||||
specifier: ^2.24.1
|
||||
@@ -2261,6 +2264,10 @@ packages:
|
||||
deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
deepmerge@4.3.1:
|
||||
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
defu@6.1.4:
|
||||
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
||||
|
||||
@@ -2407,11 +2414,11 @@ packages:
|
||||
engines: {node: '>=0.8.0'}
|
||||
|
||||
escape-string-regexp@4.0.0:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
resolution: {integrity: sha1-FLqDpdNz49MR5a/KKc9b+tllvzQ=}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
escape-string-regexp@5.0.0:
|
||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||
resolution: {integrity: sha1-RoMSa1ALYXYvLb66zhgG6L4xscg=}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
eslint-compat-utils@0.5.1:
|
||||
@@ -3020,6 +3027,10 @@ packages:
|
||||
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
is-plain-object@5.0.0:
|
||||
resolution: {integrity: sha1-RCf1CrNCnpAl6n1S6QQ6nvQVk0Q=}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-stream@3.0.0:
|
||||
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@@ -3592,6 +3603,9 @@ packages:
|
||||
parse-latin@7.0.0:
|
||||
resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==}
|
||||
|
||||
parse-srcset@1.0.2:
|
||||
resolution: {integrity: sha1-8r0iH2zJcKk42IVWq8WJyqqiveE=}
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.0.0:
|
||||
resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==}
|
||||
|
||||
@@ -4069,6 +4083,9 @@ packages:
|
||||
safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=}
|
||||
|
||||
sanitize-html@2.13.0:
|
||||
resolution: {integrity: sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==}
|
||||
|
||||
sass-formatter@0.7.9:
|
||||
resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==}
|
||||
|
||||
@@ -7019,6 +7036,8 @@ snapshots:
|
||||
|
||||
deep-is@0.1.4: {}
|
||||
|
||||
deepmerge@4.3.1: {}
|
||||
|
||||
defu@6.1.4: {}
|
||||
|
||||
delegates@1.0.0: {}
|
||||
@@ -7978,6 +7997,8 @@ snapshots:
|
||||
|
||||
is-plain-obj@4.1.0: {}
|
||||
|
||||
is-plain-object@5.0.0: {}
|
||||
|
||||
is-stream@3.0.0: {}
|
||||
|
||||
is-unicode-supported@1.3.0: {}
|
||||
@@ -8740,6 +8761,8 @@ snapshots:
|
||||
unist-util-visit-children: 3.0.0
|
||||
vfile: 6.0.2
|
||||
|
||||
parse-srcset@1.0.2: {}
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.0.0:
|
||||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
@@ -9243,6 +9266,15 @@ snapshots:
|
||||
|
||||
safe-buffer@5.2.1: {}
|
||||
|
||||
sanitize-html@2.13.0:
|
||||
dependencies:
|
||||
deepmerge: 4.3.1
|
||||
escape-string-regexp: 4.0.0
|
||||
htmlparser2: 8.0.2
|
||||
is-plain-object: 5.0.0
|
||||
parse-srcset: 1.0.2
|
||||
postcss: 8.4.40
|
||||
|
||||
sass-formatter@0.7.9:
|
||||
dependencies:
|
||||
suf-log: 2.5.3
|
||||
|
||||
@@ -62,6 +62,13 @@ function getVideo($, item, { staticProxy, index }) {
|
||||
return $.html(video) + $.html(roundVideo)
|
||||
}
|
||||
|
||||
function getAudio($, item, { staticProxy }) {
|
||||
const audio = $(item).find('.tgme_widget_message_voice')
|
||||
audio?.attr('src', staticProxy + audio?.attr('src'))
|
||||
?.attr('controls', true)
|
||||
return $.html(audio)
|
||||
}
|
||||
|
||||
function getLinkPreview($, item, { staticProxy, index }) {
|
||||
const link = $(item).find('.tgme_widget_message_link_preview')
|
||||
const title = $(item).find('.link_preview_title')?.text() || $(item).find('.link_preview_site_name')?.text()
|
||||
@@ -76,6 +83,19 @@ function getLinkPreview($, item, { staticProxy, index }) {
|
||||
return $.html(link)
|
||||
}
|
||||
|
||||
function getReply($, item, { channel }) {
|
||||
const reply = $(item).find('.tgme_widget_message_reply')
|
||||
reply?.wrapInner('<small></small>')?.wrapInner('<blockquote></blockquote>')
|
||||
|
||||
const href = reply?.attr('href')
|
||||
if (href) {
|
||||
const url = new URL(href)
|
||||
reply?.attr('href', `${url.pathname}`.replace(channel, 'posts'))
|
||||
}
|
||||
|
||||
return $.html(reply)
|
||||
}
|
||||
|
||||
function modifyHTMLContent($, content, { index } = {}) {
|
||||
$(content).find('.emoji')?.attr('style', '')
|
||||
$(content).find('a')?.each((_index, a) => {
|
||||
@@ -92,8 +112,10 @@ function modifyHTMLContent($, content, { index } = {}) {
|
||||
|
||||
function getPost($, item, { channel, staticProxy, index = 0 }) {
|
||||
item = item ? $(item).find('.tgme_widget_message') : $('.tgme_widget_message')
|
||||
const content = modifyHTMLContent($, $(item).find('.tgme_widget_message_text'), { index })
|
||||
const title = content?.text()?.match(/[^。\n]*(?=[。\n]|http)/g)?.[0] ?? content?.text() ?? ''
|
||||
const content = $(item).find('.js-message_reply_text')?.length > 0
|
||||
? modifyHTMLContent($, $(item).find('.tgme_widget_message_text.js-message_text'), { index })
|
||||
: modifyHTMLContent($, $(item).find('.tgme_widget_message_text'), { index })
|
||||
const title = content?.text()?.match(/^.*?(?=[。::]|http\S)/g)?.[0] ?? content?.text() ?? ''
|
||||
const id = $(item).attr('data-post')?.replace(`${channel}/`, '')
|
||||
|
||||
const tags = $(content).find('a[href^="?q="]')?.each((_index, a) => {
|
||||
@@ -108,16 +130,16 @@ function getPost($, item, { channel, staticProxy, index = 0 }) {
|
||||
tags,
|
||||
text: content?.text(),
|
||||
content: [
|
||||
$.html($(item).find('.tgme_widget_message_reply')?.wrapInner('<small></small>')?.wrapInner('<blockquote></blockquote>')),
|
||||
getReply($, item, { channel }),
|
||||
getImages($, item, { staticProxy, id, index, title }),
|
||||
getVideo($, item, { staticProxy, id, index, title }),
|
||||
getAudio($, item, { staticProxy, id, index, title }),
|
||||
content?.html(),
|
||||
getImageStickers($, item, { staticProxy, index }),
|
||||
getVideoStickers($, item, { staticProxy, index }),
|
||||
// $(item).find('.tgme_widget_message_sticker_wrap')?.html(),
|
||||
$(item).find('.tgme_widget_message_poll')?.html(),
|
||||
$.html($(item).find('.tgme_widget_message_document_wrap')),
|
||||
$.html($(item).find('.tgme_widget_message_voice')?.attr('controls', true)),
|
||||
$.html($(item).find('.tgme_widget_message_location_wrap')),
|
||||
getLinkPreview($, item, { staticProxy, index }),
|
||||
].filter(Boolean).join('').replace(/(url\(["'])((https?:)?\/\/)/g, (match, p1, p2, _p3) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import rss from '@astrojs/rss'
|
||||
|
||||
import sanitizeHtml from 'sanitize-html'
|
||||
import { getChannelInfo } from '../lib/telegram'
|
||||
|
||||
export const prerender = false
|
||||
@@ -22,7 +22,14 @@ export async function GET(Astro) {
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
pubDate: new Date(item.datetime),
|
||||
content: item.content,
|
||||
content: sanitizeHtml(item.content, {
|
||||
allowedTags: sanitizeHtml.defaults.allowedTags.concat(['img', 'video', 'audio']),
|
||||
allowedAttributes: {
|
||||
video: ['src', 'width', 'height', 'poster'],
|
||||
audio: ['src', 'controls'],
|
||||
img: ['src', 'width', 'height', 'loading'],
|
||||
},
|
||||
}),
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user