Skip to content

Commit

Permalink
Merge pull request #129 from icefields/version_1.00-60
Browse files Browse the repository at this point in the history
 new version release 60, bug fixes, user playlists and smartlists
  • Loading branch information
icefields committed Jun 16, 2024
2 parents fe1269b + dcde047 commit a38b780
Show file tree
Hide file tree
Showing 24 changed files with 329 additions and 109 deletions.
18 changes: 11 additions & 7 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ plugins {
id("com.google.devtools.ksp")
}

val composeVersion = "1.6.7" // rootProject.extra.get("compose_version") as String
val lifecycleVersion = "2.8.1"
val composeVersion = "1.6.8" // rootProject.extra.get("compose_version") as String
val lifecycleVersion = "2.8.2"
val retrofit2Version = "2.9.0"
val coroutinesVersion = "1.7.3"
val exoplayerVersion = "2.19.1"
Expand Down Expand Up @@ -39,6 +39,7 @@ android {
val ampacheUrlLocal = properties.getProperty("LOCAL_STABLE_URL")
val dogmazicUrl = properties.getProperty("DOGMAZIC_URL")
val dogmazicPass = properties.getProperty("DOGMAZIC_PASSWORD")
val dogmazicToken = properties.getProperty("DOGMAZIC_TOKEN")
val dogmazicUser = properties.getProperty("DOGMAZIC_USER")
val dogmazicEmail = properties.getProperty("DOGMAZIC_EMAIL")
val errorLogUrl = properties.getProperty("URL_ERROR_LOG")
Expand All @@ -55,9 +56,9 @@ android {
applicationId = "luci.sixsixsix.powerampache2"
minSdk = 28
targetSdk = 34
versionCode = 59
versionName = "1.00-59"
val versionQuote = "This version is powered by calico cats"
versionCode = 60
versionName = "1.00-60"
val versionQuote = "This version is powered by calico cats (60)"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Expand All @@ -77,9 +78,11 @@ android {
buildConfigField("String", "DEBUG_LOCAL_STABLE_URL", ampacheUrlLocal)
buildConfigField("String", "DEBUG_LOCAL_DEVELOPMENT_URL", localDevUrl)
buildConfigField("String", "DOGMAZIC_URL", dogmazicUrl)
buildConfigField("String", "DOGMAZIC_TOKEN", dogmazicToken)
buildConfigField("String", "DEFAULT_SERVER_URL", "\"\"")
buildConfigField("boolean", "FORCE_LOGIN_DIALOG_ON_ALL_VERSIONS", "true")
buildConfigField("boolean", "DEMO_VERSION", "false")
buildConfigField("String", "REMOTE_CONFIG_FILE", "\"config.json\"")
}

buildTypes {
Expand All @@ -90,7 +93,7 @@ android {
// FLAGS
buildConfigField("boolean", "MRLOG_ON", "true")
buildConfigField("boolean", "ENABLE_ERROR_LOG", "true")
buildConfigField("boolean", "ENABLE_TOKEN_LOGIN", "false")
buildConfigField("boolean", "ENABLE_TOKEN_LOGIN", "true")
buildConfigField("boolean", "ENABLE_DOGMAZIC_DEMO_SERVER", "true")
buildConfigField("boolean", "ENABLE_OFFICIAL_DEMO_SERVER", "false")
buildConfigField("boolean", "SHOW_EMPTY_PLAYLISTS", "false")
Expand Down Expand Up @@ -121,7 +124,7 @@ android {
// FLAGS
buildConfigField("boolean", "MRLOG_ON", "false")
buildConfigField("boolean", "ENABLE_ERROR_LOG", "true")
buildConfigField("boolean", "ENABLE_TOKEN_LOGIN", "false")
buildConfigField("boolean", "ENABLE_TOKEN_LOGIN", "true")
buildConfigField("boolean", "ENABLE_DOGMAZIC_DEMO_SERVER", "true")
buildConfigField("boolean", "ENABLE_OFFICIAL_DEMO_SERVER", "false")
buildConfigField("boolean", "SHOW_EMPTY_PLAYLISTS", "false")
Expand Down Expand Up @@ -197,6 +200,7 @@ android {
buildConfigField("String", "DEFAULT_SERVER_URL", dogmazicUrl)
buildConfigField("String", "URL_ERROR_LOG", "\"https://pastebin.com/api/\"")
buildConfigField("String", "PASTEBIN_API_KEY", pastebinApiKey)
buildConfigField("String", "REMOTE_CONFIG_FILE", "\"config-dogmazic.json\"")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,21 @@ class PowerAmpache2Application : Application(), ImageLoaderFactory, Configuratio
}

override fun newImageLoader(): ImageLoader = ImageLoader(this).newBuilder()
.crossfade(true)
.crossfade(200)
.placeholder(R.drawable.placeholder_album)
.error(R.drawable.placeholder_album)
.diskCachePolicy(CachePolicy.ENABLED)
.memoryCachePolicy(CachePolicy.ENABLED)
.networkCachePolicy(CachePolicy.ENABLED)
.memoryCache {
MemoryCache.Builder(this)
.maxSizePercent(0.02)
.maxSizePercent(0.12)
.strongReferencesEnabled(true)
.build()
}
.diskCache {
DiskCache.Builder()
.maxSizePercent(0.08)
.maxSizePercent(0.10)
.directory(getDir("paimages", MODE_PRIVATE))
.build()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package luci.sixsixsix.powerampache2.common

import luci.sixsixsix.powerampache2.BuildConfig


object Constants {
// LOCAL DB
const val DB_LOCAL_NAME = "musicdb.db"
Expand Down Expand Up @@ -92,6 +93,6 @@ object Constants {
const val DOGMAZIC_FAKE_CITY = "Aoshima"

// fetch this from remote config or initialize locally
const val CONFIG_URL = "https://icefields.github.io/powerampache/config.json"
const val CONFIG_URL = "https://icefields.github.io/powerampache/${BuildConfig.REMOTE_CONFIG_FILE}"
var config = Pa2Config()
}
36 changes: 31 additions & 5 deletions app/src/main/java/luci/sixsixsix/powerampache2/common/Pa2Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,35 @@ package luci.sixsixsix.powerampache2.common

import luci.sixsixsix.powerampache2.BuildConfig

const val PLAYLIST_FETCH_LIMIT = 100
const val PLAYLIST_SONGS_FETCH_LIMIT = 100
const val PLAYBACK_ERRORS_RETRIES = 16
const val PLAYLIST_FETCH_LIMIT = 0
const val PLAYLIST_ADD_NEW_ENABLE = true
const val RESET_QUEUE_ON_NEW_SESSION = BuildConfig.RESET_QUEUE_ON_NEW_SESSION
const val DOGMAZIC_USER = BuildConfig.DOGMAZIC_USER

const val PLAYLISTS_USER_FETCH = true
const val SMARTLISTS_USER_FETCH = true
const val PLAYLISTS_ADMIN_FETCH = true
const val SMARTLISTS_ADMIN_FETCH = true
const val PLAYLISTS_ALL_SERVER_FETCH = true

data class Pa2Config(
// use new fast method for adding albums and playlists to playlist
val playlistAddNewEnable: Boolean = PLAYLIST_ADD_NEW_ENABLE,

// number of playlist to fetch at once
val playlistFetchLimit: Int = PLAYLIST_FETCH_LIMIT,

// reset queue on new session
val queueResetOnNewSession: Boolean = RESET_QUEUE_ON_NEW_SESSION,

val dogmazicDemoUser: String = DOGMAZIC_USER,
val dogmazicDemoUser: String = BuildConfig.DOGMAZIC_USER,

// limit of songs to fetch for playlists
// - bigger number results in faster fetching
// - smaller number will result in data becoming visible to the user faster, but it will
// take longer to completely fetch big playlists
val playlistSongsFetchLimit: Int = PLAYLIST_FETCH_LIMIT,
val playlistSongsFetchLimit: Int = PLAYLIST_SONGS_FETCH_LIMIT,

// force login dialog instead of bottom drawer for all versions until google fixes copy paste issue
val forceLoginDialogsOnAllVersions: Boolean = BuildConfig.FORCE_LOGIN_DIALOG_ON_ALL_VERSIONS,
Expand All @@ -51,5 +60,22 @@ data class Pa2Config(
val loginWarning: String = "",

// number of retries in case of playback errors
val playbackErrorRetries: Int = PLAYBACK_ERRORS_RETRIES
val playbackErrorRetries: Int = PLAYBACK_ERRORS_RETRIES,

// Enable login via token along with username/password
val enableTokenLogin: Boolean = BuildConfig.ENABLE_TOKEN_LOGIN,

val dogmazicDemoToken: String = BuildConfig.DOGMAZIC_TOKEN,
val dogmazicDemoUrl: String = BuildConfig.DOGMAZIC_URL,

// fetch user playlists before fetching the bulk of all server playlists
val playlistsUserFetch: Boolean = PLAYLISTS_USER_FETCH,
// fetch user smartlists before fetching the bulk of all server playlists
val smartlistsUserFetch: Boolean = SMARTLISTS_USER_FETCH,
// fetch admin playlists only before fetching the bulk of all server playlists
val playlistsAdminFetch: Boolean = PLAYLISTS_ADMIN_FETCH,
// fetch admin smartlists only before fetching the bulk of all server playlists
val smartlistsAdminFetch: Boolean = SMARTLISTS_ADMIN_FETCH,
// fetch all playlists from server
val playlistsServerAllFetch: Boolean = PLAYLISTS_ALL_SERVER_FETCH,
)
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ abstract class BaseAmpacheRepository(
getSession()?.let { session ->
val cred = getCurrentCredentials()
try {
val userResponse = api.getUser(authKey = session.auth, username = cred.username)
val userResponse = api.getUser(authKey = session.auth,
username = cred.username.ifBlank { null }) // do not pass blank variables to network call
// nextcloud and other services might not implement the user api
val isNotImplemented = userResponse.error?.toError()?.isNotImplemented() == true
val user = if (isNotImplemented) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import luci.sixsixsix.powerampache2.data.local.entities.toSessionEntity
import luci.sixsixsix.powerampache2.data.local.entities.toUser
import luci.sixsixsix.powerampache2.data.local.models.UserWithCredentials
import luci.sixsixsix.powerampache2.data.local.models.toUser
import luci.sixsixsix.powerampache2.data.local.multiuserDbKey
import luci.sixsixsix.powerampache2.data.remote.MainNetwork
import luci.sixsixsix.powerampache2.data.remote.dto.toError
import luci.sixsixsix.powerampache2.data.remote.dto.toGenre
Expand Down Expand Up @@ -86,13 +85,17 @@ class MusicRepositoryImpl @Inject constructor(
): BaseAmpacheRepository(api, db, errorHandler), MusicRepository {
private val _serverInfoStateFlow = MutableStateFlow(ServerInfo())
override val serverInfoStateFlow: StateFlow<ServerInfo> = _serverInfoStateFlow

val serverVersionStateFlow = serverInfoStateFlow.mapNotNull { it.version }.distinctUntilChanged()

override val sessionLiveData = dao.getSessionLiveData().map { it?.toSession() }

override val userLiveData: Flow<User?> = dao.getUserLiveData().map {
val cred = getCurrentCredentials()
val userEntity = it ?: dao.getUser(cred.username)
userEntity?.toUser() ?: UserWithCredentials(username = cred.username).toUser(cred.serverUrl)
if (cred.username.isNotBlank()) {
val userEntity = it ?: dao.getUser(cred.username)
userEntity?.toUser() ?: UserWithCredentials(username = cred.username).toUser(cred.serverUrl)
} else null
}

// used to check if a call to getUserNetwork() is necessary
Expand Down Expand Up @@ -125,6 +128,7 @@ class MusicRepositoryImpl @Inject constructor(
Constants.config = try {
api.getConfig().toPa2Config()
} catch (e: Exception) {
L.e(e)
Pa2Config()
}
}
Expand All @@ -135,9 +139,22 @@ class MusicRepositoryImpl @Inject constructor(
dao.insertMultiUserSession(se.toMultiUserSessionEntity(username = cred.username, serverUrl = cred.serverUrl))
}

private suspend fun setCredentials(se: CredentialsEntity) {
private suspend fun setCredentials(
username: String,
sha256password: String,
authToken: String,
serverUrl: String
) {
val se: CredentialsEntity = CredentialsEntity(
username = username.lowercase(),
password = sha256password,
serverUrl = serverUrl.lowercase(),
authToken = authToken
)
dao.updateCredentials(se)
dao.insertMultiUserCredentials(se.toMultiUserCredentialEntity())
if (username.isNotBlank()) {
dao.insertMultiUserCredentials(se.toMultiUserCredentialEntity())
}
}

/**
Expand All @@ -148,7 +165,7 @@ class MusicRepositoryImpl @Inject constructor(
override suspend fun ping(): Resource<Pair<ServerInfo, Session?>> =
try {
val dbSession = getSession()
val pingResponse = api.ping(dbSession?.auth ?: "")
val pingResponse = api.ping(authKey = dbSession?.auth)

// Updated session only valid of previous session exists, authorize otherwise
dbSession?.let { cachedSession ->
Expand Down Expand Up @@ -206,11 +223,10 @@ class MusicRepositoryImpl @Inject constructor(
// Save current credentials, so they can be picked up by the interceptor,
// and for future autologin, this has to be first line of code before any network call
setCredentials(
CredentialsEntity(username = usernameLow,
password = sha256password,
serverUrl = serverUrl.lowercase(),
authToken = authToken
)
username = usernameLow,
sha256password = sha256password,
serverUrl = serverUrl.lowercase(),
authToken = authToken
)
L("authorize CREDENTIALS ${getCredentials()}")
val auth = tryAuthorize(usernameLow, sha256password, authToken, force)
Expand All @@ -220,8 +236,8 @@ class MusicRepositoryImpl @Inject constructor(

@Throws(Exception::class)
private suspend fun tryAuthorize(
username:String,
sha256password:String,
username: String,
sha256password: String,
authToken: String,
force: Boolean,
): Session {
Expand All @@ -241,6 +257,17 @@ class MusicRepositoryImpl @Inject constructor(
setSession(sess)
}
}

if (authToken.isNotBlank()) {
// set the user manually because we won't have it from handshake if logged in with token
(auth.username ?: getUserNetwork()?.username)?.let { usernameNet ->
setCredentials(
username = usernameNet.lowercase(),
sha256password = sha256password,
serverUrl = getCurrentCredentials().serverUrl,
authToken = authToken
) }
}
}

// try to get server info from ping and return the session from ping, otherwise return the
Expand All @@ -257,11 +284,11 @@ class MusicRepositoryImpl @Inject constructor(
): Flow<Resource<Any>> = flow {
emit(Resource.Loading(true))

setCredentials(CredentialsEntity(
setCredentials(
username = username,
password = sha256password,
sha256password = sha256password,
serverUrl = serverUrl.lowercase(),
authToken = "")
authToken = ""
)

val resp = api.register(
Expand Down
Loading

0 comments on commit a38b780

Please sign in to comment.