mirror of
https://github.com/sakaljurgis/kodi-api-server.git
synced 2026-07-08 20:37:41 +00:00
add ability to download to multiple locations, based which one has more space
This commit is contained in:
+12
-10
@@ -1,21 +1,23 @@
|
||||
PORT=3000
|
||||
|
||||
#needed only for docker-compose to map your filesystem, for docker run use "/srv/data/static" volume path mapping
|
||||
STATIC_SERVE_FOLDER='/mnt/hdd/videos'
|
||||
#needed only for docker-compose to map your filesystem, for docker run use "/srv/data/requests-log" volume path mapping
|
||||
LOG_FILE_REQUESTS_FOLDER='/mnt/hdd/videos'
|
||||
LOG_FILE_REQUESTS_NAME="static_log.txt"
|
||||
|
||||
#needed only for docker-compose to map your filesystem, for docker run use "/srv/data/db" volume path mapping
|
||||
DB_FOLDER='/mnt/hdd/videos/db'
|
||||
DB_FILENAME="db.db"
|
||||
|
||||
#needed only for docker-compose to map your filesystem, for docker run use "/srv/data/recent-searches" volume path mapping
|
||||
RECENT_SEARCHES_FOLDER="/mnt/hdd/videos/recent-searches"
|
||||
|
||||
#actual env variables starts here
|
||||
PORT=3000
|
||||
LOG_FILE_REQUESTS_NAME="static_log.txt"
|
||||
DB_FILENAME="db.db"
|
||||
RECENT_SEARCHES_LIMIT=20
|
||||
PATTERNS_TO_IGNORE='["AOE1/"]' #file path patterns to ignore from video files scan, must be in json format
|
||||
|
||||
#can be VIDEO_FILES_FOLDER_1, VIDEO_FILES_FOLDER_2, etc., but must be edited in docker-compose.yml as well
|
||||
#also map to same folders in your transmission file system
|
||||
VIDEO_FILES_FOLDER='/mnt/hdd/videos' #also torrent download dir
|
||||
|
||||
VIDEO_FILES_EXT='[".mkv", ".mp4", ".avi"]'
|
||||
|
||||
PATTERNS_TO_IGNORE='["AOE1/"]' #file path patterns to ignore from video files scan
|
||||
|
||||
LINKOMANIJA_USERNAME=user
|
||||
LINKOMANIJA_PASSWORD=passw
|
||||
LINKOMANIJA_PASSKEY=123pass456key789
|
||||
|
||||
@@ -10,6 +10,7 @@ import { FileEntity } from '../../../Shared/Entity/file.entity';
|
||||
import { StreamProviderEnum } from '../../../Shared/Enum/stream-provider.enum';
|
||||
import { VideoFilesFacade } from '../../../VideoFiles/video-files.facade';
|
||||
import { TorrentSeedClient } from '../../SeedClient/torrent-seed.client';
|
||||
import process, { exec } from 'child_process';
|
||||
|
||||
@Injectable()
|
||||
export class WebtorrentClient {
|
||||
@@ -42,9 +43,13 @@ export class WebtorrentClient {
|
||||
this.resumeNotStopped();
|
||||
}
|
||||
|
||||
getNewTorrentOptions(): TorrentOptions {
|
||||
async getNewTorrentOptions(): Promise<TorrentOptions> {
|
||||
const torrentOptions: Record<string, any> = {};
|
||||
torrentOptions.path = this.configService.getTorrentDownloadDir();
|
||||
//todo - risk! - torrent might be already downloaded on another folder
|
||||
torrentOptions.path = await this.findPathWithMostSpace(
|
||||
this.configService.getTorrentDownloadDirs(),
|
||||
);
|
||||
// torrentOptions.path = this.configService.getTorrentDownloadDir();
|
||||
torrentOptions.getAnnounceOpts = function () {
|
||||
const that = this as Torrent;
|
||||
|
||||
@@ -136,11 +141,9 @@ export class WebtorrentClient {
|
||||
}
|
||||
|
||||
if (!torrent) {
|
||||
const torrentOptions = await this.getNewTorrentOptions();
|
||||
return new Promise((resolve, reject) => {
|
||||
const torrent = this.client.add(
|
||||
torrentEntity.magnet,
|
||||
this.getNewTorrentOptions(),
|
||||
);
|
||||
const torrent = this.client.add(torrentEntity.magnet, torrentOptions);
|
||||
|
||||
torrent.on('ready', () => {
|
||||
resolve(torrent);
|
||||
@@ -312,4 +315,52 @@ export class WebtorrentClient {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async findPathWithMostSpace(paths: string[]): Promise<string> {
|
||||
const promises: Promise<{ path: string; free: number }>[] = [];
|
||||
for (const path of paths) {
|
||||
promises.push(this.getFreeSpace(path));
|
||||
}
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
let maxSpace = 0;
|
||||
let maxSpacePath = '';
|
||||
for (const result of results) {
|
||||
console.log(`testing path ${result.path} with ${result.free}KB`);
|
||||
if (result.free > maxSpace) {
|
||||
maxSpace = result.free;
|
||||
maxSpacePath = result.path;
|
||||
}
|
||||
}
|
||||
|
||||
return maxSpacePath;
|
||||
}
|
||||
|
||||
private getFreeSpace(path: string): Promise<{ path: string; free: number }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
exec(`df ${path}`, (err, data) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
const rows = data.split('\n');
|
||||
const fsData = rows[1].replace(/\s+/g, ' ').trim().split(' ');
|
||||
const [
|
||||
filesystem,
|
||||
sizeInKB,
|
||||
usedKB,
|
||||
availableKB,
|
||||
usePercentage,
|
||||
mountPoint,
|
||||
] = fsData;
|
||||
|
||||
const availableKbNum = Number(availableKB);
|
||||
|
||||
if (isNaN(availableKbNum)) {
|
||||
return reject(`availableKB not a number: ${availableKB}`);
|
||||
}
|
||||
|
||||
resolve({ path, free: availableKbNum });
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,19 +6,26 @@ export class VideoFilesConfig {
|
||||
}
|
||||
|
||||
public getVideoFilesFolders(): string[] {
|
||||
return [this.configService.getEnv('VIDEO_FILES_FOLDER')];
|
||||
const folders: string[] = [];
|
||||
Object.keys(process.env).forEach((key) => {
|
||||
if (key.startsWith('VIDEO_FILES_FOLDER') && process.env[key]) {
|
||||
folders.push(process.env[key]);
|
||||
}
|
||||
});
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
||||
public getVideoFilesExt(): string[] {
|
||||
return JSON.parse(this.configService.getEnv('VIDEO_FILES_EXT'));
|
||||
return ['.mkv', '.mp4', '.avi'];
|
||||
}
|
||||
|
||||
public getPathPatternsToIgnore(): string[] {
|
||||
return JSON.parse(this.configService.getEnv('PATTERNS_TO_IGNORE'));
|
||||
}
|
||||
|
||||
public getTorrentDownloadDir(): string {
|
||||
return this.configService.getEnv('VIDEO_FILES_FOLDER');
|
||||
public getTorrentDownloadDirs(): string[] {
|
||||
return this.getVideoFilesFolders();
|
||||
}
|
||||
|
||||
public getTransmissionOptions() {
|
||||
|
||||
Reference in New Issue
Block a user