diff --git a/README.md b/README.md
index ccd5dc3d5f..b0a1b8b052 100644
--- a/README.md
+++ b/README.md
@@ -82,6 +82,9 @@ RSSHub 是一个轻量、易于扩展的 RSS 生成器,可以给任何奇奇
- 用户
- Instagram
- 用户
+- Youtube
+ - 用户
+ - 频道
## 参与我们
diff --git a/config.js b/config.js
index 2bf16e0105..472a546c1d 100644
--- a/config.js
+++ b/config.js
@@ -17,5 +17,8 @@ module.exports = {
consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
access_token: process.env.TWITTER_ACCESS_TOKEN,
access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
+ },
+ youtube: {
+ key: process.env.YOUTUBE_KEY
}
};
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index 61cbd3bc1a..cf8aa50669 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -569,4 +569,22 @@ key: 产品密钥
路由: `/instagram/user/:id`
-参数: id,用户 id
\ No newline at end of file
+参数: id,用户 id
+
+## Youtube
+
+### 用户
+
+举例: [https://rss.now.sh/youtube/user/JFlaMusic](https://rss.now.sh/youtube/user/JFlaMusic)
+
+路由: `/youtube/user/:username`
+
+参数: username,用户名
+
+### 频道
+
+举例: [https://rss.now.sh/youtube/channel/UCDwDMPOZfxVV0x_dz0eQ8KQ](https://rss.now.sh/youtube/channel/UCDwDMPOZfxVV0x_dz0eQ8KQ)
+
+路由: `/youtube/channel/:id`
+
+参数: id,频道 id
\ No newline at end of file
diff --git a/package.json b/package.json
index 0da3a3ef43..ce58716384 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"crypto": "1.0.1",
"eslint": "4.19.1",
"form-data": "^2.3.2",
+ "googleapis": "30.0.0",
"json-bigint": "0.2.3",
"koa": "2.5.0",
"koa-redis-cache": "3.0.0",
diff --git a/router.js b/router.js
index 7c880ac28b..c270de7700 100644
--- a/router.js
+++ b/router.js
@@ -103,4 +103,8 @@ router.get('/twitter/user/:id', require('./routes/twitter/user'));
// Instagram
router.get('/instagram/user/:id', require('./routes/instagram/user'));
+// Youtube
+router.get('/youtube/user/:username', require('./routes/youtube/user'));
+router.get('/youtube/channel/:id', require('./routes/youtube/channel'));
+
module.exports = router;
diff --git a/routes/youtube/channel.js b/routes/youtube/channel.js
new file mode 100644
index 0000000000..c5e78bd951
--- /dev/null
+++ b/routes/youtube/channel.js
@@ -0,0 +1,40 @@
+const { google } = require('googleapis');
+const config = require('../../config');
+const template = require('../../utils/template');
+
+const youtube = google.youtube({
+ version: 'v3',
+ auth: config.youtube.key
+});
+
+module.exports = async (ctx) => {
+ const id = ctx.params.id;
+
+ const playlistIdResponst = await youtube.channels.list({
+ part: 'contentDetails',
+ id: id,
+ });
+ const playlistId = playlistIdResponst.data.items[0].contentDetails.relatedPlaylists.uploads;
+
+ const responst = await youtube.playlistItems.list({
+ part: 'snippet,contentDetails,status',
+ playlistId: playlistId
+ });
+ const data = responst.data.items;
+
+ ctx.body = template({
+ title: `${data[0].snippet.channelTitle} 的 Youtube 视频`,
+ link: `https://www.youtube.com/channel/${id}`,
+ description: `${data[0].snippet.channelTitle} 的 Youtube 视频`,
+ item: data.map((item) => {
+ const snippet = item.snippet;
+ const img = snippet.thumbnails.maxres || snippet.thumbnails.standard || snippet.thumbnails.high || snippet.thumbnails.medium || snippet.thumbnails.default;
+ return {
+ title: snippet.title,
+ description: `${snippet.description}
`,
+ pubDate: new Date(snippet.publishedAt).toUTCString(),
+ link: `https://www.youtube.com/watch?v=${snippet.resourceId.videoId}`
+ };
+ }),
+ });
+};
\ No newline at end of file
diff --git a/routes/youtube/user.js b/routes/youtube/user.js
new file mode 100644
index 0000000000..eb5eee1f64
--- /dev/null
+++ b/routes/youtube/user.js
@@ -0,0 +1,40 @@
+const { google } = require('googleapis');
+const config = require('../../config');
+const template = require('../../utils/template');
+
+const youtube = google.youtube({
+ version: 'v3',
+ auth: config.youtube.key
+});
+
+module.exports = async (ctx) => {
+ const username = ctx.params.username;
+
+ const playlistIdResponst = await youtube.channels.list({
+ part: 'contentDetails',
+ forUsername: username,
+ });
+ const playlistId = playlistIdResponst.data.items[0].contentDetails.relatedPlaylists.uploads;
+
+ const responst = await youtube.playlistItems.list({
+ part: 'snippet,contentDetails,status',
+ playlistId: playlistId
+ });
+ const data = responst.data.items;
+
+ ctx.body = template({
+ title: `${username} 的 Youtube 视频`,
+ link: `https://www.youtube.com/user/${username}`,
+ description: `${username} 的 Youtube 视频`,
+ item: data.map((item) => {
+ const snippet = item.snippet;
+ const img = snippet.thumbnails.maxres || snippet.thumbnails.standard || snippet.thumbnails.high || snippet.thumbnails.medium || snippet.thumbnails.default;
+ return {
+ title: snippet.title,
+ description: `${snippet.description}
`,
+ pubDate: new Date(snippet.publishedAt).toUTCString(),
+ link: `https://www.youtube.com/watch?v=${snippet.resourceId.videoId}`
+ };
+ }),
+ });
+};
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index b0249cdd15..2b69672c72 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -338,7 +338,7 @@ aws4@^1.6.0:
version "1.7.0"
resolved "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289"
-axios@0.18.0:
+axios@0.18.0, axios@^0.18.0:
version "0.18.0"
resolved "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
dependencies:
@@ -372,6 +372,10 @@ base64-js@^1.0.2:
version "1.3.0"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
+base64url@2.0.0, base64url@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb"
+
base@^0.11.1:
version "0.11.2"
resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
@@ -549,6 +553,10 @@ buble@^0.19.3:
os-homedir "^1.0.1"
vlq "^1.0.0"
+buffer-equal-constant-time@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
+
buffer-from@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531"
@@ -1503,6 +1511,13 @@ ecc-jsbn@~0.1.1:
dependencies:
jsbn "~0.1.0"
+ecdsa-sig-formatter@1.0.9:
+ version "1.0.9"
+ resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1"
+ dependencies:
+ base64url "^2.0.0"
+ safe-buffer "^5.0.1"
+
ee-first@1.1.1:
version "1.1.1"
resolved "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
@@ -1805,7 +1820,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
-extend@~3.0.1:
+extend@^3.0.1, extend@~3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
@@ -2037,6 +2052,14 @@ gauge@~2.7.3:
strip-ansi "^3.0.1"
wide-align "^1.1.0"
+gcp-metadata@^0.6.2:
+ version "0.6.3"
+ resolved "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-0.6.3.tgz#4550c08859c528b370459bd77a7187ea0bdbc4ab"
+ dependencies:
+ axios "^0.18.0"
+ extend "^3.0.1"
+ retry-axios "0.3.2"
+
get-port@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc"
@@ -2145,6 +2168,35 @@ good-listener@^1.2.2:
dependencies:
delegate "^3.1.2"
+google-auth-library@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.npmjs.org/google-auth-library/-/google-auth-library-1.4.0.tgz#27dae3b6aceadcc115a9910b4f1ed27b68b1eb0b"
+ dependencies:
+ axios "^0.18.0"
+ gcp-metadata "^0.6.2"
+ gtoken "^2.2.0"
+ jws "^3.1.4"
+ lodash.isstring "^4.0.1"
+ lru-cache "^4.1.2"
+ retry-axios "^0.3.2"
+
+google-p12-pem@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-1.0.2.tgz#c8a3843504012283a0dbffc7430b7c753ecd4b07"
+ dependencies:
+ node-forge "^0.7.4"
+ pify "^3.0.0"
+
+googleapis@30.0.0:
+ version "30.0.0"
+ resolved "https://registry.npmjs.org/googleapis/-/googleapis-30.0.0.tgz#4673ba34878217539ca5aa4216fef4db6c247649"
+ dependencies:
+ google-auth-library "^1.4.0"
+ pify "^3.0.0"
+ qs "^6.5.1"
+ url-template "^2.0.8"
+ uuid "^3.2.1"
+
got@^6.7.1:
version "6.7.1"
resolved "https://registry.npmjs.org/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@@ -2174,6 +2226,16 @@ gray-matter@^4.0.1:
section-matter "^1.0.0"
strip-bom-string "^1.0.0"
+gtoken@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/gtoken/-/gtoken-2.3.0.tgz#4e0ffc16432d7041a1b3dbc1d97aac17a5dc964a"
+ dependencies:
+ axios "^0.18.0"
+ google-p12-pem "^1.0.0"
+ jws "^3.1.4"
+ mime "^2.2.0"
+ pify "^3.0.0"
+
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@@ -2835,6 +2897,23 @@ jsprim@^1.2.2:
json-schema "0.2.3"
verror "1.10.0"
+jwa@^1.1.4:
+ version "1.1.5"
+ resolved "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5"
+ dependencies:
+ base64url "2.0.0"
+ buffer-equal-constant-time "1.0.1"
+ ecdsa-sig-formatter "1.0.9"
+ safe-buffer "^5.0.1"
+
+jws@^3.1.4:
+ version "3.1.4"
+ resolved "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2"
+ dependencies:
+ base64url "^2.0.0"
+ jwa "^1.1.4"
+ safe-buffer "^5.0.1"
+
keygrip@~1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91"
@@ -3088,6 +3167,10 @@ lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
+lodash.isstring@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
+
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@@ -3331,7 +3414,7 @@ mime@^1.3.4:
version "1.6.0"
resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
-mime@^2.0.3, mime@^2.1.0:
+mime@^2.0.3, mime@^2.1.0, mime@^2.2.0:
version "2.3.1"
resolved "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369"
@@ -3532,6 +3615,10 @@ no-case@^2.2.0:
dependencies:
lower-case "^1.1.1"
+node-forge@^0.7.4:
+ version "0.7.5"
+ resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
+
node-libs-browser@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz#5f94263d404f6e44767d726901fff05478d600df"
@@ -4350,7 +4437,7 @@ q@^1.1.2:
version "1.5.1"
resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
-qs@~6.5.1:
+qs@^6.5.1, qs@~6.5.1:
version "6.5.2"
resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
@@ -4661,6 +4748,10 @@ ret@~0.1.10:
version "0.1.15"
resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+retry-axios@0.3.2, retry-axios@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.npmjs.org/retry-axios/-/retry-axios-0.3.2.tgz#5757c80f585b4cc4c4986aa2ffd47a60c6d35e13"
+
rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
@@ -5459,6 +5550,10 @@ url-parse-lax@^1.0.0:
dependencies:
prepend-http "^1.0.1"
+url-template@^2.0.8:
+ version "2.0.8"
+ resolved "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21"
+
url@^0.11.0:
version "0.11.0"
resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@@ -5497,7 +5592,7 @@ utila@~0.4:
version "0.4.0"
resolved "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
-uuid@^3.1.0:
+uuid@^3.1.0, uuid@^3.2.1:
version "3.2.1"
resolved "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"