const fs = require('fs');
const path = require('path');
const axios = require('axios');
const moment = require('moment-timezone');
function getFilePath(fileName) {
if (!fileName) throw Error('getFilePath Error => missing fileName');
const osType = process.platform;
if (osType === 'win32') {
var rootPath = path.join(__dirname, '..', '/');
var fullPath = path.join(rootPath, `/media/${fileName}.json`);
} else if (osType === 'linux') {
var fullPath = `/media/${fileName}.json`
} else {
console.log(`当前系统类型为 ${osType}`);
throw Error('getFilePath Error => unknown osType');
}
return fullPath
}
/**
* 执行 GraphQL 查询。
* @async
* @param {string} queryStr - GraphQL 查询字符串。
* @param {Object} variables - GraphQL 查询变量。
* @param {string} [operate=null] - GraphQL 操作名称。
* @param {string} [auth=null] - 授权令牌。
* @returns {Promise<Object>} - GraphQL 查询结果。
* @description
* gql数据库
*/
const myGQL = async (queryStr, variables, operate = null, auth = null) => {
let res = null
await axios({
url: 'https://kvu5jiwt70.execute-api.cn-northwest-1.amazonaws.com.cn/graphql',
method: 'post',
headers: {
'accept': 'application/json',
'content-type': 'application/json',
"x-api-key": "172df9f6-2241-4f60-a4bb-b54847d5cdb0",
"authorization": auth ? "Bearer " + auth : ""
},
data: {
query: queryStr,
operationName: operate,
variables: variables
},
timeout: 60000
}).then((v) => {
if (v.data.data) res = v.data.data
else res = v.data
}).catch((err) => {
console.log(err.response.data)
console.log('gql请求报错', err.message)
});
return res
}
/**
* 添加或更新数据库内容。
* @async
* @param {string} fileName - 文件名。
* @param {string} type - 操作类型('add', 'delete', 'set')。
* @param {string} dataType - 数据类型。
* @param {Object} newData - 新数据或更新数据。
* @description
* 添加数据库内容
*/
const dataControler = async (fileName, type, dataType, newData) => {
let fullPath = getFilePath(fileName);
let dataList = require(fullPath);
let oldData = dataList[dataType]
switch (type) {
case 'add':
if (dataType === "dailyFollow") dataList[dataType] = oldData + 1
else dataList[dataType] = oldData.concat(newData)
break;
case 'delete':
{
let keys = Object.keys(newData);
console.log('对象大小', keys.length);
let ind;
if (keys.length > 1) ind = oldData.findIndex(v => (v[keys[0]] === newData[keys[0]]) && (v[keys[1]] === newData[keys[1]]));
else ind = oldData.findIndex(v => v[keys[0]] === newData[keys[0]]);
if (ind > -1) dataList[dataType].splice(ind, 1);
else console.log('未找到该数据,请检查参数', ind);
break;
}
case 'set':
if (dataType === "dailyFollow") dataList[dataType] = newData
else {
let key = newData.key
let ind = oldData.findIndex(v => v[key] === newData[key]);
delete newData.key
dataList[dataType][ind] = Object.assign({}, oldData[ind], newData);;
}
break;
default:
break;
}
fs.writeFileSync(fullPath, JSON.stringify(dataList) + '\n');
}
/**
* 查询数据库内容。
* @async
* @param {string} fileName - 文件名。
* @param {string} dataType - 数据类型。
* @param {Object} query - 查询条件。
* @returns {Promise<Object>} - 查询结果。
* @description
* 查询数据库内容
*/
const dataGetter = async (fileName, dataType, query) => {
let fullPath = getFilePath(fileName);
let dataList = require(fullPath);
let oldData = dataList[dataType]
if (dataType === "dailyFollow") return oldData
else {
if (!query.key2) {
let res = oldData.find(v => v[query.key] === query.value);
return res
}
else {
let res = oldData.find(v => (v[query.key] === query.value) && (v[query.key2] === query.value2));
return res
}
}
}
/**
* 检查文件是否存在,如果不存在则创建文件,并初始化数据结构。
* @async
* @param {string} fileName - 文件名。
* @description
* 检查文件
*/
const checkFile = async (fileName) => {
const fullPath = getFilePath(fileName);
try {
let data = require(fullPath);
if (!data.userList) {
console.log('没有userList,创建userList');
data.userList = [];
fs.writeFileSync(fullPath, JSON.stringify(data) + '\n');
}
if (!data.videoList) {
console.log('没有videoList,创建videoList');
data.videoList = [];
fs.writeFileSync(fullPath, JSON.stringify(data) + '\n');
}
if (data.dailyFollow === undefined) {
console.log('没有dailyFollow,创建dailyFollow');
data.dailyFollow = 0;
fs.writeFileSync(fullPath, JSON.stringify(data) + '\n');
}
}
catch {
console.log('没有data文件,创建文件');
fs.writeFileSync(fullPath, JSON.stringify({
"userList": [],
"videoList": [],
"dailyFollow": 0
}) + '\n');
}
}
/**
* 创建或更新用户信息。
* @async
* @param {string} platformName - 平台名称。
* @param {Object} userInfo - 用户信息。
* @param {boolean} [follow=false] - 是否关注用户。
* @description
* 创建或新增用户
*/
const createUser = async (platformName, userInfo, follow) => {
userInfo.platform = platformName
userInfo.product = 'palpalcloud'
if (follow) userInfo.follow = follow
if (typeof userInfo.otherInfo !== 'string') {
let str = ''
for (let i = 0; i < userInfo.otherInfo.length; i++) {
if (i < userInfo.otherInfo.length - 1) str += userInfo.otherInfo[i] + '###';
else str += userInfo.otherInfo[i];
}
userInfo.otherInfo = str
}
delete userInfo.id
let update = await myGQL(`
mutation updateUser(
$name: String!
$platform: String!
$product: String!
${userInfo.data ? "$data: String!" : ""}
${userInfo.intro ? "$intro: String!" : ""}
${userInfo.works ? "$works: String!" : ""}
${userInfo.otherInfo ? "$otherInfo: String!" : ""}
${follow ? "$follow: String!" : ""}
) {
updateUser(
name: $name
platform: $platform
product: $product
${userInfo.data ? "data: $data" : ""}
${userInfo.intro ? "intro: $intro" : ""}
${userInfo.works ? "works: $works" : ""}
${userInfo.otherInfo ? "otherInfo: $otherInfo" : ""}
${follow ? "follow: $follow" : ""}
)
}
`, userInfo, 'updateUser')
// console.log(update);
}
/**
* 记录已访问过的视频信息。
* @async
* @param {string} fileName - 文件名。
* @param {Object} videoInfo - 视频信息。
* @returns {Promise<string>} - 返回视频检查结果,可能是 'over', 'haveVideo' 或其他错误信息。
* @description
* 记录已访问过的视频
*/
const visitedVideo = async (fileName, videoInfo) => {
let video = await myGQL(`
mutation checkVideo($name: String!, $platform: String!, $product: String!) {
checkVideo(name: $name, platform: $platform, product: $product)
}
`, {
name: videoInfo.title + '###' + videoInfo.user,
platform: fileName,
product: "palpalcloud"
}, 'checkVideo')
if (video?.checkVideo === 'Video Created') {
return 'over'
}
else if (video?.checkVideo === 'Video Exists') {
return 'haveVideo'
}
else {
console.log('查询video结果报错', video);
}
}
/**
* 查询数据库中的特定内容。
* @async
* @param {string} fileName - 数据文件的名称。
* @param {string} param - 数据类型参数。
* @param {Object} info - 查询信息。
* @returns {Promise<Object>} - 查询结果。
* @description
* 查询内容
*/
const getInfo = async (fileName, param, info) => {
let result = await dataGetter(fileName, param, info);
return result
}
/**
* 清除每日关注数。
* @async
* @param {string} fileName - 数据文件的名称。
* @returns {Promise<Object>} - 操作结果,主键为 "main"。
* @description
* 清除每日
*/
const clearDailyFollow = async (fileName) => {
try {
console.log('~~~清除每日关注~~~');
await dataControler(fileName, 'set', 'dailyFollow', 0)
return {
"main": "over"
}
}
catch (err) {
console.log(err);
return {
"main": "error"
}
}
}
/**
* 批量增加每日关注数。
* @async
* @param {string} fileName - 数据文件的名称。
* @param {number} num - 要增加的数值。
* @description
* 批量加每日
*/
const addDailyFollow = async (fileName, num) => {
try {
let result = await dataGetter(fileName, 'dailyFollow');
await dataControler(fileName, 'set', 'dailyFollow', result + num);
}
catch (err) {
console.log('增加每日关注报错', err.message);
}
}
function checkIfOneDayPassed(lastRunTime) {
const currentTime = new Date().getTime();
const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
if (currentTime - lastRunTime >= oneDay) {
console.log('~~~已经过去了一天~~~');
return true
}
else return false
}
async function getTimeAndWait(hour, minute1, minute2, wait = 150) {
// 获取当前时间的时间戳
const timestamp = Date.now();
// 使用moment-timezone将时间戳转换为UTC+8时区的时间
const dateUtcPlus8 = moment(timestamp).tz('Asia/Shanghai');
const hours = dateUtcPlus8.hour();
const minutes = dateUtcPlus8.minute();
if (hours === hour && minutes >= minute1 && minutes <= minute2) {
let hoursStr = hours < 10 ? '0' + hours : hours;
let minutesStr = minutes < 10 ? '0' + minutes : minutes;
console.log(`当前时间: ${hoursStr}:${minutesStr}`, `预计等待: ${wait}分`);
for (let i = 0; i < wait; i++) {
await new Promise(resolve => setTimeout(resolve, 60 * 1000));
if (i % 2 === 0) console.log(`等待中... 第${i + 1}分钟`);
}
console.log('等待结束');
}
}
const autoClearDailyFollow = async (fileName) => {
const fullPath = getFilePath(`${fileName}_timer`);
try {
let data = require(fullPath);
if (!data.lastSaveTime) {
data.lastSaveTime = new Date().getTime();
fs.writeFileSync(fullPath, JSON.stringify(data) + '\n');
}
else {
let oneDayPass = checkIfOneDayPassed(data.lastSaveTime)
if (oneDayPass) {
await clearDailyFollow(fileName)
data.lastSaveTime = new Date().getTime();
fs.writeFileSync(fullPath, JSON.stringify(data) + '\n');
}
}
}
catch {
console.log('没有时间检测文件,创建文件');
await clearDailyFollow(fileName)
fs.writeFileSync(fullPath, JSON.stringify({
lastSaveTime: new Date().getTime()
}) + '\n');
}
}
module.exports = {
checkFile: checkFile,
createUser: createUser,
visitedVideo: visitedVideo,
getInfo: getInfo,
clearDailyFollow: clearDailyFollow,
addDailyFollow: addDailyFollow,
autoClearDailyFollow: autoClearDailyFollow
}