├── README.md ├── .gitmodules ├── images └── screenshot │ ├── Apple News - Locked - iOS.jpeg │ ├── Apple News - Unlock Invalid - iOS.jpeg │ └── Apple News - Unlock Success - iOS.jpeg ├── CHANGELOG.md ├── rulesets └── News.list ├── .github ├── RELEASE-TEMPLATE.md └── workflows │ ├── draft.yml │ ├── deploy.yml │ ├── release.yml │ ├── pre-release.yml │ ├── dev.yml │ └── build.yml ├── archive ├── modules │ ├── Apple_News.qxrewrite │ ├── Apple_News.sgmodule │ ├── Apple_News.beta.sgmodule │ ├── Apple_News_for_US_icon.sgmodule │ ├── Apple_News_for_Apple.sgmodule │ ├── Apple_News_for_Proxy.sgmodule │ ├── Apple_News_for_ACL4SSR.sgmodule │ ├── Apple_News_for_Apple_News.sgmodule │ ├── Apple_News_for_Apple_icon.sgmodule │ ├── Apple_News_for_DivineEngine.sgmodule │ ├── Apple_News_for_Surgio.sgmodule │ ├── Apple_News_for_US_icon.beta.sgmodule │ ├── Apple_News_for_Uppercase_PROXY.sgmodule │ ├── Apple_News_for_Apple_blank_icon.sgmodule │ ├── Apple_News.plugin │ └── Apple_News.beta.stoverride └── js │ └── Apple_News.js ├── template ├── boxjs.settings.json ├── shadowrocket.handlebars ├── quantumultx.handlebars ├── stash.handlebars ├── surge.handlebars └── loon.handlebars ├── rspack.config.js ├── rspack.dev.config.js ├── src ├── interface.ts ├── function │ ├── setENV.mjs │ └── database.mjs ├── request.js └── request.dev.js ├── package.json ├── arguments-builder.config.ts ├── .gitignore └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | # News -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/utils"] 2 | path = src/utils 3 | url = https://github.com/NanoCat-Me/utils.git 4 | -------------------------------------------------------------------------------- /images/screenshot/Apple News - Locked - iOS.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NSRingo/News/HEAD/images/screenshot/Apple News - Locked - iOS.jpeg -------------------------------------------------------------------------------- /images/screenshot/Apple News - Unlock Invalid - iOS.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NSRingo/News/HEAD/images/screenshot/Apple News - Unlock Invalid - iOS.jpeg -------------------------------------------------------------------------------- /images/screenshot/Apple News - Unlock Success - iOS.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NSRingo/News/HEAD/images/screenshot/Apple News - Unlock Success - iOS.jpeg -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 🛠️ Bug Fixes 2 | * 修复 `Surge` 模块内置`参数面板` 3 | * 修复 `Loon` 插件内置`设置面板` 4 | * 修复读取`数据库`不正确的问题 5 | 6 | ### 🔄 Other Changes 7 | * 打包器由 `rollup` 更改为 `rspack` 8 | -------------------------------------------------------------------------------- /rulesets/News.list: -------------------------------------------------------------------------------- 1 | # > News 2 | DOMAIN,news-edge.apple.com 3 | DOMAIN,news-events.apple.com 4 | DOMAIN,apple.comscoreresearch.com 5 | # News+ Audio 6 | URL-REGEX,^https?:\/\/news-assets\.apple\.com\/(audio-narrative|podcast\/audio)\/.* 7 | -------------------------------------------------------------------------------- /.github/RELEASE-TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### 🆕 New Features 2 | * none 3 | 4 | ### 🛠️ Bug Fixes 5 | * none 6 | 7 | ### 🔣 Dependencies 8 | * none 9 | 10 | ### ‼️ Breaking Changes 11 | * none 12 | 13 | ### 🔄 Other Changes 14 | * none 15 | -------------------------------------------------------------------------------- /archive/modules/Apple_News.qxrewrite: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com需走代理线路。 3 | 4 | ^https?:\/\/news-(edge|events)\.apple\.com(\/v1\/configs|\/analyticseventsv2\/async).* url script-request-body https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 5 | ^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).* url script-request-header https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 6 | 7 | hostname = news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 8 | -------------------------------------------------------------------------------- /archive/modules/Apple_News.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:需配合域名集使用,使用过程中gateway.icloud.com需走代理线路。 3 | 4 | [Script] 5 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 6 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 7 | 8 | [MITM] 9 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com 10 | -------------------------------------------------------------------------------- /template/boxjs.settings.json: -------------------------------------------------------------------------------- 1 | [{"id":"@iRingo.News.Settings.Switch","name":"总功能开关","type":"boolean","val":true,"desc":"是否启用此APP修改。"},{"id":"@iRingo.News.Settings.CountryCode","name":"国家或地区代码","type":"selects","val":"US","items":[{"key":"AUTO","label":"🇺🇳自动(跟随地区检测结果)"},{"key":"CN","label":"🇨🇳中国大陆"},{"key":"HK","label":"🇭🇰香港"},{"key":"TW","label":"🇹🇼台湾"},{"key":"SG","label":"🇸🇬新加坡"},{"key":"US","label":"🇺🇸美国"},{"key":"JP","label":"🇯🇵日本"},{"key":"AU","label":"🇦🇺澳大利亚"},{"key":"GB","label":"🇬🇧英国"},{"key":"KR","label":"🇰🇷韩国"},{"key":"CA","label":"🇨🇦加拿大"},{"key":"IE","label":"🇮🇪爱尔兰"}],"desc":"不同国家或地区提供的内容或有差别。"},{"id":"@iRingo.News.Settings.NewsPlusUser","name":"[搜索]显示News+内容","type":"boolean","val":true,"desc":"是否显示News+搜索结果。"}] -------------------------------------------------------------------------------- /archive/modules/Apple_News.beta.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=(BETA) 解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com需走代理线路。 3 | 4 | [Script] 5 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 6 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js, tag=Apple_News 7 | 8 | [MITM] 9 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 10 | -------------------------------------------------------------------------------- /.github/workflows/draft.yml: -------------------------------------------------------------------------------- 1 | name: Draft 2 | on: 3 | push: 4 | # Sequence of patterns matched against refs/heads 5 | branches: 6 | - main 7 | 8 | permissions: 9 | actions: read 10 | contents: write 11 | 12 | jobs: 13 | build: 14 | uses: ./.github/workflows/build.yml 15 | secrets: inherit 16 | draft: 17 | needs: build 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Download artifact 21 | uses: actions/download-artifact@master 22 | with: 23 | name: artifact 24 | - name: Publish Draft 25 | uses: softprops/action-gh-release@v2 26 | with: 27 | body_path: CHANGELOG.md 28 | token: ${{ secrets.GITHUB_TOKEN }} 29 | files: | 30 | rulesets/* 31 | dist/* 32 | draft: true 33 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | on: 3 | push: 4 | # Sequence of patterns matched against refs/heads 5 | branches: 6 | - dev 7 | 8 | permissions: 9 | actions: read 10 | contents: read 11 | 12 | jobs: 13 | dev: 14 | uses: ./.github/workflows/dev.yml 15 | secrets: inherit 16 | deploy: 17 | needs: dev 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Download artifact 21 | uses: actions/download-artifact@master 22 | with: 23 | name: artifact 24 | - name: Deploy 25 | uses: exuanbo/actions-deploy-gist@main 26 | with: 27 | token: ${{ secrets.GIST_TOKEN }} 28 | gist_id: fe3c29c45fd096d701ebf5b43f1e76b1 29 | gist_description: " iRingo: 📰 News β" 30 | file_path: dist/request.bundle.js 31 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | # Sequence of patterns matched against refs/tags 5 | tags: 6 | - v[0-9]+.[0-9]+.[0-9]+ 7 | 8 | permissions: 9 | actions: read 10 | contents: write 11 | 12 | jobs: 13 | build: 14 | uses: ./.github/workflows/build.yml 15 | secrets: inherit 16 | release: 17 | needs: build 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Download artifact 21 | uses: actions/download-artifact@master 22 | with: 23 | name: artifact 24 | - name: Publish Release 25 | uses: softprops/action-gh-release@v2 26 | with: 27 | body_path: CHANGELOG.md 28 | token: ${{ secrets.GITHUB_TOKEN }} 29 | files: | 30 | rulesets/* 31 | dist/* 32 | make_latest: "true" 33 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_US_icon.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com需走代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,🇺🇸美国 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_Apple.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,Apple 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_Proxy.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,Proxy 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_ACL4SSR.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,🍎 苹果服务 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_Apple_News.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,Apple News 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_Apple_icon.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,🍎Apple 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_DivineEngine.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,🌑Proxy 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_Surgio.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,📡 Apple 地区限制 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_US_icon.beta.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=(BETA) 解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com需走代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,🇺🇸美国 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_Uppercase_PROXY.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,PROXY 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /archive/modules/Apple_News_for_Apple_blank_icon.sgmodule: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | 4 | [Rule] 5 | # > Apple News 6 | RULE-SET,https://raw.githubusercontent.com/NSRingo/News/main/rulesets/News.list,🍎 Apple 7 | 8 | [Script] 9 | Apple News = type=http-request, pattern=^https?:\/\/news-(edge|events)\.apple\.com\/(v1\/configs|analyticseventsv2\/async).*, requires-body=1, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 10 | Apple News = type=http-request, pattern=^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).*, requires-body=0, script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 11 | 12 | [MITM] 13 | hostname = %APPEND% news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 14 | -------------------------------------------------------------------------------- /.github/workflows/pre-release.yml: -------------------------------------------------------------------------------- 1 | name: Pre-Release 2 | on: 3 | push: 4 | # Sequence of patterns matched against refs/tags 5 | tags: 6 | - v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+ 7 | - v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+ 8 | 9 | permissions: 10 | actions: read 11 | contents: write 12 | 13 | jobs: 14 | build: 15 | uses: ./.github/workflows/build.yml 16 | secrets: inherit 17 | pre-release: 18 | needs: build 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Download artifact 22 | uses: actions/download-artifact@master 23 | with: 24 | name: artifact 25 | - name: Publish Pre-Release 26 | uses: softprops/action-gh-release@v2 27 | with: 28 | body_path: CHANGELOG.md 29 | token: ${{ secrets.GITHUB_TOKEN }} 30 | files: | 31 | rulesets/* 32 | dist/* 33 | prerelease: true 34 | -------------------------------------------------------------------------------- /.github/workflows/dev.yml: -------------------------------------------------------------------------------- 1 | name: Dev 2 | on: 3 | workflow_call: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | actions: read 8 | contents: read 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@main 16 | with: 17 | submodules: recursive 18 | token: ${{ secrets.SUBMODULE_TOKEN }} 19 | ref: dev 20 | - name: Set up Node.js 21 | uses: actions/setup-node@main 22 | with: 23 | node-version: 'latest' 24 | cache: 'npm' 25 | - name: Install dependencies 26 | run: npm install 27 | - name: Build 28 | run: npm run build:dev 29 | - name: Upload artifact 30 | uses: actions/upload-artifact@master 31 | with: 32 | name: artifact 33 | path: | 34 | CHANGELOG.md 35 | rulesets 36 | dist 37 | -------------------------------------------------------------------------------- /rspack.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@rspack/cli"; 2 | import rspack from "@rspack/core"; 3 | import NodePolyfillPlugin from "node-polyfill-webpack-plugin"; 4 | import pkg from "./package.json" with { type: "json" }; 5 | 6 | export default defineConfig({ 7 | entry: { 8 | request: "./src/request.js", 9 | //response: "./src/response.js", 10 | }, 11 | output: { 12 | filename: "[name].bundle.js", 13 | }, 14 | plugins: [ 15 | new NodePolyfillPlugin({ 16 | //additionalAliases: ['console'], 17 | }), 18 | new rspack.BannerPlugin({ 19 | banner: `console.log('Version: ${pkg.version}');`, 20 | raw: true, 21 | }), 22 | new rspack.BannerPlugin({ 23 | banner: "console.log('[file]');", 24 | raw: true, 25 | }), 26 | new rspack.BannerPlugin({ 27 | banner: `console.log('${pkg.displayName}');`, 28 | raw: true, 29 | }), 30 | new rspack.BannerPlugin({ 31 | banner: pkg.homepage, 32 | }), 33 | ], 34 | performance: false, 35 | }); 36 | -------------------------------------------------------------------------------- /rspack.dev.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@rspack/cli"; 2 | import rspack from "@rspack/core"; 3 | import NodePolyfillPlugin from "node-polyfill-webpack-plugin"; 4 | import pkg from "./package.json" with { type: "json" }; 5 | 6 | export default defineConfig({ 7 | entry: { 8 | request: "./src/request.dev.js", 9 | //response: "./src/response.js", 10 | }, 11 | output: { 12 | filename: "[name].bundle.js", 13 | }, 14 | plugins: [ 15 | new NodePolyfillPlugin({ 16 | //additionalAliases: ['console'], 17 | }), 18 | new rspack.BannerPlugin({ 19 | banner: `console.log('Version: ${pkg.version}');`, 20 | raw: true, 21 | }), 22 | new rspack.BannerPlugin({ 23 | banner: "console.log('[file]');", 24 | raw: true, 25 | }), 26 | new rspack.BannerPlugin({ 27 | banner: `console.log('${pkg.displayName} β');`, 28 | raw: true, 29 | }), 30 | new rspack.BannerPlugin({ 31 | banner: pkg.homepage, 32 | }), 33 | ], 34 | performance: false, 35 | }); 36 | -------------------------------------------------------------------------------- /src/interface.ts: -------------------------------------------------------------------------------- 1 | export interface Settings { 2 | /** 3 | * 总功能开关 4 | * 5 | * 是否启用此APP修改。 6 | * 7 | * @defaultValue true 8 | */ 9 | Switch?: boolean; 10 | /** 11 | * 国家或地区代码 12 | * 13 | * 不同国家或地区提供的内容或有差别。 14 | * 15 | * @remarks 16 | * 17 | * Possible values: 18 | * - `'AUTO'` - 🇺🇳自动(跟随地区检测结果) 19 | * - `'CN'` - 🇨🇳中国大陆 20 | * - `'HK'` - 🇭🇰香港 21 | * - `'TW'` - 🇹🇼台湾 22 | * - `'SG'` - 🇸🇬新加坡 23 | * - `'US'` - 🇺🇸美国 24 | * - `'JP'` - 🇯🇵日本 25 | * - `'AU'` - 🇦🇺澳大利亚 26 | * - `'GB'` - 🇬🇧英国 27 | * - `'KR'` - 🇰🇷韩国 28 | * - `'CA'` - 🇨🇦加拿大 29 | * - `'IE'` - 🇮🇪爱尔兰 30 | * 31 | * @defaultValue "US" 32 | */ 33 | CountryCode?: 'AUTO' | 'CN' | 'HK' | 'TW' | 'SG' | 'US' | 'JP' | 'AU' | 'GB' | 'KR' | 'CA' | 'IE'; 34 | /** 35 | * [搜索]显示News+内容 36 | * 37 | * 是否显示News+搜索结果。 38 | * 39 | * @defaultValue true 40 | */ 41 | NewsPlusUser?: boolean; 42 | } 43 | -------------------------------------------------------------------------------- /archive/modules/Apple_News.plugin: -------------------------------------------------------------------------------- 1 | #!name= Unlock Apple News 🇺🇸US 2 | #!desc=解锁🇺🇸US地区的News,注:使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | # 该插件需要匹配代理策略组 4 | 5 | [Rule] 6 | # > Apple News 7 | # > iCloud 8 | DOMAIN-SUFFIX,gateway.icloud.com 9 | # > Apple News 10 | DOMAIN-SUFFIX,news-edge.apple.com 11 | DOMAIN-SUFFIX,news-events.apple.com 12 | DOMAIN-SUFFIX,apple.comscoreresearch.com 13 | # News+ Audio 14 | URL-REGEX,^https?:\/\/news-assets\.apple\.com\/.*(audio-narrative).* 15 | 16 | [Script] 17 | http-request ^https?:\/\/news-(edge|events)\.apple\.com(\/v1\/configs|\/analyticseventsv2\/async).* script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js, requires-body=true, tag=Apple_News 18 | http-request ^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).* script-path=https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js, tag=Apple_News 19 | 20 | [MITM] 21 | hostname = news-client.apple.com, news-client-search.apple.com, news-edge.apple.com, news-events.apple.com, newsletter-edge.apple.com 22 | -------------------------------------------------------------------------------- /archive/modules/Apple_News.beta.stoverride: -------------------------------------------------------------------------------- 1 | name:  Unlock Apple News 🇺🇸US 2 | desc: 解锁🇺🇸US地区的News,注:需配合域名集使用,使用过程中gateway.icloud.com需走代理线路。 3 | 4 | rules: 5 | - DOMAIN-SUFFIX,news-edge.apple.com,Proxy 6 | - DOMAIN-SUFFIX,news-events.apple.com,Proxy 7 | - DOMAIN-SUFFIX,apple.comscoreresearch.com,Proxy 8 | - URL-REGEX,^https?:\/\/news-assets\.apple\.com\/.*(audio-narrative).*,Proxy 9 | 10 | http: 11 | mitm: 12 | - "news-client.apple.com" 13 | - "news-client-search.apple.com" 14 | - "news-edge.apple.com" 15 | - "news-events.apple.com" 16 | - "newsletter-edge.apple.com" 17 | script: 18 | - match: ^https?:\/\/news-(edge|events)\.apple\.com(\/v1\/configs|\/analyticseventsv2\/async).* 19 | name: Apple_News 20 | type: request 21 | require-body: true 22 | timeout: 10 23 | - match: ^https?:\/\/news-(client-search)\.apple\.com\/(v1\/search\?).* 24 | name: Apple_News 25 | type: request 26 | require-body: false 27 | timeout: 10 28 | 29 | script-providers: 30 | Apple_News: 31 | url: https://raw.githubusercontent.com/NSRingo/News/main/archive/js/Apple_News.js 32 | interval: 86400 33 | -------------------------------------------------------------------------------- /src/function/setENV.mjs: -------------------------------------------------------------------------------- 1 | import getStorage from '../utils/getStorage.mjs' 2 | import { _, log } from "../utils/utils.mjs"; 3 | 4 | /** 5 | * Set Environment Variables 6 | * @author VirgilClyne 7 | * @param {String} name - Persistent Store Key 8 | * @param {Array} platforms - Platform Names 9 | * @param {Object} database - Default DataBase 10 | * @return {Object} { Settings, Caches, Configs } 11 | */ 12 | export default function setENV(name, platforms, database) { 13 | log(`☑️ Set Environment Variables`, ""); 14 | let { Settings, Caches, Configs } = getStorage(name, platforms, database); 15 | /***************** Settings *****************/ 16 | log(`✅ Set Environment Variables, Settings: ${typeof Settings}, Settings内容: ${JSON.stringify(Settings)}`, ""); 17 | /***************** Caches *****************/ 18 | //log(`✅ Set Environment Variables, Caches: ${typeof Caches}, Caches内容: ${JSON.stringify(Caches)}`, ""); 19 | /***************** Configs *****************/ 20 | //Configs.Storefront = new Map(Configs.Storefront); 21 | if (Configs.Locale) Configs.Locale = new Map(Configs.Locale); 22 | if (Configs.i18n) for (let type in Configs.i18n) Configs.i18n[type] = new Map(Configs.i18n[type]); 23 | return { Settings, Caches, Configs }; 24 | }; 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "news", 3 | "version": "3.1.5", 4 | "organizationName": " iRingo", 5 | "displayName": " iRingo: 📰 News", 6 | "description": "1.自定义解锁News的地区\n2.Coming Soon…", 7 | "homepage": "https://NSRingo.github.io/guide/apple-news", 8 | "openUrl": "http://boxjs.com/#/app/iRingo.News", 9 | "icon": "https://developer.apple.com/assets/elements/icons/news/news-128x128.png", 10 | "keywords": [], 11 | "contributors": [ 12 | "VirgilClyne[https://github.com/VirgilClyne]" 13 | ], 14 | "system": [ 15 | "iOS", 16 | "iPadOS", 17 | "tvOS", 18 | "macOS", 19 | "watchOS" 20 | ], 21 | "author": "VirgilClyne", 22 | "license": "Apache-2.0", 23 | "type": "module", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/NSRingo/News.git" 27 | }, 28 | "directories": { 29 | "example": "example" 30 | }, 31 | "scripts": { 32 | "serve": "webpack serve", 33 | "build": "rspack build", 34 | "build:dev": "rspack build -c rspack.dev.config.js --mode=development", 35 | "build:args": "arguments-builder build", 36 | "dts": "arguments-builder dts" 37 | }, 38 | "browserslist": [ 39 | "iOS >= 15" 40 | ], 41 | "devDependencies": { 42 | "@iringo/arguments-builder": "^1.7.3", 43 | "@rspack/cli": "^1.0.13", 44 | "@rspack/core": "^1.0.13", 45 | "node-polyfill-webpack-plugin": "^4.0.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | workflow_call: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | actions: read 8 | contents: read 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@main 16 | with: 17 | submodules: recursive 18 | token: ${{ secrets.SUBMODULE_TOKEN }} 19 | - name: Set up Node.js 20 | uses: actions/setup-node@main 21 | with: 22 | node-version: 'latest' 23 | cache: 'npm' 24 | - name: Install dependencies 25 | run: npm install 26 | - name: Update local package.json version from release tag 27 | if: github.ref_type == 'tag' 28 | uses: BellCubeDev/update-package-version-by-release-tag@v2 29 | with: 30 | version: ${{ github.ref_name }} 31 | keep-v: "false" # If set to "true", will not remove any 'v' prefix from the version number. 32 | ignore-semver-check: "false" # If set to "true", will not check if the version number is a valid semver version. 33 | - name: Build scripts 34 | run: npm run build 35 | - name: Generate modules 36 | run: npm run build:args 37 | - name: Upload artifact 38 | uses: actions/upload-artifact@master 39 | with: 40 | name: artifact 41 | path: | 42 | CHANGELOG.md 43 | rulesets 44 | dist 45 | -------------------------------------------------------------------------------- /template/shadowrocket.handlebars: -------------------------------------------------------------------------------- 1 | #!name = {{@package 'displayName'}} 2 | #!desc = {{inline (@package 'description')}}\n注:该模块不包含代理规则组,代理规则组需要匹配代理策略组为🇺🇸🇬🇧🇨🇦🇦🇺线路,使用过程中gateway.icloud.com应该走与News相同的代理线路。 3 | #!openUrl = {{@package 'openUrl'}} 4 | #!author = {{@package 'contributors'}} 5 | #!homepage = {{@package 'homepage'}} 6 | #!icon = {{@package 'icon'}} 7 | #!category = {{@package 'organizationName'}} 8 | #!date = {{now "yyyy-MM-dd HH:mm:ss"}} 9 | #!version = {{@package 'version'}} 10 | 11 | [Script] 12 | 📰 News.v1.configs.request = type=http-request, pattern=^https?:\/\/news(-todayconfig)?-edge\.apple\.com\/v1\/configs, requires-body=1, script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, argument= 13 | 📰 News.analyticseventsv2.async.request = type=http-request, pattern=^https?:\/\/news(-sports)?-events\.apple\.com\/analyticseventsv2\/async, requires-body=1, script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, argument= 14 | 📰 News.v1.search.request = type=http-request, pattern=^https?:\/\/news-client-search\.apple\.com\/v1\/search, requires-body=0, script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, argument= 15 | 16 | [MITM] 17 | hostname = %APPEND% news-edge.apple.com, news-todayconfig-edge.apple.com, news-events.apple.com, news-sports-events.apple.com, news-client.apple.com, news-client-search.apple.com 18 | -------------------------------------------------------------------------------- /template/quantumultx.handlebars: -------------------------------------------------------------------------------- 1 | #!name = {{@package 'displayName'}} 2 | #!desc = {{inline (@package 'description')}}\n注:该模块不包含代理规则组,代理规则组需要匹配代理策略组为🇺🇸🇬🇧🇨🇦🇦🇺线路,使用过程中gateway.icloud.com应该走与News相同的代理线路。 3 | #!openUrl = {{@package 'openUrl'}} 4 | #!author = {{@package 'contributors'}} 5 | #!homepage = {{@package 'homepage'}} 6 | #!icon = {{@package 'icon'}} 7 | #!category = {{@package 'organizationName'}} 8 | #!date = {{now "yyyy-MM-dd HH:mm:ss"}} 9 | #!version = {{@package 'version'}} 10 | 11 | #[filter_local] 12 | # > News 13 | host, news-edge.apple.com, News 14 | host, news-events.apple.com, News 15 | host, apple.comscoreresearch.com, News 16 | host, news-assets.apple.com, News 17 | 18 | #[rewrite_local] 19 | # 📰 News Configs 20 | ^https?:\/\/news(-todayconfig)?-edge\.apple\.com\/v1\/configs url script-request-body https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js 21 | # 📰 News Event 22 | ^https?:\/\/news(-sports)?-events\.apple\.com\/analyticseventsv2\/async url script-request-body https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js 23 | # 📰 News Search 24 | ^https?:\/\/news-client-search\.apple\.com\/v1\/search url script-request-header https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js 25 | 26 | #[mitm] 27 | hostname = news-edge.apple.com, news-todayconfig-edge.apple.com, news-events.apple.com, news-sports-events.apple.com, news-client.apple.com, news-client-search.apple.com 28 | -------------------------------------------------------------------------------- /template/stash.handlebars: -------------------------------------------------------------------------------- 1 | name: "{{@package 'displayName'}}" 2 | desc: |- 3 | {{#each (split (@package 'description') "\n")}} 4 | {{{this}}} 5 | {{/each}} 6 | 注:该覆写包含代理规则,使用过程中gateway.icloud.com会走与News相同的代理线路。 7 | openUrl: "{{@package 'openUrl'}}" 8 | author: |- 9 | {{#each (@package 'contributors')}} 10 | {{{this}}} 11 | {{/each}} 12 | homepage: "{{@package 'homepage'}}" 13 | icon: "{{@package 'icon'}}" 14 | category: "{{@package 'organizationName'}}" 15 | date: "{{now "yyyy-MM-dd HH:mm:ss"}}" 16 | version: "{{@package 'version'}}" 17 | 18 | rules: 19 | - DOMAIN,gateway.icloud.com,PROXY 20 | - DOMAIN,news-edge.apple.com,PROXY 21 | - DOMAIN,news-events.apple.com,PROXY 22 | - DOMAIN,apple.comscoreresearch.com,PROXY 23 | - URL-REGEX,^https?:\/\/news-assets\.apple\.com\/(audio-narrative|podcast\/audio)\/.*,PROXY 24 | 25 | http: 26 | mitm: 27 | - "news-edge.apple.com" 28 | - "news-todayconfig-edge.apple.com" 29 | - "news-sports-events.apple.com" 30 | - "news-events.apple.com" 31 | - "news-client.apple.com" 32 | - "news-client-search.apple.com" 33 | script: 34 | - match: ^https?:\/\/news(-todayconfig)?-edge\.apple\.com\/v1\/configs 35 | name: News.request 36 | type: request 37 | require-body: true 38 | - match: ^https?:\/\/news(-sports)?-events\.apple\.com\/analyticseventsv2\/async 39 | name: News.request 40 | type: request 41 | require-body: true 42 | - match: ^https?:\/\/news-client-search\.apple\.com\/v1\/search 43 | name: News.request 44 | type: request 45 | 46 | script-providers: 47 | News.request: 48 | url: https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js 49 | interval: 86400 50 | -------------------------------------------------------------------------------- /template/surge.handlebars: -------------------------------------------------------------------------------- 1 | #!name = {{@package 'displayName'}} 2 | #!desc = {{inline (@package 'description')}} 3 | #!openUrl = {{@package 'openUrl'}} 4 | #!author = {{@package 'contributors'}} 5 | #!homepage = {{@package 'homepage'}} 6 | #!icon = {{@package 'icon'}} 7 | #!category = {{@package 'organizationName'}} 8 | #!date = {{now "yyyy-MM-dd HH:mm:ss"}} 9 | #!version = {{@package 'version'}} 10 | #!arguments=Proxy:🇺🇸美国,{{{arguments}}} 11 | #!arguments-desc=Proxy: News 分流规则使用的策略名\n{{{argumentsDesc}}} 12 | 13 | [Rule] 14 | # ☁️ iCloud 15 | DOMAIN,gateway.icloud.com,\{{{Proxy}}} 16 | # 📰 News 17 | RULE-SET,https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/News.list,\{{{Proxy}}} 18 | 19 | [Script] 20 | 📰 News.v1.configs.request = type=http-request, pattern=^https?:\/\/news(-todayconfig)?-edge\.apple\.com\/v1\/configs, requires-body=1, script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, argument={{{scriptParams}}} 21 | 📰 News.analyticseventsv2.async.request = type=http-request, pattern=^https?:\/\/news(-sports)?-events\.apple\.com\/analyticseventsv2\/async, requires-body=1, script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, argument={{{scriptParams}}} 22 | 📰 News.v1.search.request = type=http-request, pattern=^https?:\/\/news-client-search\.apple\.com\/v1\/search, requires-body=0, script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, argument={{{scriptParams}}} 23 | 24 | [MITM] 25 | hostname = %APPEND% news-edge.apple.com, news-todayconfig-edge.apple.com, news-events.apple.com, news-sports-events.apple.com, news-client.apple.com, news-client-search.apple.com 26 | -------------------------------------------------------------------------------- /arguments-builder.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "@iringo/arguments-builder"; 2 | export default defineConfig({ 3 | output: { 4 | surge: { path: "./dist/News.sgmodule" }, 5 | loon: { path: "./dist/News.plugin" }, 6 | customItems: [ 7 | { 8 | path: "./dist/News.snippet", 9 | template: "./template/quantumultx.handlebars", 10 | }, 11 | { 12 | path: "./dist/News.stoverride", 13 | template: "./template/stash.handlebars", 14 | }, 15 | { 16 | path: "./dist/News.srmodule", 17 | template: "./template/shadowrocket.handlebars", 18 | }, 19 | ], 20 | dts: { isExported: true, path: "./src/interface.ts" }, 21 | boxjsSettings: { 22 | path: "./template/boxjs.settings.json", 23 | scope: "@iRingo.News.Settings", 24 | }, 25 | }, 26 | args: [ 27 | { 28 | key: "Switch", 29 | name: "总功能开关", 30 | defaultValue: true, 31 | type: "boolean", 32 | description: "是否启用此APP修改。", 33 | exclude: ["surge", "loon"], 34 | }, 35 | { 36 | key: "CountryCode", 37 | name: "国家或地区代码", 38 | defaultValue: "US", 39 | type: "string", 40 | options: [ 41 | { key: "AUTO", label: "🇺🇳自动(跟随地区检测结果)" }, 42 | { key: "CN", label: "🇨🇳中国大陆" }, 43 | { key: "HK", label: "🇭🇰香港" }, 44 | { key: "TW", label: "🇹🇼台湾" }, 45 | { key: "SG", label: "🇸🇬新加坡" }, 46 | { key: "US", label: "🇺🇸美国" }, 47 | { key: "JP", label: "🇯🇵日本" }, 48 | { key: "AU", label: "🇦🇺澳大利亚" }, 49 | { key: "GB", label: "🇬🇧英国" }, 50 | { key: "KR", label: "🇰🇷韩国" }, 51 | { key: "CA", label: "🇨🇦加拿大" }, 52 | { key: "IE", label: "🇮🇪爱尔兰" }, 53 | ], 54 | description: "不同国家或地区提供的内容或有差别。", 55 | }, 56 | { 57 | key: "NewsPlusUser", 58 | name: "[搜索]显示News+内容", 59 | defaultValue: true, 60 | type: "boolean", 61 | description: "是否显示News+搜索结果。", 62 | }, 63 | ], 64 | }); 65 | -------------------------------------------------------------------------------- /template/loon.handlebars: -------------------------------------------------------------------------------- 1 | #!name = {{@package 'displayName'}} 2 | #!desc = {{inline (@package 'description')}}\n注:该插件包含代理规则,安装过程中需要匹配代理策略组为🇺🇸🇬🇧🇨🇦🇦🇺线路,使用过程中gateway.icloud.com会走与News相同的代理线路。 3 | #!openUrl = {{@package 'openUrl'}} 4 | #!author = {{@package 'contributors'}} 5 | #!homepage = {{@package 'homepage'}} 6 | #!icon = {{@package 'icon'}} 7 | #!tag = {{@package 'organizationName'}} 8 | #!system = {{@package 'system'}} 9 | #!date = {{now "yyyy-MM-dd HH:mm:ss"}} 10 | #!version = {{@package 'version'}} 11 | 12 | [Argument] 13 | {{{arguments}}} 14 | 15 | [Rule] 16 | # > iCloud 17 | DOMAIN,gateway.icloud.com,PROXY 18 | 19 | # > News 20 | DOMAIN,news-edge.apple.com,PROXY 21 | DOMAIN,news-events.apple.com,PROXY 22 | DOMAIN,apple.comscoreresearch.com,PROXY 23 | # News+ Audio 24 | URL-REGEX,^https?:\/\/news-assets\.apple\.com\/(audio-narrative|podcast\/audio)\/.*,PROXY 25 | 26 | [Script] 27 | http-request ^https?:\/\/news(-todayconfig)?-edge\.apple\.com\/v1\/configs script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, requires-body=1, tag=📰 News.v1.configs.request, argument={{{scriptParams}}} 28 | http-request ^https?:\/\/news(-sports)?-events\.apple\.com\/analyticseventsv2\/async script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, requires-body=1, tag=📰 News.analyticseventsv2.async.request, argument={{{scriptParams}}} 29 | http-request ^https?:\/\/news-client-search\.apple\.com\/v1\/search script-path=https://github.com/NSRingo/News/releases/download/v{{@package 'version'}}/request.bundle.js, tag=📰 News.v1.search.request, argument={{{scriptParams}}} 30 | 31 | [MITM] 32 | hostname = news-edge.apple.com, news-todayconfig-edge.apple.com, news-events.apple.com, news-sports-events.apple.com, news-client.apple.com, news-client-search.apple.com 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | *.lcov 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # Snowpack dependency directory (https://snowpack.dev/) 46 | web_modules/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Optional stylelint cache 58 | .stylelintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variable files 76 | .env 77 | .env.development.local 78 | .env.test.local 79 | .env.production.local 80 | .env.local 81 | 82 | # parcel-bundler cache (https://parceljs.org/) 83 | .cache 84 | .parcel-cache 85 | 86 | # Next.js build output 87 | .next 88 | out 89 | 90 | # Nuxt.js build / generate output 91 | .nuxt 92 | dist 93 | 94 | # Gatsby files 95 | .cache/ 96 | # Comment in the public line in if your project uses Gatsby and not Next.js 97 | # https://nextjs.org/blog/next-9-1#public-directory-support 98 | # public 99 | 100 | # vuepress build output 101 | .vuepress/dist 102 | 103 | # vuepress v2.x temp and cache directory 104 | .temp 105 | .cache 106 | 107 | # Docusaurus cache and generated files 108 | .docusaurus 109 | 110 | # Serverless directories 111 | .serverless/ 112 | 113 | # FuseBox cache 114 | .fusebox/ 115 | 116 | # DynamoDB Local files 117 | .dynamodb/ 118 | 119 | # TernJS port file 120 | .tern-port 121 | 122 | # Stores VSCode versions used for testing VSCode extensions 123 | .vscode-test 124 | 125 | # yarn v2 126 | .yarn/cache 127 | .yarn/unplugged 128 | .yarn/build-state.yml 129 | .yarn/install-state.gz 130 | .pnp.* 131 | -------------------------------------------------------------------------------- /archive/js/Apple_News.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/VirgilClyne/iRingo 3 | */ 4 | 5 | var url = $request.url; 6 | var body = $request.body; 7 | 8 | const path1 = "/v1/configs"; 9 | const path2 = "/analyticseventsv2/async"; 10 | const path3 = "/v1/search?"; 11 | 12 | if (url.indexOf(path1) != -1) { 13 | console.log(path1); 14 | let configs = JSON.parse(body); 15 | configs.deviceInfo.preferredLanguages = ["zh-CN", "zh-Hans", "en-US"]; 16 | if (['US', 'CA', 'UK', 'AU'].some(_ => _ != configs.deviceInfo.countryCode)) configs.deviceInfo.countryCode = "US"; 17 | body = JSON.stringify(configs); 18 | $done({ body }); 19 | } else if (url.indexOf(path2) != -1) { 20 | console.log(path2); 21 | let async = JSON.parse(body); 22 | if (async.data.session.mobileData) { 23 | async.data.session.mobileData.countryCode = "310"; 24 | async.data.session.mobileData.carrier = "Google Fi"; 25 | async.data.session.mobileData.networkCode = "260"; 26 | }; 27 | body = JSON.stringify(async); 28 | $done({ body }); 29 | } else if (url.indexOf(path3) != -1) { 30 | console.log(path3); 31 | if (processQuery(url, 'storefrontID') == '143441') $done({ url }) //US 32 | else if (processQuery(url, 'storefrontID') == '143455') $done({ url }) //CA 33 | else if (processQuery(url, 'storefrontID') == '143444') $done({ url }) //UK 34 | else if (processQuery(url, 'storefrontID') == '143460') $done({ url }) //AU 35 | else url = processQuery(url, 'storefrontID', '143441'); $done({ url }); //Other Region, Redirect StoreFrontID to US (143441) 36 | } else $done({}); 37 | 38 | // Function 1 39 | // process Query URL 40 | // 查询并替换自身,url为链接,variable为参数,parameter为新值(如果有就替换) 41 | // https://github.com/VirgilClyne/iRingo/blob/main/js/QueryURL.js 42 | function processQuery(url, variable, parameter) { 43 | console.log(`processQuery, INPUT: variable: ${variable}, parameter: ${parameter}`, ``); 44 | if (url.indexOf("?") != -1) { 45 | if (parameter == undefined) { 46 | console.log(`getQueryVariable, INPUT: variable: ${variable}`, ``); 47 | var query = url.split("?")[1]; 48 | var vars = query.split("&"); 49 | for (var i = 0; i < vars.length; i++) { 50 | var pair = vars[i].split("="); 51 | if (pair[0] == variable) { 52 | console.log(`getQueryVariable, OUTPUT: ${variable}=${pair[1]}`, ``); 53 | return pair[1]; 54 | } 55 | } 56 | console.log(`getQueryVariable, ERROR: No such variable: ${variable}, Skip`, ``); 57 | return false; 58 | } else { 59 | console.log(`replaceQueryParamter, INPUT: ${variable}=${parameter}, Start`, ``); 60 | var re = new RegExp('(' + variable + '=)([^&]*)', 'gi') 61 | var newUrl = url.replace(re, variable + '=' + parameter) 62 | console.log(`replaceQueryParamter, OUTPUT: ${variable}=${parameter}`, newUrl, ``); 63 | return newUrl 64 | }; 65 | } else { 66 | console.log(`processQuery, ERROR: No such URL ,Skip`, url, ``); 67 | return url; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /src/request.js: -------------------------------------------------------------------------------- 1 | import { $platform, URL, _, Storage, fetch, notification, log, logError, wait, done, getScript, runScript } from "./utils/utils.mjs"; 2 | import database from "./function/database.mjs"; 3 | import setENV from "./function/setENV.mjs"; 4 | // 构造回复数据 5 | let $response = undefined; 6 | /***************** Processing *****************/ 7 | // 解构URL 8 | const url = new URL($request.url); 9 | log(`⚠ url: ${url.toJSON()}`, ""); 10 | // 获取连接参数 11 | const METHOD = $request.method, HOST = url.hostname, PATH = url.pathname; 12 | log(`⚠ METHOD: ${METHOD}, HOST: ${HOST}, PATH: ${PATH}` , ""); 13 | // 解析格式 14 | const FORMAT = ($request.headers?.["Content-Type"] ?? $request.headers?.["content-type"])?.split(";")?.[0]; 15 | log(`⚠ FORMAT: ${FORMAT}`, ""); 16 | !(async () => { 17 | /** 18 | * @type {{Settings: import('./interface').Settings}} 19 | */ 20 | const { Settings, Caches, Configs } = setENV("iRingo", "News", database); 21 | log(`⚠ Settings.Switch: ${Settings?.Switch}`, ""); 22 | switch (Settings.Switch) { 23 | case true: 24 | default: 25 | // 创建空数据 26 | let body = {}; 27 | // 方法判断 28 | switch (METHOD) { 29 | case "POST": 30 | case "PUT": 31 | case "PATCH": 32 | case "DELETE": 33 | // 格式判断 34 | switch (FORMAT) { 35 | case undefined: // 视为无body 36 | break; 37 | case "application/x-www-form-urlencoded": 38 | case "text/plain": 39 | default: 40 | break; 41 | case "application/x-mpegURL": 42 | case "application/x-mpegurl": 43 | case "application/vnd.apple.mpegurl": 44 | case "audio/mpegurl": 45 | break; 46 | case "text/xml": 47 | case "text/html": 48 | case "text/plist": 49 | case "application/xml": 50 | case "application/plist": 51 | case "application/x-plist": 52 | break; 53 | case "text/vtt": 54 | case "application/vtt": 55 | break; 56 | case "text/json": 57 | case "application/json": 58 | body = JSON.parse($request.body ?? "{}"); 59 | // 主机判断 60 | switch (HOST) { 61 | case "news-edge.apple.com": 62 | case "news-todayconfig-edge.apple.com": 63 | // 路径判断 64 | switch (PATH) { 65 | case "/v1/configs": 66 | if (Settings.CountryCode !== "AUTO") body.storefrontId = Configs.Storefront[Settings.CountryCode]; 67 | if (body?.deviceInfo?.preferredLanguages) { 68 | body.deviceInfo.preferredLanguages.unshift("zh-SG", "zh-Hans-US", "zh-Hant-US"); 69 | body.deviceInfo.preferredLanguages.push("en"); 70 | }; 71 | if (Settings.CountryCode !== "AUTO") body.deviceInfo.countryCode = Settings?.CountryCode ?? "US"; 72 | break; 73 | }; 74 | break; 75 | case "news-events.apple.com": 76 | case "news-sports-events.apple.com": 77 | switch (PATH) { 78 | case "/analyticseventsv2/async": 79 | if (body?.data?.session?.mobileData) { 80 | body.data.session.mobileData.countryCode = "310"; 81 | body.data.session.mobileData.carrier = "Google Fi"; 82 | body.data.session.mobileData.networkCode = "260"; 83 | }; 84 | break; 85 | }; 86 | break; 87 | case "news-client-search.apple.com": 88 | switch (PATH) { 89 | case "/v1/search": 90 | break; 91 | }; 92 | break; 93 | }; 94 | $request.body = JSON.stringify(body); 95 | break; 96 | case "application/protobuf": 97 | case "application/x-protobuf": 98 | case "application/vnd.google.protobuf": 99 | case "application/grpc": 100 | case "application/grpc+proto": 101 | case "applecation/octet-stream": 102 | break; 103 | }; 104 | //break; // 不中断,继续处理URL 105 | case "GET": 106 | case "HEAD": 107 | case "OPTIONS": 108 | default: 109 | // 主机判断 110 | switch (HOST) { 111 | case "news-edge.apple.com": 112 | case "news-todayconfig-edge.apple.com": 113 | // 路径判断 114 | switch (PATH) { 115 | case "/v1/configs": 116 | break; 117 | }; 118 | break; 119 | case "news-events.apple.com": 120 | case "news-sports-events.apple.com": 121 | switch (PATH) { 122 | case "/analyticseventsv2/async": 123 | break; 124 | }; 125 | break; 126 | case "news-client-search.apple.com": 127 | switch (PATH) { 128 | case "/v1/search": 129 | const ParsecParameters = url.searchParams.get("parsecParameters"), StorefrontID = url.searchParams.get("storefrontID"), NewsPlusUser = url.searchParams.get("newsPlusUser"); 130 | if (ParsecParameters) { 131 | let parsecParameters = decodeURIComponent(ParsecParameters) 132 | parsecParameters = JSON.parse(parsecParameters); 133 | if (parsecParameters.storeFront) { 134 | if (Settings.CountryCode !== "AUTO") parsecParameters.storeFront = parsecParameters.storeFront.replace(/[\d]{6}/, Configs.Storefront[Settings.CountryCode]); 135 | }; 136 | parsecParameters = JSON.stringify(parsecParameters); 137 | parsecParameters = encodeURIComponent(parsecParameters); 138 | url.searchParams.set("parsecParameters", parsecParameters); 139 | }; 140 | if (StorefrontID) { 141 | if (Settings.CountryCode !== "AUTO") url.searchParams.set("storefrontID", Configs.Storefront[Settings.CountryCode]); 142 | }; 143 | if (NewsPlusUser) url.searchParams.set("newsPlusUser", Settings.NewsPlusUser || NewsPlusUser); 144 | break; 145 | }; 146 | break; 147 | }; 148 | break; 149 | case "CONNECT": 150 | case "TRACE": 151 | break; 152 | }; 153 | $request.url = url.toString(); 154 | log(`🚧 调试信息`, `$request.url: ${$request.url}`, ""); 155 | break; 156 | case false: 157 | break; 158 | }; 159 | })() 160 | .catch((e) => logError(e)) 161 | .finally(() => { 162 | switch ($response) { 163 | default: // 有构造回复数据,返回构造的回复数据 164 | if ($response.headers?.["Content-Encoding"]) $response.headers["Content-Encoding"] = "identity"; 165 | if ($response.headers?.["content-encoding"]) $response.headers["content-encoding"] = "identity"; 166 | switch ($platform) { 167 | default: 168 | done({ response: $response }); 169 | break; 170 | case "Quantumult X": 171 | if (!$response.status) $response.status = "HTTP/1.1 200 OK"; 172 | delete $response.headers?.["Content-Length"]; 173 | delete $response.headers?.["content-length"]; 174 | delete $response.headers?.["Transfer-Encoding"]; 175 | done($response); 176 | break; 177 | }; 178 | break; 179 | case undefined: // 无构造回复数据,发送修改的请求数据 180 | done($request); 181 | break; 182 | }; 183 | }) 184 | -------------------------------------------------------------------------------- /src/function/database.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | "News": { 3 | "Settings": { 4 | "Switch": true, 5 | "CountryCode": "US", 6 | "NewsPlusUser": true 7 | } 8 | }, 9 | "Default": { 10 | "Settings": { 11 | "Switch": true, 12 | }, 13 | "Configs": { 14 | "Storefront": { 15 | "AE": "143481", 16 | "AF": "143610", 17 | "AG": "143540", 18 | "AI": "143538", 19 | "AL": "143575", 20 | "AM": "143524", 21 | "AO": "143564", 22 | "AR": "143505", 23 | "AT": "143445", 24 | "AU": "143460", 25 | "AZ": "143568", 26 | "BA": "143612", 27 | "BB": "143541", 28 | "BD": "143490", 29 | "BE": "143446", 30 | "BF": "143578", 31 | "BG": "143526", 32 | "BH": "143559", 33 | "BJ": "143576", 34 | "BM": "143542", 35 | "BN": "143560", 36 | "BO": "143556", 37 | "BR": "143503", 38 | "BS": "143539", 39 | "BT": "143577", 40 | "BW": "143525", 41 | "BY": "143565", 42 | "BZ": "143555", 43 | "CA": "143455", 44 | "CD": "143613", 45 | "CG": "143582", 46 | "CH": "143459", 47 | "CI": "143527", 48 | "CL": "143483", 49 | "CM": "143574", 50 | "CN": "143465", 51 | "CO": "143501", 52 | "CR": "143495", 53 | "CV": "143580", 54 | "CY": "143557", 55 | "CZ": "143489", 56 | "DE": "143443", 57 | "DK": "143458", 58 | "DM": "143545", 59 | "DO": "143508", 60 | "DZ": "143563", 61 | "EC": "143509", 62 | "EE": "143518", 63 | "EG": "143516", 64 | "ES": "143454", 65 | "FI": "143447", 66 | "FJ": "143583", 67 | "FM": "143591", 68 | "FR": "143442", 69 | "GA": "143614", 70 | "GB": "143444", 71 | "GD": "143546", 72 | "GF": "143615", 73 | "GH": "143573", 74 | "GM": "143584", 75 | "GR": "143448", 76 | "GT": "143504", 77 | "GW": "143585", 78 | "GY": "143553", 79 | "HK": "143463", 80 | "HN": "143510", 81 | "HR": "143494", 82 | "HU": "143482", 83 | "ID": "143476", 84 | "IE": "143449", 85 | "IL": "143491", 86 | "IN": "143467", 87 | "IQ": "143617", 88 | "IS": "143558", 89 | "IT": "143450", 90 | "JM": "143511", 91 | "JO": "143528", 92 | "JP": "143462", 93 | "KE": "143529", 94 | "KG": "143586", 95 | "KH": "143579", 96 | "KN": "143548", 97 | "KP": "143466", 98 | "KR": "143466", 99 | "KW": "143493", 100 | "KY": "143544", 101 | "KZ": "143517", 102 | "TC": "143552", 103 | "TD": "143581", 104 | "TJ": "143603", 105 | "TH": "143475", 106 | "TM": "143604", 107 | "TN": "143536", 108 | "TO": "143608", 109 | "TR": "143480", 110 | "TT": "143551", 111 | "TW": "143470", 112 | "TZ": "143572", 113 | "LA": "143587", 114 | "LB": "143497", 115 | "LC": "143549", 116 | "LI": "143522", 117 | "LK": "143486", 118 | "LR": "143588", 119 | "LT": "143520", 120 | "LU": "143451", 121 | "LV": "143519", 122 | "LY": "143567", 123 | "MA": "143620", 124 | "MD": "143523", 125 | "ME": "143619", 126 | "MG": "143531", 127 | "MK": "143530", 128 | "ML": "143532", 129 | "MM": "143570", 130 | "MN": "143592", 131 | "MO": "143515", 132 | "MR": "143590", 133 | "MS": "143547", 134 | "MT": "143521", 135 | "MU": "143533", 136 | "MV": "143488", 137 | "MW": "143589", 138 | "MX": "143468", 139 | "MY": "143473", 140 | "MZ": "143593", 141 | "NA": "143594", 142 | "NE": "143534", 143 | "NG": "143561", 144 | "NI": "143512", 145 | "NL": "143452", 146 | "NO": "143457", 147 | "NP": "143484", 148 | "NR": "143606", 149 | "NZ": "143461", 150 | "OM": "143562", 151 | "PA": "143485", 152 | "PE": "143507", 153 | "PG": "143597", 154 | "PH": "143474", 155 | "PK": "143477", 156 | "PL": "143478", 157 | "PT": "143453", 158 | "PW": "143595", 159 | "PY": "143513", 160 | "QA": "143498", 161 | "RO": "143487", 162 | "RS": "143500", 163 | "RU": "143469", 164 | "RW": "143621", 165 | "SA": "143479", 166 | "SB": "143601", 167 | "SC": "143599", 168 | "SE": "143456", 169 | "SG": "143464", 170 | "SI": "143499", 171 | "SK": "143496", 172 | "SL": "143600", 173 | "SN": "143535", 174 | "SR": "143554", 175 | "ST": "143598", 176 | "SV": "143506", 177 | "SZ": "143602", 178 | "UA": "143492", 179 | "UG": "143537", 180 | "US": "143441", 181 | "UY": "143514", 182 | "UZ": "143566", 183 | "VC": "143550", 184 | "VE": "143502", 185 | "VG": "143543", 186 | "VN": "143471", 187 | "VU": "143609", 188 | "XK": "143624", 189 | "YE": "143571", 190 | "ZA": "143472", 191 | "ZM": "143622", 192 | "ZW": "143605", 193 | }, 194 | }, 195 | }, 196 | } 197 | -------------------------------------------------------------------------------- /src/request.dev.js: -------------------------------------------------------------------------------- 1 | import { $platform, URL, _, Storage, fetch, notification, log, logError, wait, done, getScript, runScript } from "./utils/utils.mjs"; 2 | import database from "./function/database.mjs"; 3 | import setENV from "./function/setENV.mjs"; 4 | // 构造回复数据 5 | let $response = undefined; 6 | /***************** Processing *****************/ 7 | // 解构URL 8 | const url = new URL($request.url); 9 | log(`⚠ url: ${url.toJSON()}`, ""); 10 | // 获取连接参数 11 | const METHOD = $request.method, HOST = url.hostname, PATH = url.pathname; 12 | log(`⚠ METHOD: ${METHOD}, HOST: ${HOST}, PATH: ${PATH}` , ""); 13 | // 解析格式 14 | const FORMAT = ($request.headers?.["Content-Type"] ?? $request.headers?.["content-type"])?.split(";")?.[0]; 15 | log(`⚠ FORMAT: ${FORMAT}`, ""); 16 | !(async () => { 17 | /** 18 | * @type {{Settings: import('./interface').Settings}} 19 | */ 20 | const { Settings, Caches, Configs } = setENV("iRingo", "News", database); 21 | log(`⚠ Settings.Switch: ${Settings?.Switch}`, ""); 22 | switch (Settings.Switch) { 23 | case true: 24 | default: 25 | // 创建空数据 26 | let body = {}; 27 | // 方法判断 28 | switch (METHOD) { 29 | case "POST": 30 | case "PUT": 31 | case "PATCH": 32 | case "DELETE": 33 | // 格式判断 34 | switch (FORMAT) { 35 | case undefined: // 视为无body 36 | break; 37 | case "application/x-www-form-urlencoded": 38 | case "text/plain": 39 | default: 40 | break; 41 | case "application/x-mpegURL": 42 | case "application/x-mpegurl": 43 | case "application/vnd.apple.mpegurl": 44 | case "audio/mpegurl": 45 | //body = M3U8.parse($request.body); 46 | //log(`🚧 body: ${JSON.stringify(body)}`, ""); 47 | //$request.body = M3U8.stringify(body); 48 | break; 49 | case "text/xml": 50 | case "text/html": 51 | case "text/plist": 52 | case "application/xml": 53 | case "application/plist": 54 | case "application/x-plist": 55 | //body = XML.parse($request.body); 56 | //log(`🚧 body: ${JSON.stringify(body)}`, ""); 57 | //$request.body = XML.stringify(body); 58 | break; 59 | case "text/vtt": 60 | case "application/vtt": 61 | //body = VTT.parse($request.body); 62 | //log(`🚧 body: ${JSON.stringify(body)}`, ""); 63 | //$request.body = VTT.stringify(body); 64 | break; 65 | case "text/json": 66 | case "application/json": 67 | body = JSON.parse($request.body ?? "{}"); 68 | log(`🚧 body: ${JSON.stringify(body)}`, ""); 69 | // 主机判断 70 | switch (HOST) { 71 | case "news-edge.apple.com": 72 | case "news-todayconfig-edge.apple.com": 73 | // 路径判断 74 | switch (PATH) { 75 | case "/v1/configs": 76 | if (Settings.CountryCode !== "AUTO") body.storefrontId = Configs.Storefront[Settings.CountryCode]; 77 | if (body?.deviceInfo?.preferredLanguages) { 78 | body.deviceInfo.preferredLanguages.unshift("zh-SG", "zh-Hans-US", "zh-Hant-US"); 79 | body.deviceInfo.preferredLanguages.push("en"); 80 | }; 81 | if (Settings.CountryCode !== "AUTO") body.deviceInfo.countryCode = Settings?.CountryCode ?? "US"; 82 | break; 83 | }; 84 | break; 85 | case "news-events.apple.com": 86 | case "news-sports-events.apple.com": 87 | switch (PATH) { 88 | case "/analyticseventsv2/async": 89 | if (body?.data?.session?.mobileData) { 90 | body.data.session.mobileData.countryCode = "310"; 91 | body.data.session.mobileData.carrier = "Google Fi"; 92 | body.data.session.mobileData.networkCode = "260"; 93 | }; 94 | break; 95 | }; 96 | break; 97 | case "news-client-search.apple.com": 98 | switch (PATH) { 99 | case "/v1/search": 100 | break; 101 | }; 102 | break; 103 | }; 104 | $request.body = JSON.stringify(body); 105 | break; 106 | case "application/protobuf": 107 | case "application/x-protobuf": 108 | case "application/vnd.google.protobuf": 109 | case "application/grpc": 110 | case "application/grpc+proto": 111 | case "applecation/octet-stream": 112 | break; 113 | }; 114 | //break; // 不中断,继续处理URL 115 | case "GET": 116 | case "HEAD": 117 | case "OPTIONS": 118 | default: 119 | // 主机判断 120 | switch (HOST) { 121 | case "news-edge.apple.com": 122 | case "news-todayconfig-edge.apple.com": 123 | // 路径判断 124 | switch (PATH) { 125 | case "/v1/configs": 126 | break; 127 | }; 128 | break; 129 | case "news-events.apple.com": 130 | case "news-sports-events.apple.com": 131 | switch (PATH) { 132 | case "/analyticseventsv2/async": 133 | break; 134 | }; 135 | break; 136 | case "news-client-search.apple.com": 137 | switch (PATH) { 138 | case "/v1/search": 139 | const ParsecParameters = url.searchParams.get("parsecParameters"), StorefrontID = url.searchParams.get("storefrontID"), NewsPlusUser = url.searchParams.get("newsPlusUser"); 140 | log(`🚧 调试信息, ParsecParameters: ${ParsecParameters}, StorefrontID: ${StorefrontID}, NewsPlusUser: ${NewsPlusUser}`, ""); 141 | if (ParsecParameters) { 142 | let parsecParameters = decodeURIComponent(ParsecParameters) 143 | log(`🚧 调试信息`, `decodeURIComponent(ParsecParameters): ${parsecParameters}`, ""); 144 | parsecParameters = JSON.parse(parsecParameters); 145 | //log(`🚧 调试信息`, `JSON.parse(parsecParameters): ${parsecParameters}`, ""); 146 | if (parsecParameters.storeFront) { 147 | if (Settings.CountryCode !== "AUTO") parsecParameters.storeFront = parsecParameters.storeFront.replace(/[\d]{6}/, Configs.Storefront[Settings.CountryCode]); 148 | }; 149 | parsecParameters = JSON.stringify(parsecParameters); 150 | //log(`🚧 调试信息`, `JSON.stringify(parsecParameters): ${parsecParameters}`, ""); 151 | parsecParameters = encodeURIComponent(parsecParameters); 152 | //log(`🚧 调试信息`, `encodeURIComponent(parsecParameters): ${parsecParameters}`, ""); 153 | url.searchParams.set("parsecParameters", parsecParameters); 154 | }; 155 | if (StorefrontID) { 156 | if (Settings.CountryCode !== "AUTO") url.searchParams.set("storefrontID", Configs.Storefront[Settings.CountryCode]); 157 | }; 158 | if (NewsPlusUser) url.searchParams.set("newsPlusUser", Settings.NewsPlusUser || NewsPlusUser); 159 | break; 160 | }; 161 | break; 162 | }; 163 | break; 164 | case "CONNECT": 165 | case "TRACE": 166 | break; 167 | }; 168 | $request.url = url.toString(); 169 | log(`🚧 调试信息`, `$request.url: ${$request.url}`, ""); 170 | break; 171 | case false: 172 | break; 173 | }; 174 | })() 175 | .catch((e) => logError(e)) 176 | .finally(() => { 177 | switch ($response) { 178 | default: // 有构造回复数据,返回构造的回复数据 179 | //log(`🚧 finally`, `echo $response: ${JSON.stringify($response, null, 2)}`, ""); 180 | if ($response.headers?.["Content-Encoding"]) $response.headers["Content-Encoding"] = "identity"; 181 | if ($response.headers?.["content-encoding"]) $response.headers["content-encoding"] = "identity"; 182 | switch ($platform) { 183 | default: 184 | done({ response: $response }); 185 | break; 186 | case "Quantumult X": 187 | if (!$response.status) $response.status = "HTTP/1.1 200 OK"; 188 | delete $response.headers?.["Content-Length"]; 189 | delete $response.headers?.["content-length"]; 190 | delete $response.headers?.["Transfer-Encoding"]; 191 | done($response); 192 | break; 193 | }; 194 | break; 195 | case undefined: // 无构造回复数据,发送修改的请求数据 196 | //log(`🚧 finally`, `$request: ${JSON.stringify($request, null, 2)}`, ""); 197 | done($request); 198 | break; 199 | }; 200 | }) 201 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------