PageSourceSearch

https://rsshub.netlify.app/assets/js/a3854e2a.c2c20afc.js

js rsshub.netlify.app collected 2026-10-03 11:22:01 UTC 18,783 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkwebsite=self.webpackChunkwebsite||[]).push([[3331],{6322:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>d,contentTitle:()=>o,default:()=>l,frontMatter:()=>i,metadata:()=>a,toc:()=>c});var t=s(1527),r=s(4128);const i={sidebar_position:3},o="New RSSHub Radar Rules",a={id:"joinus/new-radar",title:"New RSSHub Radar Rules",description:"The following document is the old version standard, please refer /lib/types.ts#L183 to the new version standard",source:"@site/docs/joinus/new-radar.md",sourceDirName:"joinus",slug:"/joinus/new-radar",permalink:"/joinus/new-radar",draft:!1,unlisted:!1,editUrl:"https://github.com/DIYgod/RSSHub/blob/master/website/docs/joinus/new-radar.md",tags:[],version:"current",lastUpdatedBy:"Tony",lastUpdatedAt:1710530924,formattedLastUpdatedAt:"Mar 15, 2024",sidebarPosition:3,frontMatter:{sidebar_position:3},sidebar:"joinusSidebar",previous:{title:"Submit your route",permalink:"/joinus/new-rss/submit-route"},next:{title:"RSS Feed Fundamentals",permalink:"/joinus/advanced/advanced-feed"}},d={},c=[{value:"Code the rule",id:"code-the-rule",level:2},{value:"Top-level Object key",id:"top-level-object-key",level:2},{value:"Inner object key",id:"inner-object-key",level:2},{value:"<code>title</code>",id:"title",level:3},{value:"<code>docs</code>",id:"docs",level:3},{value:"<code>source</code>",id:"source",level:3},{value:"<code>target</code>",id:"target",level:3},{value:"<code>target</code> as a function",id:"target-as-a-function",level:4},{value:"RSSBud",id:"rssbud",level:3},{value:"Debugging Radar Rules",id:"debugging-radar-rules",level:2}];function h(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,r.a)(),...e.components},{TabItem:s,Tabs:i}=n;return s||u("TabItem",!0),i||u("Tabs",!0),(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.h1,{id:"new-rsshub-radar-rules",children:"New RSSHub Radar Rules"}),"\n",(0,t.jsx)(n.admonition,{type:"warning",children:(0,t.jsxs)(n.p,{children:["The following document is the old version standard, please refer ",(0,t.jsx)(n.a,{href:"https://github.com/DIYgod/RSSHub/blob/master/lib/types.ts#L183",children:"/lib/types.ts#L183"})," to the new version standard"]})}),"\n",(0,t.jsxs)(n.p,{children:["If you want to see the results, we suggest you install the browser extension. You can download it for your browser on the ",(0,t.jsx)(n.a,{href:"/joinus/quick-start#submit-new-rsshub-radar-rules-before-you-start",children:"Join Us"})," page."]}),"\n",(0,t.jsx)(n.h2,{id:"code-the-rule",children:"Code the rule"}),"\n",(0,t.jsxs)(n.p,{children:["To create a new RSS feed, create a file called ",(0,t.jsx)(n.code,{children:"radar.ts"})," under the corresponding namespace in ",(0,t.jsx)(n.a,{href:"https://github.com/DIYgod/RSSHub/tree/master/lib/routes",children:"/lib/routes/"}),". We will continue to use the example of creating an RSS feed for ",(0,t.jsx)(n.code,{children:"GitHub Repo Issues"}),", which is described ",(0,t.jsx)(n.a,{href:"/joinus/new-rss/before-start",children:"here"}),". The resulting code will look like this:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"export default {\n    'github.com': {\n        _name: 'GitHub',\n        '.': [\n            {\n                title: 'Repo Issues',\n                docs: 'https://docs.rsshub.app/routes/programming#github',\n                source: ['/:user/:repo/issues/:id', '/:user/:repo/issues',  '/:user/:repo'],\n                target: '/github/issue/:user/:repo',\n            },\n        ],\n    },\n};\n"})}),"\n",(0,t.jsx)(n.h2,{id:"top-level-object-key",children:"Top-level Object key"}),"\n",(0,t.jsx)(n.p,{children:"The object key is the domain name without any subdomains, URL path, or protocol."}),"\n",(0,t.jsx)(n.p,{children:(0,t.jsx)(n.img,{src:"https://wsrv.nl/?url=https://enwpgo.files.wordpress.com/2022/10/image-30.png&output=webp",alt:"Struction of a URL"})}),"\n",(0,t.jsxs)(n.p,{children:["In this case, the domain name is ",(0,t.jsx)(n.code,{children:"github.com"}),", so the object key is ",(0,t.jsx)(n.code,{children:"github.com"}),"."]}),"\n",(0,t.jsx)(n.h2,{id:"inner-object-key",children:"Inner object key"}),"\n",(0,t.jsxs)(n.p,{children:["The first inner object key is ",(0,t.jsx)(n.code,{children:"_name"}),", which is the name of the website. This should be the same as the level 2 heading (",(0,t.jsx)(n.code,{children:"##"}),") of the route documentation. In this case, it's ",(0,t.jsx)(n.code,{children:"GitHub"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["The rest of the inner object keys are the subdomains of a website. If a website you want to match does not have any subdomains, or you want to match both ",(0,t.jsx)(n.code,{children:"www.example.com"})," and ",(0,t.jsx)(n.code,{children:"example.com"}),", use ",(0,t.jsx)(n.code,{children:"'.'"})," instead. In this case, we will use ",(0,t.jsx)(n.code,{children:"'.'"})," since we want to match ",(0,t.jsx)(n.code,{children:"github.com"}),". Note that each subdomain should return ",(0,t.jsx)(n.strong,{children:"an array of objects"}),"."]}),"\n",(0,t.jsxs)(i,{children:[(0,t.jsx)(s,{value:"github.com",label:"github.com and www.github.com",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"export default {\n    'github.com': {\n        _name: 'GitHub',\n        // highlight-next-line\n        '.': [\n            {\n                title: '...',\n                docs: '...',\n                source: ['/...'],\n                target: '/...',\n            },\n        ],\n    },\n};\n"})})}),(0,t.jsx)(s,{value:"abc.github.com",label:"abc.github.com",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"export default {\n    'github.com': {\n        _name: 'GitHub',\n        // highlight-next-line\n        abc: [\n            {\n                title: '...',\n                docs: '...',\n                source: ['/...'],\n                target: '/...',\n            },\n        ],\n    },\n};\n"})})}),(0,t.jsx)(s,{value:"abc.def.github.com",label:"abc.def.github.com",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"export default {\n    'github.com': {\n        _name: 'GitHub',\n        // highlight-next-line\n        'abc.def': [\n            {\n                title: '...',\n                docs: '...',\n                source: ['/...'],\n                target: '/...',\n            },\n        ],\n    },\n};\n"})})})]}),"\n",(0,t.jsx)(n.h3,{id:"title",children:(0,t.jsx)(n.code,{children:"title"})}),"\n",(0,t.jsxs)(n.p,{children:["The title is a ",(0,t.jsx)(n.em,{children:"required"})," field and should be the same as the level 3 heading (",(0,t.jsx)(n.code,{children:"###"}),") of the route documentation. In this case, it's ",(0,t.jsx)(n.code,{children:"Repo Issues"}),". Do not repeat the website name (",(0,t.jsx)(n.code,{children:"_name"}),"), which is ",(0,t.jsx)(n.code,{children:"GitHub"}),", in ",(0,t.jsx)(n.code,{children:"title"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"docs",children:(0,t.jsx)(n.code,{children:"docs"})}),"\n",(0,t.jsxs)(n.p,{children:["The documentation link is also a ",(0,t.jsx)(n.em,{children:"required"})," field. In this case, the documentation link for ",(0,t.jsx)(n.code,{children:"GitHub Repo Issues"})," will be ",(0,t.jsx)(n.code,{children:"https://docs.rsshub.app/routes/programming#github"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["Note that the hash should be positioned to the level 2 heading (",(0,t.jsx)(n.code,{children:"##"}),"), and not ",(0,t.jsx)(n.code,{children:"https://docs.rsshub.app/routes/programming#github-repo-issues"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"source",children:(0,t.jsx)(n.code,{children:"source"})}),"\n",(0,t.jsxs)(n.p,{children:["The source field is ",(0,t.jsx)(n.em,{children:"optional"})," and should specifies the URL path. Leave it blank if you don't want to match any URL paths. It only appears in ",(0,t.jsx)(n.code,{children:"RSSHub for the current site"})," option of the RSSHub Radar browser extension."]}),"\n",(0,t.jsxs)(n.p,{children:["The source should be an array of str
1ings. For example, if the source for ",(0,t.jsx)(n.code,{children:"GitHub Repo Issues"})," is ",(0,t.jsx)(n.code,{children:"/:user/:repo"}),", it means that when you visit ",(0,t.jsx)(n.code,{children:"https://github.com/DIYgod/RSSHub"}),", which matches the ",(0,t.jsx)(n.code,{children:"github.com/:user/:repo"})," pattern, the parameters for this URL will be: ",(0,t.jsx)(n.code,{children:"{user: 'DIYgod', repo: 'RSSHub'}"}),". The browser extension uses these parameters to create an RSSHub subscription address based on the ",(0,t.jsx)(n.code,{children:"target"})," field."]}),"\n",(0,t.jsx)(n.admonition,{type:"warning",children:(0,t.jsxs)(n.p,{children:["If the value you want to extract is in the URL search parameters or URL hash, use target as a function instead of the ",(0,t.jsx)(n.code,{children:"source"})," field. Also, remember that the ",(0,t.jsx)(n.code,{children:"source"})," field only matches the URL path and not any other parts of the URL."]})}),"\n",(0,t.jsxs)(n.p,{children:["You can use the ",(0,t.jsx)(n.code,{children:"*"})," symbol to perform wildcard matching. Note that the syntax here is not the same as the ",(0,t.jsx)(n.a,{href:"https://github.com/pillarjs/path-to-regexp",children:"path-to-regexp"}),". For instance, ",(0,t.jsx)(n.code,{children:"/:user/:repo/*"})," will match both ",(0,t.jsx)(n.code,{children:"https://github.com/DIYgod/RSSHub/issues"})," and ",(0,t.jsx)(n.code,{children:"https://github.com/DIYgod/RSSHub/issues/1234"}),". If you want to name the matching result, you can place the variable name after the ",(0,t.jsx)(n.code,{children:"*"})," symbol. For example, ",(0,t.jsx)(n.code,{children:"/user/:repo/*path"}),", whereby path will be ",(0,t.jsx)(n.code,{children:"issues"})," and ",(0,t.jsx)(n.code,{children:"issues/1234"})," in the above scenario."]}),"\n",(0,t.jsx)(n.h3,{id:"target",children:(0,t.jsx)(n.code,{children:"target"})}),"\n",(0,t.jsxs)(n.p,{children:["The target field is ",(0,t.jsx)(n.em,{children:"optional"})," and is used to generate an RSSHub subscription address. It accepts both a string or a function. If you don't want to create an RSSHub subscription address, leave this field empty."]}),"\n",(0,t.jsxs)(n.p,{children:["For the ",(0,t.jsx)(n.code,{children:"GitHub Repo Issues"})," example, the corresponding route path in the RSSHub documentation is ",(0,t.jsx)(n.code,{children:"/github/issue/:user/:repo"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["After matching the ",(0,t.jsx)(n.code,{children:"user"})," with ",(0,t.jsx)(n.code,{children:"DIYgod"})," and ",(0,t.jsx)(n.code,{children:"repo"})," with ",(0,t.jsx)(n.code,{children:"RSSHub"})," in the source path, the ",(0,t.jsx)(n.code,{children:":user"})," in the RSSHub route path will be replaced with ",(0,t.jsx)(n.code,{children:"DIYgod"}),", and ",(0,t.jsx)(n.code,{children:":repo"})," will be replaced with ",(0,t.jsx)(n.code,{children:"RSSHub"}),", resulting in ",(0,t.jsx)(n.code,{children:"/github/issue/DIYgod/RSSHub"}),"."]}),"\n",(0,t.jsxs)(n.h4,{id:"target-as-a-function",children:[(0,t.jsx)(n.code,{children:"target"})," as a function"]}),"\n",(0,t.jsxs)(n.p,{children:["In some cases, the source path may not match the desired parameters for an RSSHub route. In these situations, we can use the ",(0,t.jsx)(n.code,{children:"target"})," field as a function with ",(0,t.jsx)(n.code,{children:"params"}),", ",(0,t.jsx)(n.code,{children:"url"}),", and ",(0,t.jsx)(n.code,{children:"document"})," parameters."]}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"params"})," parameter contains the parameters matched by the ",(0,t.jsx)(n.code,{children:"source"})," field, while the ",(0,t.jsx)(n.code,{children:"url"})," parameter is the current web page URL string, and the ",(0,t.jsx)(n.code,{children:"document"})," parameter is the ",(0,t.jsx)(n.a,{href:"https://developer.mozilla.org/docs/Web/API/document",children:"document interface"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["It is essential to note that the ",(0,t.jsx)(n.code,{children:"target"})," method runs in a sandbox, and any changes made to ",(0,t.jsx)(n.code,{children:"document"})," will not be reflected in the web page."]}),"\n",(0,t.jsxs)(n.p,{children:["Here are two examples of how to use the ",(0,t.jsx)(n.code,{children:"target"})," field as a function:"]}),"\n",(0,t.jsxs)(i,{children:[(0,t.jsx)(s,{value:"params",label:"Match using params",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"export default {\n    'github.com': {\n        _name: 'GitHub',\n        '.': [\n            {\n                title: 'Repo Issues',\n                docs: 'https://docs.rsshub.app/routes/programming#github',\n                source: ['/:user/:repo/issues/:id', '/:user/:repo/issues',  '/:user/:repo'],\n                // highlight-next-line\n                target: (params) => `/github/issue/${params.user}/${params.repo}`,\n            },\n        ],\n    },\n};\n"})})}),(0,t.jsx)(s,{value:"url",label:"Match using URL",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"export default {\n    'github.com': {\n        _name: 'GitHub',\n        '.': [\n            {\n                title: 'Repo Issues',\n                docs: 'https://docs.rsshub.app/routes/programming#github',\n                source: ['/:user/:repo'],\n                // highlight-next-line\n                target: (_, url) => `/github/issue${new URL(url).pathname}`\n            },\n        ],\n    },\n};\n"})})})]}),"\n",(0,t.jsxs)(n.p,{children:["Both the above examples will return the same RSSHub subscription address as the ",(0,t.jsx)(n.a,{href:"/joinus/new-radar#code-the-rule",children:"first example"}),"."]}),"\n",(0,t.jsx)(n.h3,{id:"rssbud",children:"RSSBud"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.a,{href:"https://github.com/Cay-Zhang/RSSBud",children:"RSSBud"})," supports RSSHub Radar rules and will also be updated automatically, but please note that:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Use ",(0,t.jsx)(n.code,{children:"'.'"})," subdomain allows RSSBud to support common mobile domains such as ",(0,t.jsx)(n.code,{children:"m"})," / ",(0,t.jsx)(n.code,{children:"mobile"})]}),"\n",(0,t.jsxs)(n.li,{children:["Use ",(0,t.jsx)(n.code,{children:"document"})," in ",(0,t.jsx)(n.code,{children:"target"})," does not apply to RSSBud: RSSBud is not a browser extension, it only fetches and analyzes the URL of a website, it cannot run JavaScript"]}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"debugging-radar-rules",children:"Debugging Radar Rules"}),"\n",(0,t.jsx)(n.p,{children:'You can debug your radar rules in the RSSHub Radar extension settings of your browser. First, open the settings and switch to the "List of rules" tab. Then scroll down to the bottom of the page and you will see a text field. Here, you can replace the old rules with your new rules for debugging.'}),"\n",(0,t.jsx)(n.p,{children:'If you are worried about losing the original RSSHub radar, don\'t be. It will be restored if you click the "Update Now" button in the settings page.'}),"\n",(0,t.jsx)(n.p,{children:"Here's an example radar rule that you can play with:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"({\n    'github.com': {\n        _name: 'GitHub',\n        '.': [\n            {\n                title: 'Repo Issues',\n                docs: 'https://docs.rsshub.app/routes/programming#github',\n                source: ['/:user/:repo/issues/:id', '/:user/:repo/issues',  '/:user/:repo'],\n                target: '/github/issue/:user/:repo',\n            },\n        ],\n    },\n})\n"})}),"\n",(0,t.jsx)(n.admonition,{title:"Extra examples",type:"note",children:(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-js",children:"({\n    'bilibili.com': {\n        _name: 'bilibili',\n        www: [\n            {\n                title: '\u5206\u533a\u89c6\u9891',\n                docs: 'https://docs.rsshub.app/social-media#bilibili',\n                source: '/v/*tpath',\n                target: (params) => {\n                    let tid;\n                    switch (params.tpath) {\n                        case 'douga/mad':\n                            tid = '24';\n                            break;\n                        default:\n                            return false;\n                    }
1\n                    return `/bilibili/partion/${tid}`;\n                },\n            },\n        ],\n    },\n    'twitter.com': {\n        _name: 'Twitter',\n        '.': [\n            {\n                // for twitter.com\n                title: '\u7528\u6237\u65f6\u95f4\u7ebf',\n                docs: 'https://docs.rsshub.app/social-media#twitter',\n                source: '/:id',\n                target: (params) => {\n                    if (params.id !== 'home') {\n                        return '/twitter/user/:id';\n                    }\n                },\n            },\n        ],\n    },\n    'pixiv.net': {\n        _name: 'Pixiv',\n        www: [\n            {\n                title: '\u7528\u6237\u6536\u85cf',\n                docs: 'https://docs.rsshub.app/social-media#pixiv',\n                source: '/bookmark.php',\n                target: (params, url) => `/pixiv/user/bookmarks/${new URL(url).searchParams.get('id')}`,\n            },\n        ],\n    },\n    'weibo.com': {\n        _name: '\u5fae\u535a',\n        '.': [\n            {\n                title: '\u535a\u4e3b',\n                docs: 'https://docs.rsshub.app/social-media#%E5%BE%AE%E5%8D%9A',\n                source: ['/u/:id', '/:id'],\n                target: (params, url, document) => {\n                    const uid = document && document.documentElement.innerHTML.match(/\\$CONFIG\\['oid']='(\\d+)'/)[1];\n                    return uid ? `/weibo/user/${uid}` : '';\n                },\n            },\n        ],\n    },\n})\n"})})})]})}function l(e={}){const{wrapper:n}={...(0,r.a)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}function u(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}},4128:(e,n,s)=>{s.d(n,{Z:()=>a,a:()=>o});var t=s(959);const r={},i=t.createContext(r);function o(e){const n=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),t.createElement(i.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.