eslint fix
This commit is contained in:
@@ -139,7 +139,7 @@ export class AESDecryptor {
|
||||
const invSubMix2 = invSubMix[2];
|
||||
const invSubMix3 = invSubMix[3];
|
||||
|
||||
let prev: number = 0;
|
||||
let prev = 0;
|
||||
let t: number;
|
||||
|
||||
for (ksRow = 0; ksRow < ksRows; ksRow++) {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import { fetchDoubanData as fetchDoubanAPI } from '@/lib/douban';
|
||||
import { searchTMDB, getTVSeasons } from '@/lib/tmdb.search';
|
||||
import { getNextApiKey } from '@/lib/tmdb.client';
|
||||
|
||||
export interface VideoContext {
|
||||
|
||||
+10
-12
@@ -1,6 +1,14 @@
|
||||
// 弹幕 API 服务封装(通过本地代理转发)
|
||||
import {
|
||||
clearAllDanmakuCache,
|
||||
clearDanmakuCache,
|
||||
clearExpiredDanmakuCache,
|
||||
generateCacheKey,
|
||||
getDanmakuCacheStats,
|
||||
getDanmakuFromCache,
|
||||
saveDanmakuToCache,
|
||||
} from './cache';
|
||||
import type {
|
||||
DanmakuAnime,
|
||||
DanmakuComment,
|
||||
DanmakuCommentsResponse,
|
||||
DanmakuEpisodesResponse,
|
||||
@@ -10,16 +18,6 @@ import type {
|
||||
DanmakuSettings,
|
||||
} from './types';
|
||||
|
||||
import {
|
||||
getDanmakuFromCache,
|
||||
saveDanmakuToCache,
|
||||
clearExpiredDanmakuCache,
|
||||
clearAllDanmakuCache,
|
||||
clearDanmakuCache,
|
||||
getDanmakuCacheStats,
|
||||
generateCacheKey,
|
||||
} from './cache';
|
||||
|
||||
// 初始化弹幕模块(清理过期缓存)
|
||||
let _cacheCleanupInitialized = false;
|
||||
|
||||
@@ -46,8 +44,8 @@ export {
|
||||
clearAllDanmakuCache,
|
||||
clearDanmakuCache,
|
||||
clearExpiredDanmakuCache,
|
||||
getDanmakuCacheStats,
|
||||
generateCacheKey,
|
||||
getDanmakuCacheStats,
|
||||
getDanmakuFromCache,
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { getAuthInfoFromBrowserCookie } from './auth';
|
||||
import { SkipConfig, DanmakuFilterConfig, EpisodeFilterConfig } from './types';
|
||||
import { DanmakuFilterConfig, EpisodeFilterConfig,SkipConfig } from './types';
|
||||
|
||||
// 全局错误触发函数
|
||||
function triggerGlobalError(message: string) {
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
import { AdminConfig } from './admin.types';
|
||||
import { KvrocksStorage } from './kvrocks.db';
|
||||
import { RedisStorage } from './redis.db';
|
||||
import { Favorite, IStorage, PlayRecord, SkipConfig, DanmakuFilterConfig } from './types';
|
||||
import { DanmakuFilterConfig,Favorite, IStorage, PlayRecord, SkipConfig } from './types';
|
||||
import { UpstashRedisStorage } from './upstash.db';
|
||||
|
||||
// storage type 常量: 'localstorage' | 'redis' | 'upstash',默认 'localstorage'
|
||||
@@ -224,8 +224,8 @@ export class DbManager {
|
||||
}
|
||||
|
||||
async getUserListV2(
|
||||
offset: number = 0,
|
||||
limit: number = 20,
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
ownerUsername?: string
|
||||
): Promise<{
|
||||
users: Array<{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import nodemailer from 'nodemailer';
|
||||
|
||||
import type { AdminConfig } from './admin.types';
|
||||
|
||||
export interface EmailOptions {
|
||||
|
||||
@@ -72,7 +72,7 @@ export function clearEmbyCache(): { cleared: number } {
|
||||
/**
|
||||
* 获取缓存的 Emby 媒体库列表
|
||||
*/
|
||||
export function getCachedEmbyViews(embyKey: string = 'default'): any | null {
|
||||
export function getCachedEmbyViews(embyKey = 'default'): any | null {
|
||||
const cacheKey = `${EMBY_VIEWS_CACHE_KEY}:${embyKey}`;
|
||||
const entry = EMBY_CACHE.get(cacheKey);
|
||||
if (!entry) return null;
|
||||
@@ -89,7 +89,7 @@ export function getCachedEmbyViews(embyKey: string = 'default'): any | null {
|
||||
/**
|
||||
* 设置缓存的 Emby 媒体库列表
|
||||
*/
|
||||
export function setCachedEmbyViews(embyKey: string = 'default', data: any): void {
|
||||
export function setCachedEmbyViews(embyKey = 'default', data: any): void {
|
||||
const now = Date.now();
|
||||
const cacheKey = `${EMBY_VIEWS_CACHE_KEY}:${embyKey}`;
|
||||
EMBY_CACHE.set(cacheKey, {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { EmbyClient } from './emby.client';
|
||||
import { getConfig } from './config';
|
||||
import { AdminConfig } from './admin.types';
|
||||
import { getConfig } from './config';
|
||||
import { EmbyClient } from './emby.client';
|
||||
|
||||
interface EmbySourceConfig {
|
||||
key: string;
|
||||
|
||||
+8
-12
@@ -165,19 +165,15 @@ export class EmbyClient {
|
||||
const url = `${this.serverUrl}/Users/Me`;
|
||||
const headers = this.getHeaders();
|
||||
|
||||
try {
|
||||
const response = await fetch(url, { headers });
|
||||
const response = await fetch(url, { headers });
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`获取当前用户信息失败 (${response.status}): ${errorText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`获取当前用户信息失败 (${response.status}): ${errorText}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
|
||||
async getUserViews(): Promise<EmbyView[]> {
|
||||
@@ -467,7 +463,7 @@ export class EmbyClient {
|
||||
}
|
||||
}
|
||||
|
||||
async getStreamUrl(itemId: string, direct: boolean = true, forceDirectUrl: boolean = false): Promise<string> {
|
||||
async getStreamUrl(itemId: string, direct = true, forceDirectUrl = false): Promise<string> {
|
||||
const token = this.apiKey || this.authToken;
|
||||
|
||||
// 如果启用了代理播放且不是强制获取直接URL,返回代理URL
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { BaseRedisStorage, createRedisClient, createRetryWrapper } from './redis-base.db';
|
||||
import { StandardRedisAdapter } from './redis-adapter';
|
||||
import { BaseRedisStorage, createRedisClient, createRetryWrapper } from './redis-base.db';
|
||||
|
||||
export class KvrocksStorage extends BaseRedisStorage {
|
||||
constructor() {
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
* 基于 M3U8Download 项目改造为 TypeScript 版本
|
||||
*/
|
||||
|
||||
import { AESDecryptor } from './aes-decryptor';
|
||||
// @ts-ignore - mux.js 没有类型定义
|
||||
import * as muxjs from 'mux.js';
|
||||
|
||||
import { AESDecryptor } from './aes-decryptor';
|
||||
|
||||
export interface M3U8DownloadTask {
|
||||
id: string;
|
||||
url: string;
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as https from 'https';
|
||||
import * as http from 'http';
|
||||
import * as zlib from 'zlib';
|
||||
import * as https from 'https';
|
||||
import * as path from 'path';
|
||||
import { URL } from 'url';
|
||||
import * as zlib from 'zlib';
|
||||
|
||||
export interface OfflineDownloadTask {
|
||||
id: string;
|
||||
@@ -467,12 +467,16 @@ export class OfflineDownloader {
|
||||
});
|
||||
|
||||
fileStream.on('error', (err) => {
|
||||
fs.unlink(savePath, () => {});
|
||||
fs.unlink(savePath, () => {
|
||||
// Ignore unlink errors
|
||||
});
|
||||
reject(err);
|
||||
});
|
||||
|
||||
stream.on('error', (err) => {
|
||||
fs.unlink(savePath, () => {});
|
||||
fs.unlink(savePath, () => {
|
||||
// Ignore unlink errors
|
||||
});
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any, no-console */
|
||||
|
||||
import parseTorrentName from 'parse-torrent-name';
|
||||
|
||||
import type { AdminConfig } from '@/lib/admin.types';
|
||||
import { getConfig } from '@/lib/config';
|
||||
import { generateFolderKey } from '@/lib/crypto';
|
||||
import { db } from '@/lib/db';
|
||||
import { OpenListClient } from '@/lib/openlist.client';
|
||||
import {
|
||||
getCachedMetaInfo,
|
||||
invalidateMetaInfoCache,
|
||||
MetaInfo,
|
||||
setCachedMetaInfo,
|
||||
@@ -18,9 +20,7 @@ import {
|
||||
updateScanTaskProgress,
|
||||
} from '@/lib/scan-task';
|
||||
import { parseSeasonFromTitle } from '@/lib/season-parser';
|
||||
import { searchTMDB, getTVSeasonDetails } from '@/lib/tmdb.search';
|
||||
import parseTorrentName from 'parse-torrent-name';
|
||||
import type { AdminConfig } from '@/lib/admin.types';
|
||||
import { getTVSeasonDetails,searchTMDB } from '@/lib/tmdb.search';
|
||||
|
||||
/**
|
||||
* 获取根目录列表(兼容新旧配置)
|
||||
@@ -58,7 +58,7 @@ async function migrateToMultiRoot(openListConfig: NonNullable<AdminConfig['OpenL
|
||||
const metaInfo: MetaInfo = JSON.parse(metainfoContent);
|
||||
|
||||
// 2. 迁移 folderName:加上原根路径前缀
|
||||
for (const [key, info] of Object.entries(metaInfo.folders)) {
|
||||
for (const [_key, info] of Object.entries(metaInfo.folders)) {
|
||||
const oldFolderName = info.folderName;
|
||||
const newFolderName = `${oldRootPath}${oldRootPath.endsWith('/') ? '' : '/'}${oldFolderName}`;
|
||||
info.folderName = newFolderName;
|
||||
@@ -83,7 +83,7 @@ async function migrateToMultiRoot(openListConfig: NonNullable<AdminConfig['OpenL
|
||||
/**
|
||||
* 启动 OpenList 刷新任务
|
||||
*/
|
||||
export async function startOpenListRefresh(clearMetaInfo: boolean = false): Promise<{ taskId: string }> {
|
||||
export async function startOpenListRefresh(clearMetaInfo = false): Promise<{ taskId: string }> {
|
||||
const config = await getConfig();
|
||||
const openListConfig = config.OpenListConfig;
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ export interface OpenListGetResponse {
|
||||
}
|
||||
|
||||
export class OpenListClient {
|
||||
private token: string = '';
|
||||
private token = '';
|
||||
|
||||
constructor(
|
||||
private baseURL: string,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { RedisClientType } from 'redis';
|
||||
import { Redis } from '@upstash/redis';
|
||||
import { RedisClientType } from 'redis';
|
||||
|
||||
/**
|
||||
* 统一的 Redis 适配器接口
|
||||
|
||||
@@ -796,8 +796,8 @@ export abstract class BaseRedisStorage implements IStorage {
|
||||
|
||||
// 获取用户列表(分页,新版本)
|
||||
async getUserListV2(
|
||||
offset: number = 0,
|
||||
limit: number = 20,
|
||||
offset = 0,
|
||||
limit = 20,
|
||||
ownerUsername?: string
|
||||
): Promise<{
|
||||
users: Array<{
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { BaseRedisStorage, createRedisClient, createRetryWrapper } from './redis-base.db';
|
||||
import { StandardRedisAdapter } from './redis-adapter';
|
||||
import { BaseRedisStorage, createRedisClient, createRetryWrapper } from './redis-base.db';
|
||||
|
||||
export class RedisStorage extends BaseRedisStorage {
|
||||
constructor() {
|
||||
|
||||
@@ -85,8 +85,8 @@ interface TMDBTVAiringTodayResponse {
|
||||
*/
|
||||
export async function getTMDBUpcomingMovies(
|
||||
apiKey: string,
|
||||
page: number = 1,
|
||||
region: string = 'CN',
|
||||
page = 1,
|
||||
region = 'CN',
|
||||
proxy?: string,
|
||||
reverseProxyBaseUrl?: string
|
||||
): Promise<{ code: number; list: TMDBMovie[] }> {
|
||||
@@ -140,7 +140,7 @@ export async function getTMDBUpcomingMovies(
|
||||
*/
|
||||
export async function getTMDBUpcomingTVShows(
|
||||
apiKey: string,
|
||||
page: number = 1,
|
||||
page = 1,
|
||||
proxy?: string,
|
||||
reverseProxyBaseUrl?: string
|
||||
): Promise<{ code: number; list: TMDBTVShow[] }> {
|
||||
@@ -400,7 +400,7 @@ export async function getTMDBTrendingContent(
|
||||
*/
|
||||
export function getTMDBImageUrl(
|
||||
path: string | null,
|
||||
size: string = 'w500'
|
||||
size = 'w500'
|
||||
): string {
|
||||
if (!path) return '';
|
||||
const baseUrl = typeof window !== 'undefined'
|
||||
@@ -450,7 +450,7 @@ export const TMDB_GENRES: Record<number, string> = {
|
||||
* @param limit - 最多返回几个类型,默认2个
|
||||
* @returns 类型名称数组
|
||||
*/
|
||||
export function getGenreNames(genreIds: number[] = [], limit: number = 2): string[] {
|
||||
export function getGenreNames(genreIds: number[] = [], limit = 2): string[] {
|
||||
return genreIds
|
||||
.map(id => TMDB_GENRES[id])
|
||||
.filter(Boolean)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||
import nodeFetch from 'node-fetch';
|
||||
|
||||
import { getNextApiKey } from './tmdb.client';
|
||||
|
||||
// TMDB API 默认 Base URL(不包含 /3/,由程序拼接)
|
||||
@@ -226,7 +227,7 @@ export async function getTVSeasonDetails(
|
||||
*/
|
||||
export function getTMDBImageUrl(
|
||||
path: string | null,
|
||||
size: string = 'w500'
|
||||
size = 'w500'
|
||||
): string {
|
||||
if (!path) return '';
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import { Redis } from '@upstash/redis';
|
||||
|
||||
import { BaseRedisStorage } from './redis-base.db';
|
||||
import { UpstashRedisAdapter } from './redis-adapter';
|
||||
import { BaseRedisStorage } from './redis-base.db';
|
||||
|
||||
// 添加Upstash Redis操作重试包装器
|
||||
async function withRetry<T>(
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any,no-console */
|
||||
import bs58 from 'bs58';
|
||||
import he from 'he';
|
||||
import Hls from 'hls.js';
|
||||
import bs58 from 'bs58';
|
||||
|
||||
function getDoubanImageProxyConfig(): {
|
||||
proxyType:
|
||||
@@ -155,7 +155,7 @@ export function processVideoUrl(originalUrl: string): string {
|
||||
*/
|
||||
export async function getVideoResolutionFromM3u8(
|
||||
m3u8Url: string,
|
||||
timeoutMs: number = 4000
|
||||
timeoutMs = 4000
|
||||
): Promise<{
|
||||
quality: string; // 如720p、1080p等
|
||||
loadSpeed: string; // 自动转换为KB/s或MB/s
|
||||
|
||||
@@ -34,13 +34,13 @@ export function parseVideoFileName(fileName: string): ParsedVideoInfo {
|
||||
// S01E01, s01e01, S01E1234, S01E01.5 (支持1-4位数字和小数) - 最具体
|
||||
{ pattern: /[Ss](\d+)[Ee](\d{1,4}(?:\.\d+)?)/, extractSeason: true },
|
||||
// [01], (01), [01.5], (01.5) (支持小数,但要排除中文括号内容) - 很具体
|
||||
{ pattern: /[\[\(](\d+(?:\.\d+)?)[\]\)]/ },
|
||||
{ pattern: /[[(](\d+(?:\.\d+)?)[)\]]/ },
|
||||
// E01, E1, e01, e1, E01.5 (支持小数)
|
||||
{ pattern: /[Ee](\d+(?:\.\d+)?)/ },
|
||||
// 第01集, 第1集, 第01话, 第1话, 第1.5集 (支持小数)
|
||||
{ pattern: /第(\d+(?:\.\d+)?)[集话]/ },
|
||||
// _01_, -01-, _01.5_, -01.5- (支持小数)
|
||||
{ pattern: /[_\-](\d+(?:\.\d+)?)[_\-]/ },
|
||||
{ pattern: /[_-](\d+(?:\.\d+)?)[_-]/ },
|
||||
// 01.mp4, 001.mp4, 01.5.mp4 (纯数字开头,支持小数) - 最不具体
|
||||
{ pattern: /^(\d+(?:\.\d+)?)[^\d.]/ },
|
||||
];
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
// Socket.IO 观影室服务器逻辑(共享代码)
|
||||
import { Server as SocketIOServer, Socket } from 'socket.io';
|
||||
|
||||
import type {
|
||||
Room,
|
||||
Member,
|
||||
PlayState,
|
||||
LiveState,
|
||||
ChatMessage,
|
||||
ServerToClientEvents,
|
||||
ClientToServerEvents,
|
||||
Member,
|
||||
Room,
|
||||
RoomMemberInfo,
|
||||
ServerToClientEvents,
|
||||
} from '@/types/watch-room';
|
||||
|
||||
type TypedSocket = Socket<ClientToServerEvents, ServerToClientEvents>;
|
||||
|
||||
@@ -153,7 +153,7 @@ class WatchRoomSocketManager {
|
||||
});
|
||||
|
||||
// 监听心跳响应
|
||||
this.socket.on('heartbeat:pong', (data: { timestamp: number }) => {
|
||||
this.socket.on('heartbeat:pong', (_data: { timestamp: number }) => {
|
||||
this.lastHeartbeatResponse = Date.now();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { XiaoyaClient } from './xiaoya.client';
|
||||
import { parseNFO, NFOMetadata } from './nfo-parser';
|
||||
import { NFOMetadata,parseNFO } from './nfo-parser';
|
||||
import { parseVideoFileName } from './video-parser';
|
||||
import { XiaoyaClient } from './xiaoya.client';
|
||||
|
||||
export interface XiaoyaMetadata {
|
||||
tmdbId?: number;
|
||||
@@ -208,7 +208,7 @@ export async function getXiaoyaMetadata(
|
||||
const fileName = pathParts[pathParts.length - 1];
|
||||
const searchQuery = fileName
|
||||
.replace(/\.(mp4|mkv|avi|m3u8|flv|ts)$/i, '')
|
||||
.replace(/[\[\]()]/g, ' ')
|
||||
.replace(/[[\]()]/g, ' ')
|
||||
.trim();
|
||||
|
||||
// 如果文件名是纯数字(可能带小数点)或者是 SxxExx 格式,跳过文件名搜索,直接使用文件夹名
|
||||
@@ -240,7 +240,7 @@ export async function getXiaoyaMetadata(
|
||||
// 优先级 4: 实时搜索 TMDb(使用文件夹名)
|
||||
if (tmdbApiKey) {
|
||||
const searchQuery = folderName
|
||||
.replace(/[\[\](){}]/g, ' ')
|
||||
.replace(/[[\](){}]/g, ' ')
|
||||
.replace(/\d{4}/g, '')
|
||||
.trim();
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export interface XiaoyaListResponse {
|
||||
}
|
||||
|
||||
export class XiaoyaClient {
|
||||
private token: string = '';
|
||||
private token = '';
|
||||
|
||||
constructor(
|
||||
private baseURL: string,
|
||||
|
||||
Reference in New Issue
Block a user