Compare commits

...

5 Commits

Author SHA1 Message Date
a. fox 54f71ce23f removed extra file 2024-02-29 21:44:40 -05:00
a. fox d8c47bd905 updated download command to use SearchResult struct 2024-02-29 21:43:57 -05:00
a. fox b00669a167 fixed issues where search command always returned no results 2024-02-29 21:37:37 -05:00
a. fox ecdb1bdc35 fixed encoder issue for UserAuthentication struct 2024-02-29 21:01:14 -05:00
a. fox d9cbb90575 fixed issue creating cache folder
fixed issues saving access token to file
2024-02-29 20:59:55 -05:00
9 changed files with 51 additions and 44 deletions

View File

@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "Seanut",
platforms: [
.macOS(.v10_15),
.macOS(.v13),
],
products: [
.executable(name: "seanut", targets: ["Seanut"])

View File

@ -57,14 +57,14 @@ extension Seanut {
let newPath = outputPath.appendingPathComponent(rootInfo.name!)
createDirectory(String(newPath.absoluteString.suffix(newPath.absoluteString.count - 7)))
let childReq: Request<[Item]> = Seanut.jellyfinRequest(
result: [Item()],
let childReq: Request<SearchResult> = Seanut.jellyfinRequest(
result: SearchResult(),
config: DownloadCommand.config,
path: "/Items",
method: .get,
query: [("userId", DownloadCommand.userId!), ("parentId", id)]
)
guard let childInfo = try? await DownloadCommand.client.send(childReq).value else {
guard let childInfo = try? await DownloadCommand.client.send(childReq).value.items else {
return
}

View File

@ -21,18 +21,21 @@ extension Seanut {
mutating func run() async {
Seanut.maybeSetLogger(options)
let seanutCacheFolder = "~/.seanut/".expandingTildeInPath
let seanutCacheFolder = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".seanut/")
if !FileManager.default.fileExists(atPath: seanutCacheFolder.absoluteString) {
if !FileManager.default.fileExists(atPath: seanutCacheFolder) {
do {
try FileManager.default.createDirectory(at: seanutCacheFolder, withIntermediateDirectories: false)
try FileManager.default.createDirectory(
at: URL(filePath: seanutCacheFolder),
withIntermediateDirectories: false
)
} catch {
fatalError("could not create seanut token cache folder. quitting...")
}
}
let client = APIClient(baseURL: options.domain.toURL()!)
// Seanut.generateJellyfinConfiguration(url: options.domain.toURL()!)
await Seanut.getAccessToken(
client: client,

View File

@ -17,33 +17,31 @@ extension Seanut {
var query: String
static let columnWidth = 40
var queryItems: [(String, String)] {
[
("isRecursive", "true"),
("searchTerm", query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!),
("fields", "Path,ChildCount".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!),
("includeItemTypes", "MusicAlbum,MusicArtist,Movie,Book,Playlist,Series,Audio".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)
]
}
mutating func run() async {
Seanut.maybeSetLogger(options)
let config = Seanut.generateJellyfinConfiguration(url: options.domain.toURL()!,
token: Seanut.retrieveAccessToken(for: options.domain.toURL()!))
let config = Seanut.generateJellyfinConfiguration(
url: options.domain.toURL()!,
token: Seanut.retrieveAccessToken(for: options.domain.toURL()!)
)
let client = APIClient(baseURL: options.domain.toURL()!)
let searchRequest: Request<[Item]> = Seanut.jellyfinRequest(
result: [Item()],
let searchRequest: Request<SearchResult> = Seanut.jellyfinRequest(
result: SearchResult(),
config: config,
path: "/Items",
method: .get,
query: queryItems
query: [
("recursive", "true"),
("fields", "Path,ChildCount"),
("searchTerm", query),
("includeItemTypes", "MusicAlbum,MusicArtist,Movie,Book,Playlist,Series,Audio")
]
)
let response = try? await client.send(searchRequest).value
if let items = response {
if let items = response?.items {
print("Found \(items.count) results:")
let header = "ID".padding(toLength: SearchCommand.columnWidth, withPad: " ", startingAt: 0) +
"Type".padding(toLength: 15, withPad: " ", startingAt: 0) +

View File

@ -1,13 +0,0 @@
// CustomTypes.swift
import ArgumentParser
enum MediaType: String, ExpressibleByArgument {
case book, movie, season, series, playlist, album, artist
}
extension MediaType: CustomStringConvertible {
var description: String {
return rawValue.capitalized
}
}

View File

@ -2,12 +2,30 @@
import Foundation
struct SearchResult: Codable {
let items: [Item]?
enum CodingKeys: String, CodingKey {
case items = "Items"
}
init() { self.items = nil }
}
struct Item: Codable {
let id: String?
let type: String?
let name: String?
let childCount: Int?
let path: String?
enum CodingKeys: String, CodingKey {
case id = "Id"
case type = "Type"
case name = "Name"
case childCount = "ChildCount"
case path = "Path"
}
init() {
self.id = nil

View File

@ -4,4 +4,8 @@ struct User: Codable {
let id: String?
init() { id = nil }
enum CodingKeys: String, CodingKey {
case id = "Id"
}
}

View File

@ -7,7 +7,7 @@ struct UserAuthentication: Codable {
var username: String?
enum CodingKeys: String, CodingKey {
case password = "Password"
case password = "Pw"
case username = "Username"
}
}

View File

@ -51,7 +51,7 @@ struct Seanut: AsyncParsableCommand {
path: String,
method: HTTPMethod,
body: Encodable? = nil,
query: [(String, String)]? = nil
query: [(String, String?)]? = nil
) -> Request<T> {
let id = String(path.split(separator: "/").last!)
return Request(
@ -72,12 +72,9 @@ struct Seanut: AsyncParsableCommand {
let domain = client.configuration.baseURL!
let configuration = generateJellyfinConfiguration(url: domain)
let fileName = FileManager.default
.homeDirectoryForCurrentUser
.appendingPathComponent(".seanut/\(domain)")
let fileName = "~/.seanut/\(domain.host()!)".expandingTildeInPath
do {
// FIXME: remove helper function "signIn" and call path directly
let signIn: Request<AuthenticationResponse> = jellyfinRequest(
result: AuthenticationResponse(),
config: configuration,
@ -87,8 +84,8 @@ struct Seanut: AsyncParsableCommand {
)
let resp = try await client.send(signIn).value
try resp.accessToken!.write(to: fileName, atomically: false, encoding: .utf8)
try resp.accessToken!.write(to: URL(filePath: fileName), atomically: false, encoding: .utf8)
print("Access token retrieved ☑️")
} catch {
print("Failed to login with provided credentials. please try again later.")