first commit

This commit is contained in:
编码猿
2024-09-27 02:06:13 +08:00
commit 852d94fbb9
36760 changed files with 3274413 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# misc
.DS_Store
# umi
/src/.umi/
/.env.local
.idea/

View File

@@ -0,0 +1,34 @@
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var agentRouter = require('./routes/agent');
var app = express();
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use('/api/json/', indexRouter);
app.use('/api/json/', agentRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
});
module.exports = app;

View File

@@ -0,0 +1,90 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('tujigu:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
console.log('App is run: http://127.0.0.1:'+addr.port);
}

View File

@@ -0,0 +1,26 @@
module.exports = {
BaseUrl: 'https://www.tujigu.net/',
AgentUrl: 'https://www.tujidao.com/index.php?m=Api',
InfoUrl: (id, page) => {
return page == 1 ? `https://www.tujigu.net/a/${id}/` : `https://www.tujigu.net/a/${id}/${page}.html`
},
// 机构的网址
jigou: function () {
return this.BaseUrl +'jigou/'
},
jigouList: function (id, page) {
return page == 0 ? `${this.BaseUrl}x/${id}/` : `${this.BaseUrl}x/${id}/index_${page}.html`
},
ClassList: function (id, page) {
return page == 0 ? `${this.BaseUrl}s/${id}/` : `${this.BaseUrl}s/${id}/index_${page}.html`
},
AllModel: function () {
return `${this.BaseUrl}mote/`;
},
ModelList: function (id, page) {
return page == 0 ? `${this.BaseUrl}t/${id}/` : `${this.BaseUrl}t/${id}/index_${page}.html`
},
Search: function (keyword) {
return `${this.BaseUrl}search/${encodeURIComponent(keyword)}`
}
}

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<img src="http://127.0.0.1:3000/api/json/url?url=https://lns.hywly.com/a/1/24510/0.jpg" alt="">
</body>
</html>

View File

@@ -0,0 +1,21 @@
{
"name": "tujigu",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node-dev ./bin/www",
"build": "pm2 start ./bin/www --name mt --watch -i max"
},
"dependencies": {
"axios": "^0.21.0",
"cheerio": "^1.0.0-rc.3",
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"hydrogen-js-sdk": "^2.2.4",
"image-size": "^0.9.3",
"morgan": "~1.9.1",
"qs": "^6.9.4"
}
}

View File

@@ -0,0 +1,61 @@
# POST http://127.0.0.1:3000/api/json/agent/info HTTP/1.1
# Content-Type: application/x-www-form-urlencoded
# id=27464
# POST https://www.tujidao.com/index.php?m=Api&c=Biaoqian&a=tulist&id=253&p=1 HTTP/1.1
# Content-Type: application/x-www-form-urlencoded
# POST http://127.0.0.1:3000/api/json/agent/recently HTTP/1.1
# Content-Type: application/x-www-form-urlencoded
# page=1
# POST http://127.0.0.1:3000/api/json/register HTTP/1.1
# content-type: application/json
# {
# "userphone": "15155145351",
# "userpwd": "lb714500."
# }
# POST http://127.0.0.1:3000/api/json/login HTTP/1.1
# content-type: application/json
# {
# "username": "13666062265",
# "userpwd": "123456"
# }
# POST http://127.0.0.1:3000/api/json/agentreg HTTP/1.1
# content-type: application/json
# {
# "userphone": "13666062265",
# "userpwd": "123456",
# "agentcode": "#%tg^&*%",
# "userweixin": "xy7145"
# }
# POST http://127.0.0.1:3000/api/json/freeUse HTTP/1.1
# content-type: application/json
# {
# "objectId": "fb66d99779"
# }
# POST http://127.0.0.1:3000/api/json/placeOrder HTTP/1.1
# content-type: application/json
# {
# "objectId": "73d96341a1",
# "vipLevel": "1"
# }
POST http://127.0.0.1:3000/api/json/orderStatus HTTP/1.1
content-type: application/json
{
"objectId": "73d96341a1"
}

View File

@@ -0,0 +1,350 @@
const { urlencoded } = require('express');
var express = require('express'),
router = express.Router(),
utils = require("../utils"),
config = require("../config"),
bmobUtils = require("../utils/bmob");
/**
* 后端代理,实现调用原网站的 App 接口获取数据
*/
router.post('/agent/info', async (req, res, next) => {
var ids = req.body.id;
var url = `${config.AgentUrl}&c=Tuji&a=index`
var data = await utils.AgentPost(url, { id: ids })
res.json(data)
})
router.post('/agent/classList', async (req, res, next) => {
var id = req.body.id;
var page = req.body.page;
var url = `${config.AgentUrl}&c=Biaoqian&a=tulist&id=${id}&p=${page}`;
var result = await utils.AgentPost(url);
result.data.page = String(page);
res.json(result)
})
router.post('/agent/mechanismList', async (req, res, next) => {
var id = req.body.id;
var page = req.body.page;
var url = `${config.AgentUrl}&c=Jigou&a=tulist&id=${id}&p=${page}`;
var result = await utils.AgentPost(url);
result.data.page = String(page);
res.json(result)
})
router.post('/agent/recently', async (req, res, next) => {
var page = req.body.page;
var url = `${config.AgentUrl}&c=Index&a=gengxin&p=${page}`;
var result = await utils.AgentPost(url);
result.data.page = String(page);
res.json(result)
})
// http://127.0.0.1:3000/api/json/agent/search
router.post('/agent/search', async (req, res, next) => {
var keyword = req.body.keyword;
var url = `${config.AgentUrl}&c=Search&a=Tuji&key=${encodeURIComponent(keyword)}`;
var result = await utils.AgentPost(url);
res.json(result)
})
// http://127.0.0.1:3000/api/json/agent/random
router.post('/agent/random', async (req, res, next) => {
var url = config.AgentUrl;
var result = await utils.AgentPost(url);
result.data.page = String("1");
res.json(result)
})
router.get('/updateVersion', async (req, res, next) => {
const query = bmobUtils.bmob.Query("UpdateVersion");
var update = function () {
query.find()
.then(result => {
res.json(result[0]);
})
.catch(err => {
console.log(`升级出现错误 ------- ${err}`);
update();
});
}
update();
})
// 普通注册
// http://127.0.0.1:3000/api/json/register
router.post('/register', async (req, res, next) => {
var userphone = req.body.userphone;
var userpwd = req.body.userpwd;
var superior = req.body.hasOwnProperty("superior") ? req.body.superior : '';
let params = {
username: userphone,
password: userpwd,
mobilePhoneNumber: userphone,
userType: '0',
FreeNumber: 6,
superiorObjectId: superior
};
var response = {
code: '',
error: '',
createdAt: '',
objectId: '',
}
bmobUtils.bmob.User.register(params).then(result => {
response.code = 200;
response.createdAt = result.createdAt;
response.objectId = result.objectId;
res.json(response);
}).catch(err => {
response.code = err.code;
response.error = err.error;
res.json(response);
});
});
// 代理用户注册
// http://127.0.0.1:3000/api/json/agentreg
router.post('/agentreg', async (req, res, next) => {
var userphone = req.body.userphone;
var userpwd = req.body.userpwd;
var agentCode = req.body.agentcode;
var userWeiXin = req.body.userweixin;
var response = {
code: '',
error: '',
createdAt: '',
objectId: '',
}
// 去代理码表查询这个激活码是否存在
const query = bmobUtils.bmob.Query('AgentCode');
query.equalTo("code", "==", agentCode);
let codeList = await query.find();
// 激活码存在
if (codeList.length != 0) {
bmobUtils.bmob.User.register({
username: userphone,
password: userpwd,
mobilePhoneNumber: userphone,
userType: '1',
userWeiXin: userWeiXin,
FreeNumber: 6
}).then(result => {
response.code = 200;
response.createdAt = result.createdAt;
response.objectId = result.objectId;
res.json(response);
// 注册代理失败
}).catch(err => {
response.code = err.code;
response.error = err.error;
res.json(response);
});
// 激活码不存在
} else {
response.code = 404;
response.error = "无法注册,因为激活码不存在,请找总代理确认!";
res.json(response);
}
});
// 登录
// http://127.0.0.1:3000/api/json/login
router.post('/login', async (req, res, next) => {
var username = req.body.username;
var userpwd = req.body.userpwd;
var response = {
code: '',
error: '',
username: '',
createdAt: '',
objectId: '',
userType: '',
userWeiXin: '',
}
bmobUtils.bmob.User.login(username, userpwd).then(result => {
console.log("result ===== ", result);
response.code = 200;
response.username = result.username;
response.createdAt = result.createdAt;
response.objectId = result.objectId;
response.userType = result.userType;
response.userWeiXin = result.userWeiXin;
res.json(response);
}).catch(err => {
response.code = err.code;
response.error = err.error;
res.json(response);
});
});
// 每访问一次详情页,就减少一次使用次数,总共6次免费使用
// http://127.0.0.1:3000/api/json/freeUse
router.post('/freeUse', async (req, res, next) => {
let objectId = req.body.objectId;
let query = bmobUtils.bmob.Query('_User');
query.equalTo("objectId", "==", objectId);
query.find().then((data) => {
// 剩余次数
let FreeNumber = data[0].FreeNumber;
if (FreeNumber != -1) {
FreeNumber--;
if (FreeNumber <= 0) {
updateNumbers(0)
res.json({
code: 403,
error: '免费次数用尽,请开通VIP',
FreeNumber: 0
})
return;
} else {
updateNumbers(FreeNumber)
}
} else {
res.json({
code: 200,
error: '',
FreeNumber: FreeNumber
});
return;
}
})
.catch(err => {
});
var updateNumbers = function (number) {
query.get(objectId).then(list => {
list.set('FreeNumber', number);
list.save()
res.json({
code: 200,
error: '',
FreeNumber: number
})
}).catch(err => {
})
}
});
// 办理会员的时候的 下单接口
// http://127.0.0.1:3000/api/json/placeOrder
router.post('/placeOrder', async (req, res, next) => {
let objectId = req.body.objectId;
let vipLevel = req.body.vipLevel;
const query = bmobUtils.bmob.Query('_User');
const savePurchase = bmobUtils.bmob.Query('purchase');
query.get(objectId).then(async result => {
if (result.hasOwnProperty('superiorObjectId')) {
console.log("有上级代理");
let superiorInfo = await query.get(result.superiorObjectId);
console.log("上级代理的用户信息为: ", superiorInfo);
saveOrderItem(superiorInfo.userWeiXin, result.objectId)
} else {
console.log("没有上级代理,返回总代理");
saveOrderItem('xy7145', result.objectId)
}
}).catch(err => {
console.log(err)
});
let saveOrderItem = async (weixin, objectId) => {
var response = {
code: '',
error: '',
createdAt: '',
objectId: '',
}
savePurchase.equalTo("userObjectId", "==", objectId);
let isHave = await savePurchase.find();
// 拒绝重复购买,如果等于0表示没有买,那么下单
if (isHave.length == 0) {
// 用户的objectId
savePurchase.set("userObjectId", objectId)
// 用户的购买类型
savePurchase.set("vipLevel", vipLevel)
// 订单号,也就是 用户的object
savePurchase.set("orderNumber", objectId)
// 当前用户的上级代理的微信号
savePurchase.set("superiorWeixin", weixin)
// 这笔订单的状态,0 未支付
savePurchase.set("activateStatus", "0")
savePurchase.save().then(saveInfo => {
console.log(saveInfo)
response.code = 200;
response.createdAt = saveInfo.createdAt;
response.objectId = saveInfo.objectId;
res.json(response)
}).catch(err => {
response.code = err.code;
response.error = err.error;
res.json(response)
})
} else {
response.code = 505;
response.error = '已经办理过,请转账完成激活';
res.json(response)
}
}
});
// 查询订单状态
// http://127.0.0.1:3000/api/json/orderStatus
router.post('/orderStatus', async (req, res, next) => {
let objectId = req.body.objectId;
const query = bmobUtils.bmob.Query('purchase');
var response = {
code: '',
error: '',
arr: ''
}
query.equalTo("userObjectId", "==", objectId);
let result = await query.find();
if (result.length == 0) {
response.code = 404;
response.error = '没有记录',
response.arr = []
} else {
response.code = 200;
response.error = '',
response.arr = result
}
res.json(response);
})
module.exports = router;

View File

@@ -0,0 +1,632 @@
var express = require('express'),
router = express.Router(),
utils = require("../utils"),
config = require("../config");
var isA = true;
// 别人的后端c
router.all('*', (req, res, next) => {
isA = Boolean(req.query.isAndroid) || false
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", 'bmy')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
/**
* 1:获取首页推荐写真集列表 【页面完成】
* 接口地址:http://127.0.0.1:3000/api/json/index
*/
router.get('/index', async (req, res, next) => {
let $ = await utils.get(config.BaseUrl);
let result = {
recommended: {
title: '今日推荐',
data: []
},
newest: {
title: '最新收录',
data: []
},
model: {
title: '女神模特',
res: []
}
};
var inx = 0;
$(".hezi ul li").each(function (i, el) {
if (i < 8) {
result.recommended.data.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
total: parseInt($(this).find(".shuliang").text()),
total_page: Math.ceil(parseInt($(this).find(".shuliang").text()) / 5),
source: clearText(`来源机构:${$(this).find("p").eq(0).find("a").text()}`),
user: clearText($(this).find("p").eq(1).text()),
tags: [],
title: clearText($(this).find(".biaoti a").text()),
preview: returnUrl($(this).find("a img").attr("src")),
});
$(this).find("p").eq(2).find("a").each(function (index, ele) {
result.recommended.data[i].tags.push({
title: $(this).text(),
id: parseInt($(this).attr("href").split("/s/")[1])
})
});
} else {
result.newest.data.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
total: parseInt($(this).find(".shuliang").text()),
total_page: Math.ceil(parseInt($(this).find(".shuliang").text()) / 5),
source: clearText(`来源机构:${$(this).find("p").eq(0).find("a").text()}`),
user: clearText($(this).find("p").eq(1).text()),
tags: [],
title: $(this).find(".biaoti a").text(),
preview: returnUrl($(this).find("a img").attr("src")),
})
$(this).find("p").eq(2).find("a").each(function (index, ele) {
result.newest.data[inx].tags.push({
title: $(this).text(),
id: parseInt($(this).attr("href").split("/s/")[1])
})
});
inx += 1;
}
});
$(".hezi_t ul li").each(function () {
result.model.res.push({
id: parseInt($(this).find("p a").attr("href").split("/t/")[1]),
title: $(this).find("p a").text(),
total: $(this).find(".shuliang").text(),
preview: returnUrl($(this).find("a img").attr("src")),
})
})
res.json({
status: 200,
msg: '请求成功',
result: result
})
});
// ================ 查看写真详情 接口 ======================
/**
* 2:进入写真集详情
* 接口地址:http://127.0.0.1:3000/api/json/info
* 参数:
* page 页数
* id 从首页带过来的 id参数
* 示例:http://127.0.0.1:3000/api/json/info?id=36351&page=1
*
*/
router.get('/info', async (req, res, next) => {
let page = req.query.page;
let id = req.query.id;
let $ = await utils.get(config.InfoUrl(id, page));
let result = {
title: '', // 写真标题
source: '', // 来源
total: '', // 图片总数
info: '', // 模特详情
current_page: '', // 当前页
total_page: '', // 总页数
data: [], // 图片数组
recommend: [], // 推荐写真
relevant: [], // 相关写真集
};
result.title = $(".tuji .weizhi h1").text().split(" / ")[0];
result.source = clearText(`拍摄机构:${$(".tuji p").eq(0).find("a").text()}`);
if ($(".tuji p").eq(1).text().includes("图片数量")) {
result.total = $(".tuji p").eq(1).text();
} else {
result.total = $(".tuji p").eq(2).text();
}
if ($(".tuji .shuoming").length == 0) {
result.info = clearText(`${$(".tuji p").eq($(".tuji p").length - 1).text()}`);
} else {
result.info = clearText(`${$(".tuji p").eq($(".tuji p").length - 2).text()}`);
}
result.current_page = Number(page);
result.total_page = Math.ceil(parseInt(result.total.split("图片数量: ")[1]) / 5);
$(".content img").each(async function (i) {
result.data.push({
title: $(this).attr("alt"),
src: returnUrl($(this).attr("src"))
})
})
$(".hezi").eq(0).find("ul li").each(function (i) {
result.recommend.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
total: parseInt($(this).find(".shuliang").text()),
total_page: Math.ceil(parseInt($(this).find(".shuliang").text()) / 5),
source: clearText(`来源机构:${$(this).find("p").eq(0).find("a").text()}`),
user: clearText($(this).find("p").eq(1).text()),
tags: [],
title: clearText($(this).find(".biaoti a").text()),
preview: returnUrl($(this).find("a img").attr("src")),
});
$(this).find("p").eq(2).find("a").each(function (index, ele) {
result.recommend[i].tags.push({
title: $(this).text(),
id: parseInt($(this).attr("href").split("/s/")[1])
})
})
})
$(".hezi").eq(1).find("ul li").each(function (i) {
result.relevant.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
total: parseInt($(this).find(".shuliang").text()),
total_page: Math.ceil(parseInt($(this).find(".shuliang").text()) / 5),
source: clearText(`来源机构:${$(this).find("p").eq(0).find("a").text()}`),
user: clearText($(this).find("p").eq(1).text()),
tags: [],
title: $(this).find(".biaoti a").text(),
preview: returnUrl($(this).find("a img").attr("src")),
});
$(this).find("p").eq(2).find("a").each(function (index, ele) {
result.relevant[i].tags.push({
title: $(this).text(),
id: parseInt($(this).attr("href").split("/s/")[1])
})
})
});
res.json({
status: 200,
msg: '请求成功',
result: result
})
})
// ================ 写真机构 接口 ======================
/**
* 3:获取各大国内外写真机构列表 【页面完成】
* 接口地址:http://127.0.0.1:3000/api/json/mechanism
*/
router.get('/mechanism', async (req, res, next) => {
let $ = await utils.get(config.jigou());
var result = []
$(".jigou li").each(function () {
result.push({
id: parseInt($(this).find("a").attr("href").split("/x/")[1]),
title: $(this).find("a").text(),
quantity: $(this).find("span").text()
})
});
res.json({
status: 200,
msg: '请求成功',
result: result
})
})
/**
* 4:获取该机构下写真套图列表 【页面完成】
* 接口地址:http://127.0.0.1:3000/api/json/mechanismList
* 参数:
* page 页数 注意page默认从 0 开始
* id 接口3的id
* 示例:http://127.0.0.1:3000/api/json/mechanismList?id=82&page=0
*/
router.get('/mechanismList', async (req, res, next) => {
var id = req.query.id;
var page = req.query.page;
let $ = await utils.get(config.jigouList(id, page));
var TotalList = $(".shoulushuliang span").text();
var calculation = TotalList / 40;
var result = {
group: TotalList, // 该分类下有多少套写真图
current_page: Number(page), // 当前页数
// 该分类有多少页
total_page: Number.isInteger(calculation) ? calculation - 1 : parseInt(calculation),
// 当页的数据
data: []
};
$(".hezi ul li").each(function (i, el) {
result.data.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
total: parseInt($(this).find(".shuliang").text()),
total_page: Math.ceil(parseInt($(this).find(".shuliang").text()) / 5),
source: '',
user: clearText($(this).find("p").eq(0).text()),
tags: [],
title: $(this).find(".biaoti a").text(),
preview: returnUrl($(this).find("a img").attr("src")),
});
$(this).find("p").eq(1).find("a").each(function (index, ele) {
result.data[i].tags.push({
title: $(this).text(),
id: parseInt($(this).attr("href").split("/s/")[1])
})
})
});
res.json({
status: 200,
msg: '请求成功',
result: result
})
})
// ================ 推荐分类 接口 ======================
/**
* 5:获取写真分类列表 【页面完成】
* 接口地址:http://127.0.0.1:3000/api/json/class
*/
router.get('/class', async (req, res, next) => {
let $ = await utils.get(config.BaseUrl);
var result = {
principal: [],
additional: [
{id: 40,title:'萝莉控',page: 0},
{id: 104,title:'白丝诱惑',page: 0},
{id: 189,title:'双马尾',page: 0},
{id: 20,title:'护士制服',page: 0},
{id: 207,title:'丝足诱惑',page: 0},
{id: 27,title:'性感女仆装',page: 0},
{id: 50,title:'湿身诱惑',page: 0},
{id: 62,title:'御姐控',page: 0},
{id: 68,title:'古典气质',page: 0},
{id: 69,title:'旗袍美女',page: 0},
{id: 70,title:'人体艺术',page: 0},
{id: 43,title:'福利图片',page: 0},
{id: 75,title:'性感浴室',page: 0},
{id: 78,title:'性感网袜',page: 0},
{id: 81,title:'阳光少女',page: 0},
{id: 82,title:'居家私房',page: 0},
{id: 89,title:'巨乳波霸',page: 0},
{id: 110,title:'性感豹纹',page: 0},
{id: 100,title:'日本女明星',page: 0},
{id: 112,title:'空姐制服',page: 0},
{id: 114,title:'SM镣铐',page: 0},
{id: 121,title:'粉嫩少女',page: 0},
{id: 122,title:'教师制服',page: 0},
{id: 123,title:'美女警察',page: 0},
{id: 145,title:'床上美女',page: 0},
{id: 147,title:'OL制服',page: 0},
{id: 130,title:'姐妹花',page: 0},
{id: 131,title:'性感健身',page: 0},
{id: 125,title:'美厨娘',page: 0},
{id: 128,title:'情趣皮衣',page: 0},
{id: 134,title:'透视诱惑',page: 0},
{id: 146,title:'美女秘书',page: 0},
{id: 157,title:'西装美女',page: 0},
{id: 184,title:'黑长直',page: 0},
{id: 190,title:'老照片美女',page: 0},
{id: 191,title:'肉感美女',page: 0},
{id: 192,title:'学生装美女',page: 0},
{id: 194,title:'写真杂志',page: 0},
{id: 195,title:'欧美巨乳',page: 0},
{id: 196,title:'金发美女',page: 0},
{id: 197,title:'欧美熟妇',page: 0},
{id: 199,title:'欧美制服',page: 0},
{id: 201,title:'黑人美女',page: 0},
{id: 202,title:'巨乳肥臀',page: 0},
{id: 203,title:'长靴美女',page: 0},
{id: 204,title:'丝袜美臀',page: 0},
{id: 206,title:'美臀少妇',page: 0},
{id: 228,title:'美女制服诱惑',page: 0},
{id: 211,title:'不知火舞COS',page: 0},
{id: 212,title:'性感女郎',page: 0},
{id: 213,title:'丝袜女郎',page: 0},
{id: 214,title:'轻熟女写真集',page: 0},
{id: 215,title:'比基尼少女',page: 0},
{id: 216,title:'日本比基尼',page: 0},
{id: 217,title:'中国比基尼',page: 0},
{id: 219,title:'风骚诱惑',page: 0},
{id: 220,title:'风骚少妇',page: 0},
{id: 221,title:'丰满少妇',page: 0},
{id: 222,title:'丝袜少妇',page: 0},
{id: 224,title:'黑丝美腿',page: 0},
{id: 225,title:'黑丝制服',page: 0},
{id: 226,title:'街拍黑丝',page: 0},
{id: 227,title:'日本巨乳AV女优',page: 0},
{id: 229,title:'蕾丝诱惑',page: 0},
{id: 231,title:'半裸尤物',page: 0},
{id: 232,title:'勾魂尤物',page: 0},
{id: 233,title:'丝袜肥臀',page: 0},
{id: 235,title:'街拍美腿',page: 0},
{id: 236,title:'巨乳萝莉',page: 0},
{id: 237,title:'丝袜制服',page: 0},
{id: 238,title:'街拍短裙',page: 0},
{id: 239,title:'丝袜短裙',page: 0},
{id: 240,title:'丝袜人体艺术',page: 0},
{id: 242,title:'性感丰满',page: 0},
{id: 243,title:'街拍丝袜',page: 0},
{id: 244,title:'超短迷你裙',page: 0},
{id: 245,title:'开背毛衣',page: 0},
{id: 247,title:'性感香车',page: 0},
{id: 248,title:'吊带美女',page: 0},
{id: 249,title:'极品美丝',page: 0},
{id: 250,title:'眼镜娘',page: 0},
{id: 251,title:'极品女友',page: 0},
{id: 53,title:'大胸嫩模',page: 0},
{id: 73,title:'情趣内衣',page: 0},
{id: 254,title:'白领丽人',page: 0},
{id: 255,title:'美女故事',page: 0},
{id: 256,title:'极品抹胸',page: 0},
{id: 257,title:'情趣制服',page: 0},
{id: 258,title:'肉丝高跟',page: 0},
{id: 259,title:'黑丝袜诱惑',page: 0},
{id: 113,title:'婚纱美女',page: 0},
{id: 108,title:'丽柜美束系列',page: 0},
]
};
$("#tag_ul li a").each(function () {
result.principal.push({
id: parseInt($(this).attr("href").split("/s/")[1]),
title: $(this).text(),
page: 0
})
})
result.principal.unshift({ id: 36, title: 'COSPLAY',page: 0 })
result.principal.unshift({ id: 10, title: '办公室',page: 0 })
result.principal.unshift({ id: 124, title: 'JK制服',page: 0 })
result.principal.unshift({ id: 46, title: '翘臀',page: 0 })
result.principal.unshift({ id: 12, title: '长筒袜',page: 0 })
result.principal.unshift({ id: 65, title: '街拍',page: 0 })
result.principal.unshift({ id: 67, title: '捆绑绳艺',page: 0 })
result.principal.unshift({ id: 253, title: '黑丝萝莉',page: 0 })
result.principal.unshift({ id: 127, title: '紧身裤',page: 0 })
result.principal.unshift({ id: 252, title: '白丝萝莉',page: 0 })
result.principal.unshift({ id: 64, title: '丁字裤',page: 0 })
result.principal.unshift({ id: 18, title: '热裤',page: 0 })
result.principal.unshift({ id: 48, title: '猫女郎',page: 0 })
// 【必看】模特列表:https://www.tujigu.com/s/85/
// 网红美女、网红模特写真 https://www.tujigu.com/s/116/
// 日本AV女优写真 https://www.tujigu.com/s/159/
// B罩杯美女 https://www.tujigu.com/s/170/ 171 172 173 174 175 176 177 178 179
res.json({
status: 200,
msg: '请求成功',
result: result
})
})
/**
* 6:进入分类的详情列表,获取该分类下有多少套图,用在接口5上 【页面完成】
* 接口地址:http://127.0.0.1:3000/api/json/classList
* 参数:
* page 页数 注意page默认从 0 开始
* id 代入的接口4 id 或者 接口1 的tags id
* 示例:http://127.0.0.1:3000/api/json/classList?id=124&page=0
*/
router.get('/classList', async (req, res, next) => {
var id = req.query.id;
var page = req.query.page;
let $ = await utils.get(config.ClassList(id, page));
var TotalList = $(".shoulushuliang span").text();
var calculation = TotalList / 40;
var result = {
group: TotalList, // 该分类下有多少套写真图
current_page: Number(page), // 当前页数
// 该分类有多少页
total_page: Number.isInteger(calculation) ? calculation - 1 : parseInt(calculation),
// 当页的数据
data: []
};
$(".hezi ul li").each(function (i, el) {
result.data.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
total: parseInt($(this).find(".shuliang").text()),
total_page: Math.ceil(parseInt($(this).find(".shuliang").text()) / 5),
source: clearText(`来源机构:${$(this).find("p").eq(0).find("a").text()}`),
user: clearText($(this).find("p").eq(1).text()),
tags: [],
title: $(this).find(".biaoti a").text(),
preview: returnUrl($(this).find("a img").attr("src")),
});
$(this).find("p").eq(2).find("a").each(function (index, ele) {
result.data[i].tags.push({
title: $(this).text(),
id: parseInt($(this).attr("href").split("/s/")[1])
})
})
});
res.json({
status: 200,
msg: '请求成功',
result: result
})
})
// ================ 模特相关 接口 ======================
/**
* 7:获取所有模特 【页面完成】
* 接口地址:http://127.0.0.1:3000/api/json/allModel
* 示例:http://127.0.0.1:3000/api/json/allModel
*/
router.get('/allModel', async (req, res, next) => {
let $ = await utils.get(config.AllModel());
var result = {
hot_models: [],
newest: []
};
$(".hezi_t").eq(0).find("ul li").each(function () {
result.hot_models.push({
id: parseInt($(this).find("p a").attr("href").split("/t/")[1]),
title: $(this).find("p a").text(),
total: $(this).find(".shuliang").text(),
preview: returnUrl($(this).find("a img").attr("src")),
})
})
$(".hezi_t").eq(1).find("ul li").each(function () {
result.newest.push({
id: parseInt($(this).find("p a").attr("href").split("/t/")[1]),
title: $(this).find("p a").text(),
total: $(this).find(".shuliang").text(),
preview: returnUrl($(this).find("a img").attr("src")),
})
})
res.json({
status: 200,
msg: '请求成功',
result: result
})
});
/**
* 8:进入模特的个人套图页,可用于 接口1 的 model 【页面完成】
* 接口地址:http://127.0.0.1:3000/api/json/modelList
* 参数:
* page 页数 注意page默认从 0 开始
* id 从首页带过来的 id参数
* 示例:http://127.0.0.1:3000/api/json/modelList?id=3265&page=0
*/
router.get('/modelList', async (req, res, next) => {
var id = req.query.id;
var page = req.query.page;
let $ = await utils.get(config.ModelList(id, page));
var total = $(".shoulushuliang span").text();
var result = {
current_page: parseInt(page),
total_page: total <= 40 ? 99999 : Number.isInteger(total / 40) ? total / 40 - 1 : parseInt(total / 40),
model_info: {
portrait: returnUrl($(".renwu .left img").attr("src")),
name: clearText($(".renwu .left img").attr("alt")),
explain: clearText($(".renwu .shuoming").text().split("模特标签: ")[0]),
total: total
},
data: [],
similar: []
}
$(".hezi ul li").each(function (i, el) {
result.data.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
total: parseInt($(this).find(".shuliang").text()),
total_page: Math.ceil(parseInt($(this).find(".shuliang").text()) / 5),
source: clearText(`来源机构:${$(this).find("p").eq(0).find("a").text()}`),
tags: [],
user: '',
title: $(this).find(".biaoti a").text(),
preview: returnUrl($(this).find("a img").attr("src")),
});
$(this).find("p").eq(1).find("a").each(function (index, ele) {
result.data[i].tags.push({
title: $(this).text(),
id: parseInt($(this).attr("href").split("/s/")[1])
})
})
});
$(".hezi_t ul li").each(function () {
result.similar.push({
id: parseInt($(this).find("p a").attr("href").split("/t/")[1]),
title: $(this).find("p a").text(),
total: $(this).find(".shuliang").text(),
preview: returnUrl($(this).find("a img").attr("src")),
})
})
res.json({
status: 200,
msg: '请求成功',
result: result
})
})
// ================ 搜索 接口 ======================
/**
* 9:根据关键词搜索写真接口
* 接口地址:http://127.0.0.1:3000/api/json/search
* 参数:
* keyword 搜索关键词
* 示例:http://127.0.0.1:3000/api/json/search?keyword=女神
*/
router.get('/search', async (req, res, next) => {
var keyword = req.query.keyword;
let $ = await utils.get(config.Search(keyword));
var result = [];
$(".hezi ul li").each(function () {
result.push({
id: parseInt($(this).find("a").attr("href").split("/a/")[1]),
title: $(this).find(".biaoti a").text(),
preview: returnUrl($(this).find("a img").attr("src")),
})
})
res.json({
status: 200,
msg: '请求成功',
result: result
})
})
/**
* 10: 破解有防盗链的图片地址
* 接口地址:http://127.0.0.1:3000/api/json/url
* 参数:
* url 图片地址
* 示例:http://127.0.0.1:3000/api/json/url?url=https://lns.hywly.com/a/1/24510/0.jpg
*/
router.get('/url', async (req, res, next) => {
const http = require('https');
const URL = require('url');
var url = URL.parse(req.query.url);
var option={
hostname: url.hostname,
path: url.path,
rejectUnauthorized: false,
headers:{ "Referer":"https://www.tujigu.com/" }
};
http.get(option, function (response) {
var chunks = [];
response.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function () {
// 保存图片ArrayBuffer 数据
var buffer = Buffer.concat(chunks);
// 设置前端请求头
res.set(response.headers)
// 两次二进制转换
res.end(buffer.toString("binary"), 'binary')
});
});
});
function returnUrl(url) {
isA = true;
return isA ? url : "http://47.114.153.249:3000/api/json/url?url="+url
}
function clearText(text) {
return text.replace(/\ +/g,"").replace(/[\r\n]/g,"");;
}
module.exports = router;

View File

@@ -0,0 +1,19 @@
var url = require('url');
var http = require('https');
var sizeOf = require('image-size');
var imgUrl = 'https://lns.hywly.com/a/1/36441/1.jpg';
var options = url.parse(imgUrl);
http.get(imgUrl, function (response) {
var chunks = [];
response.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function() {
var buffer = Buffer.concat(chunks);
console.log(sizeOf(buffer));
});
});

View File

@@ -0,0 +1,10 @@
const Bmob = require("hydrogen-js-sdk");
class BmobUtils {
constructor () {
Bmob.initialize("961e3acb659d5e29", "714500","c6c8bdf682027398a82139212cfb8bc9");
this.bmob = Bmob;
}
}
module.exports = new BmobUtils();

View File

@@ -0,0 +1,81 @@
const cheer = require('cheerio');
const axios = require('axios');
const http = require('https');
const sizeOf = require('image-size');
const { log } = require('console');
const qs = require('qs');
class utils {
constructor() {
this.ax = axios
this.ResponseInterceptor()
}
/**
* 返回 cheerio 数据结构
* @param html
* @returns {*}
*/
cheerio(html) {
return cheer.load(html)
}
/**
*
* @param url 请求的地址
* @returns {Promise<AxiosResponse<any>>}
*/
async get(url) {
return await this.ax.get(url, {
headers: {
'Cookie': 'UM_distinctid=1755c44df43878-0c375e3b746b17-1e1d4b58-232800-1755c44df4439a; CNZZDATA1278970723=1349859603-1603567786-%7C1605270356',
'Referer': 'https://www.tujigu.com/',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'Accept-Encoding': 'gzip, deflate, br'
}
});
}
async AgentPost(url, params = {}) {
return await this.ax.post(url, qs.stringify(params), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'refer': '',
'TOKEN': '/NWOYjE9WKn66bBitGVVEy7XfnW2sYpjGUJR5IzndI0l9yLhb/Btqd01ln1JWBA+8e8nmuivxpJrElXCnxPSJg==',
}
});
}
/**
*
* 响应拦截器
* @constructor
*/
async ResponseInterceptor() {
this.ax.interceptors.response.use((response) => {
console.log(response.config.method == 'post');
if (response.config.method == 'post') {
return response.data;
} else {
return this.cheerio(response.data);
}
}, (error) => {
return Promise.reject(error)
})
}
async GetImageWidthOrHeight(url) {
return new Promise((resolve,reject) => {
http.get(url, function (response) {
var chunks = [];
response.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function () {
var buffer = Buffer.concat(chunks);
resolve(sizeOf(buffer))
});
});
})
}
}
module.exports = new utils();

View File

@@ -0,0 +1,5 @@
/x/ : 写真机构
/s/ : 分类的详情列表
/a/ : 每一套写真的详情
/t/ : 模特列表