Skip to content

Commit

Permalink
feat: refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
k.mesniankin committed Sep 29, 2024
1 parent 866c5db commit 29cd6f8
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 59 deletions.
100 changes: 56 additions & 44 deletions src/middlewares/torrents.ts → src/composers/TorrentsComposer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,37 @@ import { type Message } from 'grammy/types';

import { type QBTorrent } from '../qBittorrent/models.js';
import { type QBittorrentClient } from '../qBittorrent/QBittorrentClient.js';
import { type Engine, type SearchResult } from '../searchEngines/Engine.js';
import {
type SearchEngine,
type SearchResult,
} from '../searchEngines/SearchEngine.js';
import { formatBytes } from '../utils/formatBytes.js';
import { formatDuration } from '../utils/formatDuration.js';
import { type Logger } from '../utils/Logger.js';

export interface TorrentParams {
export interface TorrentComposerOptions {
bot: Bot;
engines: Engine[];
searchEngines: SearchEngine[];
qBittorrent: QBittorrentClient;
logger: Logger;
}

export class Torrents<C extends Context> extends Composer<C> {
export class TorrentsComposer<C extends Context> extends Composer<C> {
private bot: Bot;
private engines: Engine[];
private searchEngines: SearchEngine[];
private qBittorrent: QBittorrentClient;
private chatMessages = new Map<number, Message>();
private chatTorrents = new Map<number, string[]>();
private timeout: NodeJS.Timeout;
private logger: Logger;

constructor(params: TorrentParams) {
constructor(options: TorrentComposerOptions) {
super();

this.bot = params.bot;
this.engines = params.engines;
this.qBittorrent = params.qBittorrent;
this.logger = params.logger;
this.bot = options.bot;
this.searchEngines = options.searchEngines;
this.qBittorrent = options.qBittorrent;
this.logger = options.logger;

this.timeout = setInterval(() => {
this.createOrUpdateCardMessages();
Expand Down Expand Up @@ -76,8 +79,10 @@ export class Torrents<C extends Context> extends Composer<C> {

const text = results
.slice(0, 5)
.map(([engine, result]) => this.formatSearchResult(engine, result))
.join('\n\n');
.map(([searchEngines, result]) =>
this.formatSearchResult(searchEngines, result),
)
.join('\n\n\n');

return ctx.reply(text, {
parse_mode: 'HTML',
Expand All @@ -92,19 +97,21 @@ export class Torrents<C extends Context> extends Composer<C> {
}
const tag = ctx.message.text.replace('/dl_', '');
const tagParts = tag.split('_');
const engineName = tagParts[0];
const searchEngineName = tagParts[0];
const torrentId = tagParts[1];

const engine = this.engines.find((engine) => engine.name === engineName);
const searchEngine = this.searchEngines.find(
(searchEngine) => searchEngine.name === searchEngineName,
);

if (!engine) {
if (!searchEngine) {
return ctx.reply('Трекер не поддерживается');
}

let torrent: string | undefined;

try {
torrent = await engine.downloadTorrentFile(torrentId);
torrent = await searchEngine.downloadTorrentFile(torrentId);
} catch {
return ctx.reply('При добавлении торрента произошла ошибка');
}
Expand Down Expand Up @@ -156,9 +163,9 @@ export class Torrents<C extends Context> extends Composer<C> {

private async searchTorrents(query: string) {
try {
const promises = this.engines.map(async (engine) => {
const results = await engine.search(query);
return results.map((result) => [engine, result] as const);
const promises = this.searchEngines.map(async (searchEngine) => {
const results = await searchEngine.search(query);
return results.map((result) => [searchEngine, result] as const);
});

const results = await Promise.all(promises);
Expand Down Expand Up @@ -325,7 +332,7 @@ export class Torrents<C extends Context> extends Composer<C> {

const cardText = pending
.map((torrent) => this.formatTorrent(torrent))
.join('\n\n');
.join('\n\n\n');

await (message
? this.updateCardMessage(message, cardText)
Expand All @@ -338,55 +345,60 @@ export class Torrents<C extends Context> extends Composer<C> {
}
}

private formatSearchResult(engine: Engine, result: SearchResult) {
const lines = [`<b>${result.title}</b>`];

lines.push('---');

if (result.date) {
lines.push(`Дата: ${result.date.toLocaleDateString('ru')}`);
}
private formatSearchResult(searchEngine: SearchEngine, result: SearchResult) {
const lines = [`<b>${result.title}</b>`, '---'];
const info: string[] = [];

if (result.totalSize) {
lines.push(`Размер: ${formatBytes(result.totalSize)}`);
info.push(formatBytes(result.totalSize));
}

if (
typeof result.seeds === 'number' ||
typeof result.leeches === 'number'
) {
lines.push(`Сиды/Пиры: ${result.seeds ?? 0} / ${result.leeches ?? 0}`);
const seeds = `${result.seeds ?? 0}`;
const peers = `${result.leeches ?? 0}`;
info.push(`${seeds}/${peers}`);
}

if (result.date) {
info.push(result.date.toLocaleDateString('ru'));
}

const tag = `${engine.name}_${result.id}`;
lines.push(info.join(' | '), '---');

const tag = `${searchEngine.name}_${result.id}`;
lines.push(`Скачать: /dl_${tag}`);
lines.push('');

return lines.join('\n');
}

private formatTorrent(torrent: QBTorrent) {
const lines = [`<b>${torrent.name}</b>`];

const eta = torrent.eta >= 8_640_000 ? '∞' : formatDuration(torrent.eta);
const lines = [`<b>${torrent.name}</b>`, '---'];

if (torrent.progress < 1) {
const seeds = `${torrent.num_seeds} (${torrent.num_complete})`;
const peers = `${torrent.num_leechs} (${torrent.num_incomplete})`;
const eta = torrent.eta >= 8_640_000 ? '∞' : formatDuration(torrent.eta);
const progress = `${Math.round(torrent.progress * 100 * 100) / 100}%`;

lines.push(`Сиды: ${seeds}, Личи: ${peers}`);
lines.push(`Скорость: ${formatBytes(torrent.dlspeed)}/s`);
lines.push(`Осталось: ${eta}`);
lines.push(`Прогресс: ${progress}`);
} else {
lines.push(`Статус: Загружен`);
}

lines.push('---');
lines.push(`Сиды: ${torrent.num_seeds} (${torrent.num_complete})`);
lines.push(`Пиры: ${torrent.num_leechs} (${torrent.num_incomplete})`);
lines.push(`Скорость: ${formatBytes(torrent.dlspeed)}/s`);
lines.push(`Осталось: ${eta}`);
lines.push(
`Прогресс: <code>${Math.round(torrent.progress * 100 * 100) / 100}%</code>`,
);

const [tag] = torrent.tags;

if (tag) {
lines.push(`Удалить: /rm_${tag}`);
}

lines.push('');

return lines.join('\n');
}
}
21 changes: 11 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import './dayjs.js';

import { Bot, GrammyError, HttpError } from 'grammy';

import { TorrentsComposer } from './composers/TorrentsComposer.js';
import {
botToken,
cookiesFilePath,
Expand All @@ -14,31 +15,31 @@ import {
rutrackerUsername,
} from './config.js';
import { logger } from './logger.js';
import { Torrents } from './middlewares/torrents.js';
import { QBittorrentClient } from './qBittorrent/QBittorrentClient.js';
import { RuTrackerEngine } from './searchEngines/RutrackerEngine.js';
import { RutrackerSearchEngine } from './searchEngines/RutrackerSearchEngine.js';
import { CookieStorage } from './utils/CookieStorage.js';

const bot = new Bot(botToken);
const cookieStorage = new CookieStorage({
filePath: cookiesFilePath,
logger,
});
const rutracker = new RuTrackerEngine({
username: rutrackerUsername,
password: rutrackerPassword,
cookieStorage,
logger,
});
const qBittorrent = new QBittorrentClient({
url: `http://${qbtWebuiHost}:${qbtWebuiPort}`,
username: qbtWebuiUsername,
password: qbtWebuiPassword,
savePath: qbtSavePath,
});
const torrents = new Torrents({
const torrents = new TorrentsComposer({
bot,
engines: [rutracker],
searchEngines: [
new RutrackerSearchEngine({
username: rutrackerUsername,
password: rutrackerPassword,
cookieStorage,
logger,
}),
],
qBittorrent,
logger,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ import * as cheerio from 'cheerio';

import { type CookieStorage } from '../utils/CookieStorage.js';
import { type Logger } from '../utils/Logger.js';
import { Engine, type SearchResult } from './Engine.js';
import { SearchEngine, type SearchResult } from './SearchEngine.js';

const BASE_URL = 'https://rutracker.org/forum';
const LOGIN_URL = `${BASE_URL}/login.php`;
const SEARCH_URL = `${BASE_URL}/tracker.php`;
const DOWNLOAD_URL = `${BASE_URL}/dl.php`;

export interface RuTrackerEngineOptions {
export interface RutrackerSearchEngineOptions {
username: string;
password: string;
cookieStorage: CookieStorage;
logger: Logger;
}

export class RuTrackerEngine extends Engine {
export class RutrackerSearchEngine extends SearchEngine {
public name = 'rutracker';
private username: string;
private password: string;
private cookieStorage: CookieStorage;
private logger: Logger;

constructor(options: RuTrackerEngineOptions) {
constructor(options: RutrackerSearchEngineOptions) {
super();

this.username = options.username;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface SearchResult {
downloadUrl: string;
}

export abstract class Engine {
export abstract class SearchEngine {
abstract name: string;
abstract search(query: string): Promise<SearchResult[]>;
abstract downloadTorrentFile(id: string): Promise<string>;
Expand Down

0 comments on commit 29cd6f8

Please sign in to comment.