Merge pull request #36 from EYHN/pixiv

Pixiv 用户动态 RSS  Close #28
This commit is contained in:
DIYgod
2018-04-20 18:22:42 +08:00
committed by GitHub
6 changed files with 187 additions and 1 deletions
+2
View File
@@ -46,6 +46,8 @@ RSSHub 是一个轻量、易于扩展的 RSS 生成器,可以给任何奇奇
- 所有专题
- 专题详情
- 详情
- Pixiv
- 用户动态
## 参与我们
+6
View File
@@ -3,4 +3,10 @@ module.exports = {
cacheType: 'memory', // support memory and redis, set empty to disable cache
cacheExpire: 5 * 60,
ua: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
// pixiv: {
// client_id: 'XXXXXXXXXXXXXXXXXXX',
// client_secret: 'XXXXXXXXXXXXXXXXX',
// username: 'xxxx@xxx.xx',
// password: 'xxxxx'
// }
};
+1
View File
@@ -26,6 +26,7 @@
"cheerio": "1.0.0-rc.2",
"crypto": "1.0.1",
"eslint": "4.19.1",
"form-data": "^2.3.2",
"koa": "2.5.0",
"koa-redis-cache": "3.0.0",
"koa-router": "7.4.0",
+3
View File
@@ -57,4 +57,7 @@ router.get('/mzitu/category/:category', require('./routes/mzitu/category'));
router.get('/mzitu/post/:id', require('./routes/mzitu/post'));
router.get('/mzitu/tag/:tag', require('./routes/mzitu/tag'));
// // Pixiv
router.get('/pixiv/user/:id', require('./routes/pixiv/user'));
module.exports = router;
+152
View File
@@ -0,0 +1,152 @@
const axios = require('axios');
const art = require('art-template');
const path = require('path');
const config = require('../../config');
const logger = require('../../utils/logger');
const FormData = require('form-data');
const pixivConfig = config.pixiv;
if (!pixivConfig) {
logger.info('Pixiv RSS disable.');
module.exports = () => {};
return;
}
const authorizationInfo = {
client_id: pixivConfig.client_id,
client_secret: pixivConfig.client_secret,
username: pixivConfig.username,
password: pixivConfig.password
};
const maskHeader = {
'App-OS': 'ios',
'App-OS-Version': '10.3.1',
'App-Version': '6.7.1',
'User-Agent': 'PixivIOSApp/6.7.1 (iOS 10.3.1; iPhone8,1)'
};
let token = null;
async function getToken() {
const data = new FormData();
const jsonData = {
...authorizationInfo,
get_secure_url: 1,
grant_type: 'password'
};
for (const key in jsonData) {
if (jsonData.hasOwnProperty(key)) {
const element = jsonData[key];
data.append(key,element);
}
}
const response = await axios.post('https://oauth.secure.pixiv.net/auth/token', data, {
headers: {
...maskHeader,
...data.getHeaders()
}
});
return response.data.response;
}
async function refreshToken(refresh_token) {
const data = new FormData();
const jsonData = {
...authorizationInfo,
get_secure_url: 1,
grant_type: 'refresh_token',
refresh_token: refresh_token
};
for (const key in jsonData) {
if (jsonData.hasOwnProperty(key)) {
const element = jsonData[key];
data.append(key,element);
}
}
const response = await axios.post('https://oauth.secure.pixiv.net/auth/token', data, {
headers: {
...maskHeader,
...data.getHeaders()
}
});
return response.data.response;
}
function wait(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function tokenLoop() {
const res = await getToken();
logger.info('Pixiv login success.');
token = res.access_token;
let refresh_token = res.refresh_token;
let expires_in = res.expires_in * 0.9;
while (true) {
await wait(expires_in * 1000);
try {
const refresh_res = await refreshToken(refresh_token);
logger.debug('Pixiv refresh token success.');
token = refresh_res.access_token;
refresh_token = refresh_res.refresh_token;
expires_in = refresh_res.expires_in * 0.9;
} catch (err) {
expires_in = 30;
logger.err('Pixiv refresh token failed, retry in ${expires_in} seconds.', err);
}
}
}
tokenLoop();
module.exports = async (ctx) => {
const id = ctx.params.id;
if (typeof token === 'null') {
ctx.throw(500);
return;
}
const response = await axios({
method: 'get',
url: 'https://app-api.pixiv.net/v1/user/illusts',
headers: {
...maskHeader,
'Authorization': 'Bearer ' + token
},
params: {
user_id: id,
filter: 'for_ios',
type: 'illust'
},
});
const illusts = response.data.illusts;
const username = illusts[0].user.name
ctx.body = art(path.resolve(__dirname, '../../views/rss.art'), {
title: `${username} 的 Pixiv 动态`,
link: `https://music.163.com/#/playlist?id=${id}`,
description: `${username} 的 Pixiv 最新动态`,
lastBuildDate: new Date().toUTCString(),
item: illusts.map((illust) => {
const images = [];
if (illust.page_count === 1) {
images.push(`<p><img src="https://pixiv.cat/${illust.id}.jpg"/></p>`);
} else {
for (let i = 0; i < illust.page_count; i++) {
images.push(`<p><img src="https://pixiv.cat/${illust.id}-${i+1}.jpg"/></p>`);
}
}
return {
title: illust.title,
description: `<p>画师:${username} - 上传于:${new Date(illust.create_date).toLocaleString('zh-cn')} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}</p>${images.join('')}`,
link: `https://www.pixiv.net/member_illust.php?mode=medium&illust_id=${illust.id}`
};
})
});
};
+23 -1
View File
@@ -106,6 +106,10 @@ async@^2.6.0:
dependencies:
lodash "^4.14.0"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
axios@0.18.0:
version "0.18.0"
resolved "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
@@ -262,6 +266,12 @@ colorspace@1.0.x:
color "0.8.x"
text-hex "0.0.x"
combined-stream@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
dependencies:
delayed-stream "~1.0.0"
commander@2.15.x, commander@~2.15.0:
version "2.15.1"
resolved "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
@@ -353,6 +363,10 @@ del@^2.0.2:
pinkie-promise "^2.0.0"
rimraf "^2.2.8"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@@ -618,6 +632,14 @@ follow-redirects@^1.3.0:
dependencies:
debug "^3.1.0"
form-data@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
dependencies:
asynckit "^0.4.0"
combined-stream "1.0.6"
mime-types "^2.1.12"
fresh@^0.5.2:
version "0.5.2"
resolved "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -957,7 +979,7 @@ mime-db@~1.33.0:
version "1.33.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
mime-types@^2.0.7, mime-types@~2.1.18:
mime-types@^2.0.7, mime-types@^2.1.12, mime-types@~2.1.18:
version "2.1.18"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
dependencies: