Skip to content

Commit

Permalink
Merge pull request #22 from Outlet7493/master
Browse files Browse the repository at this point in the history
  • Loading branch information
BobbyESP authored Jan 27, 2024
2 parents 072a959 + e2b447c commit d5eaab3
Show file tree
Hide file tree
Showing 52 changed files with 1,067 additions and 242 deletions.
2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Spotify Premium account is **REQUIRED***. Offline caching, DRM bypassing, or raw
- Basic playback with Spotify Connect support (Spotify Connect support is actually WIP)
- Fairly optimized R8 rules, providing the release APKs with a size of 4-5mb (with the playback and protobuf parts!)

## 📸 Screentshots
## 📸 Screenshots

<div>
<img width="300" alt="image" src="https://user-images.githubusercontent.com/60316747/205959791-b3f3098b-0d39-42b3-a4d0-3747245a8511.jpg" />
Expand Down
14 changes: 8 additions & 6 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import com.google.protobuf.gradle.*
import java.io.FileInputStream
import java.util.Properties
import com.google.protobuf.gradle.*

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("dev.zacsweers.moshix") version "0.24.0"
id("dev.zacsweers.moshix") version "0.25.1"
id("com.google.devtools.ksp")
id("dagger.hilt.android.plugin")
id("kotlin-kapt")
id("com.google.protobuf") version "0.9.0"
kotlin("plugin.serialization") version "1.9.0"
kotlin("plugin.serialization") version "1.9.22"
}

apply(plugin = "dagger.hilt.android.plugin")
Expand All @@ -30,7 +30,7 @@ val room_version: String by rootProject.extra
val librespot_commit: String by rootProject.extra
val hilt_version: String by rootProject.extra

val keystorePropertiesFile = rootProject.file("keystore.properties")
val keystorePropertiesFile: File = rootProject.file("keystore.properties")

val splitApks = !project.hasProperty("noSplits")

Expand Down Expand Up @@ -62,6 +62,7 @@ android {
}.toString()

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments["disableAnalytics"] = "true"

kapt {
correctErrorTypes = true
Expand Down Expand Up @@ -145,7 +146,7 @@ android {
disable.addAll(listOf("MissingTranslation", "ExtraTranslation"))
}

packagingOptions {
packaging {
resources {
excludes += "/META-INF/*.kotlin_module"
excludes += "/META-INF/*.version"
Expand Down Expand Up @@ -181,7 +182,7 @@ dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.palette:palette-ktx:1.0.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.appcompat:appcompat:1.7.0-alpha03")

// Compose
Expand Down Expand Up @@ -229,6 +230,7 @@ dependencies {
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-moshi:2.9.0")
implementation("com.squareup.retrofit2:converter-protobuf:2.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")

// Data - SQL
implementation("androidx.room:room-runtime:$room_version")
Expand Down
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ import androidx.compose.material.rememberBottomSheetScaffoldState
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.navigation.NavController
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import bruhcollective.itaysonlab.jetispot.core.SpAuthManager
import bruhcollective.itaysonlab.jetispot.core.SpPlayerServiceManager
import bruhcollective.itaysonlab.jetispot.core.SpSessionManager
Expand Down Expand Up @@ -178,6 +178,7 @@ class MainActivity : ComponentActivity() {
)
},
label = { Text(stringResource(screen.title)) },
alwaysShowLabel = false,
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.route) {
Expand All @@ -193,7 +194,7 @@ class MainActivity : ComponentActivity() {
}
}
}
) { innerPadding ->
) { _ ->
BottomSheetScaffold(
sheetContent = {
NowPlayingScreen(
Expand All @@ -208,6 +209,7 @@ class MainActivity : ComponentActivity() {
scaffoldState = bsState,
sheetPeekHeight = bsPeek,
backgroundColor = MaterialTheme.colorScheme.surface,
sheetBackgroundColor = Color.Transparent,
sheetGesturesEnabled = !bsQueueOpened && !bsLyricsOpened
) { innerScaffoldPadding ->
AppNavigation(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package bruhcollective.itaysonlab.jetispot.core

import android.os.Looper
import bruhcollective.itaysonlab.jetispot.proto.AudioNormalization
import bruhcollective.itaysonlab.jetispot.playback.service.refl.SpReflect
import bruhcollective.itaysonlab.jetispot.playback.sp.AndroidSinkOutput
import bruhcollective.itaysonlab.jetispot.playback.sp.LowToHighQualityPicker
import bruhcollective.itaysonlab.jetispot.proto.AudioNormalization
import xyz.gianlu.librespot.audio.decoders.AudioQuality
import xyz.gianlu.librespot.player.Player
import xyz.gianlu.librespot.player.PlayerConfiguration
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package bruhcollective.itaysonlab.jetispot.core.collection

import bruhcollective.itaysonlab.jetispot.core.SpMetadataRequester
import bruhcollective.itaysonlab.jetispot.core.util.Log
import bruhcollective.itaysonlab.jetispot.core.SpSessionManager
import bruhcollective.itaysonlab.jetispot.core.api.SpCollectionApi
import bruhcollective.itaysonlab.jetispot.core.api.SpInternalApi
import bruhcollective.itaysonlab.jetispot.core.collection.db.LocalCollectionDao
import bruhcollective.itaysonlab.jetispot.core.collection.db.LocalCollectionRepository
import bruhcollective.itaysonlab.jetispot.core.util.Log
import bruhcollective.itaysonlab.swedentricks.protos.CollectionUpdate
import com.spotify.playlist4.Playlist4ApiProto
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import xyz.gianlu.librespot.common.Utils
import xyz.gianlu.librespot.dealer.DealerClient
import java.util.concurrent.Executors
Expand Down Expand Up @@ -87,6 +91,21 @@ class SpCollectionManager @Inject constructor(
writer.performRemove(id, set)
}

suspend fun getRootlistImage(
uri: String
) = dao.getRootlistImage(uri)

suspend fun updateRootlistImage(
uri: String,
image: String,
overwrite: Boolean
) = dao.updateRootlistPicture(uri, image, overwrite)

suspend fun clearRootlist() {
dao.deleteRootList()
dao.deleteCollectionCategory("rootlist")
}

override fun onMessage(p0: String, p1: MutableMap<String, String>, p2: ByteArray) {
if (p0.startsWith("hm://playlist/v2/user/")) {
writer.pubsubUpdateRootlist(Playlist4ApiProto.PlaylistModificationInfo.parseFrom(p2))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
package bruhcollective.itaysonlab.jetispot.core.collection

import bruhcollective.itaysonlab.jetispot.core.SpMetadataRequester
import bruhcollective.itaysonlab.jetispot.core.util.Log
import bruhcollective.itaysonlab.jetispot.core.SpSessionManager
import bruhcollective.itaysonlab.jetispot.core.api.SpCollectionApi
import bruhcollective.itaysonlab.jetispot.core.api.SpInternalApi
import bruhcollective.itaysonlab.jetispot.core.collection.db.LocalCollectionDao
import bruhcollective.itaysonlab.jetispot.core.collection.db.LocalCollectionRepository
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.*
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionAlbum
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionArtist
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionContentFilter
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionEpisode
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionPinnedItem
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionShow
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionTrack
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.rootlist.CollectionRootlistItem
import bruhcollective.itaysonlab.jetispot.core.objs.tags.ContentFilterResponse
import bruhcollective.itaysonlab.jetispot.core.util.Log
import bruhcollective.itaysonlab.jetispot.core.util.Revision
import bruhcollective.itaysonlab.jetispot.core.util.SpUtils
import bruhcollective.itaysonlab.swedentricks.protos.CollectionUpdate
import bruhcollective.itaysonlab.swedentricks.protos.CollectionUpdateEntry
import com.google.protobuf.ByteString
import com.spotify.collection2.v2.proto.Collection2V2
import com.spotify.extendedmetadata.ExtendedMetadata
import com.spotify.extendedmetadata.ExtensionKindOuterClass
import com.spotify.metadata.Metadata
import com.spotify.playlist4.Playlist4ApiProto
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import xyz.gianlu.librespot.common.Utils
import xyz.gianlu.librespot.metadata.*
import java.nio.charset.StandardCharsets
import xyz.gianlu.librespot.metadata.AlbumId
import xyz.gianlu.librespot.metadata.ArtistId
import xyz.gianlu.librespot.metadata.EpisodeId
import xyz.gianlu.librespot.metadata.ImageId
import xyz.gianlu.librespot.metadata.PlaylistId
import xyz.gianlu.librespot.metadata.ShowId
import xyz.gianlu.librespot.metadata.TrackId

class SpCollectionWriter(
private val spSessionManager: SpSessionManager,
Expand Down Expand Up @@ -381,7 +393,7 @@ class SpCollectionWriter(
timestamp = pair.first.attributes.timestamp,
name = pair.second.attributes.name,
ownerUsername = pair.second.ownerUsername,
picture = pair.second.attributes.pictureSizeList.find { it.targetName == "default" }?.url ?: "https://i.scdn.co/image/${Utils.bytesToHex(pair.second.attributes.picture).lowercase()}"
picture = pair.second.attributes.pictureSizeList.find { it.targetName == "default" }?.url ?: if (pair.second.attributes.picture.isEmpty) "" else "https://i.scdn.co/image/${Utils.bytesToHex(pair.second.attributes.picture).lowercase()}"
)
}.toTypedArray())
}
Expand All @@ -407,7 +419,7 @@ class SpCollectionWriter(
timestamp = pair.first.attributes.timestamp,
name = pair.second.attributes.name,
ownerUsername = pair.second.ownerUsername,
picture = pair.second.attributes.pictureSizeList.find { it.targetName == "default" }?.url ?: "https://i.scdn.co/image/${Utils.bytesToHex(pair.second.attributes.picture).lowercase()}"
picture = pair.second.attributes.pictureSizeList.find { it.targetName == "default" }?.url ?: if (pair.second.attributes.picture.isEmpty) "" else "https://i.scdn.co/image/${Utils.bytesToHex(pair.second.attributes.picture).lowercase()}"
)
}.toTypedArray()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package bruhcollective.itaysonlab.jetispot.core.collection.db

import androidx.room.*
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RawQuery
import androidx.sqlite.db.SimpleSQLiteQuery
import androidx.sqlite.db.SupportSQLiteQuery
import bruhcollective.itaysonlab.jetispot.core.collection.db.model.LocalCollectionCategory
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.*
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionAlbum
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionArtist
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionContentFilter
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionEpisode
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionPinnedItem
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionShow
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.CollectionTrack
import bruhcollective.itaysonlab.jetispot.core.collection.db.model2.rootlist.CollectionRootlistItem
import kotlinx.coroutines.flow.Flow

Expand Down Expand Up @@ -37,6 +47,9 @@ interface LocalCollectionDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addEpisodes(vararg items: CollectionEpisode)

@Query("UPDATE rootlist SET picture = :picture WHERE uri = :uri AND CASE WHEN :overwrite THEN 1 ELSE picture == '' END")
suspend fun updateRootlistPicture(uri: String, picture: String, overwrite: Boolean)

@Query("SELECT * from lcTypes WHERE type = :of")
suspend fun getCollection(of: String): LocalCollectionCategory?

Expand All @@ -52,6 +65,9 @@ interface LocalCollectionDao {
@Query("DELETE FROM lcAlbums WHERE id IN (:ids)")
suspend fun deleteAlbums(vararg ids: String)

@Query("DELETE FROM lcTypes WHERE type = :of")
suspend fun deleteCollectionCategory(of: String)

@Query("SELECT * from lcArtists ORDER BY addedAt DESC")
suspend fun getArtists(): List<CollectionArtist>

Expand All @@ -73,6 +89,9 @@ interface LocalCollectionDao {
@Query("SELECT * from rootlist ORDER BY timestamp DESC")
suspend fun getRootlist(): List<CollectionRootlistItem>

@Query("SELECT picture FROM rootlist WHERE uri = :uri")
suspend fun getRootlistImage(uri: String): String?

@Query("DELETE from lcTracks")
suspend fun deleteTracks()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ interface CollectionEntry {
}

enum class PredefCeType {
COLLECTION, EPISODES
COLLECTION, EPISODES, YOUR_EPISODES, ROOTLIST
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.converter.protobuf.ProtoConverterFactory
Expand Down Expand Up @@ -59,6 +60,11 @@ object ApiModule {
}.build())
}
}
if (BuildConfig.DEBUG) {
addInterceptor(HttpLoggingInterceptor().apply {
setLevel(HttpLoggingInterceptor.Level.BODY)
})
}
}.build()

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@ package bruhcollective.itaysonlab.jetispot.core.di

import android.content.Context
import androidx.room.Room
import bruhcollective.itaysonlab.jetispot.core.SpMetadataRequester
import bruhcollective.itaysonlab.jetispot.core.SpSessionManager
import bruhcollective.itaysonlab.jetispot.core.api.SpCollectionApi
import bruhcollective.itaysonlab.jetispot.core.api.SpInternalApi
import bruhcollective.itaysonlab.jetispot.core.collection.SpCollectionManager
import bruhcollective.itaysonlab.jetispot.core.collection.db.LocalCollectionDao
import bruhcollective.itaysonlab.jetispot.core.collection.db.LocalCollectionDatabase
import bruhcollective.itaysonlab.jetispot.core.collection.db.LocalCollectionRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package bruhcollective.itaysonlab.jetispot.core.util

import bruhcollective.itaysonlab.jetispot.core.objs.player.*
import bruhcollective.itaysonlab.jetispot.core.objs.player.PfcContextData
import bruhcollective.itaysonlab.jetispot.core.objs.player.PfcOptSkipTo
import bruhcollective.itaysonlab.jetispot.core.objs.player.PfcOptions
import bruhcollective.itaysonlab.jetispot.core.objs.player.PfcStateOptions
import bruhcollective.itaysonlab.jetispot.core.objs.player.PlayFromContextData
import bruhcollective.itaysonlab.jetispot.core.objs.player.PlayFromContextPlayerData
import com.spotify.dac.player.v1.proto.PlayCommand
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter

@DslMarker
@Target(AnnotationTarget.TYPE, AnnotationTarget.CLASS)
Expand Down Expand Up @@ -39,8 +43,9 @@ class PlayCommandBuilder (
}

fun PlayCommand.toApplicationPlayCommand(moshi: Moshi): PlayFromContextData {
// TODO playing needs investigation when coming from album i.e. 'new release from' on DAC
val context = moshi.adapter(PfcContextData::class.java).fromJson(this.context.toStringUtf8())!!
val options = moshi.adapter(PlayFromContextPlayerData::class.java).fromJson(this.options.toStringUtf8())!!.options!!
val options = moshi.adapter(PlayFromContextPlayerData::class.java).fromJson(this.options.toStringUtf8())?.options

return PlayFromContextData(
uri = context.uri,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import androidx.media2.session.LibraryResult
import androidx.media2.session.MediaLibraryService
import androidx.media2.session.MediaSession
import androidx.media2.session.SessionResult
Expand Down Expand Up @@ -72,7 +70,7 @@ class SpPlaybackService : MediaLibraryService(), CoroutineScope by CoroutineScop
Intent(this@SpPlaybackService, MainActivity::class.java).apply {
putExtra("openPlayer", true)
},
(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0) or PendingIntent.FLAG_UPDATE_CURRENT
(PendingIntent.FLAG_IMMUTABLE) or PendingIntent.FLAG_UPDATE_CURRENT
)
)
}.build()
Expand Down
Loading

0 comments on commit d5eaab3

Please sign in to comment.