266 lines
6.6 KiB
TypeScript
266 lines
6.6 KiB
TypeScript
import { createClient, WebDAVClient, FileStat } from 'webdav';
|
|
import { createReadStream, createWriteStream, statSync } from 'fs';
|
|
import { Readable } from 'stream';
|
|
import { configOperations } from '../db/database';
|
|
|
|
let webdavClient: WebDAVClient | null = null;
|
|
|
|
export interface WebDAVConfig {
|
|
url: string;
|
|
username: string;
|
|
password: string;
|
|
path: string;
|
|
}
|
|
|
|
/**
|
|
* Get WebDAV configuration from database
|
|
*/
|
|
function getWebDAVConfig(): WebDAVConfig | null {
|
|
const config = configOperations.getAll();
|
|
|
|
if (config.webdavEnabled !== 'true') {
|
|
return null;
|
|
}
|
|
|
|
if (!config.webdavUrl || !config.webdavUsername || !config.webdavPassword) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
url: config.webdavUrl,
|
|
username: config.webdavUsername,
|
|
password: config.webdavPassword,
|
|
path: config.webdavPath || '/vidrip/'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create authenticated WebDAV client from config
|
|
*/
|
|
export function createWebDAVClient(config?: WebDAVConfig): WebDAVClient | null {
|
|
const webdavConfig = config || getWebDAVConfig();
|
|
|
|
if (!webdavConfig) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return createClient(webdavConfig.url, {
|
|
username: webdavConfig.username,
|
|
password: webdavConfig.password
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to create WebDAV client:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test WebDAV connection and permissions
|
|
*/
|
|
export async function testConnection(config: WebDAVConfig): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const client = createWebDAVClient(config);
|
|
|
|
if (!client) {
|
|
return { success: false, message: 'Failed to create WebDAV client' };
|
|
}
|
|
|
|
// Ensure path ends with /
|
|
const basePath = config.path.endsWith('/') ? config.path : `${config.path}/`;
|
|
|
|
// Test connection by checking if base path exists
|
|
const exists = await client.exists(basePath);
|
|
|
|
if (!exists) {
|
|
// Try to create the directory
|
|
try {
|
|
await client.createDirectory(basePath, { recursive: true });
|
|
return { success: true, message: 'Connected successfully and created directory' };
|
|
} catch (createError) {
|
|
return { success: false, message: `Directory doesn't exist and cannot be created: ${createError}` };
|
|
}
|
|
}
|
|
|
|
// Try to get directory contents to verify read permissions
|
|
await client.getDirectoryContents(basePath);
|
|
|
|
return { success: true, message: 'Connected successfully' };
|
|
} catch (error) {
|
|
console.error('WebDAV connection test failed:', error);
|
|
return {
|
|
success: false,
|
|
message: error instanceof Error ? error.message : 'Connection failed'
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get full WebDAV path for a video
|
|
*/
|
|
function getVideoPath(videoId: string): string {
|
|
const config = getWebDAVConfig();
|
|
if (!config) {
|
|
throw new Error('WebDAV not configured');
|
|
}
|
|
|
|
const basePath = config.path.endsWith('/') ? config.path : `${config.path}/`;
|
|
return `${basePath}${videoId}.mp4`;
|
|
}
|
|
|
|
/**
|
|
* Upload video file to WebDAV
|
|
*/
|
|
export async function uploadVideo(localPath: string, videoId: string): Promise<void> {
|
|
const config = getWebDAVConfig();
|
|
|
|
if (!config) {
|
|
throw new Error('WebDAV not configured');
|
|
}
|
|
|
|
const client = createWebDAVClient(config);
|
|
|
|
if (!client) {
|
|
throw new Error('Failed to create WebDAV client');
|
|
}
|
|
|
|
try {
|
|
const remotePath = getVideoPath(videoId);
|
|
const basePath = config.path.endsWith('/') ? config.path : `${config.path}/`;
|
|
|
|
// Ensure directory exists
|
|
const dirExists = await client.exists(basePath);
|
|
if (!dirExists) {
|
|
await client.createDirectory(basePath, { recursive: true });
|
|
}
|
|
|
|
// Upload file
|
|
const fileStream = createReadStream(localPath);
|
|
await client.putFileContents(remotePath, fileStream, {
|
|
overwrite: true
|
|
});
|
|
|
|
console.log(`Successfully uploaded ${videoId}.mp4 to WebDAV`);
|
|
} catch (error) {
|
|
console.error('Failed to upload to WebDAV:', error);
|
|
throw new Error(`WebDAV upload failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete video from WebDAV server
|
|
*/
|
|
export async function deleteVideo(videoId: string): Promise<void> {
|
|
const config = getWebDAVConfig();
|
|
|
|
if (!config) {
|
|
// If WebDAV not configured, silently return (nothing to delete)
|
|
return;
|
|
}
|
|
|
|
const client = createWebDAVClient(config);
|
|
|
|
if (!client) {
|
|
throw new Error('Failed to create WebDAV client');
|
|
}
|
|
|
|
try {
|
|
const remotePath = getVideoPath(videoId);
|
|
|
|
const exists = await client.exists(remotePath);
|
|
if (exists) {
|
|
await client.deleteFile(remotePath);
|
|
console.log(`Successfully deleted ${videoId}.mp4 from WebDAV`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to delete from WebDAV:', error);
|
|
throw new Error(`WebDAV delete failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get readable stream from WebDAV for proxying
|
|
*/
|
|
export async function streamVideo(videoId: string): Promise<Readable> {
|
|
const config = getWebDAVConfig();
|
|
|
|
if (!config) {
|
|
throw new Error('WebDAV not configured');
|
|
}
|
|
|
|
const client = createWebDAVClient(config);
|
|
|
|
if (!client) {
|
|
throw new Error('Failed to create WebDAV client');
|
|
}
|
|
|
|
try {
|
|
const remotePath = getVideoPath(videoId);
|
|
|
|
const stream = client.createReadStream(remotePath);
|
|
return stream as Readable;
|
|
} catch (error) {
|
|
console.error('Failed to stream from WebDAV:', error);
|
|
throw new Error(`WebDAV stream failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if video exists on WebDAV
|
|
*/
|
|
export async function getVideoExists(videoId: string): Promise<boolean> {
|
|
const config = getWebDAVConfig();
|
|
|
|
if (!config) {
|
|
return false;
|
|
}
|
|
|
|
const client = createWebDAVClient(config);
|
|
|
|
if (!client) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
const remotePath = getVideoPath(videoId);
|
|
return await client.exists(remotePath);
|
|
} catch (error) {
|
|
console.error('Failed to check video existence on WebDAV:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get video file stats from WebDAV
|
|
*/
|
|
export async function getVideoStats(videoId: string): Promise<FileStat | null> {
|
|
const config = getWebDAVConfig();
|
|
|
|
if (!config) {
|
|
return null;
|
|
}
|
|
|
|
const client = createWebDAVClient(config);
|
|
|
|
if (!client) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const remotePath = getVideoPath(videoId);
|
|
const stat = await client.stat(remotePath) as FileStat;
|
|
return stat;
|
|
} catch (error) {
|
|
console.error('Failed to get video stats from WebDAV:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if WebDAV is enabled and configured
|
|
*/
|
|
export function isWebDAVEnabled(): boolean {
|
|
const config = getWebDAVConfig();
|
|
return config !== null;
|
|
}
|