Merge pull request #17 from Trivernis/develop

(Last?) Release Candidate before release
main v1.0.0-rc.4
Julius Riegel 2 years ago committed by GitHub
commit 84f36a6875
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,11 +19,6 @@ RUN apt-get install -y \
curl \ curl \
wget \ wget \
pkg-config \ pkg-config \
libavutil-dev \
libavformat-dev \
libavcodec-dev \
libavfilter-dev \
libavdevice-dev \
clang \ clang \
nodejs \ nodejs \
npm \ npm \
@ -39,4 +34,4 @@ ENV PATH="/root/.cargo/bin:${PATH}"
RUN python3 scripts/clean.py RUN python3 scripts/clean.py
RUN python3 scripts/check.py --install RUN python3 scripts/check.py --install
RUN python3 scripts/build.py all --verbose --ffmpeg RUN python3 scripts/build.py all --verbose

@ -77,16 +77,14 @@ $ ./scripts/check.py --install
All Componens: All Componens:
```sh ```sh
$ ./scripts/build.py all --ffmpeg $ ./scripts/build.py all
``` ```
Daemon only: Daemon only:
```sh ```sh
$ ./scripts/build.py daemon --ffmpeg $ ./scripts/build.py daemon
``` ```
If you don't want to build with ffmpeg support omit the `--ffmpeg` flag.
UI only: UI only:
```sh ```sh
$ ./scripts/build.py ui $ ./scripts/build.py ui

File diff suppressed because it is too large Load Diff

@ -4,7 +4,7 @@ default-members = ["mediarepo-core", "mediarepo-database", "mediarepo-logic", "m
[package] [package]
name = "mediarepo-daemon" name = "mediarepo-daemon"
version = "1.0.0-rc.3" version = "1.0.0-rc.4"
edition = "2018" edition = "2018"
license = "gpl-3" license = "gpl-3"
repository = "https://github.com/Trivernis/mediarepo-daemon" repository = "https://github.com/Trivernis/mediarepo-daemon"
@ -16,7 +16,7 @@ name = "mediarepo-daemon"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
tracing = "0.1.30" tracing = "0.1.31"
toml = "0.5.8" toml = "0.5.8"
structopt = "0.3.26" structopt = "0.3.26"
glob = "0.3.0" glob = "0.3.0"
@ -25,7 +25,7 @@ tracing-appender = "0.2.0"
tracing-log = "0.1.2" tracing-log = "0.1.2"
rolling-file = "0.1.0" rolling-file = "0.1.0"
num-integer = "0.1.44" num-integer = "0.1.44"
console-subscriber = "0.1.1" console-subscriber = "0.1.3"
log = "0.4.14" log = "0.4.14"
[dependencies.mediarepo-core] [dependencies.mediarepo-core]
@ -38,13 +38,9 @@ path = "mediarepo-logic"
path = "./mediarepo-socket" path = "./mediarepo-socket"
[dependencies.tokio] [dependencies.tokio]
version = "1.16.1" version = "1.17.0"
features = ["macros", "rt-multi-thread", "io-std", "io-util"] features = ["macros", "rt-multi-thread", "io-std", "io-util"]
[dependencies.tracing-subscriber] [dependencies.tracing-subscriber]
version= "0.3.8" version= "0.3.9"
features = ["env-filter", "ansi", "json"] features = ["env-filter", "ansi", "json"]
[features]
default = ["ffmpeg"]
ffmpeg = ["mediarepo-core/ffmpeg", "mediarepo-logic/ffmpeg"]

@ -17,35 +17,28 @@ typemap_rev = "0.1.5"
futures = "0.3.21" futures = "0.3.21"
itertools = "0.10.3" itertools = "0.10.3"
glob = "0.3.0" glob = "0.3.0"
tracing = "0.1.30" tracing = "0.1.31"
data-encoding = "2.3.2" data-encoding = "2.3.2"
tokio-graceful-shutdown = "0.4.3" tokio-graceful-shutdown = "0.4.3"
thumbnailer = "0.4.0"
[dependencies.thumbnailer]
version = "0.3.0"
default-features = false
[dependencies.sea-orm] [dependencies.sea-orm]
version = "0.6.0" version = "0.6.0"
default-features = false default-features = false
[dependencies.sqlx] [dependencies.sqlx]
version = "0.5.10" version = "0.5.11"
default-features = false default-features = false
features = ["migrate"] features = ["migrate"]
[dependencies.tokio] [dependencies.tokio]
version = "1.16.1" version = "1.17.0"
features = ["fs", "io-util", "io-std"] features = ["fs", "io-util", "io-std"]
[dependencies.config] [dependencies.config]
version = "0.11.0" version = "0.12.0"
features = ["toml"] features = ["toml"]
[dependencies.mediarepo-api] [dependencies.mediarepo-api]
path = "../../mediarepo-api" path = "../../mediarepo-api"
features = ["bromine"] features = ["bromine"]
[features]
default = []
ffmpeg = ["thumbnailer/ffmpeg"]

@ -25,17 +25,17 @@ pub struct Settings {
impl Settings { impl Settings {
pub fn read(root: &PathBuf) -> RepoResult<Self> { pub fn read(root: &PathBuf) -> RepoResult<Self> {
let mut settings = Config::default(); let settings = Config::builder()
settings .add_source(config::File::from_str(
.merge(config::File::from_str(
&*Settings::default().to_toml_string()?, &*Settings::default().to_toml_string()?,
FileFormat::Toml, FileFormat::Toml,
))? ))
.merge(config::File::from(root.join("repo")))? .add_source(config::File::from(root.join("repo")))
.merge(config::Environment::with_prefix("MEDIAREPO").separator("."))?; .add_source(config::Environment::with_prefix("MEDIAREPO").separator("."))
.build()?;
tracing::debug!("Settings are: {:#?}", settings); tracing::debug!("Settings are: {:#?}", settings);
Ok(settings.try_into::<Settings>()?) Ok(settings.try_deserialize()?)
} }
/// Parses settings from a string /// Parses settings from a string
@ -50,16 +50,16 @@ impl Settings {
.map(|p| p.to_string_lossy().to_string()) .map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|| String::from("./")); .unwrap_or_else(|| String::from("./"));
let mut settings = Config::default(); let settings = Config::builder()
settings .add_source(config::File::from_str(
.merge(config::File::from_str(
&*settings_main.to_toml_string()?, &*settings_main.to_toml_string()?,
FileFormat::Toml, FileFormat::Toml,
))? ))
.merge(config::Environment::with_prefix("MEDIAREPO"))?; .add_source(config::Environment::with_prefix("MEDIAREPO"))
.build()?;
tracing::debug!("Settings are: {:#?}", settings); tracing::debug!("Settings are: {:#?}", settings);
Ok(settings.try_into::<Settings>()?) Ok(settings.try_deserialize()?)
} }
/// Converts the settings into a toml string /// Converts the settings into a toml string

@ -8,13 +8,13 @@ workspace = ".."
[dependencies] [dependencies]
chrono = "0.4.19" chrono = "0.4.19"
tracing = "0.1.30" tracing = "0.1.31"
[dependencies.mediarepo-core] [dependencies.mediarepo-core]
path = "../mediarepo-core" path = "../mediarepo-core"
[dependencies.sqlx] [dependencies.sqlx]
version = "0.5.10" version = "0.5.11"
features = ["migrate"] features = ["migrate"]
[dependencies.sea-orm] [dependencies.sea-orm]

@ -10,9 +10,9 @@ workspace = ".."
chrono = "0.4.19" chrono = "0.4.19"
typemap_rev = "0.1.5" typemap_rev = "0.1.5"
serde = "1.0.136" serde = "1.0.136"
mime_guess = "2.0.3" mime_guess = "2.0.4"
mime = "0.3.16" mime = "0.3.16"
tracing = "0.1.30" tracing = "0.1.31"
async-trait = "0.1.52" async-trait = "0.1.52"
[dependencies.mediarepo-core] [dependencies.mediarepo-core]
@ -27,9 +27,6 @@ features = ["runtime-tokio-native-tls", "macros"]
default-features = false default-features = false
[dependencies.tokio] [dependencies.tokio]
version = "1.16.1" version = "1.17.0"
features = ["fs", "io-std", "io-util"] features = ["fs", "io-std", "io-util"]
[features]
ffmpeg = ["mediarepo-core/ffmpeg"]

@ -8,7 +8,7 @@ workspace = ".."
[dependencies] [dependencies]
serde = "1.0.136" serde = "1.0.136"
tracing = "0.1.30" tracing = "0.1.31"
compare = "0.1.0" compare = "0.1.0"
port_check = "0.1.5" port_check = "0.1.5"
rayon = "1.5.1" rayon = "1.5.1"
@ -23,7 +23,7 @@ path = "../mediarepo-database"
path = "../mediarepo-logic" path = "../mediarepo-logic"
[dependencies.tokio] [dependencies.tokio]
version = "1.16.1" version = "1.17.0"
features = ["net"] features = ["net"]
[dependencies.chrono] [dependencies.chrono]

@ -40,7 +40,9 @@
"src/styles.scss", "src/styles.scss",
"src/material-theme-correction.scss" "src/material-theme-correction.scss"
], ],
"scripts": [] "scripts": [
"./node_modules/chart.js/dist/chart.js"
]
}, },
"configurations": { "configurations": {
"production": { "production": {
@ -114,7 +116,9 @@
"src/styles.scss", "src/styles.scss",
"src/material-theme-correction.scss" "src/material-theme-correction.scss"
], ],
"scripts": [] "scripts": [
"./node_modules/chart.js/dist/chart.js"
]
} }
}, },
"lint": { "lint": {

@ -1,6 +1,6 @@
{ {
"name": "mediarepo-ui", "name": "mediarepo-ui",
"version": "1.0.0-rc.3", "version": "1.0.0-rc.4",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
@ -28,6 +28,7 @@
"@ng-icons/feather-icons": "^13.2.1", "@ng-icons/feather-icons": "^13.2.1",
"@ng-icons/material-icons": "^13.2.1", "@ng-icons/material-icons": "^13.2.1",
"@tauri-apps/api": "^1.0.0-beta.8", "@tauri-apps/api": "^1.0.0-beta.8",
"chart.js": "^3.7.1",
"primeicons": "^5.0.0", "primeicons": "^5.0.0",
"primeng": "^13.0.4", "primeng": "^13.0.4",
"rxjs": "~7.5.2", "rxjs": "~7.5.2",
@ -59,4 +60,4 @@
"karma-jasmine-html-reporter": "~1.7.0", "karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.5.4" "typescript": "~4.5.4"
} }
} }

@ -40,7 +40,7 @@ checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
[[package]] [[package]]
name = "app" name = "app"
version = "1.0.0-rc.3" version = "1.0.0-rc.4"
dependencies = [ dependencies = [
"mediarepo-api", "mediarepo-api",
"serde", "serde",

@ -1,6 +1,6 @@
[package] [package]
name = "app" name = "app"
version = "1.0.0-rc.3" version = "1.0.0-rc.4"
description = "The UI for the mediarepo media management tool" description = "The UI for the mediarepo media management tool"
authors = ["you"] authors = ["you"]
license = "" license = ""

@ -89,7 +89,7 @@ import {AboutDialogComponent} from "./repositories-tab/repository-overview/about
MatInputModule, MatInputModule,
TagModule, TagModule,
RepositoryModule, RepositoryModule,
MatToolbarModule, MatToolbarModule
] ]
}) })
export class CoreModule { export class CoreModule {

@ -1,6 +1,4 @@
<div *ngIf="!this.selectedRepository"> <app-repository-overview *ngIf="!this.selectedRepository"></app-repository-overview>
<app-repository-overview></app-repository-overview> <app-repository-details-view *ngIf="this.selectedRepository"
</div> [repository]="this.selectedRepository"></app-repository-details-view>
<div *ngIf="this.selectedRepository" class="repo-details">
<app-repository-details-view [repository]="this.selectedRepository"></app-repository-details-view>
</div>

@ -4,45 +4,56 @@
</button> </button>
</mat-toolbar> </mat-toolbar>
<div class="details-content" fxLayout="row"> <div class="details-content" fxLayout="row">
<div class="repository-metadata" fxFlex="100%"> <div class="repository-metadata" fxFlex="50%">
<h1>Stats</h1> <div class="stats-container">
<app-metadata-entry *ngIf="repository.path" attributeName="Path">{{repository.path}}</app-metadata-entry> <h1>Stats</h1>
<app-metadata-entry *ngIf="repository.address" <app-metadata-entry *ngIf="repository.path" attributeName="Path">{{repository.path}}</app-metadata-entry>
attributeName="Address">{{repository.address}}</app-metadata-entry> <app-metadata-entry *ngIf="repository.address"
<app-metadata-entry attributeName="File Count"> attributeName="Address">{{repository.address}}</app-metadata-entry>
<mat-progress-bar *ngIf="!metadata"></mat-progress-bar> <app-metadata-entry attributeName="File Count">
{{metadata ? metadata!.file_count.toString() : ''}} <mat-progress-bar *ngIf="!metadata"></mat-progress-bar>
</app-metadata-entry> {{metadata ? metadata!.file_count.toString() : ''}}
<app-metadata-entry attributeName="Tag Count"> </app-metadata-entry>
<mat-progress-bar *ngIf="!metadata"></mat-progress-bar> <app-metadata-entry attributeName="Tag Count">
{{metadata ? metadata!.tag_count.toString() : ''}} <mat-progress-bar *ngIf="!metadata"></mat-progress-bar>
</app-metadata-entry> {{metadata ? metadata!.tag_count.toString() : ''}}
<app-metadata-entry attributeName="Namespace Count"> </app-metadata-entry>
<mat-progress-bar *ngIf="!metadata"></mat-progress-bar> <app-metadata-entry attributeName="Namespace Count">
{{metadata ? metadata!.namespace_count.toString() : ''}} <mat-progress-bar *ngIf="!metadata"></mat-progress-bar>
</app-metadata-entry> {{metadata ? metadata!.namespace_count.toString() : ''}}
<app-metadata-entry attributeName="Mapping Count"> </app-metadata-entry>
<mat-progress-bar *ngIf="!metadata"></mat-progress-bar> <app-metadata-entry attributeName="Mapping Count">
{{metadata ? metadata!.mapping_count.toString() : ''}} <mat-progress-bar *ngIf="!metadata"></mat-progress-bar>
</app-metadata-entry> {{metadata ? metadata!.mapping_count.toString() : ''}}
<app-metadata-entry attributeName="Total Size"> </app-metadata-entry>
<mat-progress-bar *ngIf="(this.totalSize | async) === undefined" mode="indeterminate"></mat-progress-bar> <app-metadata-entry attributeName="Total Size">
{{this.totalSize | async}} <mat-progress-bar *ngIf="(this.totalSize | async) === undefined"
</app-metadata-entry> mode="indeterminate"></mat-progress-bar>
<app-metadata-entry attributeName="File Folder Size"> {{this.totalSize | async}}
<mat-progress-bar *ngIf="(this.fileFolderSize | async) === undefined" </app-metadata-entry>
mode="indeterminate"></mat-progress-bar> <app-metadata-entry attributeName="File Folder Size">
{{this.fileFolderSize | async}} <mat-progress-bar *ngIf="(this.fileFolderSize | async) === undefined"
</app-metadata-entry> mode="indeterminate"></mat-progress-bar>
<app-metadata-entry attributeName="Thumbnail Folder Size"> {{this.fileFolderSize | async}}
<mat-progress-bar *ngIf="(this.thumbFolderSize | async) === undefined" </app-metadata-entry>
mode="indeterminate"></mat-progress-bar> <app-metadata-entry attributeName="Thumbnail Folder Size">
{{this.thumbFolderSize | async}} <mat-progress-bar *ngIf="(this.thumbFolderSize | async) === undefined"
</app-metadata-entry> mode="indeterminate"></mat-progress-bar>
<app-metadata-entry attributeName="Database File Size"> {{this.thumbFolderSize | async}}
<mat-progress-bar *ngIf="(this.databaseFileSize | async) === undefined" </app-metadata-entry>
mode="indeterminate"></mat-progress-bar> <app-metadata-entry attributeName="Database File Size">
{{this.databaseFileSize | async}} <mat-progress-bar *ngIf="(this.databaseFileSize | async) === undefined"
</app-metadata-entry> mode="indeterminate"></mat-progress-bar>
{{this.databaseFileSize | async}}
</app-metadata-entry>
</div>
</div>
<div class="repository-charts" fxFlex="50%">
<app-chart *ngIf="this.chartData"
[datasets]="this.chartData"
[labels]="this.chartLabels"
chartType="doughnut"
class="size-chart"
title="Sizes"></app-chart>
</div> </div>
</div> </div>

@ -1,3 +1,10 @@
@import "src/colors";
:host {
height: 100%;
width: 100%;
}
.repository-name { .repository-name {
text-align: center; text-align: center;
align-self: center; align-self: center;
@ -12,16 +19,38 @@
padding: 1em 1em 1em 3em; padding: 1em 1em 1em 3em;
overflow-y: auto; overflow-y: auto;
user-select: none; user-select: none;
margin-left: 20%; margin-top: 4em;
margin-right: 20%; margin-left: 2em;
display: flex;
app-metadata-entry { app-metadata-entry {
margin-bottom: 0.5em; margin-bottom: 0.5em;
display: block; display: block;
} }
.stats-container {
margin-left: auto;
margin-right: auto;
}
}
.repository-charts {
margin-top: 4em;
margin-right: 2em;
height: 100%;
display: block;
} }
.details-content { .details-content {
height: calc(100% - 64px); height: calc(100% - 64px);
overflow: hidden; overflow: hidden;
width: 75%;
margin: auto;
background: $background-lighter-05;
}
.size-chart {
min-height: 50%;
max-width: 500px;
margin: auto;
} }

@ -5,6 +5,7 @@ import {RepositoryMetadata} from "../../../../models/RepositoryMetadata";
import {BehaviorSubject} from "rxjs"; import {BehaviorSubject} from "rxjs";
import {MatDialog} from "@angular/material/dialog"; import {MatDialog} from "@angular/material/dialog";
import {BusyDialogComponent} from "../../../shared/app-common/busy-dialog/busy-dialog.component"; import {BusyDialogComponent} from "../../../shared/app-common/busy-dialog/busy-dialog.component";
import {Dataset} from "../../../shared/app-common/chart/chart.component";
@Component({ @Component({
selector: "app-repository-details-view", selector: "app-repository-details-view",
@ -19,9 +20,14 @@ export class RepositoryDetailsViewComponent implements OnInit, OnChanges, OnDest
public fileFolderSize = new BehaviorSubject<string | undefined>(undefined); public fileFolderSize = new BehaviorSubject<string | undefined>(undefined);
public thumbFolderSize = new BehaviorSubject<string | undefined>(undefined); public thumbFolderSize = new BehaviorSubject<string | undefined>(undefined);
public databaseFileSize = new BehaviorSubject<string | undefined>(undefined); public databaseFileSize = new BehaviorSubject<string | undefined>(undefined);
public chartData?: Dataset[];
public chartLabels = ["Files", "Thumbnails", "Database"];
private refreshMetadataInterval?: number; private refreshMetadataInterval?: number;
constructor(private repoService: RepositoryService, public dialog: MatDialog) { constructor(
private repoService: RepositoryService,
public dialog: MatDialog
) {
} }
public async ngOnInit() { public async ngOnInit() {
@ -63,6 +69,11 @@ export class RepositoryDetailsViewComponent implements OnInit, OnChanges, OnDest
this.thumbFolderSize.next(this.formatByteSize(thumbSize.size)); this.thumbFolderSize.next(this.formatByteSize(thumbSize.size));
const databaseSize = await this.repoService.getSize("DatabaseFile"); const databaseSize = await this.repoService.getSize("DatabaseFile");
this.databaseFileSize.next(this.formatByteSize(databaseSize.size)); this.databaseFileSize.next(this.formatByteSize(databaseSize.size));
this.chartData = [
{
data: [fileSize.size, thumbSize.size, databaseSize.size],
},
];
} }
public formatByteSize(size: number): string { public formatByteSize(size: number): string {

@ -1,10 +1,17 @@
:host {
height: 100%;
width: 100%;
display: block;
overflow: hidden;
}
.repository-container { .repository-container {
padding: 1em; padding: 1em;
margin: auto; margin: auto;
display: block; display: block;
width: calc(600px - 2em); width: calc(600px - 2em);
float: left; float: left;
app-repository-card { app-repository-card {
display: block; display: block;
position: relative; position: relative;
@ -31,7 +38,8 @@
flex-wrap: wrap; flex-wrap: wrap;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
height: calc(100% - 5em); max-height: calc(100% - 2em);
padding-bottom: 2em;
} }

@ -26,6 +26,8 @@ import {FlapButtonComponent} from "./flap-button/flap-button.component";
import {MiddleCenteredComponent} from "./middle-centered/middle-centered.component"; import {MiddleCenteredComponent} from "./middle-centered/middle-centered.component";
import {FormatBytesPipe} from "./pipes/format-bytes.pipe"; import {FormatBytesPipe} from "./pipes/format-bytes.pipe";
import {ExternalUrlComponent} from "./external-url/external-url.component"; import {ExternalUrlComponent} from "./external-url/external-url.component";
import {ChartComponent} from "./chart/chart.component";
import {ChartModule} from "primeng/chart";
@NgModule({ @NgModule({
@ -46,6 +48,7 @@ import {ExternalUrlComponent} from "./external-url/external-url.component";
MiddleCenteredComponent, MiddleCenteredComponent,
FormatBytesPipe, FormatBytesPipe,
ExternalUrlComponent, ExternalUrlComponent,
ChartComponent,
], ],
exports: [ exports: [
ConfirmDialogComponent, ConfirmDialogComponent,
@ -63,6 +66,7 @@ import {ExternalUrlComponent} from "./external-url/external-url.component";
MiddleCenteredComponent, MiddleCenteredComponent,
FormatBytesPipe, FormatBytesPipe,
ExternalUrlComponent, ExternalUrlComponent,
ChartComponent,
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -74,7 +78,8 @@ import {ExternalUrlComponent} from "./external-url/external-url.component";
MatProgressBarModule, MatProgressBarModule,
MatSidenavModule, MatSidenavModule,
FlexLayoutModule, FlexLayoutModule,
MatRippleModule MatRippleModule,
ChartModule
] ]
}) })
export class AppCommonModule { export class AppCommonModule {

@ -0,0 +1,2 @@
<h2 *ngIf="this.title" class="title">{{this.title}}</h2>
<p-chart [data]="data" [options]="this.options" [type]="this.chartType ?? ''"></p-chart>

@ -0,0 +1,15 @@
:host {
height: 100%;
width: 100%;
display: block;
}
.title {
width: 100%;
text-align: center;
}
p-chart {
height: 100%;
width: 100%;
}

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from "@angular/core/testing";
import {ChartComponent} from "./chart.component";
describe("ChartComponent", () => {
let component: ChartComponent;
let fixture: ComponentFixture<ChartComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ChartComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,86 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, SimpleChanges} from "@angular/core";
import {ChartOptions} from "chart.js";
export type ChartType = "doughnut";
export type Dataset = {
label?: string,
data: number[],
};
@Component({
selector: "app-chart",
templateUrl: "./chart.component.html",
styleUrls: ["./chart.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChartComponent implements OnChanges {
@Input() chartType?: ChartType;
@Input() title?: string;
@Input() labels: string[] = [];
@Input() datasets: Dataset[] = [];
public data: any = {};
public options: ChartOptions = {
responsive: true,
elements: {
arc: {
borderWidth: 0
}
},
plugins: {
legend: {
labels: {
color: "#FFF",
boxHeight: 20,
font: {
size: 16,
}
},
},
tooltip: {
titleFont: {
size: 16
},
bodyFont: {
size: 14
}
}
}
};
private readonly colors = [
"#771e86",
"#4650b5",
"#0073d0",
"#0091d6",
"#00aacb",
"#00c0b7"
];
constructor(private changeDetector: ChangeDetectorRef) {
}
public ngOnChanges(changes: SimpleChanges): void {
if (changes["labels"] || changes["dataset"]) {
this.generateData();
this.changeDetector.markForCheck();
}
if (changes["chartType"]) {
this.changeDetector.markForCheck();
}
}
private generateData() {
this.data = {
labels: this.labels,
datasets: this.datasets.map(set => {
return {
label: set.label,
data: set.data,
backgroundColor: this.colors,
hoverBackgroundColor: this.colors,
};
})
};
}
}

@ -8,12 +8,15 @@
minBufferPx="500"> minBufferPx="500">
<div *cdkVirtualFor="let rowEntry of partitionedGridEntries; trackBy: trackByFileRowId"> <div *cdkVirtualFor="let rowEntry of partitionedGridEntries; trackBy: trackByFileRowId">
<div class="file-row"> <div class="file-row">
<app-file-card <ng-container *ngFor="let gridEntry of rowEntry; trackBy: trackByFileId">
(clickEvent)="setSelectedFile($event.entry)" <app-file-card
(contextmenu)="this.selectEntryWhenNotSelected(gridEntry); fileContextMenu.onContextMenu($event, this.getSelectedFiles())" (clickEvent)="setSelectedFile($event.entry)"
(dblClickEvent)="fileOpen.emit($event.entry.data)" (contextmenu)="this.selectEntryWhenNotSelected(gridEntry); fileContextMenu.onContextMenu($event, this.getSelectedFiles())"
*ngFor="let gridEntry of rowEntry; trackBy: trackByFileId" (dblClickEvent)="fileOpen.emit($event.entry.data)"
[entry]="gridEntry" [fileChanged]="this.fileChanged"></app-file-card> *ngIf="gridEntry"
[entry]="gridEntry" [fileChanged]="this.fileChanged"></app-file-card>
<div *ngIf="!gridEntry" class="empty-grid-entry"></div>
</ng-container>
</div> </div>
</div> </div>
</cdk-virtual-scroll-viewport> </cdk-virtual-scroll-viewport>

@ -6,6 +6,13 @@ app-file-card {
margin: 5px; margin: 5px;
} }
.empty-grid-entry {
width: 100%;
height: 250px;
margin: 5px;
display: block;
}
.file-scroll { .file-scroll {
height: 100%; height: 100%;
width: 100%; width: 100%;

@ -43,7 +43,7 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit, Afte
public fileChanged = new BehaviorSubject<void>(undefined); public fileChanged = new BehaviorSubject<void>(undefined);
public selectedEntries: Selectable<File>[] = []; public selectedEntries: Selectable<File>[] = [];
public partitionedGridEntries: Selectable<File>[][] = []; public partitionedGridEntries: (Selectable<File> | undefined)[][] = [];
private columns = 6; private columns = 6;
private entrySizePx = 260; private entrySizePx = 260;
@ -187,12 +187,12 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit, Afte
this.ctrlClicked = event.ctrlKey ? false : this.ctrlClicked; this.ctrlClicked = event.ctrlKey ? false : this.ctrlClicked;
} }
public trackByFileRowId(index: number, item: Selectable<File>[]) { public trackByFileRowId(index: number, item: (Selectable<File> | undefined)[]) {
return item.map(e => e.data.id).join("-"); return item.map(e => e?.data.id).join("-");
} }
public trackByFileId(index: number, item: Selectable<File>) { public trackByFileId(index: number, item: Selectable<File> | undefined) {
return item.data.id; return item?.data.id;
} }
public onFileStatusChange(): void { public onFileStatusChange(): void {
@ -224,14 +224,18 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit, Afte
for (let i = 0; i < (Math.ceil( for (let i = 0; i < (Math.ceil(
this.gridEntries.length / this.columns)); i++) { this.gridEntries.length / this.columns)); i++) {
const entries = this.gridEntries.slice( const entries: (Selectable<File> | undefined)[] = this.gridEntries.slice(
i * this.columns, i * this.columns,
Math.min(this.gridEntries.length, (i + 1) * this.columns) Math.min(this.gridEntries.length, (i + 1) * this.columns)
); );
const length = entries.length;
for (let i = 0; i < (this.columns - length); i++) {
entries.push(undefined);
}
this.partitionedGridEntries.push(entries); this.partitionedGridEntries.push(entries);
const preselectedEntry = entries.find( const preselectedEntry = entries.find(
e => e.data.id == this.preselectedFile?.id); e => e?.data.id == this.preselectedFile?.id);
if (preselectedEntry) { if (preselectedEntry) {
scrollToIndex = i; scrollToIndex = i;
@ -256,7 +260,8 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit, Afte
private scrollToSelection() { private scrollToSelection() {
const selected = this.selectedEntries[0]; const selected = this.selectedEntries[0];
if (this.virtualScroll && selected) { if (this.virtualScroll && selected) {
const index = Math.floor(this.gridEntries.indexOf(selected) / this.columns); const index = Math.floor(
this.gridEntries.indexOf(selected) / this.columns);
setTimeout(() => { setTimeout(() => {
this.virtualScroll.scrollToIndex(index); this.virtualScroll.scrollToIndex(index);
this.changeDetector.markForCheck(); this.changeDetector.markForCheck();
@ -345,14 +350,17 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit, Afte
if (this.virtualScroll) { if (this.virtualScroll) {
const viewportSize = this.virtualScroll.getViewportSize(); const viewportSize = this.virtualScroll.getViewportSize();
let offsetTop = this.virtualScroll.measureScrollOffset("top"); let offsetTop = this.virtualScroll.measureScrollOffset("top");
const contentOffset = Math.floor(selectedIndex / this.columns) * 260; const contentOffset = Math.floor(
selectedIndex / this.columns) * 260;
if (contentOffset > offsetTop + viewportSize - 300 || contentOffset < offsetTop) { if (contentOffset > offsetTop + viewportSize - 300 || contentOffset < offsetTop) {
this.virtualScroll.scrollToIndex(Math.floor(selectedIndex / this.columns)); this.virtualScroll.scrollToIndex(
Math.floor(selectedIndex / this.columns));
offsetTop = this.virtualScroll.measureScrollOffset("top"); offsetTop = this.virtualScroll.measureScrollOffset("top");
if (contentOffset < offsetTop + (viewportSize / 2)) { if (contentOffset < offsetTop + (viewportSize / 2)) {
this.virtualScroll.scrollToOffset((offsetTop + 130) - viewportSize / 2); this.virtualScroll.scrollToOffset(
(offsetTop + 130) - viewportSize / 2);
} }
} }
} }
@ -361,14 +369,16 @@ export class FileGridComponent implements OnChanges, OnInit, AfterViewInit, Afte
private pageDown() { private pageDown() {
if (this.virtualScroll) { if (this.virtualScroll) {
const offsetTop = this.virtualScroll.measureScrollOffset("top"); const offsetTop = this.virtualScroll.measureScrollOffset("top");
this.virtualScroll.scrollToOffset(offsetTop + this.virtualScroll.getViewportSize()); this.virtualScroll.scrollToOffset(
offsetTop + this.virtualScroll.getViewportSize());
} }
} }
private pageUp() { private pageUp() {
if (this.virtualScroll) { if (this.virtualScroll) {
const offsetTop = this.virtualScroll.measureScrollOffset("top"); const offsetTop = this.virtualScroll.measureScrollOffset("top");
this.virtualScroll.scrollToOffset(offsetTop - this.virtualScroll.getViewportSize()); this.virtualScroll.scrollToOffset(
offsetTop - this.virtualScroll.getViewportSize());
} }
} }
} }

@ -34,8 +34,8 @@ app-content-aware-image {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
height: 18%; height: 2.5em;
width: 18%; width: 2.5em;
display: flex; display: flex;
border-bottom-left-radius: 50%; border-bottom-left-radius: 50%;
background-color: transparentize($background, .5); background-color: transparentize($background, .5);

@ -52,7 +52,7 @@ mat-option {
} }
mat-toolbar.mat-toolbar { mat-toolbar.mat-toolbar {
background: $background-darker-05; background: $background-darker-05 !important;
} }
.mat-card { .mat-card {

@ -2776,6 +2776,11 @@ chardet@^0.7.0:
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
chart.js@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.7.1.tgz#0516f690c6a8680c6c707e31a4c1807a6f400ada"
integrity sha512-8knRegQLFnPQAheZV8MjxIXc5gQEfDFD897BJgv/klO/vtIyFFmgMXrNfgrXpbTr/XbTturxRgxIXx/Y+ASJBA==
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.5.1, chokidar@^3.5.2: "chokidar@>=3.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.5.1, chokidar@^3.5.2:
version "3.5.3" version "3.5.3"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz"

@ -9,7 +9,6 @@ from typing import List
build_output = 'out' build_output = 'out'
verbose = False verbose = False
ffmpeg = False
install_tooling = False install_tooling = False
windows = os.name == 'nt' windows = os.name == 'nt'
@ -21,12 +20,10 @@ def main():
global install_tooling global install_tooling
global build_output global build_output
global verbose global verbose
global ffmpeg
global install_tooling global install_tooling
build_output = opts.output if opts.output else build_output build_output = opts.output if opts.output else build_output
verbose = opts.verbose verbose = opts.verbose
ffmpeg = opts.ffmpeg
install_tooling = opts.install_tooling install_tooling = opts.install_tooling
build(opts.component, opts.bundles) build(opts.component, opts.bundles)
@ -41,8 +38,6 @@ def parse_args():
'--verbose', action='store_true', help='Verbose build') '--verbose', action='store_true', help='Verbose build')
parser.add_argument( parser.add_argument(
'--output', action='store', help='Build output directory') '--output', action='store', help='Build output directory')
parser.add_argument(
'--ffmpeg', action='store_true', help='Build with ffmpeg')
parser.add_argument('--install-tooling', parser.add_argument('--install-tooling',
action='store_true', help='Install tooling') action='store_true', help='Install tooling')
parser.add_argument('--bundles', nargs='+', parser.add_argument('--bundles', nargs='+',
@ -74,11 +69,7 @@ def build(component: str, bundles: List[str] = None):
def build_daemon(): def build_daemon():
'''Builds daemon''' '''Builds daemon'''
cargo('fetch', 'mediarepo-daemon') cargo('fetch', 'mediarepo-daemon')
cargo('build --release --frozen', 'mediarepo-daemon')
if not ffmpeg:
cargo('build --release --frozen --no-default-features', 'mediarepo-daemon')
else:
cargo('build --release --frozen', 'mediarepo-daemon')
if windows: if windows:
store_artifact('mediarepo-daemon/target/release/mediarepo-daemon.exe') store_artifact('mediarepo-daemon/target/release/mediarepo-daemon.exe')

Loading…
Cancel
Save