Grundcode AudiobookshelfClient
This commit is contained in:
98
Audiobookshelf swift/ABSService.swift
Normal file
98
Audiobookshelf swift/ABSService.swift
Normal file
@@ -0,0 +1,98 @@
|
||||
import Foundation
|
||||
|
||||
class ABSService: ObservableObject {
|
||||
static let shared = ABSService()
|
||||
|
||||
func fetchLibraries(serverURL: String, token: String) async throws -> [Library] {
|
||||
let url = URL(string: "\(serverURL)/api/libraries")!
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
||||
|
||||
let (data, _) = try await URLSession.shared.data(for: request)
|
||||
let response = try JSONDecoder().decode(LibrariesResponse.self, from: data)
|
||||
return response.libraries
|
||||
}
|
||||
|
||||
func fetchBooks(serverURL: String, token: String, libraryId: String) async throws -> [AudiobookItem] {
|
||||
let url = URL(string: "\(serverURL)/api/libraries/\(libraryId)/items?limit=100")!
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
||||
|
||||
let (data, _) = try await URLSession.shared.data(for: request)
|
||||
let response = try JSONDecoder().decode(LibraryItemsResponse.self, from: data)
|
||||
return response.results.compactMap { item in
|
||||
AudiobookItem(
|
||||
id: item.id,
|
||||
title: item.media.metadata.title ?? "Unbekannt",
|
||||
author: item.media.metadata.authorName ?? "Unbekannt",
|
||||
coverURL: item.media.coverPath != nil ? "\(serverURL)/api/items/\(item.id)/cover" : nil,
|
||||
duration: item.media.duration ?? 0,
|
||||
mediaFiles: item.media.audioFiles?.map {
|
||||
AudiobookItem.MediaFile(ino: $0.ino, name: $0.metadata.filename, path: $0.metadata.path)
|
||||
} ?? []
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func fetchProgress(serverURL: String, token: String, itemId: String) async throws -> LibraryProgress? {
|
||||
let url = URL(string: "\(serverURL)/api/me/progress/\(itemId)")!
|
||||
var request = URLRequest(url: url)
|
||||
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
||||
|
||||
let (data, response) = try await URLSession.shared.data(for: request)
|
||||
guard (response as? HTTPURLResponse)?.statusCode == 200 else { return nil }
|
||||
return try? JSONDecoder().decode(LibraryProgress.self, from: data)
|
||||
}
|
||||
|
||||
func updateProgress(serverURL: String, token: String, itemId: String, currentTime: Double, duration: Double) async {
|
||||
guard let url = URL(string: "\(serverURL)/api/me/progress/\(itemId)") else { return }
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = "PATCH"
|
||||
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
||||
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
||||
|
||||
let body: [String: Any] = [
|
||||
"currentTime": currentTime,
|
||||
"duration": duration,
|
||||
"isFinished": currentTime >= duration - 5
|
||||
]
|
||||
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
|
||||
try? await URLSession.shared.data(for: request)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - API Response Models
|
||||
struct LibrariesResponse: Codable {
|
||||
let libraries: [Library]
|
||||
}
|
||||
|
||||
struct LibraryItemsResponse: Codable {
|
||||
let results: [RawLibraryItem]
|
||||
}
|
||||
|
||||
struct RawLibraryItem: Codable {
|
||||
let id: String
|
||||
let media: RawMedia
|
||||
}
|
||||
|
||||
struct RawMedia: Codable {
|
||||
let metadata: RawMetadata
|
||||
let coverPath: String?
|
||||
let duration: Double?
|
||||
let audioFiles: [RawAudioFile]?
|
||||
}
|
||||
|
||||
struct RawMetadata: Codable {
|
||||
let title: String?
|
||||
let authorName: String?
|
||||
}
|
||||
|
||||
struct RawAudioFile: Codable {
|
||||
let ino: String
|
||||
let metadata: RawFileMetadata
|
||||
}
|
||||
|
||||
struct RawFileMetadata: Codable {
|
||||
let filename: String
|
||||
let path: String
|
||||
}
|
||||
Reference in New Issue
Block a user