diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..de4d1f0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1cbe53e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node + +COPY package.json package.json +COPY package-lock.json package-lock.json + +RUN npm install + +COPY . . + +RUN npm run build + +CMD [ "npm", "run", "start:prod" ] diff --git a/package-lock.json b/package-lock.json index c1a1392..f09c407 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@nestjs/bull": "^0.4.0", "@nestjs/common": "^7.6.15", + "@nestjs/config": "^1.0.0", "@nestjs/core": "^7.6.15", "@nestjs/platform-express": "^7.6.15", "bull": "^3.26.0", @@ -1608,6 +1609,24 @@ } } }, + "node_modules/@nestjs/config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-1.0.0.tgz", + "integrity": "sha512-Id5dQsCISMxWu0oPKcEP4ltQ5Z6eY748WHIXNOFc2Q9qehvHVk8iMRMmTIzTJ+eCOB6qKBAdhTI4KuRyRlwAuQ==", + "dependencies": { + "dotenv": "10.0.0", + "dotenv-expand": "5.1.0", + "lodash.get": "4.4.2", + "lodash.has": "4.5.2", + "lodash.set": "4.3.2", + "uuid": "8.3.2" + }, + "peerDependencies": { + "@nestjs/common": "^7.0.0 || ^8.0.0", + "reflect-metadata": "^0.1.13", + "rxjs": "^6.0.0 || ^7.2.0" + } + }, "node_modules/@nestjs/core": { "version": "7.6.18", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-7.6.18.tgz", @@ -4385,6 +4404,19 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -7794,12 +7826,27 @@ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "node_modules/lodash.has": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", + "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, "node_modules/lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", @@ -13575,6 +13622,19 @@ "uuid": "8.3.2" } }, + "@nestjs/config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-1.0.0.tgz", + "integrity": "sha512-Id5dQsCISMxWu0oPKcEP4ltQ5Z6eY748WHIXNOFc2Q9qehvHVk8iMRMmTIzTJ+eCOB6qKBAdhTI4KuRyRlwAuQ==", + "requires": { + "dotenv": "10.0.0", + "dotenv-expand": "5.1.0", + "lodash.get": "4.4.2", + "lodash.has": "4.5.2", + "lodash.set": "4.3.2", + "uuid": "8.3.2" + } + }, "@nestjs/core": { "version": "7.6.18", "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-7.6.18.tgz", @@ -15727,6 +15787,16 @@ } } }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -18297,12 +18367,27 @@ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.has": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", + "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" + }, "lodash.toarray": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", diff --git a/package.json b/package.json index a907b80..6b327ce 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "dependencies": { "@nestjs/bull": "^0.4.0", "@nestjs/common": "^7.6.15", + "@nestjs/config": "^1.0.0", "@nestjs/core": "^7.6.15", "@nestjs/platform-express": "^7.6.15", "bull": "^3.26.0", @@ -80,4 +81,4 @@ "coverageDirectory": "../coverage", "testEnvironment": "node" } -} \ No newline at end of file +} diff --git a/src/app.module.ts b/src/app.module.ts index e91c16e..5d3656e 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,17 +1,28 @@ import { BullModule } from '@nestjs/bull'; import { Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import configuration from './config/configuration'; import { WebModule } from './web/web.module'; import { YtdlModule } from './ytdl/ytdl.module'; @Module({ imports: [ - BullModule.forRoot({ - redis: { - host: 'localhost', - port: 6379, - }, - prefix: 'vgqueue', + ConfigModule.forRoot({ + ignoreEnvFile: true, + isGlobal: true, + load: [configuration], + }), + BullModule.forRootAsync({ + imports: [ConfigModule], + useFactory: (configService: ConfigService) => ({ + redis: { + host: configService.get('redisHost'), + port: configService.get('redisPort'), + }, + prefix: 'vgqueue', + }), + inject: [ConfigService], }), YtdlModule, WebModule, diff --git a/src/config/configuration.ts b/src/config/configuration.ts new file mode 100644 index 0000000..da0c2e8 --- /dev/null +++ b/src/config/configuration.ts @@ -0,0 +1,5 @@ +export default () => ({ + redisHost: process.env.REDIS_HOST || 'localhost', + redisPort: parseInt(process.env.REDIS_PORT, 10) || 6379, + fileDir: process.env.FILE_DIR || '/tmp', +}); diff --git a/src/web/web.controller.ts b/src/web/web.controller.ts index 3f578fa..2cad59c 100644 --- a/src/web/web.controller.ts +++ b/src/web/web.controller.ts @@ -57,7 +57,16 @@ export class WebController { .slice(0, 10), }; } - s; + + @Get('/extractors') + @Render('extractors') + async listExtractors() { + const extractors = await this.ytdlService.listExtractors(); + + return { + extractors, + }; + } @Post('/getinfo') @Render('getinfo') diff --git a/src/ytdl/ytdl.processor.ts b/src/ytdl/ytdl.processor.ts index f4fd389..57be6f1 100644 --- a/src/ytdl/ytdl.processor.ts +++ b/src/ytdl/ytdl.processor.ts @@ -8,6 +8,7 @@ import { Processor, } from '@nestjs/bull'; import { Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; import { Job } from 'bull'; import { throttle } from 'lodash'; import * as split from 'split2'; @@ -21,6 +22,8 @@ export class YtdlProcessor { job.progress(progress); }, 250); + constructor(private readonly configService: ConfigService) {} + @Process('download') async handleDownload(job: Job) { this.logger.debug('Start downloading...'); @@ -29,7 +32,9 @@ export class YtdlProcessor { try { const execaProcess = raw(job.data.url, { format: job.data.format, - output: '/tmp/%(title)s-%(format_id)s.%(ext)s', + output: `${this.configService.get( + 'fileDir', + )}/%(title)s-%(format_id)s.%(ext)s`, newline: true, }); diff --git a/src/ytdl/ytdl.service.ts b/src/ytdl/ytdl.service.ts index b44cb16..caaa1c0 100644 --- a/src/ytdl/ytdl.service.ts +++ b/src/ytdl/ytdl.service.ts @@ -15,4 +15,12 @@ export class YtdlService { youtubeSkipDashManifest: true, }); } + + async listExtractors() { + const extractors = (await ytdl('', { + listExtractors: true, + })) as unknown; + + return (extractors as string).split('\n'); + } } diff --git a/views/extractors.hbs b/views/extractors.hbs new file mode 100644 index 0000000..e137df0 --- /dev/null +++ b/views/extractors.hbs @@ -0,0 +1,13 @@ +
+
+
+

Here is the list of currently supported services. This is generated dynamically because youtube-dl adds new + services all the time.

+
    + {{#each extractors}} +
  • {{this}}
  • + {{/each}} +
+
+
+
\ No newline at end of file diff --git a/views/index.hbs b/views/index.hbs index b2728b1..0ef1847 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -4,6 +4,7 @@