Compare commits

..

No commits in common. "5c062172f317e12513d9573a7239c6c3e4a85e20" and "bdfc7f43d17bc9e0018461a4ee85a1df7e24cc71" have entirely different histories.

7 changed files with 55 additions and 103 deletions

View File

@ -36,7 +36,7 @@ export class AppConfigService implements OnModuleInit {
* .env * .env
*/ */
private checkAndSyncEnv(): void { private checkAndSyncEnv(): void {
this.logger.log('检查并同步 .env 与 .envExample ...'); this.logger.log('检查并同步 .env 与 .env.example ...');
if (!fs.existsSync(this.envExamplePath)) { if (!fs.existsSync(this.envExamplePath)) {
this.logger.error(`缺少 ${this.envExamplePath} 文件,无法校验`); this.logger.error(`缺少 ${this.envExamplePath} 文件,无法校验`);
@ -67,7 +67,7 @@ export class AppConfigService implements OnModuleInit {
}); });
this.logger.log('.env 已自动补全缺失项'); this.logger.log('.env 已自动补全缺失项');
} else { } else {
this.logger.log('.env 已与 .envExample 保持一致'); this.logger.log('.env 已与 .env.example 保持一致');
} }
} }

View File

@ -66,7 +66,7 @@ export class OpenListService {
/** /**
* *
* @param path * @param path
* @returns * @returns
*/ */
public async listFiles(path: string): Promise<FsList> { public async listFiles(path: string): Promise<FsList> {

View File

@ -5,18 +5,18 @@ export interface FsList {
code: number; code: number;
message: string; message: string;
data: { data: {
content: Array<{ content: [
name: string; name: string,
size: number; size: number,
is_dir: boolean; is_dir: boolean,
modified: string; // 修改时间 modified: string, //修改时间
sign: string; // 签名 sign: string, //签名
thumb: string; // 略缩图 thumb: string, //略缩图
type: number; // 类型 type: number, //类型
}> | null; // 可能为空数组 ];
total: number; // 总数 total: number; //总数
readme: string; // 说明? readme: string; //说明?
write: boolean; // 是否可写入 write: boolean; //是否可写入
provider: string; provider: string;
header: string; header: string;
}; };

View File

@ -50,20 +50,10 @@ export class OpenListUtils {
static async listDirectory(token: string, path: string): Promise<FsList> { static async listDirectory(token: string, path: string): Promise<FsList> {
const url = `${this.apiBaseUrl}/api/fs/list`; const url = `${this.apiBaseUrl}/api/fs/list`;
try { try {
let data = JSON.stringify({ const response = await axios.get(url, {
path: path, params: { path },
headers: { Authorization: `Bearer ${token}` },
}); });
//this.logger.debug(path);
let config = {
method: 'post',
url: `${url}`,
headers: {
'Content-Type': 'application/json',
Authorization: `${token}`,
},
data: data,
};
let response = await axios(config);
this.logger.log(`列出目录${path}成功..`); this.logger.log(`列出目录${path}成功..`);
return response.data; return response.data;
} catch (error) { } catch (error) {
@ -82,7 +72,7 @@ export class OpenListUtils {
try { try {
const response = await axios.get(url, { const response = await axios.get(url, {
params: { path: filePath }, params: { path: filePath },
headers: { Authorization: `${token}` }, headers: { Authorization: `Bearer ${token}` },
}); });
this.logger.log('获取文件信息成功..'); this.logger.log('获取文件信息成功..');
return response.data; return response.data;
@ -106,7 +96,6 @@ export class OpenListUtils {
try { try {
const fileInfo = await this.getFileInfo(token, filePath); const fileInfo = await this.getFileInfo(token, filePath);
const rawUrl = fileInfo.data.raw_url; const rawUrl = fileInfo.data.raw_url;
this.logger.debug(`rawUrl: ${rawUrl}`);
if (!rawUrl) { if (!rawUrl) {
this.logger.error('文件没有找到 raw_url 地址..'); this.logger.error('文件没有找到 raw_url 地址..');
throw new Error('文件没有找到 raw_url 地址..'); throw new Error('文件没有找到 raw_url 地址..');

View File

@ -71,6 +71,7 @@ export class PathService {
this.logger.debug(`成功创建目录: ${dirToCreate}`); this.logger.debug(`成功创建目录: ${dirToCreate}`);
} catch (err) { } catch (err) {
this.logger.error(`创建目录失败: ${err}`); this.logger.error(`创建目录失败: ${err}`);
throw err;
} }
} }
} }

View File

@ -5,16 +5,9 @@ import { PathModule } from '../../core/path/path.module';
import { ToolsModule } from '../../core/tools/tools.module'; import { ToolsModule } from '../../core/tools/tools.module';
import { RedisModule } from '../../core/redis/redis.module'; import { RedisModule } from '../../core/redis/redis.module';
import { OpenListModule } from '../../core/openlist/openlist.module'; import { OpenListModule } from '../../core/openlist/openlist.module';
import { AppConfigModule } from '../../config/config.module';
@Module({ @Module({
imports: [ imports: [PathModule, OpenListModule, ToolsModule, RedisModule],
PathModule,
OpenListModule,
ToolsModule,
RedisModule,
AppConfigModule,
],
providers: [MemeService], providers: [MemeService],
controllers: [MemeController], controllers: [MemeController],
}) })

View File

@ -3,20 +3,17 @@ import * as path from 'path';
import * as fs from 'fs/promises'; import * as fs from 'fs/promises';
import { PathService } from '../../core/path/path.service'; import { PathService } from '../../core/path/path.service';
import { OpenListService } from '../../core/openlist/openlist.service'; import { OpenListService } from '../../core/openlist/openlist.service';
import { AppConfigService } from '../../config/config.service';
@Injectable() @Injectable()
export class MemeService { export class MemeService {
private readonly logger = new Logger(MemeService.name); private readonly logger = new Logger(MemeService.name);
private readonly updateMs = 150 * 60 * 1000; // 15min private readonly updateMs = 15 * 60 * 1000; // 15min
constructor( constructor(
@Inject(PathService) @Inject(PathService)
private readonly pathService: PathService, private readonly pathService: PathService,
@Inject(OpenListService) @Inject(OpenListService)
private readonly openListService: OpenListService, private readonly openListService: OpenListService,
@Inject(AppConfigService)
private readonly configService: AppConfigService,
) { ) {
this.startAutoUpdate(); this.startAutoUpdate();
} }
@ -24,30 +21,22 @@ export class MemeService {
private startAutoUpdate() { private startAutoUpdate() {
setInterval(async () => { setInterval(async () => {
const memePath = path.join(this.pathService.get('meme')); const memePath = path.join(this.pathService.get('meme'));
const remoteMemePath = this.configService.get('OPENLIST_API_MEME_PATH'); this.logger.log('定时检查表情仓库更新..');
if (remoteMemePath) { try {
this.logger.log('定时检查表情仓库更新..'); const remoteFiles = await this.openListService.listFiles(memePath);
try { if (remoteFiles.code === 200) {
const remoteFiles = const remoteFileList = remoteFiles.data.content;
await this.openListService.listFiles(remoteMemePath); const localFiles = await this.getLocalFileList(memePath);
if (remoteFiles.code === 200 && remoteFiles.data.content) { await this.compareAndDownloadFiles(
let remoteFileList = remoteFiles.data.content; memePath,
const localFiles = await this.getLocalFileList(memePath); localFiles,
//this.logger.debug(localFiles); remoteFileList,
await this.compareAndDownloadFiles( );
memePath, } else {
localFiles, this.logger.error('获取远程表情仓库文件失败..');
remoteFileList,
remoteMemePath,
);
} else {
this.logger.error('获取远程表情仓库文件失败..');
}
} catch (error) {
this.logger.error('定时检查表情仓库更新失败..', error);
} }
} else { } catch (error) {
this.logger.warn('未配置远程表情包地址..'); this.logger.error('定时检查表情仓库更新失败..', error);
} }
}, this.updateMs); }, this.updateMs);
} }
@ -58,8 +47,8 @@ export class MemeService {
* @private * @private
*/ */
private async getLocalFileList(dir: string): Promise<string[]> { private async getLocalFileList(dir: string): Promise<string[]> {
const files: string[] = []; const files: string[] = []; //文件
const dirs: string[] = []; const dirs: string[] = []; //目录
try { try {
const entries = await fs.readdir(dir, { withFileTypes: true }); const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
@ -81,57 +70,37 @@ export class MemeService {
} }
/** /**
* * ,
* @param localPath * @param localPath
* @param localFiles * @param localFiles
* @param remoteFiles * @param remoteFiles
* @param remoteMemePath
* @private * @private
*/ */
private async compareAndDownloadFiles( private async compareAndDownloadFiles(
localPath: string, localPath: string,
localFiles: string[], localFiles: string[],
remoteFiles: any[], remoteFiles: any[],
remoteMemePath: string,
) { ) {
for (const remoteFile of remoteFiles) { for (const remoteFile of remoteFiles) {
let relativePath = path.relative(remoteMemePath, remoteFile.path); const remoteFilePath = path.join(localPath, remoteFile.name);
relativePath = relativePath.replace(/D:\\alist\\crystelf\\meme/g, '');
const localFilePath = path.join(
localPath,
relativePath.replace(/\\/g, '/'),
);
if (remoteFile.is_dir) { if (remoteFile.is_dir) {
await fs.mkdir(remoteFilePath, { recursive: true });
this.logger.log(`文件夹已创建: ${remoteFile.name}`);
await this.compareAndDownloadFiles(
remoteFilePath,
[],
remoteFile.content,
);
} else if (!localFiles.includes(remoteFilePath)) {
this.logger.log(`文件缺失: ${remoteFile.name},开始下载..`);
try { try {
const localDirPath = path.dirname(localFilePath); await this.openListService.downloadFile(
await fs.mkdir(localDirPath, { recursive: true }); remoteFile.raw_url,
this.logger.log(`文件夹已创建: ${localDirPath}`); remoteFilePath,
const subRemoteFiles = await this.openListService.listFiles(
remoteFile.path,
); );
if (subRemoteFiles.code === 200 && subRemoteFiles.data.content) { this.logger.log(`文件下载成功: ${remoteFile.name}`);
await this.compareAndDownloadFiles(
localPath,
[],
subRemoteFiles.data.content,
remoteMemePath,
);
}
} catch (error) { } catch (error) {
this.logger.error(`创建文件夹失败: ${remoteFile.path}`, error); this.logger.error(`下载文件失败: ${remoteFile.name}`, error);
}
} else {
if (!localFiles.includes(localFilePath)) {
this.logger.log(`文件缺失: ${remoteFile.path}, 开始下载..`);
try {
await this.openListService.downloadFile(
remoteFile.path,
localFilePath,
);
this.logger.log(`文件下载成功: ${remoteFile.path}`);
} catch (error) {
this.logger.error(`下载文件失败: ${remoteFile.path}`, error);
}
} }
} }
} }