Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .development.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Config database
DB_HOST=localhost
DB_PORT=5433
DB_HOST=postgres
DB_PORT=5432
POSTGRES_DB=spotify
POSTGRES_USER=admin
POSTGRES_PASSWORD=admin123
3 changes: 3 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
./db/seeds/seeder
35 changes: 35 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM node:20.5-alpine3.17

# Set the working directory to /app
WORKDIR /Spotify

ENV ENV_NODE="development"

COPY . .

RUN chmod +x run_commands.sh

# Install the app's dependencies
RUN npm install

# Install Python 3.11 and create a virtual environment
RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
RUN python3 -m ensurepip
RUN pip3 install --no-cache --upgrade pip setuptools

RUN python3 -m venv venv

RUN apk add postgresql-dev gcc python3-dev musl-dev

# Activate the virtual environment and install the requirements
RUN . venv/bin/activate && \
python3 -m pip install -r requirements.txt

# Expose port 3000 for the app to listen on
EXPOSE 3000

# Start the app with npm run start
CMD ["npm", "run", "start:dev"]



4 changes: 2 additions & 2 deletions db/seeds/seeder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

# Conecta a la base de datos PostgreSQL
conn = psycopg2.connect(
host="localhost",
port=5433,
host="172.29.0.2",
port=5432,
database="spotify",
user="admin",
password="admin123"
Expand Down
13 changes: 11 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ version: '3.8'
services:
postgres:
image: postgres:16.0
container_name: spotify_dev
container_name: spotify
restart: always
env_file:
- .development.env
volumes:
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- 5433:5432
- 5432:5432
api:
build: .
ports:
- 3000:3000
volumes:
- ./csv_files:/Spotify/csv_files
depends_on:
- postgres

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "export NODE_ENV=development && npm start",
"start:dev": "nest start --watch",
"start:dev": "export NODE_ENV=development && nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
psycopg2-binary==2.9.9
psycopg2==2.9.9
16 changes: 8 additions & 8 deletions src/api/api.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class ApiController {
res.status(200).json({
"position": 1,
"title": "Loudness vs. Danceability",
"type": "Scatter",
"type": "scatter",
"datasets":[await this.apiService.scatterDanceabilityLoudness(artist, top, date)],
"xlabel": "Danceability",
"ylabel": "Loudness"
Expand All @@ -33,8 +33,8 @@ export class ApiController {
res.status(200).json({
"position": 2,
"title": "Album Type Distribution",
"type": "Pie",
"data": await this.apiService.getAlbumTypeDistribution(artist, top, date),
"type": "pie",
"datasets": await this.apiService.getAlbumTypeDistribution(artist, top, date),
"xlabel": "album type",
"ylabel": "count"
});
Expand All @@ -49,8 +49,8 @@ export class ApiController {
res.status(200).json({
"position": 3,
"title": "Artist by Track Number",
"type": "Bar",
"dataset": await this.apiService.totalTracksByArtistName(artist, top, date),
"type": "bar",
"datasets": await this.apiService.totalTracksByArtistName(artist, top, date),
"xlabel": "Artist",
"ylabel": "total tracks"
});
Expand All @@ -65,8 +65,8 @@ export class ApiController {
res.status(200).json({
"position": 4,
"title": "Number of Tracks Over Time",
"type": "Line",
"dataset": await this.apiService.numberOfTracksOverTime(artist, top, date),
"type": "line",
"datasets": await this.apiService.numberOfTracksOverTime(artist, top, date),
"xlabel": "Year",
"ylabel": "Count"
});
Expand All @@ -81,7 +81,7 @@ export class ApiController {
res.status(200).json({
"position": 5,
"title": "Instrumentalness vs Energy",
"type": "Scatter",
"type": "scatter",
"datasets":[await this.apiService.scatterInstrumentalnessEnergy(artist, top, date)],
"xlabel": "Instrumentalness",
"ylabel": "Energy"
Expand Down
56 changes: 27 additions & 29 deletions src/api/api.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,10 @@ export class ApiService {

if (date) {

const year = parseInt(date);

if (artist) query.andWhere('EXTRACT(YEAR FROM TO_DATE(release.release_date, \'YYYY-MM-DD\')) = :year', { year });
else query.where('EXTRACT(YEAR FROM TO_DATE(release.release_date, \'YYYY-MM-DD\')) = :year', { year });
const [startDate, endDate] = date.split('-');

if (artist) query.andWhere("TO_DATE(release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });
else query.where("TO_DATE(release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });

}
const danceabilityLoudness = await query.getRawMany();
Expand Down Expand Up @@ -78,10 +77,11 @@ export class ApiService {
}

if (date) {
const year = parseInt(date);

if (artist) query.andWhere('EXTRACT(YEAR FROM TO_DATE(sp_release.release_date, \'YYYY-MM-DD\')) = :year', { year });
else query.where('EXTRACT(YEAR FROM TO_DATE(release.release_date, \'YYYY-MM-DD\')) = :year', { year });
const [startDate, endDate] = date.split('-');

if (artist) query.andWhere("TO_DATE(sp_release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });
else query.where("TO_DATE(sp_release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });

}

Expand All @@ -91,14 +91,12 @@ export class ApiService {

const albumTypeDistribution = await query.getRawMany();

console.log(albumTypeDistribution);

const xList = albumTypeDistribution.map(item => item.album_type);
const yList = albumTypeDistribution.map(item => item.count);

return {
x: xList,
y: { y: yList, description: "percentage of album type" }
y: [ {y: yList, description: "percentage of album type"} ]
};
}

Expand All @@ -124,10 +122,10 @@ export class ApiService {

if (date) {

const year = parseInt(date);
const [startDate, endDate] = date.split('-');

if (artist) query.andWhere('EXTRACT(YEAR FROM TO_DATE(sp_release.release_date, \'YYYY-MM-DD\')) = :year', { year });
else query.where('EXTRACT(YEAR FROM TO_DATE(sp_release.release_date, \'YYYY-MM-DD\')) = :year', { year });
if (artist) query.andWhere("TO_DATE(sp_release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });
else query.where("TO_DATE(sp_release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });
}

const totalTracksByArtist = await query.getRawMany();
Expand All @@ -137,32 +135,33 @@ export class ApiService {

return {
x: xList,
y: {y: yList, "description": "total tracks of the artist"}
y: [ {y: yList, "description": "total tracks of the artist"} ]
};
}

async numberOfTracksOverTime(artist?: string, top?: number, date?: string) {

console.log(artist, top, date);

let query = this.spotifyTrackEntity
.createQueryBuilder('sp_track')
.select('sp_track.updated_on, COUNT(sp_track.track_id) as count')
.select('sp_release.release_date, COUNT(sp_track.track_id) as count')
.innerJoin('sp_release', 'sp_release', 'sp_release.release_id = sp_track.release_id')
.groupBy('sp_track.updated_on');
.groupBy('sp_release.release_date');

if (artist) {
query = query.innerJoin('sp_artist_track', 'artist', 'artist.track_id = sp_track.track_id')
.innerJoin('sp_artist', 'sp_artist', 'sp_artist.artist_id = artist.artist_id')
.where('sp_artist.artist_name = :artist', { artist });
}


if (date) {
const year = parseInt(date);
const [startYear, endYear] = date.split('-');

if (artist) query.andWhere('EXTRACT(YEAR FROM TO_DATE(sp_release.release_date, \'YYYY-MM-DD\')) = :year', { year });
else query.where('EXTRACT(YEAR FROM TO_DATE(release.release_date, \'YYYY-MM-DD\')) = :year', { year });
if (artist) {
query.andWhere("EXTRACT(YEAR FROM TO_DATE(sp_release.release_date, 'YYYY-MM-DD')) BETWEEN :startYear AND :endYear", { startYear, endYear });
} else {
query.andWhere("EXTRACT(YEAR FROM TO_DATE(sp_release.release_date, 'YYYY-MM-DD')) BETWEEN :startYear AND :endYear", { startYear, endYear });
}
}

if (top) {
Expand All @@ -171,12 +170,12 @@ export class ApiService {

const tracksOverTime = await query.getRawMany();

const xList = tracksOverTime.map(item => item.updated_on);
const xList = tracksOverTime.map(item => item.release_date);
const yList = tracksOverTime.map(item => item.count);

return {
x: xList,
y: { y: yList, description: "tracks over time" }
y: [ {y: yList, description: "tracks over time" } ]
};
}

Expand All @@ -202,10 +201,10 @@ export class ApiService {

if (date) {

const year = parseInt(date);
const [startDate, endDate] = date.split('-');

if (artist) query.andWhere('EXTRACT(YEAR FROM TO_DATE(release.release_date, \'YYYY-MM-DD\')) = :year', { year });
else query.where('EXTRACT(YEAR FROM TO_DATE(release.release_date, \'YYYY-MM-DD\')) = :year', { year });
if (artist) query.andWhere("TO_DATE(release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });
else query.where("TO_DATE(release.release_date, 'YYYY-MM-DD') BETWEEN TO_DATE(:startDate, 'YYYY-MM-DD') AND TO_DATE(:endDate, 'YYYY-MM-DD')", { startDate, endDate });


}
Expand Down Expand Up @@ -235,11 +234,10 @@ export class ApiService {
.getRawMany();

const xList = top10ArtistsByTrackNumber.map(item => item.artist_name);
const yList = top10ArtistsByTrackNumber.map(item => item.total);
//const yList = top10ArtistsByTrackNumber.map(item => item.total);

return {
x: xList,
y: {y: yList, "description": "top 100 artists by track number"}
x: xList
};
}

Expand Down
5 changes: 0 additions & 5 deletions src/data-retriever/data-retriever.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ export class DataRetrieverController {

constructor(private readonly dataRetrieverService: DataRetrieverService) {}

@Get()
async retrieveData() {
return this.dataRetrieverService.seederInit();
}

@Get('data')
async retrieveData2() {
return this.dataRetrieverService.retrieveData();
Expand Down
4 changes: 2 additions & 2 deletions src/data-retriever/data-retriever.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export class DataRetrieverService {
//return this.audioRepository.find({ select: {acousticness: true} })
//return this.spotifyArtistReleaseRepository.find({ select: {artistId: true} })
//return this.spotifyReleaseRepository.find({ select: {releaseId: true, albumType: true, labelName: true} })
//return this.spotifyArtistEntityRepository.find({ select: {artistId: true} })
return this.spotifyArtistEntityRepository.find({ select: {artistId: true, artistName: true, id: true, updatedOn: true} })
//return this.spotifyArtistTrackEntityRepository.find({ select: {artistId: true} })
//return this.spotifyTrackEntityRepository.find({ select: {trackId: true} })
//return this.spotifyTrackEntityRepository.find({ select: {trackId: true, discNumber: true, durationMs: true, explicit: true, id: true, isrc: true, previewUrl: true} })
}

async seederInit() {
Expand Down
11 changes: 10 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ import { AppModule } from './app.module';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000, '0.0.0.0');

app.enableCors({

origin: true,
methods: 'GET, PUT, PATCH, POST, DELETE, OPTIONS',
credentials: true

})

await app.listen(3000);

console.log(`Application running on: ${await app.getUrl()}`)
}
Expand Down