mirror of
https://github.com/BrenBroZAYT/gameyfin.git
synced 2026-06-13 16:40:01 +00:00
Added game file size
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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<Igdb.MultiplayerMode> modes) {
|
||||
return modes.stream().mapToInt(Igdb.MultiplayerMode::getOnlinecoopmax).max().orElse(0);
|
||||
}
|
||||
|
||||
private static long calculateDiskSize(Path path) {
|
||||
try(Stream<Path> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,15 +1,37 @@
|
||||
<div fxLayout="row" fxLayoutAlign="center" style="margin-top: 16px;">
|
||||
<div fxLayout="column" fxFlex="0 1 70" fxLayoutGap="16px" fxFlex.lt-xl="95">
|
||||
<div fxLayout="row" fxLayoutGap="16px">
|
||||
|
||||
<img src="v1/images/{{game.coverId}}" alt="Game cover">
|
||||
<div fxFlex="30" fxLayout="column" id="game-details">
|
||||
<h2>{{game.title}}</h2>
|
||||
|
||||
<div fxFlex="40" fxLayout="column" id="game-details">
|
||||
<h1>{{game.title}}</h1>
|
||||
<p id="game-summary">{{game.summary}}</p>
|
||||
</div>
|
||||
<div fxLayout="column" fxFlex>
|
||||
<button mat-raised-button (click)="downloadGame()">
|
||||
Download
|
||||
|
||||
<div fxFlex><!-- Spacer --></div>
|
||||
|
||||
<div fxLayout="column" fxFlex="40" fxLayoutGap="16px">
|
||||
|
||||
<button mat-raised-button color="primary" (click)="downloadGame()">
|
||||
Download ({{bytesAsHumanReadableString(game.diskSize)}})
|
||||
</button>
|
||||
|
||||
<div fxLayout="column" fxLayoutGap="24px">
|
||||
<div *ngIf="game.genres !== undefined && game.genres.length > 0">
|
||||
<h2>Genres</h2>
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let genre of game.genres">{{genre.name}}</mat-chip>
|
||||
</mat-chip-list>
|
||||
</div>
|
||||
|
||||
<div *ngIf="game.themes !== undefined && game.themes.length > 0">
|
||||
<h2>Themes</h2>
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let theme of game.themes">{{theme.name}}</mat-chip>
|
||||
</mat-chip-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div fxLayout="column" fxLayoutGap="16px">
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,6 @@ export class DetectedGameDto {
|
||||
playerPerspectives?: PlayerPerspectiveDto[];
|
||||
|
||||
path!: string;
|
||||
isFolder!: boolean;
|
||||
diskSize!: number;
|
||||
confirmedMatch!: boolean;
|
||||
}
|
||||
|
||||
@@ -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<GameOverviewDto[]> {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user