mirror of
https://github.com/crystelf/crystelf-core.git
synced 2025-10-14 13:29:19 +00:00
Compare commits
4 Commits
d0eb167245
...
baf92f470a
Author | SHA1 | Date | |
---|---|---|---|
baf92f470a | |||
7444c9090a | |||
dc479ffbdb | |||
645065b4fb |
@ -46,15 +46,15 @@
|
|||||||
"@swc/core": "^1.10.7",
|
"@swc/core": "^1.10.7",
|
||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
"@types/jest": "^29.5.14",
|
"@types/jest": "^29.5.14",
|
||||||
|
"@types/multer": "^2.0.0",
|
||||||
"@types/node": "^22.16.4",
|
"@types/node": "^22.16.4",
|
||||||
"@types/stream-throttle": "^0.1.4",
|
"@types/stream-throttle": "^0.1.4",
|
||||||
"@types/supertest": "^6.0.2",
|
"@types/supertest": "^6.0.2",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"eslint": "^9.18.0",
|
"eslint": "^9.18.0",
|
||||||
"eslint-config-prettier": "^10.0.1",
|
|
||||||
"eslint-plugin-prettier": "^5.2.2",
|
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
|
"multer": "^2.0.2",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.4.2",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"supertest": "^7.0.0",
|
"supertest": "^7.0.0",
|
||||||
|
80
pnpm-lock.yaml
generated
80
pnpm-lock.yaml
generated
@ -96,6 +96,9 @@ importers:
|
|||||||
'@types/jest':
|
'@types/jest':
|
||||||
specifier: ^29.5.14
|
specifier: ^29.5.14
|
||||||
version: 29.5.14
|
version: 29.5.14
|
||||||
|
'@types/multer':
|
||||||
|
specifier: ^2.0.0
|
||||||
|
version: 2.0.0
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.16.4
|
specifier: ^22.16.4
|
||||||
version: 22.16.5
|
version: 22.16.5
|
||||||
@ -111,18 +114,15 @@ importers:
|
|||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.18.0
|
specifier: ^9.18.0
|
||||||
version: 9.31.0
|
version: 9.31.0
|
||||||
eslint-config-prettier:
|
|
||||||
specifier: ^10.0.1
|
|
||||||
version: 10.1.8(eslint@9.31.0)
|
|
||||||
eslint-plugin-prettier:
|
|
||||||
specifier: ^5.2.2
|
|
||||||
version: 5.5.3(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.31.0))(eslint@9.31.0)(prettier@3.6.2)
|
|
||||||
globals:
|
globals:
|
||||||
specifier: ^16.0.0
|
specifier: ^16.0.0
|
||||||
version: 16.3.0
|
version: 16.3.0
|
||||||
jest:
|
jest:
|
||||||
specifier: ^29.7.0
|
specifier: ^29.7.0
|
||||||
version: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@swc/core@1.13.1)(@types/node@22.16.5)(typescript@5.8.3))
|
version: 29.7.0(@types/node@22.16.5)(ts-node@10.9.2(@swc/core@1.13.1)(@types/node@22.16.5)(typescript@5.8.3))
|
||||||
|
multer:
|
||||||
|
specifier: ^2.0.2
|
||||||
|
version: 2.0.2
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.4.2
|
specifier: ^3.4.2
|
||||||
version: 3.6.2
|
version: 3.6.2
|
||||||
@ -931,10 +931,6 @@ packages:
|
|||||||
'@paralleldrive/cuid2@2.2.2':
|
'@paralleldrive/cuid2@2.2.2':
|
||||||
resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
|
resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
|
||||||
|
|
||||||
'@pkgr/core@0.2.9':
|
|
||||||
resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
|
|
||||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
|
||||||
|
|
||||||
'@scarf/scarf@1.4.0':
|
'@scarf/scarf@1.4.0':
|
||||||
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==}
|
||||||
|
|
||||||
@ -1135,6 +1131,9 @@ packages:
|
|||||||
'@types/mime@1.3.5':
|
'@types/mime@1.3.5':
|
||||||
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
|
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
|
||||||
|
|
||||||
|
'@types/multer@2.0.0':
|
||||||
|
resolution: {integrity: sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==}
|
||||||
|
|
||||||
'@types/node@22.16.5':
|
'@types/node@22.16.5':
|
||||||
resolution: {integrity: sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==}
|
resolution: {integrity: sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==}
|
||||||
|
|
||||||
@ -1908,26 +1907,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
eslint-config-prettier@10.1.8:
|
|
||||||
resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==}
|
|
||||||
hasBin: true
|
|
||||||
peerDependencies:
|
|
||||||
eslint: '>=7.0.0'
|
|
||||||
|
|
||||||
eslint-plugin-prettier@5.5.3:
|
|
||||||
resolution: {integrity: sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==}
|
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
|
||||||
peerDependencies:
|
|
||||||
'@types/eslint': '>=8.0.0'
|
|
||||||
eslint: '>=8.0.0'
|
|
||||||
eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0'
|
|
||||||
prettier: '>=3.0.0'
|
|
||||||
peerDependenciesMeta:
|
|
||||||
'@types/eslint':
|
|
||||||
optional: true
|
|
||||||
eslint-config-prettier:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
eslint-scope@5.1.1:
|
eslint-scope@5.1.1:
|
||||||
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
|
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
|
||||||
engines: {node: '>=8.0.0'}
|
engines: {node: '>=8.0.0'}
|
||||||
@ -2026,9 +2005,6 @@ packages:
|
|||||||
fast-deep-equal@3.1.3:
|
fast-deep-equal@3.1.3:
|
||||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
fast-diff@1.3.0:
|
|
||||||
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
|
|
||||||
|
|
||||||
fast-fifo@1.3.2:
|
fast-fifo@1.3.2:
|
||||||
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
|
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
|
||||||
|
|
||||||
@ -2999,10 +2975,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
prettier-linter-helpers@1.0.0:
|
|
||||||
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
|
|
||||||
engines: {node: '>=6.0.0'}
|
|
||||||
|
|
||||||
prettier@3.6.2:
|
prettier@3.6.2:
|
||||||
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
|
resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@ -3377,10 +3349,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
|
resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==}
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
|
|
||||||
synckit@0.11.11:
|
|
||||||
resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==}
|
|
||||||
engines: {node: ^14.18.0 || >=16.0.0}
|
|
||||||
|
|
||||||
tapable@2.2.2:
|
tapable@2.2.2:
|
||||||
resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==}
|
resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -4631,8 +4599,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@noble/hashes': 1.8.0
|
'@noble/hashes': 1.8.0
|
||||||
|
|
||||||
'@pkgr/core@0.2.9': {}
|
|
||||||
|
|
||||||
'@scarf/scarf@1.4.0': {}
|
'@scarf/scarf@1.4.0': {}
|
||||||
|
|
||||||
'@sec-ant/readable-stream@0.4.1': {}
|
'@sec-ant/readable-stream@0.4.1': {}
|
||||||
@ -4830,6 +4796,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/mime@1.3.5': {}
|
'@types/mime@1.3.5': {}
|
||||||
|
|
||||||
|
'@types/multer@2.0.0':
|
||||||
|
dependencies:
|
||||||
|
'@types/express': 5.0.3
|
||||||
|
|
||||||
'@types/node@22.16.5':
|
'@types/node@22.16.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.21.0
|
undici-types: 6.21.0
|
||||||
@ -5679,20 +5649,6 @@ snapshots:
|
|||||||
|
|
||||||
escape-string-regexp@4.0.0: {}
|
escape-string-regexp@4.0.0: {}
|
||||||
|
|
||||||
eslint-config-prettier@10.1.8(eslint@9.31.0):
|
|
||||||
dependencies:
|
|
||||||
eslint: 9.31.0
|
|
||||||
|
|
||||||
eslint-plugin-prettier@5.5.3(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.31.0))(eslint@9.31.0)(prettier@3.6.2):
|
|
||||||
dependencies:
|
|
||||||
eslint: 9.31.0
|
|
||||||
prettier: 3.6.2
|
|
||||||
prettier-linter-helpers: 1.0.0
|
|
||||||
synckit: 0.11.11
|
|
||||||
optionalDependencies:
|
|
||||||
'@types/eslint': 9.6.1
|
|
||||||
eslint-config-prettier: 10.1.8(eslint@9.31.0)
|
|
||||||
|
|
||||||
eslint-scope@5.1.1:
|
eslint-scope@5.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
esrecurse: 4.3.0
|
esrecurse: 4.3.0
|
||||||
@ -5856,8 +5812,6 @@ snapshots:
|
|||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
fast-diff@1.3.0: {}
|
|
||||||
|
|
||||||
fast-fifo@1.3.2: {}
|
fast-fifo@1.3.2: {}
|
||||||
|
|
||||||
fast-glob@3.3.3:
|
fast-glob@3.3.3:
|
||||||
@ -6947,10 +6901,6 @@ snapshots:
|
|||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
prettier-linter-helpers@1.0.0:
|
|
||||||
dependencies:
|
|
||||||
fast-diff: 1.3.0
|
|
||||||
|
|
||||||
prettier@3.6.2: {}
|
prettier@3.6.2: {}
|
||||||
|
|
||||||
pretty-format@29.7.0:
|
pretty-format@29.7.0:
|
||||||
@ -7364,10 +7314,6 @@ snapshots:
|
|||||||
|
|
||||||
symbol-observable@4.0.0: {}
|
symbol-observable@4.0.0: {}
|
||||||
|
|
||||||
synckit@0.11.11:
|
|
||||||
dependencies:
|
|
||||||
'@pkgr/core': 0.2.9
|
|
||||||
|
|
||||||
tapable@2.2.2: {}
|
tapable@2.2.2: {}
|
||||||
|
|
||||||
tar-stream@3.1.7:
|
tar-stream@3.1.7:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||||
import { AppConfigService } from '../../config/config.service';
|
import { AppConfigService } from '../../config/config.service';
|
||||||
import { FileInfo, FsList } from './openlist.types';
|
import { FileInfo, FileUpload, FsList } from './openlist.types';
|
||||||
import { OpenListUtils } from './openlist.utils';
|
import { OpenListUtils } from './openlist.utils';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
@ -148,13 +148,18 @@ export class OpenListService {
|
|||||||
filePath: string,
|
filePath: string,
|
||||||
file: any,
|
file: any,
|
||||||
filePathOnserver: string,
|
filePathOnserver: string,
|
||||||
): Promise<void> {
|
): Promise<FileUpload> {
|
||||||
try {
|
try {
|
||||||
const token = await this.fetchToken(
|
const token = await this.fetchToken(
|
||||||
<string>this.configService.get('OPENLIST_API_BASE_USERNAME'),
|
<string>this.configService.get('OPENLIST_API_BASE_USERNAME'),
|
||||||
<string>this.configService.get('OPENLIST_API_BASE_PASSWORD'),
|
<string>this.configService.get('OPENLIST_API_BASE_PASSWORD'),
|
||||||
);
|
);
|
||||||
await OpenListUtils.uploadFile(token, filePath, filePathOnserver, file);
|
return await OpenListUtils.uploadFile(
|
||||||
|
token,
|
||||||
|
filePath,
|
||||||
|
filePathOnserver,
|
||||||
|
file,
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error('上传文件失败:', error);
|
this.logger.error('上传文件失败:', error);
|
||||||
throw new Error('上传文件失败');
|
throw new Error('上传文件失败');
|
||||||
|
@ -162,10 +162,13 @@ export class OpenListUtils {
|
|||||||
file: fs.ReadStream,
|
file: fs.ReadStream,
|
||||||
): Promise<FileUpload> {
|
): Promise<FileUpload> {
|
||||||
const url = `${this.apiBaseUrl}/api/fs/put`;
|
const url = `${this.apiBaseUrl}/api/fs/put`;
|
||||||
|
const stats = fs.statSync(filePath);
|
||||||
|
const fileSize = stats.size;
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `${token}`,
|
Authorization: `${token}`,
|
||||||
'Content-Type': 'application/octet-stream',
|
'Content-Type': 'application/octet-stream',
|
||||||
'Content-Length': file.bytesRead,
|
'Content-Length': fileSize,
|
||||||
'File-Path': encodeURIComponent(filePathOnServer),
|
'File-Path': encodeURIComponent(filePathOnServer),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -174,14 +177,17 @@ export class OpenListUtils {
|
|||||||
headers,
|
headers,
|
||||||
params: {
|
params: {
|
||||||
path: filePath,
|
path: filePath,
|
||||||
'As-Task': 'true', //作为任务
|
'As-Task': 'true',
|
||||||
},
|
},
|
||||||
|
maxBodyLength: Infinity,
|
||||||
|
maxContentLength: Infinity,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.logger.log(`文件上传成功: ${filePathOnServer}`);
|
this.logger.log(`文件上传成功: ${filePathOnServer}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error('上传文件失败..', error);
|
this.logger.error('上传文件失败..', error);
|
||||||
throw new Error('上传文件失败..');
|
throw new Error(`上传文件失败: ${error.message || error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,18 @@ import {
|
|||||||
Logger,
|
Logger,
|
||||||
Inject,
|
Inject,
|
||||||
Ip,
|
Ip,
|
||||||
|
UseInterceptors,
|
||||||
|
UploadedFile,
|
||||||
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags, ApiOperation, ApiBody, ApiQuery } from '@nestjs/swagger';
|
import {
|
||||||
|
ApiTags,
|
||||||
|
ApiOperation,
|
||||||
|
ApiBody,
|
||||||
|
ApiQuery,
|
||||||
|
ApiConsumes,
|
||||||
|
ApiHeader,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
import { MemeService } from './meme.service';
|
import { MemeService } from './meme.service';
|
||||||
import { Response } from 'express';
|
import { Response } from 'express';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
@ -19,6 +29,12 @@ import { Throttle } from 'stream-throttle';
|
|||||||
import { ToolsService } from '../../core/tools/tools.service';
|
import { ToolsService } from '../../core/tools/tools.service';
|
||||||
import { RedisService } from '../../core/redis/redis.service';
|
import { RedisService } from '../../core/redis/redis.service';
|
||||||
import imageType from 'image-type';
|
import imageType from 'image-type';
|
||||||
|
import { FileInterceptor } from '@nestjs/platform-express';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { OpenListService } from '../../core/openlist/openlist.service';
|
||||||
|
import { PathService } from '../../core/path/path.service';
|
||||||
|
import { TokenAuthGuard } from '../../core/tools/token-auth.guard';
|
||||||
|
import { AppConfigService } from '../../config/config.service';
|
||||||
|
|
||||||
class MemeRequestDto {
|
class MemeRequestDto {
|
||||||
character?: string;
|
character?: string;
|
||||||
@ -38,6 +54,12 @@ export class MemeController {
|
|||||||
private readonly toolsService: ToolsService,
|
private readonly toolsService: ToolsService,
|
||||||
@Inject(RedisService)
|
@Inject(RedisService)
|
||||||
private readonly redisService: RedisService,
|
private readonly redisService: RedisService,
|
||||||
|
@Inject(OpenListService)
|
||||||
|
private readonly openListService: OpenListService,
|
||||||
|
@Inject(PathService)
|
||||||
|
private readonly pathService: PathService,
|
||||||
|
@Inject(AppConfigService)
|
||||||
|
private readonly configService: AppConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Post('get')
|
@Post('get')
|
||||||
@ -158,4 +180,102 @@ export class MemeController {
|
|||||||
throw new HttpException('服务器错误', HttpStatus.INTERNAL_SERVER_ERROR);
|
throw new HttpException('服务器错误', HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件
|
||||||
|
* @param file
|
||||||
|
* @param character
|
||||||
|
* @param status
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
@Post('upload')
|
||||||
|
@ApiOperation({ summary: '上传表情包并同步' })
|
||||||
|
@ApiConsumes('multipart/form-data')
|
||||||
|
@UseInterceptors(FileInterceptor('file'))
|
||||||
|
@ApiHeader({ name: 'x-token', description: '身份验证token', required: true })
|
||||||
|
@UseGuards(TokenAuthGuard)
|
||||||
|
@ApiBody({
|
||||||
|
description: '上传表情包文件',
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
file: { type: 'string', format: 'binary' },
|
||||||
|
character: { type: 'string', description: '角色名称' },
|
||||||
|
status: { type: 'string', description: '状态' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
public async uploadMeme(
|
||||||
|
@UploadedFile() file: Express.Multer.File,
|
||||||
|
@Body('character') character: string,
|
||||||
|
@Body('status') status: string,
|
||||||
|
) {
|
||||||
|
if (!file) {
|
||||||
|
throw new HttpException('未检测到上传文件', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fsp = fs.promises;
|
||||||
|
const safeCharacter = character?.trim() || 'unknown';
|
||||||
|
const safeStatus = status?.trim() || 'default';
|
||||||
|
|
||||||
|
const memeBasePath = this.pathService.get('meme');
|
||||||
|
const localDir = path.join(memeBasePath, safeCharacter, safeStatus);
|
||||||
|
await fsp.mkdir(localDir, { recursive: true });
|
||||||
|
|
||||||
|
const buffer = file.buffer || (await fsp.readFile(file.path));
|
||||||
|
const imgType = await imageType(buffer);
|
||||||
|
if (!imgType || !['jpg', 'png', 'gif', 'webp'].includes(imgType.ext)) {
|
||||||
|
throw new HttpException(
|
||||||
|
'不支持的图片格式',
|
||||||
|
HttpStatus.UNSUPPORTED_MEDIA_TYPE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const remoteMemePath = this.configService.get('OPENLIST_API_MEME_PATH');
|
||||||
|
const remoteDir = `${remoteMemePath}/${safeCharacter}/${safeStatus}/`;
|
||||||
|
let fileList: string[] = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const listResult = await this.openListService.listFiles(remoteDir);
|
||||||
|
if (
|
||||||
|
listResult?.code === 200 &&
|
||||||
|
Array.isArray(listResult.data?.content)
|
||||||
|
) {
|
||||||
|
fileList = listResult.data.content.map((f) => f.name);
|
||||||
|
} else {
|
||||||
|
this.logger.warn(`目录为空或返回结构异常:${remoteDir}`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this.logger.warn(`获取远程目录失败(${remoteDir}),将自动创建`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const usedNumbers = fileList
|
||||||
|
.map((name) => {
|
||||||
|
const match = name.match(/^(\d+)\./);
|
||||||
|
return match ? parseInt(match[1], 10) : null;
|
||||||
|
})
|
||||||
|
.filter((n) => n !== null) as number[];
|
||||||
|
|
||||||
|
const nextNumber =
|
||||||
|
usedNumbers.length > 0 ? Math.max(...usedNumbers) + 1 : 1;
|
||||||
|
const remoteFilename = `${nextNumber}.${imgType.ext}`;
|
||||||
|
const remoteFilePath = `${remoteDir}${remoteFilename}`;
|
||||||
|
const localFilePath = path.join(localDir, remoteFilename);
|
||||||
|
await fsp.writeFile(localFilePath, buffer);
|
||||||
|
const fileStream = fs.createReadStream(localFilePath);
|
||||||
|
await this.openListService.uploadFile(
|
||||||
|
localFilePath,
|
||||||
|
fileStream,
|
||||||
|
remoteFilePath,
|
||||||
|
);
|
||||||
|
this.logger.log(`表情包上传成功: ${remoteFilePath}`);
|
||||||
|
return '表情上传成功..';
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('表情包上传失败:', error);
|
||||||
|
throw new HttpException(
|
||||||
|
`上传失败: ${error.message || error}`,
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import { FilesModule } from '../../core/files/files.module';
|
|||||||
RedisModule,
|
RedisModule,
|
||||||
AppConfigModule,
|
AppConfigModule,
|
||||||
FilesModule,
|
FilesModule,
|
||||||
|
PathModule,
|
||||||
],
|
],
|
||||||
providers: [MemeService],
|
providers: [MemeService],
|
||||||
controllers: [MemeController],
|
controllers: [MemeController],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user