From b86544b22af8c8504014eeac511c4ea0592d40bf Mon Sep 17 00:00:00 2001 From: grimsi <9295182+grimsi@users.noreply.github.com> Date: Sun, 24 Jul 2022 23:17:11 +0200 Subject: [PATCH] Added game file size --- .../gameyfin/entities/DetectedGame.java | 3 + .../de/grimsi/gameyfin/mapper/GameMapper.java | 23 ++++++++ .../gameyfin/service/DownloadService.java | 2 + frontend/src/app/app.module.ts | 58 ++++++++++--------- .../game-detail-view.component.html | 32 ++++++++-- .../game-detail-view.component.ts | 22 ++++++- .../src/app/models/dtos/DetectedGameDto.ts | 2 +- frontend/src/app/services/games.service.ts | 2 +- frontend/src/app/theme/default-theme.scss | 4 +- 9 files changed, 110 insertions(+), 38 deletions(-) diff --git a/backend/src/main/java/de/grimsi/gameyfin/entities/DetectedGame.java b/backend/src/main/java/de/grimsi/gameyfin/entities/DetectedGame.java index 0268660..5d27d91 100644 --- a/backend/src/main/java/de/grimsi/gameyfin/entities/DetectedGame.java +++ b/backend/src/main/java/de/grimsi/gameyfin/entities/DetectedGame.java @@ -80,6 +80,9 @@ public class DetectedGame { @Column(nullable = false) private String path; + @Column(nullable = false) + private long diskSize; + @Column(columnDefinition = "boolean default false") private boolean confirmedMatch; diff --git a/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java b/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java index 3a319bc..adbfd5c 100644 --- a/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java +++ b/backend/src/main/java/de/grimsi/gameyfin/mapper/GameMapper.java @@ -3,11 +3,21 @@ package de.grimsi.gameyfin.mapper; import com.igdb.proto.Igdb; import de.grimsi.gameyfin.dto.GameOverviewDto; import de.grimsi.gameyfin.entities.DetectedGame; +import de.grimsi.gameyfin.service.LibraryService; import de.grimsi.gameyfin.util.ProtobufUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.stream.Stream; +@Slf4j public class GameMapper { public static DetectedGame toDetectedGame(Igdb.Game g, Path path) { @@ -37,6 +47,7 @@ public class GameMapper { .themes(ThemeMapper.toThemes(g.getThemesList())) .playerPerspectives(PlayerPerspectiveMapper.toPlayerPerspectives(g.getPlayerPerspectivesList())) .path(path.toString()) + .diskSize(calculateDiskSize(path)) .build(); } @@ -63,4 +74,16 @@ public class GameMapper { private static int getMaxPlayers(List modes) { return modes.stream().mapToInt(Igdb.MultiplayerMode::getOnlinecoopmax).max().orElse(0); } + + private static long calculateDiskSize(Path path) { + try(Stream pathStream = Files.walk(path)) { + return pathStream + .filter(p -> p.toFile().isFile()) + .mapToLong(p -> p.toFile().length()) + .sum(); + } catch (IOException e) { + log.error("Unable to calculate size for path '{}'.", path); + return -1; + } + } } diff --git a/backend/src/main/java/de/grimsi/gameyfin/service/DownloadService.java b/backend/src/main/java/de/grimsi/gameyfin/service/DownloadService.java index 490e97e..0998693 100644 --- a/backend/src/main/java/de/grimsi/gameyfin/service/DownloadService.java +++ b/backend/src/main/java/de/grimsi/gameyfin/service/DownloadService.java @@ -13,6 +13,7 @@ import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.data.repository.core.RepositoryCreationException; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; @@ -157,6 +158,7 @@ public class DownloadService { Files.copy(path, outputStream); } catch (IOException e) { log.error("Error while downloading file:", e); + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Could not load file '%s'.".formatted(path)); } } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index d5e5772..e3470fe 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -36,6 +36,7 @@ import {MatGridListModule} from "@angular/material/grid-list"; import {GameScreenshotComponent} from './components/game-screenshot/game-screenshot.component'; import {YouTubePlayerModule} from "@angular/youtube-player"; import { GameVideoComponent } from './components/game-video/game-video.component'; +import {MatChipsModule} from "@angular/material/chips"; @NgModule({ declarations: [ @@ -52,34 +53,35 @@ import { GameVideoComponent } from './components/game-video/game-video.component GameScreenshotComponent, GameVideoComponent ], - imports: [ - BrowserModule, - AppRoutingModule, - BrowserAnimationsModule, - FormsModule, - MatFormFieldModule, - MatCardModule, - MatTabsModule, - MatToolbarModule, - MatMenuModule, - MatIconModule, - HttpClientModule, - FormsModule, - ReactiveFormsModule, - MatDialogModule, - MatButtonModule, - MatInputModule, - FlexModule, - MatProgressSpinnerModule, - MatTableModule, - MatPaginatorModule, - MatSortModule, - MatSnackBarModule, - MatGridListModule, - FlexLayoutModule, - GridModule, - YouTubePlayerModule - ], + imports: [ + BrowserModule, + AppRoutingModule, + BrowserAnimationsModule, + FormsModule, + MatFormFieldModule, + MatCardModule, + MatTabsModule, + MatToolbarModule, + MatMenuModule, + MatIconModule, + HttpClientModule, + FormsModule, + ReactiveFormsModule, + MatDialogModule, + MatButtonModule, + MatInputModule, + FlexModule, + MatProgressSpinnerModule, + MatTableModule, + MatPaginatorModule, + MatSortModule, + MatSnackBarModule, + MatGridListModule, + FlexLayoutModule, + GridModule, + YouTubePlayerModule, + MatChipsModule + ], providers: [ { provide: HTTP_INTERCEPTORS, diff --git a/frontend/src/app/components/game-detail-view/game-detail-view.component.html b/frontend/src/app/components/game-detail-view/game-detail-view.component.html index b6a3461..906bb48 100644 --- a/frontend/src/app/components/game-detail-view/game-detail-view.component.html +++ b/frontend/src/app/components/game-detail-view/game-detail-view.component.html @@ -1,15 +1,37 @@
+ Game cover -
-

{{game.title}}

+ +
+

{{game.title}}

{{game.summary}}

-
- + +
+
+

Genres

+ + {{genre.name}} + +
+ +
+

Themes

+ + {{theme.name}} + +
+
diff --git a/frontend/src/app/components/game-detail-view/game-detail-view.component.ts b/frontend/src/app/components/game-detail-view/game-detail-view.component.ts index 89e99b8..c641e4c 100644 --- a/frontend/src/app/components/game-detail-view/game-detail-view.component.ts +++ b/frontend/src/app/components/game-detail-view/game-detail-view.component.ts @@ -34,8 +34,28 @@ export class GameDetailViewComponent implements OnInit { ngOnInit(): void { } - downloadGame(): void { + public downloadGame(): void { this.gamesService.downloadGame(this.game.slug); } + public bytesAsHumanReadableString(bytes: number): string { + const thresh = 1024; + + if (Math.abs(bytes) < thresh) { + return bytes + ' B'; + } + + const units = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + const dp = 1; + let u = -1; + const r = 10**dp; + + do { + bytes /= thresh; + ++u; + } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1); + + return bytes.toFixed(dp) + ' ' + units[u]; + } + } diff --git a/frontend/src/app/models/dtos/DetectedGameDto.ts b/frontend/src/app/models/dtos/DetectedGameDto.ts index f40d020..deb2caf 100644 --- a/frontend/src/app/models/dtos/DetectedGameDto.ts +++ b/frontend/src/app/models/dtos/DetectedGameDto.ts @@ -28,6 +28,6 @@ export class DetectedGameDto { playerPerspectives?: PlayerPerspectiveDto[]; path!: string; - isFolder!: boolean; + diskSize!: number; confirmedMatch!: boolean; } diff --git a/frontend/src/app/services/games.service.ts b/frontend/src/app/services/games.service.ts index 00b88cf..727418d 100644 --- a/frontend/src/app/services/games.service.ts +++ b/frontend/src/app/services/games.service.ts @@ -24,7 +24,7 @@ export class GamesService implements GamesApi { } downloadGame(slug: String): void { - window.open(`v1/${this.apiPath}/game/${slug}/download`, '_top'); + window.open(`v1${this.apiPath}/game/${slug}/download`, '_top'); } getGameOverviews(): Observable { diff --git a/frontend/src/app/theme/default-theme.scss b/frontend/src/app/theme/default-theme.scss index 5a93d45..4689a23 100644 --- a/frontend/src/app/theme/default-theme.scss +++ b/frontend/src/app/theme/default-theme.scss @@ -1,5 +1,5 @@ -@use '~@angular/material' as mat; -@import "~@angular/material/theming"; +@use '@angular/material' as mat; +@import "@angular/material/theming"; @include mat.core();