initial dockerizing
This commit is contained in:
+2
-1
@@ -1,2 +1,3 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
/.idea
|
/.idea
|
||||||
|
**/*.sqlite
|
||||||
+1
-12
@@ -1,26 +1,15 @@
|
|||||||
# Base image
|
|
||||||
FROM node:18
|
FROM node:18
|
||||||
|
|
||||||
# Create app directory
|
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
# A wildcard is used to ensure both package.json AND package-lock.json are copied
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
# Install app dependencies
|
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
# Bundle app source
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Copy the .env and .env.development files
|
RUN npm run build
|
||||||
#COPY .env .env.development ./
|
|
||||||
|
|
||||||
# Creates a "dist" folder with the production build
|
|
||||||
RUN npm run build:be
|
|
||||||
|
|
||||||
# Expose the port on which the app will run
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
# Start the server using the production build
|
|
||||||
CMD ["npm", "run", "start"]
|
CMD ["npm", "run", "start"]
|
||||||
Generated
+57
-3
@@ -4299,6 +4299,21 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@nestjs/config": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-vGICPOui5vE6kPz1iwQ7oCnp3qWgqxldPmBQ9onkVoKlBtyc83KJCr7CjuVtf4OdovMAVcux1d8Q6jglU2ZphA==",
|
||||||
|
"dependencies": {
|
||||||
|
"dotenv": "16.4.5",
|
||||||
|
"dotenv-expand": "10.0.0",
|
||||||
|
"lodash": "4.17.21",
|
||||||
|
"uuid": "9.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0",
|
||||||
|
"rxjs": "^7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nestjs/core": {
|
"node_modules/@nestjs/core": {
|
||||||
"version": "10.3.9",
|
"version": "10.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.9.tgz",
|
||||||
@@ -4509,6 +4524,37 @@
|
|||||||
"url": "https://github.com/sponsors/jonschlinkert"
|
"url": "https://github.com/sponsors/jonschlinkert"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nestjs/serve-static": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nestjs/serve-static/-/serve-static-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-cT0vdWN5ar7jDI2NKbhf4LcwJzU4vS5sVpMkVrHuyLcltbrz6JdGi1TfIMMatP2pNiq5Ie/uUdPSFDVaZX/URQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"path-to-regexp": "0.2.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@fastify/static": "^6.5.0 || ^7.0.0",
|
||||||
|
"@nestjs/common": "^9.0.0 || ^10.0.0",
|
||||||
|
"@nestjs/core": "^9.0.0 || ^10.0.0",
|
||||||
|
"express": "^4.18.1",
|
||||||
|
"fastify": "^4.7.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@fastify/static": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"express": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"fastify": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nestjs/serve-static/node_modules/path-to-regexp": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.2.5.tgz",
|
||||||
|
"integrity": "sha512-l6qtdDPIkmAmzEO6egquYDfqQGPMRNGjYtrU13HAXb3YSRrt7HSb1sJY0pKp6o2bAa86tSB6iwaW2JbthPKr7Q=="
|
||||||
|
},
|
||||||
"node_modules/@nestjs/testing": {
|
"node_modules/@nestjs/testing": {
|
||||||
"version": "10.3.9",
|
"version": "10.3.9",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.3.9.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.3.9.tgz",
|
||||||
@@ -8538,7 +8584,6 @@
|
|||||||
"version": "16.4.5",
|
"version": "16.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
|
||||||
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
|
"integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -8546,6 +8591,14 @@
|
|||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv-expand": {
|
||||||
|
"version": "10.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz",
|
||||||
|
"integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/eastasianwidth": {
|
"node_modules/eastasianwidth": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
@@ -12418,8 +12471,7 @@
|
|||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.debounce": {
|
"node_modules/lodash.debounce": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
@@ -18852,9 +18904,11 @@
|
|||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
|
"@nestjs/config": "^3.2.2",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
"@nestjs/schedule": "^4.0.2",
|
"@nestjs/schedule": "^4.0.2",
|
||||||
|
"@nestjs/serve-static": "^4.0.2",
|
||||||
"@nestjs/typeorm": "^10.0.2",
|
"@nestjs/typeorm": "^10.0.2",
|
||||||
"@types/yt-search": "^2.10.3",
|
"@types/yt-search": "^2.10.3",
|
||||||
"isomorphic-unfetch": "^4.0.2",
|
"isomorphic-unfetch": "^4.0.2",
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
"start:be": "npm run start:dev -w spooty-be",
|
"start:be": "npm run start:dev -w spooty-be",
|
||||||
"start:fe": "npm run start -w spooty-fe",
|
"start:fe": "npm run start -w spooty-fe",
|
||||||
"build:be": "npm run build -w spooty-be",
|
"build:be": "npm run build -w spooty-be",
|
||||||
|
"build:fe": "npm run build -w spooty-fe",
|
||||||
|
"build": "npm run build:be npm run build:fe",
|
||||||
"start": "npm run start:prod -w spooty-be"
|
"start": "npm run start:prod -w spooty-be"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,9 +21,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
|
"@nestjs/config": "^3.2.2",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
"@nestjs/schedule": "^4.0.2",
|
"@nestjs/schedule": "^4.0.2",
|
||||||
|
"@nestjs/serve-static": "^4.0.2",
|
||||||
"@nestjs/typeorm": "^10.0.2",
|
"@nestjs/typeorm": "^10.0.2",
|
||||||
"@types/yt-search": "^2.10.3",
|
"@types/yt-search": "^2.10.3",
|
||||||
"isomorphic-unfetch": "^4.0.2",
|
"isomorphic-unfetch": "^4.0.2",
|
||||||
|
|||||||
@@ -1,20 +1,36 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { ScheduleModule } from '@nestjs/schedule';
|
import { ScheduleModule } from '@nestjs/schedule';
|
||||||
|
import { ServeStaticModule } from '@nestjs/serve-static';
|
||||||
|
import {ConfigModule, ConfigService} from "@nestjs/config";
|
||||||
import {TypeOrmModule} from '@nestjs/typeorm';
|
import {TypeOrmModule} from '@nestjs/typeorm';
|
||||||
import {TrackEntity} from "./track/track.entity";
|
import {TrackEntity} from "./track/track.entity";
|
||||||
import {TrackModule} from "./track/track.module";
|
import {TrackModule} from "./track/track.module";
|
||||||
import {PlaylistModule} from "./playlist/playlist.module";
|
import {PlaylistModule} from "./playlist/playlist.module";
|
||||||
import {PlaylistEntity} from "./playlist/playlist.entity";
|
import {PlaylistEntity} from "./playlist/playlist.entity";
|
||||||
|
import { resolve } from 'path';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
ConfigModule.forRoot(),
|
||||||
ScheduleModule.forRoot(),
|
ScheduleModule.forRoot(),
|
||||||
TypeOrmModule.forRoot({
|
TypeOrmModule.forRootAsync({
|
||||||
type: 'sqlite',
|
imports:[ConfigModule],
|
||||||
database: 'test.sqlite',
|
useFactory: async (configService: ConfigService) => ({
|
||||||
entities: [TrackEntity, PlaylistEntity],
|
type: 'sqlite',
|
||||||
synchronize: true,
|
database: configService.get<string>('DB'),
|
||||||
|
entities: [TrackEntity, PlaylistEntity],
|
||||||
|
synchronize: true,
|
||||||
|
}),
|
||||||
|
inject: [ConfigService]
|
||||||
|
}),
|
||||||
|
ServeStaticModule.forRootAsync({
|
||||||
|
imports:[ConfigModule],
|
||||||
|
useFactory: async (configService: ConfigService) => ([{
|
||||||
|
rootPath: resolve(__dirname, configService.get<string>('FE')),
|
||||||
|
exclude: ['/api/(.*)'],
|
||||||
|
}]),
|
||||||
|
inject: [ConfigService]
|
||||||
}),
|
}),
|
||||||
TrackModule,
|
TrackModule,
|
||||||
PlaylistModule,
|
PlaylistModule,
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import { NestFactory } from '@nestjs/core';
|
import { NestFactory } from '@nestjs/core';
|
||||||
import { AppModule } from './app.module';
|
import { AppModule } from './app.module';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { resolve } from 'path';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
|
app.setGlobalPrefix('api');
|
||||||
await app.listen(3000);
|
await app.listen(3000);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
const folderName = resolve(__dirname, process.env.DOWNLOADS);
|
||||||
|
!fs.existsSync(folderName) && fs.mkdirSync(folderName);
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ import {TrackService} from "./track.service";
|
|||||||
import {TrackModel} from "./track.model";
|
import {TrackModel} from "./track.model";
|
||||||
import {TrackEntity} from "./track.entity";
|
import {TrackEntity} from "./track.entity";
|
||||||
import {createReadStream} from "fs";
|
import {createReadStream} from "fs";
|
||||||
import { join } from 'path';
|
import { resolve } from 'path';
|
||||||
import type { Response } from 'express';
|
import type { Response } from 'express';
|
||||||
|
import {ConfigService} from "@nestjs/config";
|
||||||
|
|
||||||
@Controller('track')
|
@Controller('track')
|
||||||
export class TrackController {
|
export class TrackController {
|
||||||
|
|
||||||
constructor(private readonly service: TrackService) {
|
constructor(private readonly service: TrackService,
|
||||||
|
private readonly configService: ConfigService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@@ -40,7 +42,7 @@ export class TrackController {
|
|||||||
@Get('download/:id')
|
@Get('download/:id')
|
||||||
async getFile(@Res({ passthrough: true }) res: Response, @Param('id') id: number): Promise<StreamableFile> {
|
async getFile(@Res({ passthrough: true }) res: Response, @Param('id') id: number): Promise<StreamableFile> {
|
||||||
const track = await this.service.findOne(id);
|
const track = await this.service.findOne(id);
|
||||||
const file = createReadStream(join(process.cwd(), 'downloads', `${track.artist} - ${track.song}.mp3`));
|
const file = createReadStream(resolve(__dirname, '..', this.configService.get<string>('DOWNLOADS'), `${track.artist} - ${track.song}.mp3`));
|
||||||
res.set({'Content-Disposition': `attachment; filename="${track.artist} - ${track.song}.mp3"`,});
|
res.set({'Content-Disposition': `attachment; filename="${track.artist} - ${track.song}.mp3"`,});
|
||||||
return new StreamableFile(file);
|
return new StreamableFile(file);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,13 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
|||||||
import {TrackEntity} from "./track.entity";
|
import {TrackEntity} from "./track.entity";
|
||||||
import {TrackService} from "./track.service";
|
import {TrackService} from "./track.service";
|
||||||
import {TrackController} from "./track.controller";
|
import {TrackController} from "./track.controller";
|
||||||
|
import {ConfigModule} from "@nestjs/config";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TypeOrmModule.forFeature([TrackEntity])],
|
imports: [
|
||||||
|
TypeOrmModule.forFeature([TrackEntity]),
|
||||||
|
ConfigModule,
|
||||||
|
],
|
||||||
providers: [TrackService],
|
providers: [TrackService],
|
||||||
controllers: [TrackController],
|
controllers: [TrackController],
|
||||||
exports: [TrackService],
|
exports: [TrackService],
|
||||||
|
|||||||
@@ -8,12 +8,15 @@ import {TrackStatusEnum} from "./track.model";
|
|||||||
import * as yts from 'yt-search';
|
import * as yts from 'yt-search';
|
||||||
import * as ytdl from 'ytdl-core';
|
import * as ytdl from 'ytdl-core';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
import {ConfigService} from "@nestjs/config";
|
||||||
|
import {resolve} from "path";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TrackService {
|
export class TrackService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(TrackEntity)
|
@InjectRepository(TrackEntity)
|
||||||
private repository: Repository<TrackEntity>,
|
private repository: Repository<TrackEntity>,
|
||||||
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(criteria?: Partial<TrackEntity>): Promise<TrackEntity[]> {
|
findAll(criteria?: Partial<TrackEntity>): Promise<TrackEntity[]> {
|
||||||
@@ -50,7 +53,12 @@ export class TrackService {
|
|||||||
const queuedTracks = await this.findAll({status: TrackStatusEnum.Queued});
|
const queuedTracks = await this.findAll({status: TrackStatusEnum.Queued});
|
||||||
queuedTracks.forEach(async track => {
|
queuedTracks.forEach(async track => {
|
||||||
await ytdl(track.youtubeUrl, {quality: "highestaudio", filter: "audioonly"}).pipe(
|
await ytdl(track.youtubeUrl, {quality: "highestaudio", filter: "audioonly"}).pipe(
|
||||||
fs.createWriteStream(`downloads/${track.artist} - ${track.song.replace('/', '')}.mp3`)
|
fs.createWriteStream(resolve(
|
||||||
|
__dirname,
|
||||||
|
'..',
|
||||||
|
this.configService.get<string>('DOWNLOADS'),
|
||||||
|
`${track.artist} - ${track.song.replace('/', '')}.mp3`,
|
||||||
|
))
|
||||||
);
|
);
|
||||||
await this.update(track.id, {...track, status: TrackStatusEnum.Completed})
|
await this.update(track.id, {...track, status: TrackStatusEnum.Completed})
|
||||||
});
|
});
|
||||||
|
|||||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"/api/**": {
|
"/api/**": {
|
||||||
"target": "http://localhost:3000",
|
"target": "http://localhost:3000/api",
|
||||||
"secure": false,
|
"secure": false,
|
||||||
"changeOrigin": true,
|
"changeOrigin": true,
|
||||||
"pathRewrite": {
|
"pathRewrite": {
|
||||||
|
|||||||
Reference in New Issue
Block a user