mirror of
https://github.com/jellyfin/jellyfin-server-macos.git
synced 2024-11-23 05:59:39 +00:00
redo app
This commit is contained in:
parent
9e28d05d87
commit
5975c83354
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objectVersion = 52;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -11,6 +11,14 @@
|
||||
0919395722C35C1400392D55 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0919395622C35C1400392D55 /* Assets.xcassets */; };
|
||||
0919395A22C35C1400392D55 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0919395822C35C1400392D55 /* Main.storyboard */; };
|
||||
0924531822D5BC7E00B2E710 /* ffmpeg LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = 0924531622D5BC7E00B2E710 /* ffmpeg LICENSE.txt */; };
|
||||
E174A306289B755C0092450E /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = E174A305289B755C0092450E /* LaunchAtLogin */; };
|
||||
E174A312289B84F90092450E /* PreferencesViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E174A311289B84F90092450E /* PreferencesViewController.storyboard */; };
|
||||
E174A314289B855C0092450E /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E174A313289B855C0092450E /* PreferencesViewController.swift */; };
|
||||
E174A318289B86820092450E /* PreferencesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E174A317289B86820092450E /* PreferencesWindow.swift */; };
|
||||
E174A31B289B8D700092450E /* ActionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E174A31A289B8D700092450E /* ActionManager.swift */; };
|
||||
E174A31F289B92480092450E /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E174A31E289B92480092450E /* AlertViewController.swift */; };
|
||||
E174A322289B929F0092450E /* AlertViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E174A321289B929F0092450E /* AlertViewController.storyboard */; };
|
||||
E19E5327289B932300A94983 /* AlertWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E5326289B932300A94983 /* AlertWindow.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@ -33,6 +41,13 @@
|
||||
0924531622D5BC7E00B2E710 /* ffmpeg LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "ffmpeg LICENSE.txt"; sourceTree = "<group>"; };
|
||||
09A23D5B2468FB9B0071B5A9 /* Jellyfin Server.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Jellyfin Server.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
09A23D5C2468FBAB0071B5A9 /* Server.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Server.entitlements; sourceTree = "<group>"; };
|
||||
E174A311289B84F90092450E /* PreferencesViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PreferencesViewController.storyboard; sourceTree = "<group>"; };
|
||||
E174A313289B855C0092450E /* PreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = "<group>"; };
|
||||
E174A317289B86820092450E /* PreferencesWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindow.swift; sourceTree = "<group>"; };
|
||||
E174A31A289B8D700092450E /* ActionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionManager.swift; sourceTree = "<group>"; };
|
||||
E174A31E289B92480092450E /* AlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = "<group>"; };
|
||||
E174A321289B929F0092450E /* AlertViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = AlertViewController.storyboard; sourceTree = "<group>"; };
|
||||
E19E5326289B932300A94983 /* AlertWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertWindow.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -40,6 +55,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E174A306289B755C0092450E /* LaunchAtLogin in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -60,6 +76,9 @@
|
||||
children = (
|
||||
09A23D5C2468FBAB0071B5A9 /* Server.entitlements */,
|
||||
0919395222C35C1400392D55 /* AppDelegate.swift */,
|
||||
E174A31A289B8D700092450E /* ActionManager.swift */,
|
||||
E174A320289B926C0092450E /* AlertWindow */,
|
||||
E174A319289B8D520092450E /* PreferencesWindow */,
|
||||
0919395622C35C1400392D55 /* Assets.xcassets */,
|
||||
0919395822C35C1400392D55 /* Main.storyboard */,
|
||||
0919395B22C35C1400392D55 /* Info.plist */,
|
||||
@ -67,6 +86,26 @@
|
||||
path = "Jellyfin Server";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E174A319289B8D520092450E /* PreferencesWindow */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E174A317289B86820092450E /* PreferencesWindow.swift */,
|
||||
E174A313289B855C0092450E /* PreferencesViewController.swift */,
|
||||
E174A311289B84F90092450E /* PreferencesViewController.storyboard */,
|
||||
);
|
||||
path = PreferencesWindow;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E174A320289B926C0092450E /* AlertWindow */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E19E5326289B932300A94983 /* AlertWindow.swift */,
|
||||
E174A31E289B92480092450E /* AlertViewController.swift */,
|
||||
E174A321289B929F0092450E /* AlertViewController.storyboard */,
|
||||
);
|
||||
path = AlertWindow;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -84,6 +123,9 @@
|
||||
dependencies = (
|
||||
);
|
||||
name = "Jellyfin Server";
|
||||
packageProductDependencies = (
|
||||
E174A305289B755C0092450E /* LaunchAtLogin */,
|
||||
);
|
||||
productName = Server;
|
||||
productReference = 09A23D5B2468FB9B0071B5A9 /* Jellyfin Server.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@ -120,6 +162,9 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = 0919394622C35C1300392D55;
|
||||
packageReferences = (
|
||||
E174A304289B755C0092450E /* XCRemoteSwiftPackageReference "LaunchAtLogin" */,
|
||||
);
|
||||
productRefGroup = 0919394622C35C1300392D55;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@ -135,7 +180,9 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0924531822D5BC7E00B2E710 /* ffmpeg LICENSE.txt in Resources */,
|
||||
E174A322289B929F0092450E /* AlertViewController.storyboard in Resources */,
|
||||
0919395722C35C1400392D55 /* Assets.xcassets in Resources */,
|
||||
E174A312289B84F90092450E /* PreferencesViewController.storyboard in Resources */,
|
||||
0919395A22C35C1400392D55 /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -147,7 +194,12 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E19E5327289B932300A94983 /* AlertWindow.swift in Sources */,
|
||||
0919395322C35C1400392D55 /* AppDelegate.swift in Sources */,
|
||||
E174A318289B86820092450E /* PreferencesWindow.swift in Sources */,
|
||||
E174A314289B855C0092450E /* PreferencesViewController.swift in Sources */,
|
||||
E174A31F289B92480092450E /* AlertViewController.swift in Sources */,
|
||||
E174A31B289B8D700092450E /* ActionManager.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -285,10 +337,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "Jellyfin Server/Server.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = 6YC6EAV7ES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = "Jellyfin Server/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -299,7 +351,7 @@
|
||||
MARKETING_VERSION = 10.5.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = Jellyfin.Server;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = JellyfinMacProvision;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
@ -309,10 +361,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "Jellyfin Server/Server.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = 6YC6EAV7ES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
INFOPLIST_FILE = "Jellyfin Server/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
@ -323,7 +375,7 @@
|
||||
MARKETING_VERSION = 10.5.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = Jellyfin.Server;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = JellyfinMacProvision;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
@ -350,6 +402,25 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
E174A304289B755C0092450E /* XCRemoteSwiftPackageReference "LaunchAtLogin" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/sindresorhus/LaunchAtLogin";
|
||||
requirement = {
|
||||
branch = main;
|
||||
kind = branch;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
E174A305289B755C0092450E /* LaunchAtLogin */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = E174A304289B755C0092450E /* XCRemoteSwiftPackageReference "LaunchAtLogin" */;
|
||||
productName = LaunchAtLogin;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 0919394722C35C1300392D55 /* Project object */;
|
||||
}
|
||||
|
46
Jellyfin Server/ActionManager.swift
Normal file
46
Jellyfin Server/ActionManager.swift
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppKit
|
||||
|
||||
enum ActionManager {
|
||||
|
||||
static let shareFolder: URL = {
|
||||
FileManager.default.homeDirectoryForCurrentUser
|
||||
.appendingPathComponent(".local/share")
|
||||
}()
|
||||
|
||||
static func launchWebUI() {
|
||||
NSWorkspace.shared.open(.init(string: "http://localhost:8096")!)
|
||||
}
|
||||
|
||||
static func showLogs() {
|
||||
let logFolder = shareFolder.appendingPathComponent("jellyfin/log")
|
||||
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: logFolder.path)
|
||||
}
|
||||
|
||||
static func launchAbout() {
|
||||
NSWorkspace.shared.open(.init(string: "https://jellyfin.org")!)
|
||||
}
|
||||
|
||||
static func restart() {
|
||||
let task = Process()
|
||||
task.launchPath = "/bin/sh"
|
||||
task.arguments = ["-c", "sleep 2; open \"\(Bundle.main.bundlePath)\""]
|
||||
task.launch()
|
||||
|
||||
NSApp.terminate(self)
|
||||
exit(0)
|
||||
}
|
||||
|
||||
static func terminateWithError() {
|
||||
NSApp.terminate(self)
|
||||
exit(1)
|
||||
}
|
||||
}
|
60
Jellyfin Server/AlertWindow/AlertViewController.storyboard
Normal file
60
Jellyfin Server/AlertWindow/AlertViewController.storyboard
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="20037"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Alert View Controller-->
|
||||
<scene sceneID="PEd-7d-5j0">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="AlertViewController" id="bU7-R8-ocO" customClass="AlertViewController" customModule="Jellyfin_Server" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="tOy-S4-hL0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="356" height="76"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fdY-Da-lII">
|
||||
<rect key="frame" x="111" y="3" width="134" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="120" id="r62-wU-Ttb"/>
|
||||
<constraint firstAttribute="height" constant="20" id="scZ-eY-Uyg"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="Exit" bezelStyle="rounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Png-uI-fVN">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<color key="bezelColor" name="linkColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<action selector="exitSelected:" target="bU7-R8-ocO" id="fhS-Ze-Fpf"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="XLz-Rj-HcW">
|
||||
<rect key="frame" x="18" y="50" width="320" height="16"/>
|
||||
<textFieldCell key="cell" selectable="YES" alignment="center" title="Error" id="sZe-fP-Ack">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="XLz-Rj-HcW" firstAttribute="top" secondItem="tOy-S4-hL0" secondAttribute="top" constant="10" id="DeW-Aw-WxI"/>
|
||||
<constraint firstAttribute="trailing" secondItem="XLz-Rj-HcW" secondAttribute="trailing" constant="20" id="Dme-Ed-gzb"/>
|
||||
<constraint firstAttribute="bottom" secondItem="fdY-Da-lII" secondAttribute="bottom" constant="10" id="OAI-ie-nUf"/>
|
||||
<constraint firstItem="fdY-Da-lII" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="aA3-Kr-sGp"/>
|
||||
<constraint firstItem="XLz-Rj-HcW" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="kI9-sR-LeJ"/>
|
||||
<constraint firstItem="fdY-Da-lII" firstAttribute="top" secondItem="XLz-Rj-HcW" secondAttribute="bottom" constant="20" id="os9-F6-xid"/>
|
||||
<constraint firstItem="XLz-Rj-HcW" firstAttribute="leading" secondItem="tOy-S4-hL0" secondAttribute="leading" constant="20" id="xhS-PT-ux0"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="errorLabel" destination="XLz-Rj-HcW" id="bcD-0u-mgC"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="9uD-mB-xHs" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="12" y="67"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
19
Jellyfin Server/AlertWindow/AlertViewController.swift
Normal file
19
Jellyfin Server/AlertWindow/AlertViewController.swift
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
class AlertViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var errorLabel: NSTextField!
|
||||
|
||||
@IBAction func exitSelected(_ sender: Any) {
|
||||
view.window?.windowController?.close()
|
||||
ActionManager.terminateWithError()
|
||||
}
|
||||
}
|
28
Jellyfin Server/AlertWindow/AlertWindow.swift
Normal file
28
Jellyfin Server/AlertWindow/AlertWindow.swift
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// AlertWindow.swift
|
||||
// Jellyfin Server
|
||||
//
|
||||
// Created by Ethan Pippin on 8/3/22.
|
||||
// Copyright © 2022 Jellyfin. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
class AlertWindow: NSWindow {
|
||||
|
||||
convenience init(text: String) {
|
||||
let storyboard = NSStoryboard(name: "AlertViewController", bundle: nil)
|
||||
let alertViewController = storyboard.instantiateController(withIdentifier: "AlertViewController") as! AlertViewController
|
||||
|
||||
self.init(contentViewController: alertViewController)
|
||||
|
||||
alertViewController.errorLabel.stringValue = text
|
||||
|
||||
styleMask.remove(.fullScreen)
|
||||
styleMask.remove(.miniaturizable)
|
||||
styleMask.remove(.resizable)
|
||||
titlebarAppearsTransparent = true
|
||||
title = ""
|
||||
level = .floating
|
||||
}
|
||||
}
|
@ -1,89 +1,109 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// Server
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Created by Anthony Lavado on 2019-06-26.
|
||||
// Copyright © 2019 Anthony Lavado. All rights reserved.
|
||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import AppKit
|
||||
import Cocoa
|
||||
import LaunchAtLogin
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
|
||||
let bundle = Bundle.main
|
||||
var task = Process()
|
||||
|
||||
private let statusItem = NSStatusBar.system.statusItem(withLength:NSStatusItem.squareLength)
|
||||
private var windowController = NSWindowController(window: nil)
|
||||
|
||||
private var jellyfinTask = Process()
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
if let button = statusItem.button {
|
||||
button.image = NSImage(named:NSImage.Name("StatusBarButtonImage"))
|
||||
}
|
||||
statusItem.button?.image = NSImage(named: "StatusBarButtonImage")
|
||||
|
||||
let fileManager = FileManager.default
|
||||
let home = FileManager.default.homeDirectoryForCurrentUser
|
||||
let appFolder = home.appendingPathComponent(".local/share")
|
||||
var isDirectory: ObjCBool = false
|
||||
let folderExists = fileManager.fileExists(atPath: appFolder.path,
|
||||
isDirectory: &isDirectory)
|
||||
if !folderExists || !isDirectory.boolValue {
|
||||
do {
|
||||
|
||||
try fileManager.createDirectory(at: appFolder,
|
||||
withIntermediateDirectories: true,
|
||||
attributes: nil)
|
||||
} catch {
|
||||
// TODO: Add system dialog and stop here. Provide instructions at a link.
|
||||
print("Could not create cache folder. Reason: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
let path = Bundle.main.path(forAuxiliaryExecutable: "jellyfin")
|
||||
let webui = Bundle.main.resourceURL!.appendingPathComponent("jellyfin-web").path
|
||||
|
||||
task.launchPath = path
|
||||
task.arguments = ["--webdir", webui]
|
||||
|
||||
do {
|
||||
try task.run()
|
||||
} catch {
|
||||
// TODO: Add system dialog and stop here. Provide instructions at a link.
|
||||
print("Could not launch Jellyfin. Reason: \(error)")
|
||||
}
|
||||
|
||||
constructMenu()
|
||||
createAppFolder()
|
||||
startJellyfinTask()
|
||||
createStatusBarMenu()
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
task.terminate()
|
||||
task.waitUntilExit()
|
||||
|
||||
print("app will terminate received")
|
||||
jellyfinTask.terminate()
|
||||
jellyfinTask.waitUntilExit()
|
||||
}
|
||||
|
||||
@objc func launchWebUI(sender: Any?) {
|
||||
NSWorkspace.shared.open(NSURL(string: "http://localhost:8096")! as URL)
|
||||
private func createAppFolder() {
|
||||
var isDirectory: ObjCBool = false
|
||||
let shareFolderExists = FileManager.default.fileExists(atPath: ActionManager.shareFolder.path,
|
||||
isDirectory: &isDirectory)
|
||||
|
||||
if !shareFolderExists || !isDirectory.boolValue {
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: ActionManager.shareFolder, withIntermediateDirectories: true)
|
||||
} catch {
|
||||
let alertWindow = AlertWindow(text: "Jellyfin Server was unable to properly create expected directories.")
|
||||
|
||||
windowController.window = alertWindow
|
||||
windowController.showWindow(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func showLogs(sender: Any?){
|
||||
NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: "/Users/\(NSUserName())/.local/share/jellyfin/log")
|
||||
|
||||
private func startJellyfinTask() {
|
||||
let jellyfinPath = Bundle.main.path(forAuxiliaryExecutable: "jellyfin")
|
||||
let webUIPath = Bundle.main.resourceURL!.appendingPathComponent("jellyfin-web").path
|
||||
|
||||
guard let jellyfinPath = jellyfinPath else {
|
||||
let alertWindow = AlertWindow(text: "Jellyfin Server was unable to start underlying jellyfin task.")
|
||||
|
||||
windowController.window = alertWindow
|
||||
windowController.showWindow(self)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
jellyfinTask.launchPath = jellyfinPath
|
||||
jellyfinTask.arguments = ["--webdir", webUIPath]
|
||||
|
||||
do {
|
||||
try jellyfinTask.run()
|
||||
} catch {
|
||||
let alertWindow = AlertWindow(text: "Jellyfin Server was unable to start underlying jellyfin task.")
|
||||
|
||||
windowController.window = alertWindow
|
||||
windowController.showWindow(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func constructMenu() {
|
||||
private func createStatusBarMenu() {
|
||||
let menu = NSMenu()
|
||||
|
||||
menu.addItem(NSMenuItem(title: "Launch Web UI", action: #selector(launchWebUI(sender:)), keyEquivalent: "l"))
|
||||
menu.addItem(NSMenuItem(title: "Show Logs", action: #selector(showLogs(sender:)), keyEquivalent: "d"))
|
||||
menu.addItem(withTitle: "Launch", action: #selector(launchWebUI), keyEquivalent: "l")
|
||||
menu.addItem(withTitle: "Show Logs", action: #selector(showLogs), keyEquivalent: "d")
|
||||
menu.addItem(withTitle: "Restart", action: #selector(restart), keyEquivalent: "r")
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
menu.addItem(NSMenuItem(title: "Quit Jellyfin Server", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
|
||||
menu.addItem(withTitle: "Preferences", action: #selector(launchPreferences), keyEquivalent: ",")
|
||||
menu.addItem(NSMenuItem(title: "Quit", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
|
||||
|
||||
statusItem.menu = menu
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func launchWebUI() {
|
||||
ActionManager.launchAbout()
|
||||
}
|
||||
|
||||
@objc private func showLogs() {
|
||||
ActionManager.showLogs()
|
||||
}
|
||||
|
||||
@objc private func restart() {
|
||||
ActionManager.restart()
|
||||
}
|
||||
|
||||
@objc private func launchPreferences() {
|
||||
let window = PreferencesWindow()
|
||||
|
||||
windowController.window = window
|
||||
windowController.showWindow(self)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
82
Jellyfin Server/Assets.xcassets/jellyfin-banner.imageset/Contents.json
vendored
Normal file
82
Jellyfin Server/Assets.xcassets/jellyfin-banner.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "light"
|
||||
}
|
||||
],
|
||||
"filename" : "jellyfin-banner-light.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "jellyfin-banner-dark.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "light"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "light"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Jellyfin Server/Assets.xcassets/jellyfin-banner.imageset/jellyfin-banner-dark.png
vendored
Normal file
BIN
Jellyfin Server/Assets.xcassets/jellyfin-banner.imageset/jellyfin-banner-dark.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 153 KiB |
BIN
Jellyfin Server/Assets.xcassets/jellyfin-banner.imageset/jellyfin-banner-light.png
vendored
Normal file
BIN
Jellyfin Server/Assets.xcassets/jellyfin-banner.imageset/jellyfin-banner-light.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
@ -27,7 +27,7 @@
|
||||
<key>LSUIElement</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2020 Jellyfin Contributors. All rights reserved.</string>
|
||||
<string>Copyright © 2022 Jellyfin Contributors. All rights reserved.</string>
|
||||
<key>NSMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
|
@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="20037"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Preferences View Controller-->
|
||||
<scene sceneID="PEd-7d-5j0">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="PreferencesViewController" id="bU7-R8-ocO" customClass="PreferencesViewController" customModule="Jellyfin_Server" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="tOy-S4-hL0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="350" height="300"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="xgB-oQ-tF1">
|
||||
<rect key="frame" x="25" y="220" width="300" height="80"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="80" id="M6H-N2-AA3"/>
|
||||
<constraint firstAttribute="width" constant="300" id="jt1-AU-FH4"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="jellyfin-banner" id="e4N-CF-Dic"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="qEc-pa-mey">
|
||||
<rect key="frame" x="73" y="194" width="204" height="16"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="16" id="gGl-zS-3e9"/>
|
||||
<constraint firstAttribute="width" constant="200" id="kS1-0S-mjy"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Version 1.2.3" id="YHH-EB-Hiz">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a23-zM-ylI">
|
||||
<rect key="frame" x="-2" y="10" width="354" height="16"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Copyright © 2022 Jellyfin" id="5VS-Kj-kIo">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="iV1-fg-N8A">
|
||||
<rect key="frame" x="113" y="157" width="123" height="18"/>
|
||||
<buttonCell key="cell" type="check" title="Launch at Login" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Az4-Xj-0Mi">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gxh-eI-cDG">
|
||||
<rect key="frame" x="108" y="111" width="134" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="120" id="8x3-gy-6H5"/>
|
||||
<constraint firstAttribute="width" constant="120" id="Ahg-po-3td"/>
|
||||
<constraint firstAttribute="height" constant="20" id="xQy-q3-kdD"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="Launch Web UI" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="wE7-Nw-pDc">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="launchWebUISelected:" target="bU7-R8-ocO" id="Y1q-ze-oTU"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hE0-YK-gRX">
|
||||
<rect key="frame" x="108" y="81" width="134" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="3kk-Pb-tWB"/>
|
||||
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="120" id="QAT-4c-DkD"/>
|
||||
<constraint firstAttribute="width" constant="120" id="z2X-7N-gUG"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="Show Logs" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="6WI-yj-06V">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="showLogsSelected:" target="bU7-R8-ocO" id="9jx-gg-Oqp"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="3SL-fH-pl4">
|
||||
<rect key="frame" x="108" y="51" width="134" height="32"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="20" id="DNG-Ny-2hn"/>
|
||||
<constraint firstAttribute="width" constant="120" id="LPR-XR-Lo7"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="About" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Em3-6n-hE4">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="aboutSelected:" target="bU7-R8-ocO" id="EcU-RU-LdB"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="3SL-fH-pl4" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="0AP-KV-I7n"/>
|
||||
<constraint firstItem="a23-zM-ylI" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="0BQ-0k-2Gx"/>
|
||||
<constraint firstItem="iV1-fg-N8A" firstAttribute="top" secondItem="qEc-pa-mey" secondAttribute="bottom" constant="20" id="Gv8-P6-0ne"/>
|
||||
<constraint firstItem="qEc-pa-mey" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="HfN-me-yw6"/>
|
||||
<constraint firstItem="iV1-fg-N8A" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="Q7v-Pw-ydB"/>
|
||||
<constraint firstItem="3SL-fH-pl4" firstAttribute="top" secondItem="hE0-YK-gRX" secondAttribute="bottom" constant="10" id="Rcw-3x-JSh"/>
|
||||
<constraint firstItem="qEc-pa-mey" firstAttribute="top" secondItem="xgB-oQ-tF1" secondAttribute="bottom" constant="10" id="RlL-zN-L9n"/>
|
||||
<constraint firstItem="xgB-oQ-tF1" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="TXg-MQ-QtM"/>
|
||||
<constraint firstItem="gxh-eI-cDG" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="Xak-9M-JR1"/>
|
||||
<constraint firstAttribute="bottom" secondItem="a23-zM-ylI" secondAttribute="bottom" constant="10" id="Ymx-ng-4SZ"/>
|
||||
<constraint firstItem="gxh-eI-cDG" firstAttribute="top" secondItem="iV1-fg-N8A" secondAttribute="bottom" constant="20" id="bNt-p3-nGR"/>
|
||||
<constraint firstItem="hE0-YK-gRX" firstAttribute="top" secondItem="gxh-eI-cDG" secondAttribute="bottom" constant="10" id="jbR-nE-v6k"/>
|
||||
<constraint firstItem="xgB-oQ-tF1" firstAttribute="top" secondItem="tOy-S4-hL0" secondAttribute="top" id="lqW-1I-Euc"/>
|
||||
<constraint firstItem="hE0-YK-gRX" firstAttribute="centerX" secondItem="tOy-S4-hL0" secondAttribute="centerX" id="o2u-2j-CKZ"/>
|
||||
<constraint firstItem="a23-zM-ylI" firstAttribute="leading" secondItem="tOy-S4-hL0" secondAttribute="leading" id="ueC-AA-dgU"/>
|
||||
<constraint firstAttribute="trailing" secondItem="a23-zM-ylI" secondAttribute="trailing" id="v7l-OO-Upb"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="launchAtLoginToggle" destination="iV1-fg-N8A" id="LnK-p3-p5s"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="9uD-mB-xHs" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="91" y="124"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="jellyfin-banner" width="1481" height="466"/>
|
||||
</resources>
|
||||
</document>
|
@ -0,0 +1,30 @@
|
||||
//
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
class PreferencesViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var launchAtLoginToggle: NSButton!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
@IBAction func launchWebUISelected(_ sender: Any) {
|
||||
ActionManager.launchWebUI()
|
||||
}
|
||||
|
||||
@IBAction func showLogsSelected(_ sender: Any) {
|
||||
ActionManager.showLogs()
|
||||
}
|
||||
|
||||
@IBAction func aboutSelected(_ sender: Any) {
|
||||
ActionManager.launchAbout()
|
||||
}
|
||||
}
|
26
Jellyfin Server/PreferencesWindow/PreferencesWindow.swift
Normal file
26
Jellyfin Server/PreferencesWindow/PreferencesWindow.swift
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// Swiftfin is subject to the terms of the Mozilla Public
|
||||
// License, v2.0. If a copy of the MPL was not distributed with this
|
||||
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) 2022 Jellyfin & Jellyfin Contributors
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
class PreferencesWindow: NSWindow {
|
||||
|
||||
convenience init() {
|
||||
let storyboard = NSStoryboard(name: "PreferencesViewController", bundle: nil)
|
||||
let preferencesViewController = storyboard.instantiateController(withIdentifier: "PreferencesViewController") as! PreferencesViewController
|
||||
|
||||
self.init(contentViewController: preferencesViewController)
|
||||
|
||||
styleMask.remove(.fullScreen)
|
||||
styleMask.remove(.miniaturizable)
|
||||
styleMask.remove(.resizable)
|
||||
titlebarAppearsTransparent = true
|
||||
title = ""
|
||||
level = .floating
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user