Eine Sekunde heisst nicht „Weiterschauen"
Die Schwelle aus den Einstellungen wirkt serverseitig, also sofort überall: `/home/continue` liest die gespeicherte Spalte. Eine Stelle blieb trotzdem widersprüchlich — die **Beschriftung**. Web und Apps entschieden „Weiterschauen" gegen „Abspielen" selbst, allein daran, ob eine Stelle über null steht. Nach einer Sekunde stand der Titel damit nicht mehr in der Reihe, hiess aber weiter „Weiterschauen", trug einen Fortschrittsbalken unter der Kachel und bot „Aus Weiterschauen entfernen" an. Der Server hatte diese Frage längst beantwortet. `ItemStateResponse` bringt sie jetzt mit; `MediaItem.isResumable` und `.resumeProgress` sind die einzigen Stellen, die sie noch stellen. Im Simulator nachgeprüft: nach einer Sekunde heisst der Knopf „Abspielen", „Von vorn" fehlt, und der Balken unter der Kachel ist weg. Kennt ein Server das Feld nicht — Jellyfin, oder ein älterer Flaro —, gilt wie früher die blosse Stelle. **Und das Profilbild steht in den Apps.** `FlaroAccount` führt es mit, `/auth/me` bringt es bei jedem Start frisch, und der Buchstabenkreis tritt zurück, sobald eines da ist. Jellyfin bleibt beim Buchstaben — dort gibt es kein Profilbild, und das ist keine Lücke, sondern der Stand der Dinge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
579a49b73b
commit
e30158b84c
@@ -443,17 +443,26 @@ public struct FlaroAccount: Sendable, Equatable {
|
||||
public let userName: String
|
||||
public let isAdministrator: Bool
|
||||
|
||||
/// Das eigene Bild, als Schlüssel in die Bildablage — `nil`: der Buchstabe.
|
||||
///
|
||||
/// **Mit Vorgabewert, damit Jellyfin unberührt bleibt.** Dort gibt es
|
||||
/// kein Profilbild, und ein Pflichtfeld hier zwänge jeden Aufrufer, sich
|
||||
/// dazu zu äussern.
|
||||
public let avatarImage: String?
|
||||
|
||||
public init(
|
||||
baseURL: URL,
|
||||
serverName: String,
|
||||
userID: String,
|
||||
userName: String,
|
||||
isAdministrator: Bool
|
||||
isAdministrator: Bool,
|
||||
avatarImage: String? = nil
|
||||
) {
|
||||
self.baseURL = baseURL
|
||||
self.serverName = serverName
|
||||
self.userID = userID
|
||||
self.userName = userName
|
||||
self.isAdministrator = isAdministrator
|
||||
self.avatarImage = avatarImage
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ enum Wire {
|
||||
let id: String
|
||||
let userName: String
|
||||
let isAdministrator: Bool
|
||||
/// Das Profilbild, als Schlüssel in die Bildablage des Servers.
|
||||
let avatarImage: String?
|
||||
}
|
||||
|
||||
struct Library: Decodable, Sendable {
|
||||
@@ -78,6 +80,12 @@ enum Wire {
|
||||
let rating: Int?
|
||||
let dismissed: Bool
|
||||
let lastPlayedAt: Date?
|
||||
/// Ob der Server den Titel in „Weiterschauen" führt.
|
||||
///
|
||||
/// **Nicht dasselbe wie „Stelle über null".** Seit es eine
|
||||
/// einstellbare Untergrenze gibt, sind das zwei Fragen: eine Sekunde
|
||||
/// wird gemerkt, zählt aber nicht als angefangen.
|
||||
let inProgress: Bool?
|
||||
}
|
||||
|
||||
struct Movie: Decodable, Sendable {
|
||||
|
||||
@@ -20,6 +20,7 @@ extension Wire.Movie {
|
||||
resumeMilliseconds: state.map { Int($0.positionSeconds * 1000) },
|
||||
lastPlayedAt: state?.lastPlayedAt,
|
||||
isFavourite: state?.favourite ?? false,
|
||||
isInProgress: state?.inProgress,
|
||||
availableFrom: publishAt,
|
||||
versions: [Wire.fassung(id: id, files: files)]
|
||||
)
|
||||
@@ -69,6 +70,7 @@ extension Wire.Episode {
|
||||
resumeMilliseconds: state.map { Int($0.positionSeconds * 1000) },
|
||||
lastPlayedAt: state?.lastPlayedAt,
|
||||
isFavourite: state?.favourite ?? false,
|
||||
isInProgress: state?.inProgress,
|
||||
availableFrom: publishAt,
|
||||
versions: [Wire.fassung(id: id, files: files)]
|
||||
)
|
||||
@@ -104,6 +106,7 @@ extension Wire.Started {
|
||||
resumeMilliseconds: Int(state.positionSeconds * 1000),
|
||||
lastPlayedAt: state.lastPlayedAt,
|
||||
isFavourite: state.favourite,
|
||||
isInProgress: state.inProgress,
|
||||
availableFrom: publishAt
|
||||
)
|
||||
}
|
||||
|
||||
@@ -84,7 +84,8 @@ public enum FlaroSignIn {
|
||||
serverName: gruss.serverName,
|
||||
userID: antwort.user.id,
|
||||
userName: antwort.user.userName,
|
||||
isAdministrator: antwort.user.isAdministrator), client)
|
||||
isAdministrator: antwort.user.isAdministrator,
|
||||
avatarImage: antwort.user.avatarImage), client)
|
||||
}
|
||||
|
||||
/// Nimmt ein gespeichertes Token wieder auf.
|
||||
@@ -111,7 +112,8 @@ public enum FlaroSignIn {
|
||||
serverName: gruss?.serverName ?? baseURL.host() ?? "Flaro",
|
||||
userID: wer.id,
|
||||
userName: wer.userName,
|
||||
isAdministrator: wer.isAdministrator), client)
|
||||
isAdministrator: wer.isAdministrator,
|
||||
avatarImage: wer.avatarImage), client)
|
||||
}
|
||||
|
||||
// MARK: - Der Weg über einen Code
|
||||
@@ -179,7 +181,8 @@ public enum FlaroSignIn {
|
||||
serverName: gruss?.serverName ?? baseURL.host() ?? "Flaro",
|
||||
userID: anmeldung.user.id,
|
||||
userName: anmeldung.user.userName,
|
||||
isAdministrator: anmeldung.user.isAdministrator)), client)
|
||||
isAdministrator: anmeldung.user.isAdministrator,
|
||||
avatarImage: anmeldung.user.avatarImage)), client)
|
||||
case "expired":
|
||||
return (.expired, nil)
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user