Preserve profile names during Nuvio import

This commit is contained in:
KhooLy 2026-07-14 16:57:50 +03:00
parent cda0c17b0a
commit b0a68d6cee
6 changed files with 46 additions and 10 deletions

View file

@ -123,6 +123,7 @@ class AndroidSettingsDataSource(
displayName = profile.profileName?.takeIf { it.isNotBlank() } ?: profile.email,
avatarUrl = profile.avatarUrl,
isGuest = profile.isGuest,
hasNuvio = !profile.nuvioAccessToken.isNullOrBlank(),
hasTrakt = !profile.traktAccessToken.isNullOrBlank(),
hasSimkl = !profile.simklAccessToken.isNullOrBlank(),
hasAnilist = !profile.anilistAccessToken.isNullOrBlank(),

View file

@ -177,12 +177,13 @@ internal fun TvProfileEditScreen(
androidx.tv.material3.Button(
onClick = {
val profile = initialProfile?.copy(
email = name,
profileName = name,
avatarUrl = selectedAvatarUrl,
pinHash = resolvePinHash()
) ?: UserProfile(
id = java.util.UUID.randomUUID().toString(),
email = name,
profileName = name,
authKey = "",
isGuest = false,
language = "en",

View file

@ -1,5 +1,6 @@
package com.fluxa.app.ui.catalog
import android.util.Log
import com.fluxa.app.common.AppStrings
import com.fluxa.app.data.local.UserProfile
import com.fluxa.app.data.remote.NuvioSession
@ -192,7 +193,8 @@ internal fun MobileNuvioLoginView(
}
importedProfile = result
done = true
} catch (_: Exception) {
} catch (importError: Exception) {
Log.e("NuvioImport", "Nuvio account import failed", importError)
error = AppStrings.t(lang, "auth.error.network")
submitting = false
view = MobileNuvioView.Credentials

View file

@ -87,13 +87,14 @@ fun MobileProfileEditScreen(
TextButton(
onClick = {
val profile = initialProfile?.copy(
email = name,
profileName = name,
avatarUrl = selectedAvatarUrl,
pinHash = resolvePinHash(),
biometricEnabled = resolveBiometricEnabled()
) ?: UserProfile(
id = java.util.UUID.randomUUID().toString(),
email = name,
profileName = name,
authKey = "",
isGuest = false,
language = "en",

View file

@ -18,6 +18,7 @@ data class UserProfile(
val id: String,
val email: String,
val authKey: String,
val profileName: String? = null,
val colorArgb: Int = 0xFFFFFFFF.toInt(),
val isGuest: Boolean = false,
val avatarUrl: String? = null,
@ -304,6 +305,7 @@ data class UserProfile(
val safeLibraryCollections: List<LibraryUserCollection> get() = libraryCollections ?: homeFeedSettings?.libraryCollections.orEmpty()
val displayName: String get() = when {
!profileName.isNullOrBlank() -> profileName
isGuest -> if (email.isBlank() || email == "guest") "Guest" else email
email.contains("@") -> email.substringBefore("@")
else -> email

View file

@ -1,5 +1,6 @@
package com.fluxa.app.data.repository
import android.util.Log
import com.fluxa.app.data.local.LibraryUserCollection
import com.fluxa.app.data.local.LibraryUserCollectionFolder
import com.fluxa.app.data.local.LibraryCatalogSource
@ -91,22 +92,29 @@ class NuvioAccountImportCoordinator(
nuvioEmail = session.user?.email ?: baseProfile.email
)
val token = "Bearer ${session.accessToken}"
profileManager.saveProfile(connectedProfile)
profileManager.setLastActiveProfile(connectedProfile)
watchlistManager.setActiveProfile(baseProfile.id)
var profile = connectedProfile
val profiles = nuvioService.pullProfiles(token).requireBody()
val profiles = importOrDefault(NuvioImportStep.PROFILE, emptyList()) {
nuvioService.pullProfiles(token).requireBody()
}
val primary = profiles.firstOrNull { it.profileIndex == connectedProfile.nuvioProfileIndex }
?: profiles.minByOrNull { it.profileIndex }
val profileIndex = primary?.profileIndex ?: connectedProfile.nuvioProfileIndex ?: 1
if (primary != null) {
val avatarUrl = primary.avatarUrl ?: primary.avatarId?.let { avatarId ->
nuvioService.listAvatars().requireBody()
importOrDefault(NuvioImportStep.PROFILE, emptyList()) {
nuvioService.listAvatars().requireBody()
}
?.firstOrNull { it.id == avatarId }
?.storagePath
?.let { "${supabaseUrl}storage/v1/object/public/avatars/$it" }
}
profile = profile.copy(
profileName = primary.name?.takeIf { it.isNotBlank() } ?: profile.profileName,
avatarUrl = avatarUrl ?: profile.avatarUrl,
nuvioProfileIndex = profileIndex
)
@ -115,14 +123,18 @@ class NuvioAccountImportCoordinator(
}
onStep(NuvioImportStep.PROFILE)
val addons = nuvioService.pullAddons(token, profileId = "eq.$profileIndex").requireBody()
val addons = importOrDefault(NuvioImportStep.ADDONS, emptyList()) {
nuvioService.pullAddons(token, profileId = "eq.$profileIndex").requireBody()
}
if (addons.isNotEmpty()) {
val enabledUrls = addons.filter { it.enabled }.sortedBy { it.sortOrder }.map { it.url }
profile = profile.copy(localAddons = (profile.localAddons.orEmpty() + enabledUrls).distinct())
}
onStep(NuvioImportStep.ADDONS)
val libraryItems = nuvioService.pullLibrary(token, mapOf("p_profile_id" to profileIndex, "p_limit" to 500, "p_offset" to 0)).requireBody()
val libraryItems = importOrDefault(NuvioImportStep.LIBRARY, emptyList()) {
nuvioService.pullLibrary(token, mapOf("p_profile_id" to profileIndex, "p_limit" to 500, "p_offset" to 0)).requireBody()
}
val metaById = libraryItems.associate { item ->
item.contentId to Meta(
id = item.contentId,
@ -143,7 +155,9 @@ class NuvioAccountImportCoordinator(
}
onStep(NuvioImportStep.LIBRARY)
val watchProgress = nuvioService.pullWatchProgress(token, mapOf("p_profile_id" to profileIndex, "p_limit" to 200)).requireBody()
val watchProgress = importOrDefault(NuvioImportStep.PROGRESS, emptyList()) {
nuvioService.pullWatchProgress(token, mapOf("p_profile_id" to profileIndex, "p_limit" to 200)).requireBody()
}
for (entry in watchProgress) {
val meta = metaById[entry.contentId] ?: run {
val detail = runCatching {
@ -176,7 +190,9 @@ class NuvioAccountImportCoordinator(
}
onStep(NuvioImportStep.PROGRESS)
val watchedItems = nuvioService.pullWatchedItems(token, mapOf("p_profile_id" to profileIndex, "p_page" to 1, "p_page_size" to 500)).requireBody()
val watchedItems = importOrDefault(NuvioImportStep.HISTORY, emptyList()) {
nuvioService.pullWatchedItems(token, mapOf("p_profile_id" to profileIndex, "p_page" to 1, "p_page_size" to 500)).requireBody()
}
val watchedBySeries = mutableMapOf<String, MutableSet<String>>()
for (item in watchedItems) {
val videoId = if (item.season != null && item.episode != null) {
@ -191,7 +207,9 @@ class NuvioAccountImportCoordinator(
}
onStep(NuvioImportStep.HISTORY)
val collectionRows = nuvioService.pullCollections(token, mapOf("p_profile_id" to profileIndex)).requireBody()
val collectionRows = importOrDefault(NuvioImportStep.COLLECTIONS, emptyList()) {
nuvioService.pullCollections(token, mapOf("p_profile_id" to profileIndex)).requireBody()
}
val collections = collectionRows.firstOrNull()?.collectionsJson.orEmpty().map { collection ->
LibraryUserCollection(
id = collection.id ?: java.util.UUID.randomUUID().toString(),
@ -232,6 +250,17 @@ class NuvioAccountImportCoordinator(
profileManager.setLastActiveProfile(profile)
return profile
}
private suspend fun <T> importOrDefault(
step: NuvioImportStep,
fallback: T,
call: suspend () -> T
): T = try {
call()
} catch (error: Exception) {
Log.w("NuvioImport", "Import step $step failed; continuing without it", error)
fallback
}
}
private fun <T> Response<T>.requireBody(): T {