first commit

This commit is contained in:
编码猿
2024-09-27 01:31:25 +08:00
commit 07c46ac300
558 changed files with 37414 additions and 0 deletions

1
mApi/src/.pydio Normal file
View File

@@ -0,0 +1 @@
b13a6818-95b9-48ac-88f1-9dde569b879d

1
mApi/src/api/.pydio Normal file
View File

@@ -0,0 +1 @@
6dab72fe-06a3-4667-bf7a-d3183fc559c8

225
mApi/src/api/index.ts Executable file
View File

@@ -0,0 +1,225 @@
import * as request from "request";
import * as cheerio from "cheerio";
import config from "./../config";
class api {
private videoList: Array<any>;
private imgList: Array<any>;
private pagination: string;
private videBaseUrl: string;
private videoType: string;
constructor() {
this.videoList = [];
this.videBaseUrl = config.url.video
this.videoType = '.mp4'
}
/**
* 发送GET请求获取网站html代码
* @param url 网站地址
*/
public get(url: string) {
let options: any = {
url: url,
headers: {
'Referer': 'https://www.657xd.com/'
}
};
return new Promise((resolve, reject) => {
request(url, function (error, response, body) {
if (error) {
console.log(`-----请求出错----`);
console.log(error);
console.log(`-----请求出错----`);
reject('error')
} else {
resolve(body)
}
});
})
}
/**
* 解析网页代码,获取数据
* @param html html代码
* @param callback 回调
*/
public cheerios(html: string, callback: any, total?: boolean) {
let videoListHtml: any = this.CheerioLoad(html, '.movie2_list ul li')
total ? this.pagination = videoListHtml.$('.pagination').find('strong').text() : ''
this.videoList = [];
(_this => {
videoListHtml.data.each(function (item) {
let list: any = videoListHtml.$(this);
if (list.find('span').text().length != 0) {
let mp4Url = _this.mp4URL(
list.find('span').text(),
list.find('a').attr('href'),
list.html().match(/get_local\(\"([\s\S]*?).jpg/)[1]
);
_this.videoList.push({
title: list.find('h3').text(), // 视频标题
href: `${config.url.BaseUrl()}${list.find('a').attr('href')}`, // 视频链接地址
gif: `${config.url.video}${list.html().match(/get_local\(\"([\s\S]*?)\"\)/)[1]}`, // 视频缩略图
time: list.find('span').text(), // 视频发布时间
mp4: config.url.video+mp4Url,
m3u8: _this.mp42(mp4Url)
})
}
})
})(this)
callback(this.videoList, this.pagination)
}
/**
* http://127.0.0.1:3000/image?type=63&page=3
* 查看首页图片
* @param html
* @param callback
* @param total
*/
public cheeriosIMG(html: string, callback: any, total?: boolean) {
let imgListHtml: any = this.CheerioLoad(html, '.box ul li')
total ? this.pagination = imgListHtml.$('.pagination').text() : ''
this.imgList = [];
(_this => {
imgListHtml.data.each(function (item) {
let list: any = imgListHtml.$(this);
_this.imgList.push({
title: list.find('a').text(),
href: list.find('a').attr('href'),
time: list.find('a').find('span').text()
})
})
})(this)
callback(this.imgList, this.pagination)
}
/**
* http://127.0.0.1:3000/imageinfo?id=/Html/63/12544.html
* 从图片列表进入图片详情
* @param html
* @param callback
*/
public enterInfos(html: string, callback: any) {
let list: any = this.CheerioLoad(html, '.content img')
let title: string = list.$('.page_title h1').text()
let imgdata: Array<any> = []
list.data.each(function (item) {
let img: any = list.$(this);
imgdata.push({
title: title,
url: img.attr('src')
})
});
callback(imgdata)
}
/**
* 根据规律直接分析得到视频的真实mp4地址
* @param time 视频发布时间
* @param href 视频链接地址
* @param id 视频缩略图
*/
public mp4URL(time: string, href: string, id: string) {
let times: string = time.replace(/-/ig, '')
let hrefs: string = href.match(/\/(\d*)\//)[1]
let ids: string = this.chechImgUrl(id);
let URLS: string;
if (ids != 'null') {
URLS = `/${times}/${hrefs}/${ids}/${ids}${this.videoType}`
} else {
URLS = 'http://static.runoob.com/video/f0381j0mxd7.m701.mp4'
}
return URLS;
// return this.mp42(URLS);
}
//线路一 根据视频MP4地址获取m3u8播放地址
public mp42(s) {
var purls = [
"https://1dbffh8.com",
"https://1bhut8.com",
"https://1bfsdgfht.com",
"https://1bhyr6.com",
"https://1bryts1.com"
];
var spcl_url = "https://p.043vb.com";
var purl = purls[Math.floor(Math.random() * purls.length)];
var uu = purl + s + ".m3u8";
var hour = new Date().getHours();
var sdate = new Date().getDay();
var x = Math.random();//0-1之间
if (hour >= 21 || hour < 22) {
if (x < 0.3) {
uu = spcl_url + s + ".m3u8";
}
if (sdate == 5 || sdate == 6) {
if (x < 0.5) {
uu = spcl_url + s + ".m3u8";
}
}
} else {
uu = purl + s + ".m3u8";
}
if (hour >= 22 || hour <= 1) {
if (x < 0.45) {
uu = spcl_url + s + ".m3u8";
}
if (sdate == 5 || sdate == 6) {
if (x < 0.55) {
uu = spcl_url + s + ".m3u8";
}
}
} else {
uu = purl + s + ".m3u8";
}
return uu;
}
/**
* 返回Cheerio数据
* @param html html代码
* @param dom 需要获取的dom节点
*/
public CheerioLoad(html: any, dom) {
let $: any = cheerio.load(html);
return {
$: $,
data: $(dom)
};
}
public chechImgUrl(url) {
if (url.match(/\/(\d*).mp4/) == null) {
url = 'null'
} else {
url = url.match(/\/(\d*).mp4/)[1]
}
return url
}
}
export default api

14
mApi/src/app.ts Executable file
View File

@@ -0,0 +1,14 @@
import * as express from 'express';
import * as path from 'path';
let app = express();
import indexRouter from './routes/modular/index';
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/", indexRouter);
export default app

1
mApi/src/config/.pydio Normal file
View File

@@ -0,0 +1 @@
6bec38f6-dcf5-4ff3-95a1-23cd9c666a11

185
mApi/src/config/index.ts Executable file
View File

@@ -0,0 +1,185 @@
export default {
address: 'http://127.0.0.1',
port: 1314,
rsa: {
public: "../../rsa/rsa_pub.pem",
private: "../../rsa/rsa_priv.pem"
},
mysql: {
connectionLimit: 10,
host: "127.0.0.1",
user: "root",
password: "714500",
database: "haozhuo"
},
url: {
BaseUrl: () => {
var host = "";
var getdz = "";
var url = new Array();
url.push("1b572.com");
url.push("1b667.com");
url.push("1b669.com");
url.push("1b670.com");
url.push("1b671.com");
url.push("11b12.com");
url.push("11b13.com");
url.push("11b15.com");
url.push("11b16.com");
url.push("11b17.com");
url.push("11b18.com");
url.push("11b19.com");
url.push("11b20.com");
url.push("11b21.com");
url.push("11b23.com");
url.push("11b25.com");
url.push("11b26.com");
url.push("11b27.com");
url.push("11b28.com");
url.push("11b29.com");
url.push("11b30.com");
url.push("11b32.com");
url.push("22b11.com");
url.push("22b12.com");
url.push("22b13.com");
url.push("22b15.com");
url.push("22b16.com");
url.push("22b17.com");
url.push("22b18.com");
url.push("22b19.com");
url.push("22b20.com");
url.push("22b21.com");
url.push("22b23.com");
url.push("22b25.com");
url.push("22b26.com");
url.push("22b27.com");
url.push("22b28.com");
url.push("22b29.com");
url.push("22b30.com");
url.push("22b32.com");
url.push("33b12.com");
url.push("33b13.com");
url.push("33b15.com");
url.push("33b16.com");
url.push("33b17.com");
url.push("33b18.com");
url.push("33b19.com");
url.push("33b20.com");
url.push("33b21.com");
url.push("33b22.com");
url.push("33b23.com");
url.push("33b25.com");
url.push("33b26.com");
url.push("33b27.com");
url.push("33b28.com");
var UyoOfAKC1 = new Date("2020/12/24 18:30:00".replace(/\-/g, "/")).getTime();
var VK2 = 1; //VK2>=1
var PhKNMS3 = (Math.floor((new Date().getTime() - UyoOfAKC1) / 86400000) + 1) * VK2;
var i4 = 0;
var cncOFZ5 = VK2 - 1;
var MrZRcYn6 = Math.floor(Math.random() * (cncOFZ5 - i4 + 1) + i4);
var a7 = PhKNMS3 + MrZRcYn6;
if (a7 < 0 || a7 >= url.length) {
a7 = url.length - (MrZRcYn6 + 1);
PhKNMS3 = url.length - (cncOFZ5 + 1);
}
var D$Uja8 = true;
for (var j = i4; j <= cncOFZ5; j++) {
if (host.indexOf(url[PhKNMS3 + j]) >= 0) {
D$Uja8 = false;
break
}
}
var i = a7;
if (D$Uja8 == true) {
var Rvq9 = url[a7];
if (typeof (Rvq9) == "undefined") {
Rvq9 = url[url.length - 1]
}
var x_ratio = Math.random();//0~1
if (x_ratio < 0.5) {
getdz = "https://" + escape(Rvq9);
} else {
getdz = "https://www." + escape(Rvq9);
}
}
return getdz;
},
video: 'https://1dhgjyr9.com',
index: '/index.html',
class: [
{
title: '国产精品',
url: '/60/'
},
{
title: '中文字幕',
url: '/94/'
},
{
title: 'S级女优',
url: '/100/'
},
{
title: '欧美性爱',
url: '/62/'
},
{
title: '成人动漫',
url: '/101/'
},
{
title: '自拍偷拍',
url: '/89/'
},
{
title: '夫妻同房',
url: '/87/'
},
{
title: '开放90后',
url: '/93/'
},
{
title: '换妻游戏',
url: '/90/'
},
{
title: '网红主播',
url: '/91/'
},
{
title: '手机小视频',
url: '/88/'
},
{
title: '经典三级',
url: '/109/'
},
{
title: '无码在线',
url: '/110/'
},
{
title: '熟女人妻',
url: '/111/'
},
{
title: '美颜巨乳',
url: '/112/'
},
{
title: '颜射吃精',
url: '/113/'
},
{
title: '丝袜制服',
url: '/114/'
}
]
}
}

1
mApi/src/mysql/.pydio Normal file
View File

@@ -0,0 +1 @@
aa1faf5e-b04a-4264-9ba0-745100cdd496

38
mApi/src/mysql/index.ts Executable file
View File

@@ -0,0 +1,38 @@
import * as mysql from "mysql";
import config from "../config";
class MySql {
private pool:any
constructor(){
this.pool = mysql.createPool(config.mysql);
}
/**
* 执行数据库操作
* @param sql sql语句
* @param values 参数值
*/
query (sql:string, values?:Array<any>) {
return new Promise((resolve, reject) => {
this.pool.getConnection(function(err, connection) {
if (err) {
reject(err);
} else {
connection.query(sql, values, (err, rows) => {
if (err) {
reject(err);
} else {
rows.length == 0 ? (rows = ["NoData..."]) : rows;
resolve(rows);
}
// 结束会话
connection.release();
});
}
});
})
}
}
export default MySql

1
mApi/src/routes/.pydio Normal file
View File

@@ -0,0 +1 @@
195eddce-af6f-49ce-9e1f-ddc16e30ca4a

103
mApi/src/routes/controller.ts Executable file
View File

@@ -0,0 +1,103 @@
import * as express from 'express'
import utils from '../utils'
const router = express.Router()
class Controller {
public routers: any;
public response: any;
public request: any;
public utils = new utils();
constructor () {
router.all('*', (req, res, next) => {
this.response = res
this.request= req
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With, token, X-Bmob-Application-Id, X-Bmob-REST-API-Key");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
if(req.method == "OPTIONS") res.send(200);
else next();
});
// 暴露 router方便其他路由使用
this.routers = router
}
/**
* GET 请求
* @param url 请求的地址
* @param callback 回调
*/
public GetRoutes(url: string,callback: any) : void {
router.get(url, (req, res) => {
let params;
switch (url) {
case '/index':
callback(res, req)
break;
case '/imageinfo':
if(params.id != ''){
callback(res, req, params)
}else {
res.json({
status: 404,
message: '参数缺失'
})
}
break;
case '/image':
if(req.query.type != '' &&
req.query.page != ''){
callback(res, req)
}else {
res.json({
status: 404,
message: '参数缺失'
})
}
case '/videoClass':
// 判断是否存在必要参数key和值
console.log(req.query);
if(req.query.type != '' &&
req.query.page != '') {
callback(res, req)
}else {
res.json({
status: 404,
message: '参数缺失'
})
}
break;
default:
break;
}
})
}
/**
* POST 请求
* @param url 请求的地址
* @param callback 回调
*/
public PostRoutes(url: string, callback: any) : void {
router.post(url, (req, res) => {
callback(res, req)
})
}
private useApiStyle (req,res) {
if(req.query.hasOwnProperty("_rsa") && req.query._rsa != ''){
res.json({
status: "SRA接口等待实现..."
})
}else {
return false
}
}
}
export default Controller

View File

@@ -0,0 +1 @@
5ada070d-70e8-4b4f-80f2-ada2d255cf95

138
mApi/src/routes/modular/index.ts Executable file
View File

@@ -0,0 +1,138 @@
import Controller from "../controller";
// import mysql from "./../../mysql";
import utils from "./../../utils";
import api from "./../../api";
import config from "./../../config";
class index extends Controller{
public utils = new utils();
// public db = new mysql();
public api = new api();
constructor () {
super();
this.indexRouter()
this.otherClass()
this.imageRouter()
this.enterInfo()
}
/**
* 网站首页api
* 接口地址http://127.0.0.1:3000/index
*/
private indexRouter(): void {
this.GetRoutes('/index',async (res, req) => {
let data:any = await this.api.get(config.url.BaseUrl())
this.api.cheerios(data, (result)=>{
return res.json({
status: 200,
length: result.length,
time: this.utils.GetTime(),
result: result
})
})
})
}
/**
* 网站分类页面api
* 接口地址http://127.0.0.1:3000/videoClass?type=60&page=1
* @param type 网站栏目id
* @param page 想要获取第几页的数据
*/
private otherClass(): void {
this.GetRoutes('/videoClass', async (res,req) => {
let type: string = req.query.type
let page: string = req.query.page
let data: any = await this.api.get(this.returnURL(type, page))
this.api.cheerios(data, (result, pagination)=>{
return res.json({
status: 200,
length: result.length,
time: this.utils.GetTime(),
resultList: {
total: this.returnPage(pagination),
video: result
}
})
}, true)
})
}
/**
* 获取图片列表
*/
private imageRouter(): void {
this.GetRoutes('/image', async (res,req) => {
let type: string = req.query.type
let page: string = req.query.page
let data:any = await this.api.get(this.returnURL(type,page))
this.api.cheeriosIMG(data, (result, pagination)=>{
return res.json({
status: 200,
length: result.length,
time: this.utils.GetTime(),
total: this.returnPage(pagination.substring(0,22), true),
result: result
})
},true)
})
}
/**
* 进入图片详情
*/
private enterInfo() {
this.GetRoutes('/imageinfo', async (res,req,params) => {
let id: string = params.id
let data:any = await this.api.get(`${config.url.BaseUrl()}${id}`)
this.api.enterInfos(data,(result) =>{
return res.json({
status: 200,
length: result.length,
time: this.utils.GetTime(),
result: result
})
})
})
}
/**
* 因为这里第一个URL地址和其他之后每一个的地址不一样所以这里做下简单判断
* @param type
* @param page
*/
private returnURL(type:string, page:string): any {
let URL:string;
page === '1' ? URL = `${config.url.BaseUrl()}/Html/${type}/` : URL = `${config.url.BaseUrl()}/Html/${type}/index-${page}.html`
return URL
}
/**
* 返回总视频数,当前页,总页数
* @param page
*/
private returnPage(page:string, action?:boolean):any {
let pages:any;
if(action) {
pages = {
totalNumber: page.match(/共(\S*)篇/)[1],
currentPage: page.match(/:(\S*)\//)[1],
totalPage: page.match(/\/(\S*)页/)[1]
}
}else {
pages = {
totalNumber: page.match(/共(\S*)部/)[1],
currentPage: page.match(/\s+(\S*)\//)[1],
totalPage: page.match(/\/(\S*)/)[1]
}
}
return pages
}
}
export default new index().routers

1
mApi/src/rsa/.pydio Normal file
View File

@@ -0,0 +1 @@
e91c2418-1979-4c6b-83c4-c5d6a1ea9a0b

5
mApi/src/rsa/help.md Executable file
View File

@@ -0,0 +1,5 @@
RSA 非对称性加密在api接口中的使用
rsa_pub.pem 公钥发给前端前端ajax请求用公钥加密参数
rsa_priv.pem私钥留在服务器上用来解密前端ajax参数

15
mApi/src/rsa/rsa_priv.pem Executable file
View File

@@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDUbu7pfBOXprboQ4P/jBDHYAQqB7GTp/uzcDGiwHfdaGnjAxio
NHgim9zO+/Bz/A/K9g5z7LKy/URl94QOKVpyTf1ac1WF6E7N0H3ALkylc0rS5Ciy
5FY9MdwhyhuzlBkYoBsd7tY8/QxuDuzZ/hwFooZsGW9/C7DnjeEQ7RRRgQIDAQAB
AoGBALp9LHWCfDysmXOrGaz0jCJLEzzGhkjGtnsfKiPjbRbMu/ATXskDTterFpwK
pltb041sluGD0Ji7KBmPwbkg6olFB8EUCu5U281+8vNXaynzwCYF/tdaRoRUcIVf
VZS1y48LwH1JdPCtQvNldIAho5Nop7dWgz0qT2dCUezu7ab1AkEA/twQt1vnRpbk
vp3donKkux6hI8gwV58X7jtZjIOstVWlbGUBI90nln71lEUUmkuWK6YCyJy6fhAo
+gZ1OlltzwJBANViRRFJoGmZZLL9Jhgmeg52syVSWYcxquihKUdP4Wg6lbiETaHT
iqNnIBTG/c5W462zJ4JfKMB1NPKUwcYy768CQQDdVZle5H3SnDFEKi3VauMNbuha
/vyc3BoYV4rJsYFIan0jygRXdTVwSgpVHjlqVsKwXZiFSTfdS4OKwBkG96uZAkAL
YfqdOXg9KdmdUrO9hg/sxZg43XO5KoUbc71n+HLlxHpIJYaeo1I59T5Y3WScpTXw
BiaNZdYeriHs7tKHaCAxAkB548KLYhkxrl1SjLdmW8OcvenVORTim03dmsgUDg57
RRenq8VNgEvEdl/5N2k8evrr3bciMAxnk0oAGUYCsbDI
-----END RSA PRIVATE KEY-----

6
mApi/src/rsa/rsa_pub.pem Executable file
View File

@@ -0,0 +1,6 @@
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUbu7pfBOXprboQ4P/jBDHYAQq
B7GTp/uzcDGiwHfdaGnjAxioNHgim9zO+/Bz/A/K9g5z7LKy/URl94QOKVpyTf1a
c1WF6E7N0H3ALkylc0rS5Ciy5FY9MdwhyhuzlBkYoBsd7tY8/QxuDuzZ/hwFooZs
GW9/C7DnjeEQ7RRRgQIDAQAB
-----END PUBLIC KEY-----

1
mApi/src/utils/.pydio Normal file
View File

@@ -0,0 +1 @@
1ce2a739-84af-4587-a927-daf5d4118598

48
mApi/src/utils/index.ts Executable file
View File

@@ -0,0 +1,48 @@
import * as moment from "moment";
import * as fs from "fs";
import * as path from "path";
import config from "./../config";
import * as JsEncrypt from "node-jsencrypt";
import * as querystring from "querystring";
class Utils {
private publicKey;
private privateKey;
private RsaEncrypt = new JsEncrypt()
constructor () {
// 公钥
this.publicKey = fs.readFileSync(path.join(__filename,config.rsa.public), "utf8")
// 私钥
this.privateKey = fs.readFileSync(path.join(__filename,config.rsa.private), "utf8")
}
/**
* 返回指定的时间
* @param timer 时间的格式
*/
public GetTime (timer?:string) {
timer = timer || 'YYYY-MM-DD HH:mm:ss'
return moment().format(timer);
}
/**
* 使用公钥( rsa_pub.pem )对接口参数进行加密
* @param ciphertext 需要加密的数据
*/
// public Encryption (ciphertext: string) {
// let encrypted = crypto.publicEncrypt(this.publicKey, Buffer.from(ciphertext))
// return encrypted.toString('base64')
// }
/**
* 使用私钥( rsa_priv.pem ) 对接口参数 token 进行解密
* 解密后在使用 querystring 进行序列化
* @param ciphertext 需要解密的参数
*/
public Decrypt(ciphertext: string) {
this.RsaEncrypt.setPrivateKey(this.privateKey)
return this.RsaEncrypt.decrypt(ciphertext)
}
}
export default Utils

50
mApi/src/www.ts Executable file
View File

@@ -0,0 +1,50 @@
import app from './app';
import config from "./config";
import * as http from 'http';
class service {
port: number;
server: any;
constructor () {
this.port = config.port
this.init()
}
private init (): void {
this.server = http.createServer(app)
this.start()
}
private start (): void {
this.server.listen(this.port);
this.server.on('error', this.error);
this.server.on('listening', this.onListening);
}
private error (error:any): void {
if (error.syscall !== 'listen') {
throw error;
}
var bind = this.port;
switch (error.code) {
case 'EACCES':
console.error(`端口:${bind} 需要提升权限..`);
process.exit(1);
break;
case 'EADDRINUSE':
console.error(`端口:${bind} 被占用...`);
process.exit(1);
break;
default:
throw error;
}
}
private onListening(): void {
console.log(`App is run: ${config.address}:${config.port}`)
}
}
new service()