mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* ffmpeg profile functionality, sweetalert2 * add new files * cleanup controller; remove unused classes * apply formatting * cleanup core project * don't use bom * whitespace * remove generated css * remove generated js/map * Remove attempted linter fix, channels button, watermarks page. Fixed handlerror. * Changed deleted confirmation to toast. * Localized strings for language change. Modified Action icons to buttons and left default sizes. Changed Cancel to No where Yes is an option * lint Co-authored-by: Jason Dove <jason@jasondove.me>pull/834/head
24 changed files with 1411 additions and 15 deletions
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
using ErsatzTV.Core.Api.FFmpegProfiles; |
||||
|
||||
namespace ErsatzTV.Application.FFmpegProfiles; |
||||
|
||||
public record GetFFmpegFullProfileByIdForApi(int Id) : IRequest<Option<FFmpegFullProfileResponseModel>>; |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
using ErsatzTV.Core.Api.FFmpegProfiles; |
||||
using ErsatzTV.Infrastructure.Data; |
||||
using ErsatzTV.Infrastructure.Extensions; |
||||
using Microsoft.EntityFrameworkCore; |
||||
using static ErsatzTV.Application.FFmpegProfiles.Mapper; |
||||
|
||||
namespace ErsatzTV.Application.FFmpegProfiles; |
||||
|
||||
public class |
||||
GetFFmpegProfileByIdForApiHandler : IRequestHandler<GetFFmpegFullProfileByIdForApi, |
||||
Option<FFmpegFullProfileResponseModel>> |
||||
{ |
||||
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||
|
||||
public GetFFmpegProfileByIdForApiHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||
_dbContextFactory = dbContextFactory; |
||||
|
||||
public async Task<Option<FFmpegFullProfileResponseModel>> Handle( |
||||
GetFFmpegFullProfileByIdForApi request, |
||||
CancellationToken cancellationToken) |
||||
{ |
||||
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); |
||||
return await dbContext.FFmpegProfiles |
||||
.Include(p => p.Resolution) |
||||
.SelectOneAsync(p => p.Id, p => p.Id == request.Id) |
||||
.MapT(ProjectToFullResponseModel); |
||||
} |
||||
} |
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
namespace ErsatzTV.Core.Api.FFmpegProfiles; |
||||
|
||||
public record FFmpegFullProfileResponseModel( |
||||
int Id, |
||||
string Name, |
||||
int ThreadCount, |
||||
int HardwareAcceleration, |
||||
int VaapiDriver, |
||||
string VaapiDevice, |
||||
int ResolutionId, |
||||
int VideoFormat, |
||||
int VideoBitrate, |
||||
int VideoBufferSize, |
||||
int AudioFormat, |
||||
int AudioBitrate, |
||||
int AudioBufferSize, |
||||
bool NormalizeLoudness, |
||||
int AudioChannels, |
||||
int AudioSampleRate, |
||||
bool NormalizeFramerate, |
||||
bool? DeinterlaceVideo); |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
.swal2-container.swal2-center > .swal2-popup { |
||||
background-color: #1E1E1E !important; |
||||
border-color: green; |
||||
border-width: thin; |
||||
border-style: solid; |
||||
width: fit-content; |
||||
} |
||||
|
||||
.swal2-html-container, .swal2-title { |
||||
color: white !important; |
||||
font-family:Cambria; |
||||
} |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
export interface FFmpegFullProfile { |
||||
Id: number; |
||||
name: string; |
||||
threadCount: number; |
||||
hardwareAcceleration: number; |
||||
vaapiDriver: number; |
||||
vaapiDevice: string; |
||||
resolutionId: number; |
||||
videoFormat: number; |
||||
videoBitrate: number; |
||||
videoBufferSize: number; |
||||
audioFormat: number; |
||||
audioBitrate: number; |
||||
audioBufferSize: number; |
||||
normalizeLoudness: boolean; |
||||
audioChannels: number; |
||||
audioSampleRate: number; |
||||
normalizeFramerate: boolean; |
||||
deinterlaceVideo: boolean; |
||||
} |
@ -0,0 +1,909 @@
@@ -0,0 +1,909 @@
|
||||
<template> |
||||
<div id="AddEditFFmpegProfile"> |
||||
<h1 id="title" class="mx-4" /> |
||||
<v-divider color="success" class="ma-2"></v-divider> |
||||
<v-app> |
||||
<v-form |
||||
ref="form" |
||||
v-model="isFormValid" |
||||
id="ffmpegForm" |
||||
lazy-validation |
||||
> |
||||
<v-container> |
||||
<v-row justify="center"> |
||||
<v-flex shrink class="pb-10"> |
||||
<v-container style="max-height: 80px"> |
||||
<v-row justify="center"> |
||||
<h2 class="mx"> |
||||
{{ $t('edit-ffmpeg-profile.General') }} |
||||
</h2> |
||||
</v-row> |
||||
</v-container> |
||||
<v-container style="max-height: 80px"> |
||||
<v-text-field |
||||
v-model="newProfile.name" |
||||
:rules="textRules" |
||||
:label="$t('edit-ffmpeg-profile.Name')" |
||||
required |
||||
></v-text-field> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-text-field |
||||
ref="myThreadCount" |
||||
v-model="threadCount" |
||||
:label=" |
||||
$t('edit-ffmpeg-profile.thread-count') |
||||
" |
||||
:rules="validInt" |
||||
number |
||||
required |
||||
></v-text-field> |
||||
<v-tooltip v-model="threadCountShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container style="max-height: 40px"> |
||||
<v-select |
||||
v-model="selectedResolution" |
||||
@change="preferredResolutionChange" |
||||
:items="preferredResolutions" |
||||
item-value="id" |
||||
item-text="name" |
||||
:label=" |
||||
$t( |
||||
'edit-ffmpeg-profile.preferred-resolution' |
||||
) |
||||
" |
||||
required |
||||
></v-select> |
||||
</v-container> |
||||
</v-flex> |
||||
<v-divider |
||||
style="max-height: 500px" |
||||
vertical |
||||
color="grey" |
||||
></v-divider> |
||||
<v-flex shrink class="pb-10"> |
||||
<v-container style="max-height: 80px"> |
||||
<v-row justify="center"> |
||||
<h2 class="mx"> |
||||
{{ $t('edit-ffmpeg-profile.Video') }} |
||||
</h2> |
||||
</v-row> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-select |
||||
v-model="selectedVideoFormat" |
||||
@change="videoFormatChanged" |
||||
:items="videoFormats" |
||||
item-value="id" |
||||
item-text="name" |
||||
id="videoFormatSelector" |
||||
:label="$t('edit-ffmpeg-profile.format')" |
||||
required |
||||
></v-select> |
||||
<v-tooltip v-model="videoFormatShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-text-field |
||||
v-model="newProfile.videoBitRate" |
||||
:label="$t('edit-ffmpeg-profile.bitrate')" |
||||
:rules="validIntNonZero" |
||||
required |
||||
></v-text-field> |
||||
<v-tooltip v-model="videoBitRateShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-text-field |
||||
v-model="newProfile.videoBufferSize" |
||||
:label=" |
||||
$t('edit-ffmpeg-profile.buffer-size') |
||||
" |
||||
:rules="validIntNonZero" |
||||
required |
||||
></v-text-field> |
||||
<v-tooltip v-model="videoBufferSizeShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-select |
||||
v-model="selectedHardwareAcceleration" |
||||
@change="hardwareAccelerationChanged" |
||||
:items="hardwareAccelerations" |
||||
item-value="id" |
||||
item-text="name" |
||||
:label=" |
||||
$t( |
||||
'edit-ffmpeg-profile.hardware-acceleration' |
||||
) |
||||
" |
||||
required |
||||
></v-select> |
||||
<v-tooltip |
||||
v-model="hardwareAccelerationShow" |
||||
top |
||||
> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-select |
||||
v-model="selectedVaapiDriver" |
||||
@change="vaapiDriverChanged" |
||||
:items="vaapiDrivers" |
||||
:disabled="vaapiDriverDisabled" |
||||
item-value="id" |
||||
item-text="name" |
||||
:label=" |
||||
$t('edit-ffmpeg-profile.vaapi-driver') |
||||
" |
||||
required |
||||
></v-select> |
||||
<v-tooltip v-model="vaapiDriverShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-select |
||||
v-model="selectedVaapiDevice" |
||||
@change="vaapiDeviceChanged" |
||||
:items="vaapiDevices" |
||||
:disabled="vaapiDriverDisabled" |
||||
:label=" |
||||
$t('edit-ffmpeg-profile.vaapi-device') |
||||
" |
||||
required |
||||
></v-select> |
||||
<v-tooltip v-model="vaapiDeviceShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 50px" |
||||
> |
||||
<v-checkbox |
||||
class="mr-2" |
||||
v-model="normalizeFrameRate" |
||||
:label=" |
||||
$t( |
||||
'edit-ffmpeg-profile.normalize-framerate' |
||||
) |
||||
" |
||||
color="green lighten-1" |
||||
required |
||||
></v-checkbox> |
||||
<v-tooltip v-model="normalizeFrameRateShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pt-8" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 50px" |
||||
> |
||||
<v-checkbox |
||||
class="mr-2" |
||||
v-model="autoDeinterlaceVideo" |
||||
:label=" |
||||
$t( |
||||
'edit-ffmpeg-profile.auto-deinterlace-video' |
||||
) |
||||
" |
||||
color="green lighten-1" |
||||
required |
||||
></v-checkbox> |
||||
<v-tooltip |
||||
v-model="autoDeinterlaceVideoShow" |
||||
top |
||||
> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pt-8" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
</v-flex> |
||||
<v-divider |
||||
style="max-height: 500px" |
||||
vertical |
||||
color="grey" |
||||
></v-divider> |
||||
<v-flex shrink class="pb-10"> |
||||
<v-container style="max-height: 80px"> |
||||
<v-row justify="center"> |
||||
<h2 class="mx"> |
||||
{{ $t('edit-ffmpeg-profile.Audio') }} |
||||
</h2> |
||||
</v-row> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-select |
||||
v-model="selectedAudioFormat" |
||||
@change="audioFormatChanged" |
||||
:items="audioFormats" |
||||
item-value="id" |
||||
item-text="name" |
||||
:label="$t('edit-ffmpeg-profile.format')" |
||||
ref="audioFormat" |
||||
required |
||||
></v-select> |
||||
<v-tooltip v-model="audioFormatShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-text-field |
||||
v-model="newProfile.audioBitRate" |
||||
:label="$t('edit-ffmpeg-profile.bitrate')" |
||||
:rules="validIntNonZero" |
||||
required |
||||
></v-text-field> |
||||
<v-tooltip v-model="audioBitRateShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-text-field |
||||
v-model="newProfile.audioBufferSize" |
||||
:label=" |
||||
$t('edit-ffmpeg-profile.buffer-size') |
||||
" |
||||
:rules="validIntNonZero" |
||||
required |
||||
></v-text-field> |
||||
<v-tooltip v-model="audioBufferSizeShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-text-field |
||||
v-model="newProfile.channels" |
||||
:label="$t('edit-ffmpeg-profile.channels')" |
||||
:rules="validIntNonZero" |
||||
required |
||||
></v-text-field> |
||||
<v-tooltip v-model="audioChannelsShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-text-field |
||||
v-model="newProfile.audioSampleRate" |
||||
:label=" |
||||
$t('edit-ffmpeg-profile.sample-rate') |
||||
" |
||||
:rules="validIntNonZero" |
||||
required |
||||
></v-text-field> |
||||
<v-tooltip v-model="audioSampleRateShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-container |
||||
class="d-flex" |
||||
style="max-height: 80px" |
||||
> |
||||
<v-checkbox |
||||
v-model="normalizeLoudness" |
||||
:label=" |
||||
$t( |
||||
'edit-ffmpeg-profile.normalize-loudness' |
||||
) |
||||
" |
||||
color="green lighten-1" |
||||
required |
||||
></v-checkbox> |
||||
<v-tooltip v-model="normalizeLoudnessShow" top> |
||||
<template v-slot:activator="{ on, attrs }"> |
||||
<v-icon |
||||
class="pl-2" |
||||
color="grey" |
||||
v-ripple="false" |
||||
:retain-focus="false" |
||||
v-bind="attrs" |
||||
v-on="on" |
||||
> |
||||
mdi-help-circle-outline |
||||
</v-icon> |
||||
</template> |
||||
<span>Recommended Thread Count: 0</span> |
||||
</v-tooltip> |
||||
</v-container> |
||||
<v-spacer style="height: 80px"></v-spacer> |
||||
<v-container> |
||||
<v-btn |
||||
color="green lighten-1" |
||||
class="ma-2" |
||||
:disabled="!isFormValid" |
||||
@click="saveFFmpegProfile()" |
||||
> |
||||
{{ $t('edit-ffmpeg-profile.save-profile') }} |
||||
</v-btn> |
||||
<v-btn |
||||
color="cancel" |
||||
class="ma-2" |
||||
@click="cancelAdd()" |
||||
> |
||||
{{ $t('edit-ffmpeg-profile.cancel') }} |
||||
</v-btn> |
||||
<v-btn |
||||
color="indigo accent-1" |
||||
class="ma-2" |
||||
@click="cancelAdd()" |
||||
> |
||||
{{ $t('edit-ffmpeg-profile.help') }} |
||||
</v-btn> |
||||
</v-container> |
||||
</v-flex> |
||||
</v-row> |
||||
</v-container> |
||||
</v-form> |
||||
</v-app> |
||||
</div> |
||||
</template> |
||||
|
||||
<script lang="ts"> |
||||
import { Vue, Component, Watch } from 'vue-property-decorator'; |
||||
import { ffmpegProfileApiService } from '@/services/FFmpegProfileService'; |
||||
|
||||
@Component |
||||
export default class AddEditFFmpegProfile extends Vue { |
||||
//@Name({ default: 'AddEditFFmpegProfile' }) AddEditFFmpegProfile!: string; |
||||
//@Prop({ default: -1 }) private id!: number; |
||||
public newProfile: any = {}; |
||||
private refForm: any = this.$refs.form; |
||||
public isFormValid = false; |
||||
public threadCountShow = false; |
||||
public videoFormatShow = false; |
||||
public videoBitRateShow = false; |
||||
public videoBufferSizeShow = false; |
||||
public hardwareAccelerationShow = false; |
||||
public vaapiDriverShow = false; |
||||
public vaapiDeviceShow = false; |
||||
public normalizeFrameRateShow = false; |
||||
public autoDeinterlaceVideoShow = false; |
||||
public audioFormatShow = false; |
||||
public audioBitRateShow = false; |
||||
public audioBufferSizeShow = false; |
||||
public audioChannelsShow = false; |
||||
public audioSampleRateShow = false; |
||||
public normalizeLoudnessShow = false; |
||||
|
||||
public AddEditFFmpegProfile() { |
||||
console.log('test'); |
||||
} |
||||
|
||||
public audioFormats: [ |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string } |
||||
] = [ |
||||
{ id: 1, name: 'aac' }, |
||||
{ id: 2, name: 'ac3' } |
||||
]; |
||||
|
||||
private _selectedAudioFormat: number = 2; |
||||
public selectedAudioFormat: { id: number; name: string } = { |
||||
id: 2, |
||||
name: 'ac3' |
||||
}; |
||||
|
||||
public preferredResolutions: [ |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string } |
||||
] = [ |
||||
{ id: 0, name: '720x480' }, |
||||
{ id: 1, name: '1280x720' }, |
||||
{ id: 2, name: '1920x1080' }, |
||||
{ id: 3, name: '3840x2160' } |
||||
]; |
||||
|
||||
private _selectedResolution: number = 2; |
||||
public selectedResolution: { id: number; name: string } = { |
||||
id: 2, |
||||
name: '1920x1080' |
||||
}; |
||||
|
||||
public videoFormats: [ |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string } |
||||
] = [ |
||||
{ id: 1, name: 'h264' }, |
||||
{ id: 2, name: 'hevc' }, |
||||
{ id: 3, name: 'mpeg-2' } |
||||
]; |
||||
|
||||
private _selectedVideoFormat: number = 1; |
||||
public selectedVideoFormat: { id: number; name: string } = { |
||||
id: 1, |
||||
name: 'h264' |
||||
}; |
||||
|
||||
public hardwareAccelerations: [ |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string } |
||||
] = [ |
||||
{ id: 0, name: 'None' }, |
||||
{ id: 1, name: 'Qsv' }, |
||||
{ id: 2, name: 'Nvenc' }, |
||||
{ id: 3, name: 'Vaapi' }, |
||||
{ id: 4, name: 'VideoToolbox' } |
||||
]; |
||||
|
||||
private _selectedHardwareAcceleration: number = 0; |
||||
public selectedHardwareAcceleration: { id: number; name: string } = { |
||||
id: 0, |
||||
name: 'None' |
||||
}; |
||||
|
||||
public vaapiDrivers: [ |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string }, |
||||
{ id: number; name: string } |
||||
] = [ |
||||
{ id: 0, name: 'Default' }, |
||||
{ id: 1, name: 'iHD' }, |
||||
{ id: 2, name: 'i965' }, |
||||
{ id: 3, name: 'RadeonSI' }, |
||||
{ id: 4, name: 'Nouveau' } |
||||
]; |
||||
|
||||
public vaapiDriverDisabled = true; |
||||
private _selectedVaapiDriver: number = 0; |
||||
public selectedVaapiDriver: { id: number; name: string } = { |
||||
id: 0, |
||||
name: 'Default' |
||||
}; |
||||
|
||||
public selectedVaapiDevice: string = ''; |
||||
public vaapiDevices: [string, string] = ['', '/dev/dri/renderD128']; |
||||
|
||||
public normalizeFrameRate: boolean = false; |
||||
public autoDeinterlaceVideo: boolean = true; |
||||
public normalizeLoudness: boolean = true; |
||||
|
||||
saveFFmpegProfile() { |
||||
//this means we're adding |
||||
if (isNaN(this.id)) { |
||||
ffmpegProfileApiService.newFFmpegProfile( |
||||
this.newProfile.name, |
||||
this.threadCount, |
||||
this._selectedHardwareAcceleration, |
||||
this._selectedVaapiDriver, |
||||
this.selectedVaapiDevice, |
||||
this._selectedResolution, |
||||
this._selectedVideoFormat, |
||||
this.newProfile.videoBitRate, |
||||
this.newProfile.videoBufferSize, |
||||
this._selectedAudioFormat, |
||||
this.newProfile.audioBitRate, |
||||
this.newProfile.audioBufferSize, |
||||
this.normalizeLoudness, |
||||
this.newProfile.channels, |
||||
this.newProfile.audioSampleRate, |
||||
this.normalizeFrameRate, |
||||
this.autoDeinterlaceVideo |
||||
); |
||||
} else { |
||||
//this means we're editing |
||||
ffmpegProfileApiService.updateFFmpegProfile( |
||||
this.id, |
||||
this.newProfile.name, |
||||
this.threadCount, |
||||
this._selectedHardwareAcceleration, |
||||
this._selectedVaapiDriver, |
||||
this.selectedVaapiDevice, |
||||
this._selectedResolution, |
||||
this._selectedVideoFormat, |
||||
this.newProfile.videoBitRate, |
||||
this.newProfile.videoBufferSize, |
||||
this._selectedAudioFormat, |
||||
this.newProfile.audioBitRate, |
||||
this.newProfile.audioBufferSize, |
||||
this.normalizeLoudness, |
||||
this.newProfile.channels, |
||||
this.newProfile.audioSampleRate, |
||||
this.normalizeFrameRate, |
||||
this.autoDeinterlaceVideo |
||||
); |
||||
} |
||||
const Toast = this.$swal.mixin({ |
||||
toast: true, |
||||
position: 'top-end', |
||||
showConfirmButton: false, |
||||
timer: 3000, |
||||
timerProgressBar: true, |
||||
didOpen: (toast) => { |
||||
toast.addEventListener('mouseenter', this.$swal.stopTimer); |
||||
toast.addEventListener('mouseleave', this.$swal.resumeTimer); |
||||
} |
||||
}); |
||||
|
||||
Toast.fire({ |
||||
icon: 'success', |
||||
title: this.$t('edit-ffmpeg-profile.profile-saved').toString() |
||||
}); |
||||
this.$router.push({ |
||||
name: 'ffmpeg-profiles.title' |
||||
}); |
||||
} |
||||
|
||||
cancelAdd() { |
||||
this.$router.push({ |
||||
name: 'ffmpeg-profiles.title' |
||||
}); |
||||
} |
||||
|
||||
//~change events~// |
||||
public audioFormatChanged(selectObj: number) { |
||||
this._selectedAudioFormat = selectObj; |
||||
} |
||||
|
||||
public preferredResolutionChange(selectObj: number) { |
||||
this._selectedResolution = selectObj + 1; |
||||
} |
||||
|
||||
public videoFormatChanged(selectObj: number) { |
||||
this._selectedVideoFormat = selectObj; |
||||
} |
||||
|
||||
public hardwareAccelerationChanged(selectObj: number) { |
||||
this._selectedHardwareAcceleration = selectObj; |
||||
this.applyVaapiValidation(); |
||||
} |
||||
|
||||
public applyVaapiValidation() { |
||||
//If they pick VAAPI as the hardware acceleration, |
||||
//they can now choose a vaapi driver and device. |
||||
//If not, they cannot change the default options. |
||||
if (this._selectedHardwareAcceleration == 3) { |
||||
this.vaapiDriverDisabled = false; |
||||
} else { |
||||
this.vaapiDriverDisabled = true; |
||||
this._selectedVaapiDriver = 0; |
||||
this.selectedVaapiDriver = { id: 0, name: 'Default' }; |
||||
this.selectedVaapiDevice = ''; |
||||
} |
||||
} |
||||
|
||||
public vaapiDriverChanged(selectObj: number) { |
||||
this._selectedVaapiDriver = selectObj; |
||||
} |
||||
|
||||
public vaapiDeviceChanged(selectObj: string) { |
||||
this.selectedVaapiDevice = selectObj; |
||||
} |
||||
|
||||
//~ end change events~// |
||||
|
||||
public threadCount = 0; |
||||
|
||||
get validIntNonZero() { |
||||
return [ |
||||
(v: any) => |
||||
(v && /^[0-9]+$/.test(v)) || this.$t('Must be a valid number.'), |
||||
(v: any) => (v && v > 0) || 'Must be greater than 0.' |
||||
]; |
||||
} |
||||
|
||||
get validInt() { |
||||
return [ |
||||
(v: any) => |
||||
(v && /^[0-9]+$/.test(v)) || this.$t('Must be a valid number.') |
||||
]; |
||||
} |
||||
|
||||
get textRules() { |
||||
return [(v: any) => (v && v.length > 0) || 'Value must not be empty.']; |
||||
} |
||||
|
||||
props!: { id: number }; |
||||
@Watch('id', { immediate: true }) async onItemChanged() { |
||||
console.log('ID', this.id); |
||||
this.id = Number(this.$route.query.id) ?? -1; |
||||
await this.loadPage(); |
||||
} |
||||
|
||||
private loaded = false; |
||||
private id = -1; |
||||
|
||||
title: string = 'Modify FFmpeg Profile'; |
||||
|
||||
async loadPage(): Promise<void> { |
||||
if (this.loaded) { |
||||
return; |
||||
} |
||||
var title = document.getElementById('title'); |
||||
if (title === null || title === undefined) { |
||||
//sometimes the element isn't loaded yet, it'll come |
||||
//back to this when it's good to go. So skip for now. |
||||
return; |
||||
} |
||||
if (!isNaN(this.id)) { |
||||
title.innerHTML = this.$t( |
||||
'edit-ffmpeg-profile.edit-profile' |
||||
).toString(); |
||||
var ffmpegFullProfile = await ffmpegProfileApiService.getOne( |
||||
this.id.toString() |
||||
); |
||||
var result = ffmpegFullProfile[0]; |
||||
if (result !== undefined) { |
||||
//We have a profile, let's load it. |
||||
this.threadCount = result.threadCount; |
||||
this.selectedVaapiDevice = result.vaapiDevice; |
||||
this.autoDeinterlaceVideo = result.deinterlaceVideo; |
||||
this.normalizeFrameRate = result.normalizeFramerate; |
||||
this.normalizeLoudness = result.normalizeLoudness; |
||||
this.newProfile = { |
||||
name: result.name, |
||||
videoBitRate: result.videoBitrate, |
||||
videoBufferSize: result.videoBufferSize, |
||||
audioBitRate: result.audioBitrate, |
||||
audioBufferSize: result.audioBufferSize, |
||||
channels: result.audioChannels, |
||||
audioSampleRate: result.audioSampleRate |
||||
}; |
||||
|
||||
this._selectedAudioFormat = result.audioFormat; |
||||
this.selectedAudioFormat = |
||||
this.audioFormats[result.audioFormat - 1]; |
||||
this._selectedVideoFormat = result.videoFormat; |
||||
this.selectedVideoFormat = |
||||
this.videoFormats[result.videoFormat - 1]; |
||||
this._selectedResolution = result.resolutionId; |
||||
this.selectedResolution = |
||||
this.preferredResolutions[result.resolutionId - 1]; |
||||
this._selectedHardwareAcceleration = |
||||
result.hardwareAcceleration; |
||||
this.selectedHardwareAcceleration = |
||||
this.hardwareAccelerations[result.hardwareAcceleration]; |
||||
this._selectedVaapiDriver = result.vaapiDriver; |
||||
this.selectedVaapiDriver = |
||||
this.vaapiDrivers[result.vaapiDriver]; |
||||
this.applyVaapiValidation(); |
||||
this.loaded = true; |
||||
} else { |
||||
//an ID was entered (probably in the URL) that doesn't exist. Let's returnt to the profile list. |
||||
console.log('No ffmpeg profile found for ID: ' + this.id); |
||||
this.$router.push({ |
||||
name: 'ffmpeg-profiles.title' |
||||
}); |
||||
} |
||||
} else { |
||||
//new profile! |
||||
title.innerHTML = this.$t( |
||||
'edit-ffmpeg-profile.add-profile' |
||||
).toString(); |
||||
this._selectedAudioFormat = 2; |
||||
this._selectedResolution = 3; |
||||
this._selectedVideoFormat = 1; |
||||
this._selectedHardwareAcceleration = 0; |
||||
this._selectedVaapiDriver = 0; |
||||
this.selectedVaapiDevice = ''; |
||||
this.newProfile = { |
||||
name: 'New Profile', |
||||
videoBitRate: 2000, |
||||
videoBufferSize: 4000, |
||||
audioBitRate: 192, |
||||
audioBufferSize: 384, |
||||
channels: 2, |
||||
audioSampleRate: 48 |
||||
}; |
||||
this.loaded = true; |
||||
} |
||||
} |
||||
} |
||||
</script> |
Loading…
Reference in new issue