diff --git a/dashboard/src/app/app-routing.module.ts b/dashboard/src/app/app-routing.module.ts index 6b31b0e..6db11d8 100644 --- a/dashboard/src/app/app-routing.module.ts +++ b/dashboard/src/app/app-routing.module.ts @@ -7,6 +7,7 @@ import { ArtistComponent } from './artist/artist.component'; import { GenreComponent } from './genre/genre.component'; import { TopPlayedComponent } from './top-played/top-played.component'; import { AlbumsComponent } from './albums/albums.component'; +import { ToSortComponent } from './to-sort/to-sort.component'; const routes: Routes = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full' }, @@ -15,7 +16,8 @@ const routes: Routes = [ { path: 'album', component: AlbumsComponent }, { path: 'artist/:name', component: ArtistComponent }, { path: 'genre/:name', component: GenreComponent }, - { path: 'top-played', component: TopPlayedComponent } + { path: 'top-played', component: TopPlayedComponent }, + { path: 'to-sort', component: ToSortComponent } ]; @NgModule({ diff --git a/dashboard/src/app/app.component.html b/dashboard/src/app/app.component.html index 2005326..7e8db6e 100644 --- a/dashboard/src/app/app.component.html +++ b/dashboard/src/app/app.component.html @@ -1,5 +1,8 @@ diff --git a/dashboard/src/app/app.module.ts b/dashboard/src/app/app.module.ts index 1f15372..1d6767d 100644 --- a/dashboard/src/app/app.module.ts +++ b/dashboard/src/app/app.module.ts @@ -21,6 +21,7 @@ import { SortByPipe } from './pipes/sort-by.pipe'; import { ConvertSizeToStringPipe } from './pipes/convert-size-to-string.pipe'; import { RoundPipe } from './pipes/round.pipe'; import { AlbumsComponent } from './albums/albums.component'; +import { ToSortComponent } from './to-sort/to-sort.component'; @NgModule({ imports: [ @@ -41,7 +42,8 @@ import { AlbumsComponent } from './albums/albums.component'; SortByPipe, ConvertSizeToStringPipe, TopPlayedComponent, - RoundPipe + RoundPipe, + ToSortComponent ], providers: [ ElsService, diff --git a/dashboard/src/app/els-sort.service.spec.ts b/dashboard/src/app/els-sort.service.spec.ts new file mode 100644 index 0000000..67a3185 --- /dev/null +++ b/dashboard/src/app/els-sort.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ElsSortService } from './els-sort.service'; + +describe('ElsSortService', () => { + let service: ElsSortService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ElsSortService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/dashboard/src/app/els-sort.service.ts b/dashboard/src/app/els-sort.service.ts new file mode 100644 index 0000000..a0990a3 --- /dev/null +++ b/dashboard/src/app/els-sort.service.ts @@ -0,0 +1,147 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map, catchError } from 'rxjs/operators'; +import { ElsService } from './els.service'; +import { Album } from './model/album'; +import { Bucket } from './model/bucket'; +import { Song } from './model/song'; + +@Injectable({ + providedIn: 'root' +}) +export class ElsSortService extends ElsService { + + constructor(protected http: HttpClient) { + super(http); + } + + getTime(): Promise { + return this.http + .post(this.elsUrl + ElsService.SONG_INDEX_NAME + ElsService.ACTION_SEARCH, + JSON.stringify({ + query: { + bool: { + must_not: [ + { + term: { + "Location.tree": "/F:/Musique" + } + } + ] + } + }, + aggs: { + sum_time: { + sum: { field: 'Total Time'} + } + }, + 'size': 0 + }), {headers: this.headers}) + .toPromise() + .then(res => res.aggregations.sum_time.value as number) + .catch(error => this.handleError(error, 'getTime()')); + } + + getSize(): Promise { + return this.http + .post(this.elsUrl + ElsService.SONG_INDEX_NAME + ElsService.ACTION_SEARCH, + JSON.stringify({ + query: { + bool: { + must_not: [ + { + term: { + "Location.tree": "/F:/Musique" + } + } + ] + } + }, + aggs: { + sum_time: { + sum: { field: 'Size' } + } + }, + 'size': 0 + }), {headers: this.headers}) + .toPromise() + .then(res => res.aggregations.sum_time.value as number) + .catch(error => this.handleError(error, 'getSize()')); + } + + getCountSong(): Promise { + return this.http + .post(this.elsUrl + ElsService.SONG_INDEX_NAME + ElsService.ACTION_COUNT, + JSON.stringify({ + query: { + bool: { + must_not: [ + { + term: { + "Location.tree": "/F:/Musique" + } + } + ] + } + } + }), {headers: this.headers}) + .toPromise() + .then(res => res.count as number) + .catch(error => this.handleError(error, 'getCountSong()')); + } + + getCountNeverListenSong(): Promise { + return this.http + .post(this.elsUrl + ElsService.SONG_INDEX_NAME + ElsService.ACTION_COUNT, + JSON.stringify({ + 'query': { + 'bool': { + 'must_not': [ + { + 'exists': { 'field': 'Play Count'} + }, { + term: { + "Location.tree": "/F:/Musique" + } } + ] + } + } + }), {headers: this.headers}) + .toPromise() + .then(res => res.count as number) + .catch(error => this.handleError(error, 'getCountNeverListenSong()')); + } + + getAlbums(): Observable { + return this.http + .post(this.elsUrl + ElsService.SONG_INDEX_NAME + ElsService.ACTION_SEARCH, + JSON.stringify({ + query: { + bool: { + must_not: [ + { + term: { + "Location.tree": "/F:/Musique" + } + } + ] + } + }, + 'size': 0, + 'aggs': { + 'albums' : { + 'terms': { + 'field' : 'Album.raw', + 'order': { '_term': 'asc' }, + 'size': 50 + } + } + } + }), {headers: this.headers}) + .pipe( + map(res => this.responseAggregationToBucket(res, "albums")), + catchError(error => this.handleError(error, 'getAlbums')) + ); + } +} diff --git a/dashboard/src/app/els.service.ts b/dashboard/src/app/els.service.ts index d130861..b84c19d 100644 --- a/dashboard/src/app/els.service.ts +++ b/dashboard/src/app/els.service.ts @@ -337,7 +337,7 @@ export class ElsService { // TODO Take in consideration "sum_other_doc_count" } - getArtistFromAlbumName(albumname: string): Observable { + getArtistFromAlbumName(albumname: string): Observable { // TODO Rename ? return this.http .post(this.elsUrl + ElsService.ALBUM_INDEX_NAME + ElsService.ACTION_SEARCH, JSON.stringify({ @@ -406,7 +406,7 @@ export class ElsService { * * @param res Response to process */ - private responseToSongs(res: any): Song[] { + protected responseToSongs(res: any): Song[] { const result: Array = []; res.hits.hits.forEach((hit) => { result.push(hit._source); @@ -444,7 +444,7 @@ export class ElsService { * @param res Response to process * @param name Name of aggregation */ - private responseAggregationToBucket(res: any, name: string): Bucket[] { + protected responseAggregationToBucket(res: any, name: string): Bucket[] { const result: Array = []; res.aggregations[name].buckets.forEach((bucket) => { result.push(bucket); diff --git a/dashboard/src/app/to-sort/to-sort.component.css b/dashboard/src/app/to-sort/to-sort.component.css new file mode 100644 index 0000000..af4b796 --- /dev/null +++ b/dashboard/src/app/to-sort/to-sort.component.css @@ -0,0 +1,38 @@ +.panel-stat { + min-height: 102px; +} + +.panel-green { +background-color: #16a085; +color:white; +} +.panel-yellow { +background-color: #f1c40f; +color:white; +} + +.panel-red { +background-color: #d9534f; +color:white; +} + +.panel-purple { +background-color: #9b59b6; +color:white; +} + +.panel-blue { +background-color: #3498db; +color:white; +} + +.stats_icon { +font-size: 3em; +} + +.circle { +border-radius: 50%; +background-color: #9b59b6; +margin: 0 auto; + +} diff --git a/dashboard/src/app/to-sort/to-sort.component.html b/dashboard/src/app/to-sort/to-sort.component.html new file mode 100644 index 0000000..c5621d1 --- /dev/null +++ b/dashboard/src/app/to-sort/to-sort.component.html @@ -0,0 +1,130 @@ +
+

To sort Songs -

+ +
+
+
+
+
+
+
+ +
+
+
+

+

{{totalTime | convertMs}}

+
+

Total time ({{totalTime | convertMoreExact}})
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+

{{totalSize | convertSizeToString}}

+
+

Total size
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+

{{trackCountSong}}

+
+

Total Songs
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+

+

{{neverListenSong}}

+
+

Never list. songs (~{{neverListenSong / trackCountSong * 100 | round}}%)
+
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AlbumTrack CountArtist/Album ArtistPlay CountRating
+ {{album.key}}  + {{albums[album.key]['Track Count']}} + {{albums[album.key]['Album Artist']}}  + + {{albums[album.key].Artist}}  + + {{albums[album.key].Artist}}  + + {{albums[album.key]['Play Count']}} ({{albums[album.key]['Play Count']/albums[album.key]['Track Count'] | number:'1.0-0'}}/songs) + + + + +
+
+
diff --git a/dashboard/src/app/to-sort/to-sort.component.spec.ts b/dashboard/src/app/to-sort/to-sort.component.spec.ts new file mode 100644 index 0000000..75fcefc --- /dev/null +++ b/dashboard/src/app/to-sort/to-sort.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ToSortComponent } from './to-sort.component'; + +describe('ToSortComponent', () => { + let component: ToSortComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ToSortComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ToSortComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/dashboard/src/app/to-sort/to-sort.component.ts b/dashboard/src/app/to-sort/to-sort.component.ts new file mode 100644 index 0000000..4e224dc --- /dev/null +++ b/dashboard/src/app/to-sort/to-sort.component.ts @@ -0,0 +1,89 @@ +import { Component, OnInit } from '@angular/core'; +import { ElsSortService } from '../els-sort.service'; +import { Album } from '../model/album'; +import { Bucket } from '../model/bucket'; +import { Song } from '../model/song'; + +import { Utils } from '../utils'; + +@Component({ + selector: 'app-to-sort', + templateUrl: './to-sort.component.html', + styleUrls: ['./to-sort.component.css'] +}) +export class ToSortComponent implements OnInit { + numberToArray = Utils.numberToArray; + // Stats var + totalTime = 0; + totalSize = 0; + trackCountSong = 0; + neverListenSong = 0; + + // Global var + toSortAlbum: Bucket[] = []; + albums = [] + + constructor(private elsService: ElsSortService) { } + + ngOnInit(): void { + // **** GET STATS ****// + this.elsService.getTime().then(result => this.totalTime = result); + this.elsService.getSize().then(result => this.totalSize = result); + this.elsService.getCountSong().then(result => this.trackCountSong = result); + this.elsService.getCountNeverListenSong().then(result => this.neverListenSong = result); + + // **** GET ALBUMS ****// + const tmpToSortAlbums: Bucket[] = []; + this.elsService.getAlbums().subscribe(buckets => { + buckets.forEach(bucket => { + if (tmpToSortAlbums.length === 0) { + tmpToSortAlbums.push(bucket); + } else { + let found = false; + tmpToSortAlbums.forEach(element => { + if (element.key === bucket.key) { + element.doc_count += bucket.doc_count; + found = true; + } + }); + if (!found) { + tmpToSortAlbums.push(bucket); + } + } + }); + + this.toSortAlbum = tmpToSortAlbums; + this.toSortAlbum.forEach(bucket => this.getAlbum(bucket)); + // console.log(this.toSortAlbum) + // console.log(this.albums) + }); + } + + private getAlbum(albumBucket: Bucket) { + // For each bucket.key (album name), get Album document + // Use track count to compare + this.elsService.getArtistFromAlbumName(albumBucket.key).subscribe(albums => { + // Identification of the good album + let goodAlbum; + if (albums.length > 1) { + // More than one result for an album name: search good by track count + albums.forEach(album => { + if (album['Track Count'] === albumBucket.doc_count) { + goodAlbum = album; + } + }); + } else { + // Just one result for album name + goodAlbum = albums[0]; + } + + // TODO Crap security if no good album found + if (goodAlbum == undefined) { + goodAlbum = albums[0] + } + + this.albums[albumBucket.key] = goodAlbum; + }); + } + +}