import QtQuick
import Konvergo 1.0
import QtWebEngine
import QtWebChannel
import QtQuick.Window
import QtQuick.Controls
import Qt.labs.platform as Labs
Window
{
id: mainWindow
title: "Jellyfin Desktop"
objectName: "mainWindow"
width: 1280
height: 720
minimumWidth: 213
minimumHeight: 120
visible: true
color: "#000000"
// Properties previously from KonvergoWindow
property bool webDesktopMode: true
property bool showDebugLayer: false
property string debugInfo: ""
property string videoInfo: ""
property string webUrl: ""
property bool showSystemTrayIcon: webDesktopMode && components.system.isWindows &&
components.settings.windowsTrayIcon
signal reloadWebClient()
Component.onCompleted: {
if (components && components.settings) {
webUrl = components.settings.getWebClientUrl(webDesktopMode)
}
}
onClosing: function(close) {
if (showSystemTrayIcon) {
// Minimize to tray on close.
close.accepted = false
mainWindow.hide()
}
}
function toggleFullscreen() {
visibility = (visibility === Window.FullScreen) ? Window.Windowed : Window.FullScreen
}
function toggleDebug() {
showDebugLayer = !showDebugLayer
}
function setFullScreen(enable) {
visibility = enable ? Window.FullScreen : Window.Windowed
}
function minimizeWindow() {
if (visibility !== Window.FullScreen)
visibility = Window.Minimized
}
function restoreWindow() {
mainWindow.show()
mainWindow.raise()
mainWindow.requestActivate()
}
function runWebAction(action)
{
if (mainWindow.webDesktopMode)
web.triggerWebAction(action)
}
Action
{
enabled: mainWindow.webDesktopMode
shortcut:
{
if (components.system.isMacos) return "Ctrl+Meta+F"
return "F11"
}
onTriggered: mainWindow.toggleFullscreen()
}
Action
{
shortcut: "Alt+Return"
enabled:
{
if (mainWindow.webDesktopMode && components.system.isWindows)
return true;
return false;
}
onTriggered: mainWindow.toggleFullscreen()
}
Action
{
enabled: mainWindow.webDesktopMode
shortcut: StandardKey.Close
onTriggered: mainWindow.close()
}
Action
{
enabled: mainWindow.webDesktopMode
shortcut: {
if (components.system.isMacos) return "Ctrl+M";
return "Meta+Down";
}
onTriggered: mainWindow.minimizeWindow()
}
Action
{
enabled: mainWindow.webDesktopMode
shortcut: components.system.isWindows ? "Ctrl+Q" : StandardKey.Quit
onTriggered: Qt.quit()
}
Action
{
shortcut: "Ctrl+Shift+D"
enabled: mainWindow.webDesktopMode
onTriggered: mainWindow.toggleDebug()
}
Action
{
shortcut: StandardKey.Copy
onTriggered: runWebAction(WebEngineView.Copy)
id: action_copy
}
Action
{
shortcut: StandardKey.Cut
onTriggered: runWebAction(WebEngineView.Cut)
id: action_cut
}
Action
{
shortcut: StandardKey.Paste
onTriggered: runWebAction(WebEngineView.Paste)
id: action_paste
}
Action
{
shortcut: StandardKey.SelectAll
onTriggered: runWebAction(WebEngineView.SelectAll)
id: action_selectall
}
Action
{
shortcut: StandardKey.Undo
onTriggered: runWebAction(WebEngineView.Undo)
id: action_undo
}
Action
{
shortcut: StandardKey.Redo
onTriggered: runWebAction(WebEngineView.Redo)
id: action_redo
}
Action
{
shortcut: StandardKey.Back
onTriggered: runWebAction(WebEngineView.Back)
id: action_back
}
Action
{
shortcut: StandardKey.Forward
onTriggered: runWebAction(WebEngineView.Forward)
id: action_forward
}
Action
{
enabled: mainWindow.webDesktopMode
shortcut: "Ctrl+0"
onTriggered: web.zoomFactor = 1.0
}
WebChannel
{
id: webChannelObject
}
Binding
{
target: web
property: "zoomFactor"
value: 1.0
when: !components.settings.allowBrowserZoom()
}
MpvVideoItem
{
id: video
objectName: "video"
enabled: true
width: mainWindow.contentItem.width
height: mainWindow.contentItem.height
anchors.left: mainWindow.contentItem.left
anchors.right: mainWindow.contentItem.right
anchors.top: mainWindow.contentItem.top
Component.onCompleted: {
console.log("MpvVideoItem size:", width, "x", height, "visible:", visible)
}
onWidthChanged: console.log("MpvVideoItem width changed:", width)
onHeightChanged: console.log("MpvVideoItem height changed:", height)
}
WebEngineView
{
id: web
objectName: "web"
width: mainWindow.width
height: mainWindow.height
z: 100
backgroundColor: "transparent"
// this is needed to prevent intermittent(?) black screens when unminizing
// or resumsing from suspend (linux/{x11/wayland}, possibly others).
layer.enabled: true
webChannel: webChannelObject
settings.errorPageEnabled: false
settings.localContentCanAccessRemoteUrls: true
settings.localContentCanAccessFileUrls: true
settings.allowRunningInsecureContent: true
settings.playbackRequiresUserGesture: false
profile.httpUserAgent: components.system.getUserAgent()
profile.httpCacheType: WebEngineProfile.DiskHttpCache
url: mainWindow.webUrl
focus: true
property string currentHoveredUrl: ""
onLinkHovered: function(hoveredUrl)
{
web.currentHoveredUrl = hoveredUrl;
}
profile.persistentCookiesPolicy: WebEngineProfile.AllowPersistentCookies
profile.offTheRecord: false
profile.storageName: "JellyfinDesktopStorage"
Component.onCompleted:
{
console.log("WebEngineView size:", width, "x", height, "backgroundColor:", backgroundColor)
forceActiveFocus()
mainWindow.reloadWebClient.connect(reload)
// Handle CSP workaround from C++
components.system.pageContentReady.connect(function(html, finalUrl, hadCSP) {
if (hadCSP) {
console.log("CSP workaround: navigating to", finalUrl);
web.url = finalUrl;
}
})
var nativeshell =
{
sourceCode: components.system.getNativeShellScript(),
injectionPoint: WebEngineScript.DocumentCreation,
worldId: WebEngineScript.MainWorld
}
web.profile.userScripts.collection = [ nativeshell ];
}
onLoadingChanged: function(loadingInfo)
{
// we use a timer here to switch to the webview since
// it take a few moments for the webview to render
// after it has loaded.
//
if (loadingInfo.status == WebEngineView.LoadStartedStatus)
{
console.log("WebEngineLoadRequest starting: " + loadingInfo.url);
}
else if (loadingInfo.status == WebEngineView.LoadSucceededStatus)
{
console.log("WebEngineLoadRequest success: " + loadingInfo.url);
}
else if (loadingInfo.status == WebEngineView.LoadFailedStatus)
{
console.log("WebEngineLoadRequest failure: " + loadingInfo.url + " error code: " + loadingInfo.errorCode);
errorLabel.visible = true
errorLabel.text = "Error loading client, this is bad and should not happen
" +
"You can try to reload or head to our support page
Actual Error:
" +
loadingInfo.errorString + " [" + loadingInfo.errorCode + "]