2023-04-10 06:24:59 +00:00
< template >
< div class = "outer" v-if ="loaded" >
2023-04-10 06:42:23 +00:00
< h2 > { { t ( "memories" , "EXIF Extraction" ) } } < / h2 >
2023-04-10 07:20:17 +00:00
< template v-if ="status" >
< NcNoteCard :type ="binaryStatusType(status.exiftool)" >
{ { binaryStatus ( "exiftool" , status . exiftool ) } }
< / NcNoteCard >
< / template >
2023-04-10 06:42:23 +00:00
< NcTextField
: label = "t('memories', 'Path to packaged exiftool binary')"
: label - visible = "true"
: value = "exiftoolPath"
@ change = "update('exiftoolPath', $event.target.value)"
disabled
/ >
2023-04-10 07:20:17 +00:00
< template v-if ="status" >
< NcNoteCard : type = "binaryStatusType(status.perl, false)" >
{ { binaryStatus ( "perl" , status . perl ) } }
< / NcNoteCard >
< / template >
2023-04-10 06:42:23 +00:00
< NcCheckboxRadioSwitch
: checked . sync = "exiftoolPerl"
@ update : checked = "update('exiftoolPerl')"
type = "switch"
>
{ {
t ( "memories" , "Use system perl (only if packaged binary does not work)" )
} }
< / NcCheckboxRadioSwitch >
< h2 > { { t ( "memories" , "Video Streaming" ) } } < / h2 >
< p >
{ {
t (
"memories" ,
"Live transcoding provides for adaptive streaming of videos using HLS."
)
} }
< br / >
{ {
t (
"memories" ,
2023-04-10 21:33:24 +00:00
"Note that this may be very CPU intensive without hardware acceleration, and transcoding will not be used for external storage."
2023-04-10 06:42:23 +00:00
)
} }
< NcCheckboxRadioSwitch
: checked . sync = "enableTranscoding"
@ update : checked = "update('enableTranscoding')"
type = "switch"
>
{ { t ( "memories" , "Enable Transcoding" ) } }
< / NcCheckboxRadioSwitch >
2023-04-10 07:20:17 +00:00
< template v-if ="status" >
< NcNoteCard :type ="binaryStatusType(status.ffmpeg)" >
{ { binaryStatus ( "ffmpeg" , status . ffmpeg ) } }
< / NcNoteCard >
< NcNoteCard :type ="binaryStatusType(status.ffprobe)" >
{ { binaryStatus ( "ffprobe" , status . ffprobe ) } }
< / NcNoteCard >
< / template >
2023-04-10 06:42:23 +00:00
< NcTextField
: label = "t('memories', 'ffmpeg path')"
: label - visible = "true"
: value = "ffmpegPath"
@ change = "update('ffmpegPath', $event.target.value)"
/ >
< NcTextField
: label = "t('memories', 'ffprobe path')"
: label - visible = "true"
: value = "ffprobePath"
@ change = "update('ffprobePath', $event.target.value)"
/ >
< br / >
{ { t ( "memories" , "Global default video quality (user may override)" ) } }
< NcCheckboxRadioSwitch
: checked . sync = "videoDefaultQuality"
value = "0"
name = "vdq_radio"
type = "radio"
@ update : checked = "update('videoDefaultQuality')"
> { { t ( "memories" , "Auto (adaptive transcode)" ) } }
< / NcCheckboxRadioSwitch >
< NcCheckboxRadioSwitch
: checked . sync = "videoDefaultQuality"
value = "-1"
name = "vdq_radio"
type = "radio"
@ update : checked = "update('videoDefaultQuality')"
> { { t ( "memories" , "Original (transcode with max quality)" ) } }
< / NcCheckboxRadioSwitch >
< NcCheckboxRadioSwitch
: checked . sync = "videoDefaultQuality"
value = "-2"
name = "vdq_radio"
type = "radio"
@ update : checked = "update('videoDefaultQuality')"
> { { t ( "memories" , "Direct (original video file without transcode)" ) } }
< / NcCheckboxRadioSwitch >
< / p >
< h3 > { { t ( "memories" , "Transcoder configuration" ) } } < / h3 >
< p >
{ {
t (
"memories" ,
"Memories uses the go-vod transcoder. You can run go-vod exernally (e.g. in a separate Docker container for hardware acceleration) or use the built-in transcoder. To use an external transcoder, enable the following option and follow the instructions at this link:"
)
} }
< a
target = "_blank"
href = "https://github.com/pulsejet/memories/wiki/HW-Transcoding"
>
{ { t ( "memories" , "external transcoder configuration" ) } }
< / a >
2023-04-10 07:20:17 +00:00
< template v-if ="status" >
< NcNoteCard :type ="binaryStatusType(status.govod)" >
{ { binaryStatus ( "go-vod" , status . govod ) } }
< / NcNoteCard >
< / template >
2023-04-10 06:42:23 +00:00
< NcCheckboxRadioSwitch
: checked . sync = "enableExternalTranscoder"
@ update : checked = "update('enableExternalTranscoder')"
type = "switch"
>
{ { t ( "memories" , "Enable external transcoder (go-vod)" ) } }
< / NcCheckboxRadioSwitch >
< NcTextField
: label = "t('memories', 'Binary path (local only)')"
: label - visible = "true"
: value = "goVodPath"
@ change = "update('goVodPath', $event.target.value)"
/ >
< NcTextField
: label = "t('memories', 'Bind address (local only)')"
: label - visible = "true"
: value = "goVodBind"
@ change = "update('goVodBind', $event.target.value)"
/ >
< NcTextField
: label = "t('memories', 'Connection address (same as bind if local)')"
: label - visible = "true"
: value = "goVodConnect"
@ change = "update('goVodConnect', $event.target.value)"
/ >
< / p >
< h3 > { { t ( "memories" , "Hardware Acceleration" ) } } < / h3 >
< p >
{ {
t (
"memories" ,
"You must first make sure the correct drivers are installed before configuring acceleration."
)
} }
< br / >
{ {
t (
"memories" ,
"Make sure you test hardware acceleration with various options after enabling."
)
} }
< br / >
{ {
t (
"memories" ,
"Do not enable multiple types of hardware acceleration simultaneously."
)
} }
< br / >
< br / >
{ {
t (
"memories" ,
"Intel processors supporting QuickSync Video (QSV) as well as some AMD GPUs can be used for transcoding using VA-API acceleration."
)
} }
{ {
t (
"memories" ,
"For more details on driver installation, check the following link:"
)
} }
< a
target = "_blank"
href = "https://github.com/pulsejet/memories/wiki/HW-Transcoding#va-api"
>
VA - API configuration
< / a >
2023-04-10 07:20:17 +00:00
< NcNoteCard :type ="vaapiStatusType()" v-if ="status" >
{ { vaapiStatusText ( ) } }
2023-04-10 06:42:23 +00:00
< / NcNoteCard >
< NcCheckboxRadioSwitch
: checked . sync = "enableVaapi"
@ update : checked = "update('enableVaapi')"
type = "switch"
>
{ { t ( "memories" , "Enable acceleration with VA-API" ) } }
< / NcCheckboxRadioSwitch >
< NcCheckboxRadioSwitch
: checked . sync = "enableVaapiLowPower"
@ update : checked = "update('enableVaapiLowPower')"
type = "switch"
>
{ { t ( "memories" , "Enable low-power mode (QSV)" ) } }
< / NcCheckboxRadioSwitch >
{ {
t (
"memories" ,
"NVIDIA GPUs can be used for transcoding using the NVENC encoder with the proper drivers."
)
} }
< br / >
{ {
t (
"memories" ,
"Depending on the versions of the installed SDK and ffmpeg, you need to specify the scaler to use"
)
} }
< NcNoteCard type = "warning" >
2023-04-10 06:24:59 +00:00
{ {
t (
"memories" ,
2023-04-10 06:42:23 +00:00
"No automated tests are available for NVIDIA acceleration."
2023-04-10 06:24:59 +00:00
)
} }
2023-04-10 06:42:23 +00:00
< / NcNoteCard >
< NcCheckboxRadioSwitch
: checked . sync = "enableNvenc"
@ update : checked = "update('enableNvenc')"
type = "switch"
>
{ { t ( "memories" , "Enable acceleration with NVENC" ) } }
< / NcCheckboxRadioSwitch >
< NcCheckboxRadioSwitch
: checked . sync = "enableNvencTemporalAQ"
@ update : checked = "update('enableNvencTemporalAQ')"
type = "switch"
>
{ { t ( "memories" , "Enable NVENC Temporal AQ" ) } }
< / NcCheckboxRadioSwitch >
< NcCheckboxRadioSwitch
: checked . sync = "nvencScaler"
value = "npp"
name = "nvence_scaler_radio"
type = "radio"
@ update : checked = "update('nvencScaler')"
class = "m-radio"
> { { t ( "memories" , "NPP scaler" ) } }
< / NcCheckboxRadioSwitch >
< NcCheckboxRadioSwitch
: checked . sync = "nvencScaler"
value = "cuda"
name = "nvence_scaler_radio"
type = "radio"
class = "m-radio"
@ update : checked = "update('nvencScaler')"
> { { t ( "memories" , "CUDA scaler" ) } }
< / NcCheckboxRadioSwitch >
< / p >
2023-04-10 06:24:59 +00:00
< / div >
< / template >
< script lang = "ts" >
import { defineComponent } from "vue" ;
import axios from "@nextcloud/axios" ;
import { API } from "./services/API" ;
import { showError } from "@nextcloud/dialogs" ;
const NcCheckboxRadioSwitch = ( ) =>
import ( "@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch" ) ;
const NcNoteCard = ( ) => import ( "@nextcloud/vue/dist/Components/NcNoteCard" ) ;
const NcTextField = ( ) => import ( "@nextcloud/vue/dist/Components/NcTextField" ) ;
/** Map from UI to backend settings */
const settings = {
2023-04-10 06:42:23 +00:00
exiftoolPath : "memories.exiftool" ,
exiftoolPerl : "memories.exiftool_no_local" ,
2023-04-10 06:24:59 +00:00
enableTranscoding : "memories.vod.disable" ,
ffmpegPath : "memories.vod.ffmpeg" ,
ffprobePath : "memories.vod.ffprobe" ,
goVodPath : "memories.vod.path" ,
goVodBind : "memories.vod.bind" ,
goVodConnect : "memories.vod.connect" ,
enableExternalTranscoder : "memories.vod.external" ,
videoDefaultQuality : "memories.video_default_quality" ,
enableVaapi : "memories.vod.vaapi" ,
enableVaapiLowPower : "memories.vod.vaapi.low_power" ,
enableNvenc : "memories.vod.nvenc" ,
enableNvencTemporalAQ : "memories.vod.nvenc.temporal_aq" ,
nvencScaler : "memories.vod.nvenc.scale" ,
} ;
/** Invert setting before saving */
const invertedBooleans = [ "enableTranscoding" ] ;
2023-04-10 07:28:23 +00:00
type BinaryStatus = "ok" | "not_found" | "not_executable" | "test_ok" | string ;
2023-04-10 07:20:17 +00:00
type IStatus = {
exiftool : BinaryStatus ;
perl : BinaryStatus ;
ffmpeg : BinaryStatus ;
ffprobe : BinaryStatus ;
govod : BinaryStatus ;
vaapi _dev : "ok" | "not_found" | "not_readable" ;
} ;
2023-04-10 06:24:59 +00:00
export default defineComponent ( {
name : "Admin" ,
components : {
NcCheckboxRadioSwitch ,
NcNoteCard ,
NcTextField ,
} ,
data : ( ) => ( {
loaded : false ,
2023-04-10 06:42:23 +00:00
exiftoolPath : "" ,
exiftoolPerl : false ,
2023-04-10 06:24:59 +00:00
enableTranscoding : false ,
ffmpegPath : "" ,
ffprobePath : "" ,
goVodPath : "" ,
goVodBind : "" ,
goVodConnect : "" ,
enableExternalTranscoder : false ,
videoDefaultQuality : "" ,
enableVaapi : false ,
enableVaapiLowPower : false ,
enableNvenc : false ,
enableNvencTemporalAQ : false ,
nvencScaler : "" ,
2023-04-10 07:20:17 +00:00
status : null as IStatus ,
2023-04-10 06:24:59 +00:00
} ) ,
mounted ( ) {
this . reload ( ) ;
2023-04-10 07:20:17 +00:00
this . refreshStatus ( ) ;
2023-04-10 06:24:59 +00:00
} ,
methods : {
async reload ( ) {
const res = await axios . get ( API . SYSTEM _CONFIG ( null ) ) ;
for ( const key in settings ) {
if ( ! res . data . hasOwnProperty ( settings [ key ] ) ) {
console . error (
` Setting ${ settings [ key ] } not found in backend response `
) ;
continue ;
}
this [ key ] = res . data [ settings [ key ] ] ;
if ( invertedBooleans . includes ( key ) ) {
this [ key ] = ! this [ key ] ;
}
}
this . loaded = true ;
} ,
2023-04-10 07:20:17 +00:00
async refreshStatus ( ) {
const res = await axios . get ( API . SYSTEM _STATUS ( ) ) ;
this . status = res . data ;
} ,
2023-04-10 06:24:59 +00:00
async update ( key : string , value = null ) {
2023-04-10 21:32:35 +00:00
value = value ? ? this [ key ] ;
2023-04-10 06:24:59 +00:00
const setting = settings [ key ] ;
// Inversion
if ( invertedBooleans . includes ( key ) ) {
value = ! value ;
}
axios
. put ( API . SYSTEM _CONFIG ( setting ) , {
value : value ,
} )
. catch ( ( err ) => {
console . error ( err ) ;
showError ( this . t ( "memories" , "Failed to update setting" ) ) ;
} ) ;
} ,
2023-04-10 07:20:17 +00:00
binaryStatus ( name : string , status : BinaryStatus ) : string {
if ( status === "ok" ) {
return this . t ( "memories" , "{name} binary exists and is executable" , {
name ,
} ) ;
} else if ( status === "not_found" ) {
return this . t ( "memories" , "{name} binary not found" , { name } ) ;
} else if ( status === "not_executable" ) {
return this . t ( "memories" , "{name} binary is not executable" , {
name ,
} ) ;
2023-04-10 07:28:23 +00:00
} else if ( status . startsWith ( "test_fail" ) ) {
return this . t (
"memories" ,
2023-04-10 21:01:29 +00:00
"{name} failed test: {info}" ,
2023-04-10 07:28:23 +00:00
{
name ,
info : status . substring ( 10 ) ,
} ,
0 ,
{
escape : false ,
sanitize : false ,
}
) ;
2023-04-10 07:20:17 +00:00
} else if ( status === "test_ok" ) {
return this . t ( "memories" , "{name} binary exists and is usable" , {
name ,
} ) ;
} else {
return this . t ( "memories" , "{name} binary status: {status}" , {
name ,
status ,
} ) ;
}
} ,
binaryStatusType ( status : BinaryStatus , critical = true ) : string {
if ( status === "ok" || status === "test_ok" ) {
return "success" ;
} else if (
status === "not_found" ||
status === "not_executable" ||
2023-04-10 07:28:23 +00:00
status . startsWith ( "test_fail" )
2023-04-10 07:20:17 +00:00
) {
return critical ? "error" : "warning" ;
} else {
return "warning" ;
}
} ,
vaapiStatusText ( ) : string {
const dev = "/dev/dri/renderD128" ;
if ( this . status . vaapi _dev === "ok" ) {
return this . t ( "memories" , "VA-API device ({dev}) is readable" , { dev } ) ;
} else if ( this . status . vaapi _dev === "not_found" ) {
return this . t ( "memories" , "VA-API device ({dev}) not found" , { dev } ) ;
} else if ( this . status . vaapi _dev === "not_readable" ) {
return this . t (
"memories" ,
"VA-API device ({dev}) has incorrect permissions" ,
{ dev }
) ;
} else {
return this . t ( "memories" , "VA-API device status: {status}" , {
status : this . status . vaapi _dev ,
} ) ;
}
} ,
vaapiStatusType ( ) : string {
return this . status . vaapi _dev === "ok" ? "success" : "error" ;
} ,
2023-04-10 06:24:59 +00:00
} ,
} ) ;
< / script >
< style lang = "scss" scoped >
. outer {
padding : 20 px ;
2023-04-10 06:42:23 +00:00
padding - top : 0 px ;
2023-04-10 06:24:59 +00:00
. checkbox - radio - switch {
margin : 2 px 8 px ;
}
. m - radio {
display : inline - block ;
}
h2 {
font - size : 1.5 em ;
font - weight : bold ;
2023-04-10 06:42:23 +00:00
margin - top : 25 px ;
2023-04-10 06:24:59 +00:00
}
h3 {
font - size : 1.2 em ;
font - weight : 500 ;
margin - top : 20 px ;
}
a {
color : var ( -- color - primary - element ) ;
}
}
< / style >