Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 3 additions & 48 deletions Plugins/CreateAPI/GeneratePlugin.swift
Comment thread
LePips marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ struct Plugin: CommandPlugin {
func performCommand(context: PluginContext, arguments: [String]) async throws {

// Apply schema pre patches
try await patchTaskTriggerInfoSchema(context: context)

try await generate(context: context)

Expand All @@ -27,9 +26,6 @@ struct Plugin: CommandPlugin {
try await patchAnyJSON(context: context)
try await patchGroupUpdateDiscriminator(context: context)

// Move patch files
try await addTaskTriggerType(context: context)

// Create the version SDK
try await generateVersionFile(context: context)

Expand Down Expand Up @@ -107,30 +103,9 @@ struct Plugin: CommandPlugin {
.directory
.appending(["Sources", "jellyfin-openapi-stable-patched.json"])

try FileManager.default.removeItem(atPath: filePath.string)
}

private func patchTaskTriggerInfoSchema(context: PluginContext) async throws {
let contents = try await parseOriginalSchema(context: context)

guard case var .object(file) = contents else { return }
guard case var .object(components) = file["components"] else { return }
guard case var .object(schemas) = components["schemas"] else { return }
guard case var .object(taskTriggerInfo) = schemas["TaskTriggerInfo"] else { return }
guard case var .object(properties) = taskTriggerInfo["properties"] else { return }

properties["Type"] = AnyJSON.object([
"type": .string("string"),
"format": .string("TaskTriggerType"),
"nullable": .bool(true),
])

taskTriggerInfo["properties"] = .object(properties)
schemas["TaskTriggerInfo"] = .object(taskTriggerInfo)
components["schemas"] = .object(schemas)
file["components"] = .object(components)

try await savePatchedSchema(context: context, json: .object(file))
if FileManager.default.fileExists(atPath: filePath.string) {
try FileManager.default.removeItem(atPath: filePath.string)
}
}

// Entities/RemoteSearchResult.swift: remove `Hashable`
Expand Down Expand Up @@ -173,26 +148,6 @@ struct Plugin: CommandPlugin {
.write(to: URL(fileURLWithPath: filePath.string))
}

private func addTaskTriggerType(context: PluginContext) async throws {
let sourceFilePath = context
.package
.directory
.appending(["Plugins", "CreateAPI", "PatchFiles", "TaskTriggerType.swift"])

let destinationFilePath = context
.package
.directory
.appending(["Sources", "Entities", "TaskTriggerType.swift"])

let fileManager = FileManager.default

if fileManager.fileExists(atPath: destinationFilePath.string) {
try fileManager.removeItem(atPath: destinationFilePath.string)
}

try fileManager.copyItem(atPath: sourceFilePath.string, toPath: destinationFilePath.string)
}

// TODO: Remove if/when fixed within CreateAPI
// Entities/GroupUpdate.swift: change generated `Type` name to `_Type`
private func patchGroupUpdateDiscriminator(context: PluginContext) async throws {
Expand Down
55 changes: 55 additions & 0 deletions Sources/Entities/BackupManifestDto.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// jellyfin-sdk-swift 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) 2025 Jellyfin & Jellyfin Contributors
//

import Foundation

/// Manifest type for backups internal structure.
public struct BackupManifestDto: Codable, Hashable {
/// Gets or sets the backup engine version this backup was created with.
public var backupEngineVersion: String?
/// Gets or sets the date this backup was created with.
public var dateCreated: Date?
/// Gets or sets the contents of the backup archive.
public var options: BackupOptionsDto?
/// Gets or sets the path to the backup on the system.
public var path: String?
/// Gets or sets the jellyfin version this backup was created with.
public var serverVersion: String?

public init(
backupEngineVersion: String? = nil,
dateCreated: Date? = nil,
options: BackupOptionsDto? = nil,
path: String? = nil,
serverVersion: String? = nil
) {
self.backupEngineVersion = backupEngineVersion
self.dateCreated = dateCreated
self.options = options
self.path = path
self.serverVersion = serverVersion
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: StringCodingKey.self)
self.backupEngineVersion = try values.decodeIfPresent(String.self, forKey: "BackupEngineVersion")
self.dateCreated = try values.decodeIfPresent(Date.self, forKey: "DateCreated")
self.options = try values.decodeIfPresent(BackupOptionsDto.self, forKey: "Options")
self.path = try values.decodeIfPresent(String.self, forKey: "Path")
self.serverVersion = try values.decodeIfPresent(String.self, forKey: "ServerVersion")
}

public func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: StringCodingKey.self)
try values.encodeIfPresent(backupEngineVersion, forKey: "BackupEngineVersion")
try values.encodeIfPresent(dateCreated, forKey: "DateCreated")
try values.encodeIfPresent(options, forKey: "Options")
try values.encodeIfPresent(path, forKey: "Path")
try values.encodeIfPresent(serverVersion, forKey: "ServerVersion")
}
}
44 changes: 44 additions & 0 deletions Sources/Entities/BackupOptionsDto.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// jellyfin-sdk-swift 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) 2025 Jellyfin & Jellyfin Contributors
//

import Foundation

/// Defines the optional contents of the backup archive.
public struct BackupOptionsDto: Codable, Hashable {
/// Gets or sets a value indicating whether the archive contains the Database contents.
public var isDatabase: Bool?
/// Gets or sets a value indicating whether the archive contains the Metadata contents.
public var isMetadata: Bool?
/// Gets or sets a value indicating whether the archive contains the Subtitle contents.
public var isSubtitles: Bool?
/// Gets or sets a value indicating whether the archive contains the Trickplay contents.
public var isTrickplay: Bool?

public init(isDatabase: Bool? = nil, isMetadata: Bool? = nil, isSubtitles: Bool? = nil, isTrickplay: Bool? = nil) {
self.isDatabase = isDatabase
self.isMetadata = isMetadata
self.isSubtitles = isSubtitles
self.isTrickplay = isTrickplay
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: StringCodingKey.self)
self.isDatabase = try values.decodeIfPresent(Bool.self, forKey: "Database")
self.isMetadata = try values.decodeIfPresent(Bool.self, forKey: "Metadata")
self.isSubtitles = try values.decodeIfPresent(Bool.self, forKey: "Subtitles")
self.isTrickplay = try values.decodeIfPresent(Bool.self, forKey: "Trickplay")
}

public func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: StringCodingKey.self)
try values.encodeIfPresent(isDatabase, forKey: "Database")
try values.encodeIfPresent(isMetadata, forKey: "Metadata")
try values.encodeIfPresent(isSubtitles, forKey: "Subtitles")
try values.encodeIfPresent(isTrickplay, forKey: "Trickplay")
}
}
30 changes: 30 additions & 0 deletions Sources/Entities/BackupRestoreRequestDto.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// jellyfin-sdk-swift 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) 2025 Jellyfin & Jellyfin Contributors
//

import Foundation

/// Defines properties used to start a restore process.
public struct BackupRestoreRequestDto: Codable, Hashable {
/// Gets or Sets the name of the backup archive to restore from. Must be present in
/// MediaBrowser.Common.Configuration.IApplicationPaths.BackupPath.
public var archiveFileName: String?

public init(archiveFileName: String? = nil) {
self.archiveFileName = archiveFileName
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: StringCodingKey.self)
self.archiveFileName = try values.decodeIfPresent(String.self, forKey: "ArchiveFileName")
}

public func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: StringCodingKey.self)
try values.encodeIfPresent(archiveFileName, forKey: "ArchiveFileName")
}
}
10 changes: 5 additions & 5 deletions Sources/Entities/BaseItemDto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public struct BaseItemDto: Codable, Hashable, Identifiable {
public var mediaSources: [MediaSourceInfo]?
/// Gets or sets the media streams.
public var mediaStreams: [MediaStream]?
/// Gets or sets the type of the media.
/// Media types.
public var mediaType: MediaType?
/// Gets or sets the movie count.
public var movieCount: Int?
Expand Down Expand Up @@ -272,8 +272,8 @@ public struct BaseItemDto: Codable, Hashable, Identifiable {
/// Gets or sets the trailer count.
public var trailerCount: Int?
/// Gets or sets the trickplay manifest.
public var trickplay: [String: [String: TrickplayInfo]]?
/// Gets or sets the type.
public var trickplay: [String: [String: TrickplayInfoDto]]?
/// The base item kind.
public var type: BaseItemKind?
/// Gets or sets the user data for this item based on the user it's being requested for.
public var userData: UserItemDataDto?
Expand Down Expand Up @@ -513,7 +513,7 @@ public struct BaseItemDto: Codable, Hashable, Identifiable {
tags: [String]? = nil,
timerID: String? = nil,
trailerCount: Int? = nil,
trickplay: [String: [String: TrickplayInfo]]? = nil,
trickplay: [String: [String: TrickplayInfoDto]]? = nil,
type: BaseItemKind? = nil,
userData: UserItemDataDto? = nil,
video3DFormat: Video3DFormat? = nil,
Expand Down Expand Up @@ -822,7 +822,7 @@ public struct BaseItemDto: Codable, Hashable, Identifiable {
self.tags = try values.decodeIfPresent([String].self, forKey: "Tags")
self.timerID = try values.decodeIfPresent(String.self, forKey: "TimerId")
self.trailerCount = try values.decodeIfPresent(Int.self, forKey: "TrailerCount")
self.trickplay = try values.decodeIfPresent([String: [String: TrickplayInfo]].self, forKey: "Trickplay")
self.trickplay = try values.decodeIfPresent([String: [String: TrickplayInfoDto]].self, forKey: "Trickplay")
self.type = try values.decodeIfPresent(BaseItemKind.self, forKey: "Type")
self.userData = try values.decodeIfPresent(UserItemDataDto.self, forKey: "UserData")
self.video3DFormat = try values.decodeIfPresent(Video3DFormat.self, forKey: "Video3DFormat")
Expand Down
2 changes: 1 addition & 1 deletion Sources/Entities/BaseItemPerson.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public struct BaseItemPerson: Codable, Hashable, Identifiable {
public var primaryImageTag: String?
/// Gets or sets the role.
public var role: String?
/// Gets or sets the type.
/// The person kind.
public var type: PersonKind?

/// Gets or sets the primary image blurhash.
Expand Down
41 changes: 41 additions & 0 deletions Sources/Entities/BrandingOptionsDto.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// jellyfin-sdk-swift 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) 2025 Jellyfin & Jellyfin Contributors
//

import Foundation

/// The branding options DTO for API use.
///
/// This DTO excludes SplashscreenLocation to prevent it from being updated via API.
public struct BrandingOptionsDto: Codable, Hashable {
/// Gets or sets the custom CSS.
public var customCss: String?
/// Gets or sets the login disclaimer.
public var loginDisclaimer: String?
/// Gets or sets a value indicating whether to enable the splashscreen.
public var isSplashscreenEnabled: Bool?

public init(customCss: String? = nil, loginDisclaimer: String? = nil, isSplashscreenEnabled: Bool? = nil) {
self.customCss = customCss
self.loginDisclaimer = loginDisclaimer
self.isSplashscreenEnabled = isSplashscreenEnabled
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: StringCodingKey.self)
self.customCss = try values.decodeIfPresent(String.self, forKey: "CustomCss")
self.loginDisclaimer = try values.decodeIfPresent(String.self, forKey: "LoginDisclaimer")
self.isSplashscreenEnabled = try values.decodeIfPresent(Bool.self, forKey: "SplashscreenEnabled")
}

public func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: StringCodingKey.self)
try values.encodeIfPresent(customCss, forKey: "CustomCss")
try values.encodeIfPresent(loginDisclaimer, forKey: "LoginDisclaimer")
try values.encodeIfPresent(isSplashscreenEnabled, forKey: "SplashscreenEnabled")
}
}
34 changes: 34 additions & 0 deletions Sources/Entities/CustomDatabaseOption.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// jellyfin-sdk-swift 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) 2025 Jellyfin & Jellyfin Contributors
//

import Foundation

/// The custom value option for custom database providers.
public struct CustomDatabaseOption: Codable, Hashable {
/// Gets or sets the key of the value.
public var key: String?
/// Gets or sets the value.
public var value: String?

public init(key: String? = nil, value: String? = nil) {
self.key = key
self.value = value
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: StringCodingKey.self)
self.key = try values.decodeIfPresent(String.self, forKey: "Key")
self.value = try values.decodeIfPresent(String.self, forKey: "Value")
}

public func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: StringCodingKey.self)
try values.encodeIfPresent(key, forKey: "Key")
try values.encodeIfPresent(value, forKey: "Value")
}
}
49 changes: 49 additions & 0 deletions Sources/Entities/CustomDatabaseOptions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// jellyfin-sdk-swift 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) 2025 Jellyfin & Jellyfin Contributors
//

import Foundation

/// Defines the options for a custom database connector.
public struct CustomDatabaseOptions: Codable, Hashable {
/// Gets or sets the connection string for the custom database provider.
public var connectionString: String?
/// Gets or sets the list of extra options for the custom provider.
public var options: [CustomDatabaseOption]?
/// Gets or sets the plugin assembly to search for providers.
public var pluginAssembly: String?
/// Gets or sets the Plugin name to search for database providers.
public var pluginName: String?

public init(
connectionString: String? = nil,
options: [CustomDatabaseOption]? = nil,
pluginAssembly: String? = nil,
pluginName: String? = nil
) {
self.connectionString = connectionString
self.options = options
self.pluginAssembly = pluginAssembly
self.pluginName = pluginName
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: StringCodingKey.self)
self.connectionString = try values.decodeIfPresent(String.self, forKey: "ConnectionString")
self.options = try values.decodeIfPresent([CustomDatabaseOption].self, forKey: "Options")
self.pluginAssembly = try values.decodeIfPresent(String.self, forKey: "PluginAssembly")
self.pluginName = try values.decodeIfPresent(String.self, forKey: "PluginName")
}

public func encode(to encoder: Encoder) throws {
var values = encoder.container(keyedBy: StringCodingKey.self)
try values.encodeIfPresent(connectionString, forKey: "ConnectionString")
try values.encodeIfPresent(options, forKey: "Options")
try values.encodeIfPresent(pluginAssembly, forKey: "PluginAssembly")
try values.encodeIfPresent(pluginName, forKey: "PluginName")
}
}
Loading