Compare commits

...

4 Commits

561 changed files with 3895 additions and 3559 deletions

View File

@ -76,7 +76,7 @@ body:
description: Where did you install Spotube from?
multiple: true
options:
- "Website (spotube.cc)"
- "Website (spotube.org)"
- "GitHub Releases (Binary)"
- "GitHub Actions (Nightly Binary)"
- "Play Store (Android)"

View File

@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Ask a question
url: https://github.com/KRTirtho/spotube/discussions/new?category=q-a
url: https://github.com/team-spotube/spotube/discussions/new?category=q-a
about: The place for questions, support and feature requests

View File

@ -141,11 +141,16 @@ jobs:
EOF
- name: Assemble Release
run: ./gradlew :composeApp:assembleRelease
run: |
if [ "${{ inputs.release_type }}" = "nightly" ]; then
./gradlew :composeApp:assembleNightlyRelease -Pnightly=true -PbuildNumber=${{ github.run_number }}
else
./gradlew :composeApp:assembleStableRelease
fi
- name: Rename APK
run: |
APK_FILE=$(find composeApp/build/outputs/apk/release -name "*.apk" -type f | head -1)
APK_FILE=$(find composeApp/build/outputs/apk -path "*elease*" -name "*.apk" -type f | head -1)
cp "$APK_FILE" Spotube-android-all-arch.apk
- name: Upload APK
@ -194,7 +199,7 @@ jobs:
run: chmod +x gradlew
- name: Package Linux
run: ./gradlew :composeApp:packageReleaseDeb :composeApp:packageReleaseRpm
run: ./gradlew :composeApp:packageReleaseDeb :composeApp:packageReleaseRpm -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
- name: Rename Linux artifacts
run: |
@ -255,7 +260,7 @@ jobs:
run: chmod +x gradlew
- name: Package Linux
run: ./gradlew :composeApp:packageReleaseDeb :composeApp:packageReleaseRpm
run: ./gradlew :composeApp:packageReleaseDeb :composeApp:packageReleaseRpm -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
- name: Rename Linux artifacts
run: |
@ -308,7 +313,7 @@ jobs:
uses: gradle/actions/setup-gradle@v4
- name: Package EXE
run: ./gradlew :composeApp:packageReleaseExe
run: ./gradlew :composeApp:packageReleaseExe -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
- name: Rename Windows artifacts
shell: pwsh
@ -357,7 +362,7 @@ jobs:
run: chmod +x gradlew
- name: Package DMG
run: ./gradlew :composeApp:packageReleaseDmg
run: ./gradlew :composeApp:packageReleaseDmg -Pnightly=${{ inputs.release_type == 'nightly' }} -PbuildNumber=${{ github.run_number }}
- name: Rename macOS artifact
run: |
@ -389,18 +394,35 @@ jobs:
steps:
- uses: actions/checkout@v4
# The build resolves its plugins from mavenLocal, so Gradle needs the same setup as the build jobs
- name: Download maven local
uses: actions/download-artifact@v4
with:
name: maven-local
path: ~/.m2/repository/
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Set release variables
id: vars
run: |
if [ "${{ inputs.release_type }}" = "stable" ]; then
VERSION=$(grep 'versionName' composeApp/build.gradle.kts | head -1 | sed 's/.*"\(.*\)".*/\1/')
chmod +x gradlew
VERSION=$(./gradlew -q :composeApp:printVersion)
TAG="v${VERSION}"
echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
echo "is_draft=true" >> "$GITHUB_OUTPUT"
echo "release_name=Spotube ${TAG}" >> "$GITHUB_OUTPUT"
else
TAG="nightly"
VERSION="$(date +%Y-%m-%d)"
VERSION="$(date +%Y-%m-%d)-${{ github.run_number }}"
echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
echo "is_draft=false" >> "$GITHUB_OUTPUT"
echo "release_name=Nightly ${VERSION}" >> "$GITHUB_OUTPUT"

View File

@ -5,14 +5,14 @@
- `:composeApp` uses custom KMP source sets (`mobileMain`, `androidJvmMain`) with explicit `dependsOn`; Gradle prints "Default Kotlin Hierarchy Template Not Applied Correctly" warning. Treat as known/expected.
## Real app entrypoints
- Desktop/JVM: `composeApp/src/jvmMain/kotlin/dev/krtirtho/spotube/main.kt` (`mainClass = dev.krtirtho.spotube.MainKt`).
- Android: `composeApp/src/androidMain/kotlin/dev/krtirtho/spotube/MainActivity.kt`.
- iOS bridge: `composeApp/src/iosMain/kotlin/dev/krtirtho/spotube/MainViewController.kt` and `iosApp/iosApp/ContentView.swift`.
- Desktop/JVM: `composeApp/src/jvmMain/kotlin/org/spotube/spotube/main.kt` (`mainClass = org.spotube.spotube.MainKt`).
- Android: `composeApp/src/androidMain/kotlin/org/spotube/spotube/MainActivity.kt`.
- iOS bridge: `composeApp/src/iosMain/kotlin/org/spotube/spotube/MainViewController.kt` and `iosApp/iosApp/ContentView.swift`.
## High-value commands
- Use Gradle wrapper (`./gradlew` or `./gradlew.bat`) only.
- Run desktop: `:composeApp:run`
- Build Android debug: `:composeApp:assembleDebug`
- Build Android debug: `:composeApp:assembleStableDebug` (or `assembleNightlyDebug`). Android has `stable`/`nightly` product flavors (nightly = beta channel: `.nightly` applicationId suffix, own icons/name in `composeApp/src/nightly/res`). Desktop icons come from `composeApp/icons/{stable,nightly}`, chosen with `-Pnightly=true`.
- Module checks: `:composeApp:check`, `:plugin_interfaces:check`, `:js_plugin_example:check`
- Focused tests: `:composeApp:jvmTest`, `:composeApp:iosSimulatorArm64Test`, `:plugin_interfaces:jvmTest`, `:plugin_interfaces:jsTest`, `:js_plugin_example:jsTest`
- No lint/typecheck/formatter tasks are configured; `:composeApp:check` is the only aggregated check.
@ -24,7 +24,7 @@
## Codegen and plugin packaging
- JS plugin bundles: `:js_plugin_example:packageDevelopmentPlugin` and `:js_plugin_example:packageProductionPlugin`. Output is `.smplug` files in `js_plugin_example/build/distributions/`.
- Zipline plugin entrypoint: `mainFunction = "dev.krtirtho.js_plugin_example.main"` in `js_plugin_example/build.gradle.kts`. Plugin metadata from `js_plugin_example/plugin.json`.
- Zipline plugin entrypoint: `mainFunction = "org.spotube.js_plugin_example.main"` in `js_plugin_example/build.gradle.kts`. Plugin metadata from `js_plugin_example/plugin.json`.
## Plugin architecture
- `plugin_interfaces` exports `zipline.core` and `semver` as API. `composeApp` depends on it for the plugin system.
@ -70,6 +70,6 @@
- **Adaptive Components:** Use `AdaptiveDropdownBottomSheet` or `AdaptiveDialogBottomSheet` inside `commonMain` for adaptive layouts[cite: 2]. Do NOT create platform-specific `expect/actual` variants unless platform-native APIs (like windowing or native scrollbars) are explicitly required[cite: 2].
### 3. Verification & Diagnostic Loops
- **Post-Edit Verification:** After editing Kotlin code, validate compilation by running `./gradlew :composeApp:check` or `./gradlew :composeApp:assembleDebug` via MCP[cite: 2].
- **Post-Edit Verification:** After editing Kotlin code, validate compilation by running `./gradlew :composeApp:check` or `./gradlew :composeApp:assembleStableDebug` via MCP[cite: 2].
- **Dispatcher Integrity:** Never remove or bypass `SwingMainDispatcherFactory` in `composeApp/src/jvmMain/.../core/coroutines/`[cite: 2]. It is required to prevent `compose-webview` from hijacking `Dispatchers.Main` away from the Swing EDT[cite: 2].
- **Live Preview Iteration:** Use `compose-hot-reload` to evaluate UI layout changes headlessly without forcing full Gradle rebuilds.

File diff suppressed because it is too large Load Diff

View File

@ -30,19 +30,19 @@ All types of contributions are encouraged and valued. See the [Table of Contents
## Code of Conduct
This project and everyone participating in it is governed by the
[Spotube Code of Conduct](https://github.com/KRTirtho/spotube/blob/master/CODE_OF_CONDUCT.md).
[Spotube Code of Conduct](https://github.com/team-spotube/spotube/blob/master/CODE_OF_CONDUCT.md).
By participating, you are expected to uphold this code. Please report unacceptable behavior
to krtirtho@gmail.com.
## I Have a Question
> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/KRTirtho/spotube#readme).
> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/team-spotube/spotube#readme).
Before you ask a question, it is best to search for existing [Issues](https://github.com/KRTirtho/spotube/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
Before you ask a question, it is best to search for existing [Issues](https://github.com/team-spotube/spotube/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
If you then still feel the need to ask a question and need clarification, we recommend the following:
- Open an [Discussion](https://github.com/KRTirtho/spotube/discussions/new) with the question label.
- Open an [Discussion](https://github.com/team-spotube/spotube/discussions/new) with the question label.
- Provide as much context as you can about what you're running into.
- Provide project and platform versions (flutter, dart, pub, linux etc..), depending on what seems relevant.
@ -61,8 +61,8 @@ We will then take care of the issue as soon as possible.
A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
- Make sure that you are using the latest version.
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/KRTirtho/spotube#readme). If you are looking for support, you might want to check [this section](#i-have-a-question)).
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/KRTirtho/spotubeissues?q=label%3Abug).
- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/team-spotube/spotube#readme). If you are looking for support, you might want to check [this section](#i-have-a-question)).
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/team-spotube/spotube/issues?q=label%3Abug).
- Also make sure to search the internet (including Stack Overflow) to see if users outside of the GitHub community have discussed the issue.
- Collect information about the bug:
- Stack trace (Traceback)
@ -77,7 +77,7 @@ A good bug report shouldn't leave others needing to chase you up for more inform
We use GitHub issues to track bugs and errors. If you run into an issue with the project:
- Open an [Issue](https://github.com/KRTirtho/spotube/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
- Open an [Issue](https://github.com/team-spotube/spotube/issues/new). (Since we can't be sure at this point whether it is a bug or not, we ask you not to talk about a bug yet and not to label the issue.)
- Explain the behavior you would expect and the actual behavior.
- Please provide as much context as possible and describe the _reproduction steps_ that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
- Provide the information you collected in the previous section.
@ -97,15 +97,15 @@ This section guides you through submitting an enhancement suggestion for Spotube
#### Before Submitting an Enhancement
- Make sure that you are using the latest version.
- Read the [documentation](https://github.com/KRTirtho/spotube#readme) carefully and find out if the functionality is already covered, maybe by an individual configuration.
- Perform a [search](https://github.com/KRTirtho/spotube/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
- Read the [documentation](https://github.com/team-spotube/spotube#readme) carefully and find out if the functionality is already covered, maybe by an individual configuration.
- Perform a [search](https://github.com/team-spotube/spotube/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset
<!-- omit in toc -->
#### How Do I Submit a Good Enhancement Suggestion?
Enhancement suggestions are tracked as [GitHub issues](https://github.com/KRTirtho/spotube/issues).
Enhancement suggestions are tracked as [GitHub issues](https://github.com/team-spotube/spotube/issues).
- Use a **clear and descriptive title** for the issue to identify the suggestion.
- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.

View File

@ -4,7 +4,7 @@
A cross-platform extensible open-source music streaming platform.<br>
Bring your own music metadata/playlist/audio-source with plugins created by community or by yourself. A small step towards the decentralized music streaming era!
<a href="https://spotube.cc"><img alt="Visit the website" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/website_vector.svg"></a>
<a href="https://spotube.org"><img alt="Visit the website" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/website_vector.svg"></a>
<a href="https://discord.gg/uJ94vxB6vg"><img alt="Discord Server" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/social/discord-plural_vector.svg"></a>
<a href="https://patreon.com/krtirtho"><img alt="Support me on Patron" height="56" src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/donate/patreon-singular_vector.svg"></a>
@ -37,21 +37,21 @@ Bring your own music metadata/playlist/audio-source with plugins created by comm
### ⬇️ Download
Download Spotube from the Official Website: https://spotube.cc
Download Spotube from the Official Website: https://spotube.org
### 🔄 Nightly Builds
Grab the latest nightly builds of Spotube [from the Offical Website](https://spotube.cc/downloads/nightly).
Grab the latest nightly builds of Spotube [from the Offical Website](https://spotube.org/downloads/nightly).
## 🕳️ Building from source
<a href="https://github.com/KRTirtho/spotube/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/KRTirtho/spotube/spotube-release-binary.yml?+label=Build%20Status"></a>
<a href="https://github.com/team-spotube/spotube/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/KRTirtho/spotube/spotube-release-binary.yml?+label=Build%20Status"></a>
You can compile Spotube's source code by [following these instructions](CONTRIBUTION.md#your-first-code-contribution).
## 👥 The Spotube team
- [Kingkor Roy Tirtho](https://github.com/KRTirtho) - The Founder, Maintainer and Lead Developer
- [Kingkor Roy Tirtho](https://github.com/team-spotube) - The Founder, Maintainer and Lead Developer
- [Owen Connor](https://github.com/owencz1998) - The Cool Discord Moderator
- [Piotr Rogowski](https://github.com/karniv00l) - The MacOS Developer
- [Rusty Apple](https://github.com/RustyApple) - The Mysterious Unknown Guy

View File

@ -27,7 +27,7 @@ render_always = true
# An array of regex based postprocessors to modify the changelog.
postprocessors = [
# Replace the placeholder <REPO> with a URL.
{ pattern = '<REPO>', replace = "https://github.com/KRTirtho/spotube" },
{ pattern = '<REPO>', replace = "https://github.com/team-spotube/spotube" },
]
# render body even when there are no releases to process
# render_always = true

View File

@ -40,22 +40,34 @@ plugins {
kotlin("plugin.atomicfu") version libs.versions.kotlin
}
val bundleId = "dev.krtirtho.spotube"
val bundleId = "org.spotube.spotube"
val version = "6.0.0"
val buildNumber = 46
// Desktop icon channel; Android picks its icons via the stable/nightly product flavor. Use -Pnightly=true.
val isNightly = providers.gradleProperty("nightly").map { it.toBoolean() }.getOrElse(false)
val desktopIconDir = if (isNightly) "icons/nightly" else "icons/stable"
// Nightlies are numbered by the CI run (-PbuildNumber=<run>, or GITHUB_RUN_NUMBER) so every build is traceable to its run.
val nightlyBuildNumber = providers.gradleProperty("buildNumber").orNull?.toIntOrNull()
?: System.getenv("GITHUB_RUN_NUMBER")?.toIntOrNull()
?: buildNumber
val targetName = "Spotube"
val homePageUrl = "https://spotube.cc"
val homePageUrl = "https://spotube.org"
val repositoryUrl = "https://github.com/team-spotube/spotube"
val appVersionName = version
val appBuildNumber = buildNumber
val appBuildNumber = if (isNightly) nightlyBuildNumber else buildNumber
val appRepositoryUrl = repositoryUrl
// CI reads the release version from here instead of scraping this file.
tasks.register("printVersion") {
val appVersion = appVersionName
doLast { println(appVersion) }
}
val githubRepositoryPath = repositoryUrl.removePrefix("https://github.com/")
val latestReleaseApiUrl = "https://api.github.com/repos/$githubRepositoryPath/releases/latest"
val generatedAppInfoDir = layout.buildDirectory.dir("generated/appBuildInfo/commonMain/kotlin")
val generateAppBuildInfo by tasks.registering(Copy::class) {
description = "Generate AppBuildInfo.kt"
from(layout.projectDirectory.file("src/commonMain/templates/AppBuildInfo.kt.template"))
into(layout.buildDirectory.dir("generated/appBuildInfo/commonMain/kotlin/dev/krtirtho/spotube"))
into(layout.buildDirectory.dir("generated/appBuildInfo/commonMain/kotlin/org/spotube/spotube"))
rename("AppBuildInfo.kt.template", "AppBuildInfo.kt")
expand(
mapOf(
@ -287,7 +299,7 @@ kotlin {
}
android {
namespace = "dev.krtirtho.spotube"
namespace = "org.spotube.spotube"
compileSdk = libs.versions.android.compileSdk.get().toInt()
defaultConfig {
@ -297,6 +309,19 @@ android {
versionCode = buildNumber
versionName = version
}
// stable = production channel, nightly = beta channel (own icon, name and installable side by side)
flavorDimensions += "channel"
productFlavors {
create("stable") {
dimension = "channel"
}
create("nightly") {
dimension = "channel"
applicationIdSuffix = ".nightly"
versionCode = nightlyBuildNumber
versionNameSuffix = "-nightly.$nightlyBuildNumber"
}
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
@ -350,7 +375,7 @@ dependencies {
}
nucleus.application {
mainClass = "dev.krtirtho.spotube.MainKt"
mainClass = "org.spotube.spotube.MainKt"
jvmArgs += listOf(
"--enable-native-access=ALL-UNNAMED", // need for JNA for compose-webview (wry) to work
@ -382,11 +407,13 @@ nucleus.application {
homepage = homePageUrl
linux {
iconFile.set(project.file("$desktopIconDir/icon.png"))
modules("jdk.security.auth")
debMaintainer = "Team Spotube <team.spotube@proton.me>"
rpmLicenseType = "AGPL-3.0-or-later"
}
windows {
iconFile.set(project.file("$desktopIconDir/icon.ico"))
shortcut = true
menu = true
dirChooser = true
@ -394,6 +421,7 @@ nucleus.application {
}
macOS {
iconFile.set(project.file("$desktopIconDir/icon.icns"))
notarization {
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

View File

@ -15,14 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.newpipe
package org.spotube.spotube.core.newpipe
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import dev.krtirtho.spotube.core.paths.Paths
import org.spotube.spotube.core.paths.Paths
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json

View File

@ -15,10 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.newpipe
package org.spotube.spotube.core.newpipe
import dev.krtirtho.plugin_interfaces.plugin_apis.audio.AudioStream
import dev.krtirtho.plugin_interfaces.plugin_apis.audio.StreamProtocol
import org.spotube.plugin_interfaces.plugin_apis.audio.AudioStream
import org.spotube.plugin_interfaces.plugin_apis.audio.StreamProtocol
import io.ktor.http.Url
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube
package org.spotube.spotube
import android.content.Intent
import android.os.Build
@ -23,10 +23,10 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import dev.krtirtho.spotube.core.deeplink.ExternalUriHandler
import dev.krtirtho.spotube.core.newpipe.NewPipeDownloader
import dev.krtirtho.spotube.core.paths.Paths
import dev.krtirtho.spotube.media.PlaybackService
import org.spotube.spotube.core.deeplink.ExternalUriHandler
import org.spotube.spotube.core.newpipe.NewPipeDownloader
import org.spotube.spotube.core.paths.Paths
import org.spotube.spotube.media.PlaybackService
import io.github.vinceglb.filekit.FileKit
import io.github.vinceglb.filekit.dialogs.init

View File

@ -15,11 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube
package org.spotube.spotube
import android.app.Application
import dev.krtirtho.spotube.core.di.initKoin
import dev.krtirtho.spotube.core.paths.Paths
import org.spotube.spotube.core.di.initKoin
import org.spotube.spotube.core.paths.Paths
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube
package org.spotube.spotube
import android.content.Context
import android.content.Intent

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.audioplayer
package org.spotube.spotube.core.audioplayer
import android.content.Context
import android.content.Intent
@ -27,7 +27,7 @@ import androidx.media3.common.MediaMetadata
import androidx.media3.common.PlaybackException
import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer
import dev.krtirtho.spotube.media.PlaybackService
import org.spotube.spotube.media.PlaybackService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob

View File

@ -15,17 +15,17 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.di
package org.spotube.spotube.core.di
import android.content.Context
import dev.krtirtho.spotube.core.audioplayer.AudioPlayer
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerInterface
import dev.krtirtho.spotube.core.paths.Paths
import dev.krtirtho.spotube.core.share.AndroidShareService
import dev.krtirtho.spotube.core.share.ShareService
import dev.krtirtho.spotube.media.MediaBrowseHelper
import dev.krtirtho.spotube.modules.library.local_tracks.media.AndroidLocalMediaDiscoveryService
import dev.krtirtho.spotube.modules.library.local_tracks.media.LocalMediaDiscoveryService
import org.spotube.spotube.core.audioplayer.AudioPlayer
import org.spotube.spotube.core.audioplayer.AudioPlayerInterface
import org.spotube.spotube.core.paths.Paths
import org.spotube.spotube.core.share.AndroidShareService
import org.spotube.spotube.core.share.ShareService
import org.spotube.spotube.media.MediaBrowseHelper
import org.spotube.spotube.modules.library.local_tracks.media.AndroidLocalMediaDiscoveryService
import org.spotube.spotube.modules.library.local_tracks.media.LocalMediaDiscoveryService
import org.koin.dsl.module
actual val platformModules = module {

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.discovery
package org.spotube.spotube.core.discovery
import android.Manifest
import android.content.pm.PackageManager

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.i18n
package org.spotube.spotube.core.i18n
import android.content.res.Configuration
import android.content.res.Resources

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.paths
package org.spotube.spotube.core.paths
import android.content.Context
import android.os.Environment

View File

@ -15,11 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.share
package org.spotube.spotube.core.share
import android.content.Context
import androidx.core.app.ShareCompat
import dev.krtirtho.spotube.core.share.ShareService
import org.spotube.spotube.core.share.ShareService
class AndroidShareService(private val context: Context) : ShareService {
override fun share(url: String, title: String) {

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.webview
package org.spotube.spotube.core.webview
import android.webkit.CookieManager
import android.webkit.WebStorage

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.zipline
package org.spotube.spotube.core.zipline
import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executors

View File

@ -15,31 +15,31 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.media
package org.spotube.spotube.media
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.media3.common.MediaItem
import androidx.media3.common.MediaMetadata
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.album.MetadataAlbum
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.artist.MetadataArtist
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.browse.MetadataBrowseItem
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.playlist.MetadataPlaylist
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.search.MetadataSearchResult
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueue
import dev.krtirtho.spotube.core.audioplayer.QueueEntry
import dev.krtirtho.spotube.core.playback.CollectionPlaybackHelper
import dev.krtirtho.spotube.modules.album.AlbumRepository
import dev.krtirtho.spotube.modules.blacklist.BlacklistRepository
import dev.krtirtho.spotube.modules.home.HomeScreenRepository
import dev.krtirtho.spotube.modules.library.LibraryRepository
import dev.krtirtho.spotube.modules.playlist.PlaylistRepository
import dev.krtirtho.spotube.modules.plugin.PluginManager
import dev.krtirtho.spotube.modules.saved_tracks.SavedTracksRepository
import dev.krtirtho.spotube.modules.search.SearchRepository
import dev.krtirtho.spotube.modules.settings.SettingsRepository
import org.spotube.plugin_interfaces.plugin_apis.metadata.album.MetadataAlbum
import org.spotube.plugin_interfaces.plugin_apis.metadata.artist.MetadataArtist
import org.spotube.plugin_interfaces.plugin_apis.metadata.browse.MetadataBrowseItem
import org.spotube.plugin_interfaces.plugin_apis.metadata.playlist.MetadataPlaylist
import org.spotube.plugin_interfaces.plugin_apis.metadata.search.MetadataSearchResult
import org.spotube.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import org.spotube.spotube.core.audioplayer.AudioPlayerQueue
import org.spotube.spotube.core.audioplayer.QueueEntry
import org.spotube.spotube.core.playback.CollectionPlaybackHelper
import org.spotube.spotube.modules.album.AlbumRepository
import org.spotube.spotube.modules.blacklist.BlacklistRepository
import org.spotube.spotube.modules.home.HomeScreenRepository
import org.spotube.spotube.modules.library.LibraryRepository
import org.spotube.spotube.modules.playlist.PlaylistRepository
import org.spotube.spotube.modules.plugin.PluginManager
import org.spotube.spotube.modules.saved_tracks.SavedTracksRepository
import org.spotube.spotube.modules.search.SearchRepository
import org.spotube.spotube.modules.settings.SettingsRepository
import kotlinx.coroutines.flow.first
import org.jetbrains.compose.resources.getString
import spotube.composeapp.generated.resources.Res

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.media
package org.spotube.spotube.media
import android.annotation.SuppressLint
import android.app.NotificationChannel
@ -29,6 +29,7 @@ import androidx.core.app.NotificationCompat
import androidx.media3.common.MediaItem as Media3MediaItem
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.session.DefaultMediaNotificationProvider
import androidx.media3.session.LibraryResult
import androidx.media3.session.MediaLibraryService
import androidx.media3.session.MediaLibraryService.LibraryParams
@ -40,11 +41,12 @@ import com.google.common.collect.ImmutableList
import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.SettableFuture
import dev.krtirtho.spotube.MainActivity
import dev.krtirtho.spotube.core.audioplayer.AudioPlayer
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerInterface
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueue
import dev.krtirtho.spotube.core.audioplayer.QueueEntry
import org.spotube.spotube.MainActivity
import org.spotube.spotube.R
import org.spotube.spotube.core.audioplayer.AudioPlayer
import org.spotube.spotube.core.audioplayer.AudioPlayerInterface
import org.spotube.spotube.core.audioplayer.AudioPlayerQueue
import org.spotube.spotube.core.audioplayer.QueueEntry
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@ -75,6 +77,16 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
createNotificationChannel()
// Media3 posts the real playback notification; point it at our channel,
// ID and monochrome icon so it replaces the placeholder below in place.
setMediaNotificationProvider(
DefaultMediaNotificationProvider.Builder(this)
.setChannelId(CHANNEL_ID)
.setNotificationId(NOTIFICATION_ID)
.build()
.apply { setSmallIcon(R.drawable.ic_stat_spotube) }
)
val sessionActivity = PendingIntent.getActivity(
this,
0,
@ -87,7 +99,7 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Spotube")
.setContentText(runBlocking { getString(Res.string.notification_playback_service_text) })
.setSmallIcon(android.R.drawable.ic_media_play)
.setSmallIcon(R.drawable.ic_stat_spotube)
.setContentIntent(sessionActivity)
.setOngoing(true)
.build()
@ -371,20 +383,20 @@ class PlaybackService : MediaLibraryService(), KoinComponent {
when {
mediaId.startsWith("${MediaBrowseHelper.MEDIA_ID_PLAYLIST}:") -> {
val playlistId = mediaId.removePrefix("${MediaBrowseHelper.MEDIA_ID_PLAYLIST}:")
val helper: dev.krtirtho.spotube.core.playback.CollectionPlaybackHelper by inject()
val helper: org.spotube.spotube.core.playback.CollectionPlaybackHelper by inject()
helper.playPlaylist(playlistId)
return
}
mediaId.startsWith("${MediaBrowseHelper.MEDIA_ID_ALBUM}:") -> {
val albumId = mediaId.removePrefix("${MediaBrowseHelper.MEDIA_ID_ALBUM}:")
val helper: dev.krtirtho.spotube.core.playback.CollectionPlaybackHelper by inject()
val helper: org.spotube.spotube.core.playback.CollectionPlaybackHelper by inject()
helper.playAlbum(albumId)
return
}
mediaId == MediaBrowseHelper.MEDIA_ID_SAVED_TRACKS -> {
val helper: dev.krtirtho.spotube.core.playback.CollectionPlaybackHelper by inject()
val helper: org.spotube.spotube.core.playback.CollectionPlaybackHelper by inject()
helper.playSavedTracks()
return
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.modules.library.local_tracks.media
package org.spotube.spotube.modules.library.local_tracks.media
import android.Manifest
import android.content.Context
@ -26,7 +26,7 @@ import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
import dev.krtirtho.spotube.core.di.injectLogger
import org.spotube.spotube.core.di.injectLogger
import org.koin.core.component.KoinComponent
import java.io.File
import java.util.Locale

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.modules.library.local_tracks.media
package org.spotube.spotube.modules.library.local_tracks.media
import android.Manifest
import android.content.pm.PackageManager

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

View File

@ -1,47 +0,0 @@
<!--
~ Copyright (C) 2026 Kingkor Roy Tirtho and Spotube Contributors
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU Affero General Public License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,187 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2026 Kingkor Roy Tirtho and Spotube Contributors
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU Affero General Public License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -17,6 +17,7 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
<background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

View File

@ -17,6 +17,7 @@
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
<background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2026 Kingkor Roy Tirtho and Spotube Contributors
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU Affero General Public License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<resources>
<color name="ic_launcher_background">#000000</color>
</resources>

View File

@ -907,6 +907,7 @@
<string name="plugin_discover_badge_verified">Verified</string>
<string name="plugin_discover_stars_content_description">GitHub stars</string>
<string name="plugin_discover_repository_content_description">GitHub repository URL</string>
<string name="plugin_discover_repository_host">github.com</string>
<!-- Plugin release install dialog -->
<string name="plugin_install_no_releases">No releases found</string>

View File

@ -1,2 +0,0 @@
package dev.krtirtho.spotube.modules.blacklist

View File

@ -1,3 +0,0 @@
package dev.krtirtho.spotube.resources.iconsax
object Iconsax

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube
package org.spotube.spotube
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
@ -33,42 +33,42 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation3.ui.NavDisplay
import dev.krtirtho.spotube.core.DebugConfig
import dev.krtirtho.spotube.core.i18n.AppLocaleProvider
import dev.krtirtho.spotube.core.navigation.Navigator
import dev.krtirtho.spotube.core.navigation.Routes
import dev.krtirtho.spotube.core.navigation.TOP_LEVEL_ROUTES
import dev.krtirtho.spotube.core.navigation.navPopTransitionSpec
import dev.krtirtho.spotube.core.navigation.navPredictivePopTransitionSpec
import dev.krtirtho.spotube.core.navigation.navPushTransitionSpec
import dev.krtirtho.spotube.core.navigation.rememberNavigationState
import dev.krtirtho.spotube.core.navigation.toEntries
import dev.krtirtho.spotube.core.ui.component.LocalSharedTransitionScope
import dev.krtirtho.spotube.core.ui.theming.SpotubeTheme
import dev.krtirtho.spotube.modules.library.LibraryTab
import dev.krtirtho.spotube.modules.settings.SettingsRepository
import dev.krtirtho.spotube.modules.settings.UserSettings
import dev.krtirtho.spotube.modules.shell.AppShell
import dev.krtirtho.spotube.modules.support.LocalSupportPrompt
import dev.krtirtho.spotube.modules.support.SupportDialog
import dev.krtirtho.spotube.modules.support.SupportReminderIntervalMillis
import dev.krtirtho.spotube.modules.update.AppUpdateDialog
import dev.krtirtho.spotube.modules.update.AppUpdateService
import dev.krtirtho.spotube.modules.update.PluginUpdateDialog
import dev.krtirtho.spotube.modules.update.PluginUpdateService
import dev.krtirtho.spotube.modules.webview.WebViewScreen
import dev.krtirtho.spotube.modules.welcome.WelcomeRepository
import dev.krtirtho.spotube.resources.iconsax.Iconsax
import dev.krtirtho.spotube.resources.iconsax.IconsaxCd
import dev.krtirtho.spotube.resources.iconsax.IconsaxDirectboxReceive
import dev.krtirtho.spotube.resources.iconsax.IconsaxHome
import dev.krtirtho.spotube.resources.iconsax.IconsaxMirrorScreenRegular
import dev.krtirtho.spotube.resources.iconsax.IconsaxMusicDashboard
import dev.krtirtho.spotube.resources.iconsax.IconsaxMusicLibrary
import dev.krtirtho.spotube.resources.iconsax.IconsaxSearch
import dev.krtirtho.spotube.resources.iconsax.IconsaxSetting2
import dev.krtirtho.spotube.resources.iconsax.IconsaxSoundTwotone
import dev.krtirtho.spotube.resources.iconsax.User
import org.spotube.spotube.core.DebugConfig
import org.spotube.spotube.core.i18n.AppLocaleProvider
import org.spotube.spotube.core.navigation.Navigator
import org.spotube.spotube.core.navigation.Routes
import org.spotube.spotube.core.navigation.TOP_LEVEL_ROUTES
import org.spotube.spotube.core.navigation.navPopTransitionSpec
import org.spotube.spotube.core.navigation.navPredictivePopTransitionSpec
import org.spotube.spotube.core.navigation.navPushTransitionSpec
import org.spotube.spotube.core.navigation.rememberNavigationState
import org.spotube.spotube.core.navigation.toEntries
import org.spotube.spotube.core.ui.component.LocalSharedTransitionScope
import org.spotube.spotube.core.ui.theming.SpotubeTheme
import org.spotube.spotube.modules.library.LibraryTab
import org.spotube.spotube.modules.settings.SettingsRepository
import org.spotube.spotube.modules.settings.UserSettings
import org.spotube.spotube.modules.shell.AppShell
import org.spotube.spotube.modules.support.LocalSupportPrompt
import org.spotube.spotube.modules.support.SupportDialog
import org.spotube.spotube.modules.support.SupportReminderIntervalMillis
import org.spotube.spotube.modules.update.AppUpdateDialog
import org.spotube.spotube.modules.update.AppUpdateService
import org.spotube.spotube.modules.update.PluginUpdateDialog
import org.spotube.spotube.modules.update.PluginUpdateService
import org.spotube.spotube.modules.webview.WebViewScreen
import org.spotube.spotube.modules.welcome.WelcomeRepository
import org.spotube.spotube.resources.iconsax.Iconsax
import org.spotube.spotube.resources.iconsax.IconsaxCd
import org.spotube.spotube.resources.iconsax.IconsaxDirectboxReceive
import org.spotube.spotube.resources.iconsax.IconsaxHome
import org.spotube.spotube.resources.iconsax.IconsaxMirrorScreenRegular
import org.spotube.spotube.resources.iconsax.IconsaxMusicDashboard
import org.spotube.spotube.resources.iconsax.IconsaxMusicLibrary
import org.spotube.spotube.resources.iconsax.IconsaxSearch
import org.spotube.spotube.resources.iconsax.IconsaxSetting2
import org.spotube.spotube.resources.iconsax.IconsaxSoundTwotone
import org.spotube.spotube.resources.iconsax.User
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlin.time.Clock
import org.koin.compose.koinInject
@ -253,7 +253,7 @@ fun App(
onDismiss = appUpdateService::dismissUpdate,
onIgnore = appUpdateService::ignoreUpdate,
onUpdate = {
runCatching { openUrlInBrowser("https://spotube.cc/downloads/") }
runCatching { openUrlInBrowser("https://spotube.org/downloads/") }
appUpdateService.dismissUpdate()
})
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube
package org.spotube.spotube
enum class PlatformType {
Android, IOS, Windows, Linux, MacOS, Unknown

View File

@ -15,10 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core
package org.spotube.spotube.core
/**
* Development-only switches. These are intentionally kept out of [dev.krtirtho.spotube.modules.settings.UserSettings]
* Development-only switches. These are intentionally kept out of [org.spotube.spotube.modules.settings.UserSettings]
* so they can never leak into user-facing configuration.
*/
object DebugConfig {

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.audioplayer
package org.spotube.spotube.core.audioplayer
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow

View File

@ -15,10 +15,10 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.audioplayer
package org.spotube.spotube.core.audioplayer
import dev.krtirtho.plugin_interfaces.plugin_apis.audio.StreamProtocol
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import org.spotube.plugin_interfaces.plugin_apis.audio.StreamProtocol
import org.spotube.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlin.time.Duration

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.audioplayer
package org.spotube.spotube.core.audioplayer
import kotlinx.coroutines.flow.StateFlow

View File

@ -15,11 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.audioplayer
package org.spotube.spotube.core.audioplayer
import androidx.datastore.preferences.core.edit
import dev.krtirtho.spotube.core.db.Database
import dev.krtirtho.spotube.core.db.DatabaseKeys
import org.spotube.spotube.core.db.Database
import org.spotube.spotube.core.db.DatabaseKeys
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.serialization.json.Json

View File

@ -15,13 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.audioplayer
package org.spotube.spotube.core.audioplayer
import dev.krtirtho.plugin_interfaces.plugin_apis.audio.StreamProtocol
import dev.krtirtho.spotube.core.di.injectLogger
import dev.krtirtho.spotube.modules.blacklist.BlacklistRepository
import dev.krtirtho.spotube.modules.plugin.PluginProvider
import dev.krtirtho.spotube.modules.settings.SettingsProvider
import org.spotube.plugin_interfaces.plugin_apis.audio.StreamProtocol
import org.spotube.spotube.core.di.injectLogger
import org.spotube.spotube.modules.blacklist.BlacklistRepository
import org.spotube.spotube.modules.plugin.PluginProvider
import org.spotube.spotube.modules.settings.SettingsProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO

View File

@ -15,14 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.db
package org.spotube.spotube.core.db
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import dev.krtirtho.spotube.core.paths.Paths
import org.spotube.spotube.core.paths.Paths
import okio.FileSystem
import okio.Path.Companion.toPath
import okio.SYSTEM
@ -77,6 +77,12 @@ class Database(val paths: Paths) {
)
}
val windowStateDataStore: DataStore<Preferences> by lazy {
PreferenceDataStoreFactory.createWithPath(
produceFile = { "${paths.getApplicationDataDirPath()}/spotube_window.preferences_pb".toPath() }
)
}
private companion object {
/** Preference files written by previous launches; their presence means an upgrade. */
val EXISTING_INSTALL_PROBE_FILES = listOf(
@ -95,4 +101,5 @@ object DatabaseKeys {
val AUDIO_PLAYER_QUEUE_STATE_KEY = stringPreferencesKey("audio_player_queue_state")
val LOCAL_MEDIA_CACHE_STATE_KEY = stringPreferencesKey("local_media_cache_state")
val LOCAL_MEDIA_LAST_SCAN_AT_KEY = longPreferencesKey("local_media_last_scan_at")
val WINDOW_STATE_KEY = stringPreferencesKey("window_state")
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.deeplink
package org.spotube.spotube.core.deeplink
/**
* Cross-platform receiver for URIs handed to the app by the operating system

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.di
package org.spotube.spotube.core.di
import androidx.compose.runtime.Composable
import co.touchlab.kermit.Logger

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.di
package org.spotube.spotube.core.di
import co.touchlab.kermit.Logger
import co.touchlab.kermit.koin.KermitKoinLogger

View File

@ -15,82 +15,82 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.di
package org.spotube.spotube.core.di
import co.touchlab.kermit.Logger
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueue
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueueRepository
import dev.krtirtho.spotube.core.audioplayer.DeviceAudioPlayerQueue
import dev.krtirtho.spotube.core.audioplayer.QueueStateRepository
import dev.krtirtho.spotube.core.db.Database
import dev.krtirtho.spotube.core.discovery.DeviceDiscoveryService
import dev.krtirtho.spotube.core.discord.DiscordRpcService
import dev.krtirtho.spotube.core.jam.JamRoomClient
import dev.krtirtho.spotube.core.jam.JamRoomService
import dev.krtirtho.spotube.core.navigation.navigationModule
import dev.krtirtho.spotube.core.remote.RemoteControlClient
import dev.krtirtho.spotube.core.remote.RemoteControlHandler
import dev.krtirtho.spotube.core.remote.RemoteControlService
import dev.krtirtho.spotube.core.remote.RemotePlaybackController
import dev.krtirtho.spotube.core.scrobble.ScrobbleManager
import dev.krtirtho.spotube.core.playback.CollectionPlaybackHelper
import dev.krtirtho.spotube.core.server.AlternativeTracksRepository
import dev.krtirtho.spotube.core.server.CacheManager
import dev.krtirtho.spotube.core.server.LocalServer
import dev.krtirtho.spotube.core.server.MatchedTracksRepository
import dev.krtirtho.spotube.core.server.TrackSourceRepository
import dev.krtirtho.spotube.core.server.StreamingUrlRepository
import dev.krtirtho.spotube.core.webview.WebViewController
import dev.krtirtho.spotube.modules.album.AlbumRepository
import dev.krtirtho.spotube.modules.album.AlbumViewModel
import dev.krtirtho.spotube.modules.artist.ArtistRepository
import dev.krtirtho.spotube.modules.artist.ArtistViewModel
import dev.krtirtho.spotube.modules.blacklist.BlacklistRepository
import dev.krtirtho.spotube.modules.blacklist.BlacklistViewModel
import dev.krtirtho.spotube.modules.devices.DevicesViewModel
import dev.krtirtho.spotube.modules.devices.RemoteControlViewModel
import dev.krtirtho.spotube.modules.jam.JamViewModel
import dev.krtirtho.spotube.modules.downloads.DownloadManager
import dev.krtirtho.spotube.modules.downloads.DownloadsViewModel
import dev.krtirtho.spotube.modules.home.HomeScreenRepository
import dev.krtirtho.spotube.modules.home.HomeScreenViewModel
import dev.krtirtho.spotube.modules.plugin.MetadataAuthViewModel
import dev.krtirtho.spotube.modules.library.LibraryRepository
import dev.krtirtho.spotube.modules.library.LibraryState
import dev.krtirtho.spotube.modules.library.album.LibraryAlbumsViewModel
import dev.krtirtho.spotube.modules.library.artist.LibraryArtistsViewModel
import dev.krtirtho.spotube.modules.library.local_tracks.LibraryLocalTracksViewModel
import dev.krtirtho.spotube.modules.library.local_tracks.media.LocalMediaCacheRepository
import dev.krtirtho.spotube.modules.library.local_tracks.media.LocalMediaFoldersConfig
import dev.krtirtho.spotube.modules.library.local_tracks.media.LocalMediaLibraryCoordinator
import dev.krtirtho.spotube.modules.library.playlist.LibraryPlaylistsViewModel
import dev.krtirtho.spotube.modules.lyrics.LyricsViewModel
import dev.krtirtho.spotube.modules.playlist.PlaylistRepository
import dev.krtirtho.spotube.modules.playlist.PlaylistViewModel
import dev.krtirtho.spotube.modules.plugin.AudioPluginSource
import dev.krtirtho.spotube.modules.plugin.PluginManager
import dev.krtirtho.spotube.modules.plugin.PluginProvider
import dev.krtirtho.spotube.modules.plugin.PluginViewModel
import dev.krtirtho.spotube.modules.plugin.guard.MetadataPluginGuardViewModel
import dev.krtirtho.spotube.modules.plugin.ScrobblePluginSource
import dev.krtirtho.spotube.modules.saved_tracks.SavedTracksRepository
import dev.krtirtho.spotube.modules.saved_tracks.SavedTracksViewModel
import dev.krtirtho.spotube.modules.search.SearchRepository
import dev.krtirtho.spotube.modules.search.SearchScreenViewModel
import dev.krtirtho.spotube.modules.update.AppUpdateService
import dev.krtirtho.spotube.modules.update.PluginUpdateService
import dev.krtirtho.spotube.modules.settings.SettingsProvider
import dev.krtirtho.spotube.modules.settings.SettingsRepository
import dev.krtirtho.spotube.modules.settings.UserSettingsSource
import dev.krtirtho.spotube.modules.settings.SettingsViewModel
import dev.krtirtho.spotube.modules.settings.JamSettingsViewModel
import dev.krtirtho.spotube.modules.settings.LocalMediaFoldersViewModel
import dev.krtirtho.spotube.modules.shell.AppShellViewModel
import dev.krtirtho.spotube.modules.shell.PlayerOptionsViewModel
import dev.krtirtho.spotube.modules.shell.alternative_track.AlternativeTrackContentViewModel
import dev.krtirtho.spotube.modules.shell.player_queue.PlayerQueueContentViewModel
import dev.krtirtho.spotube.modules.welcome.WelcomeRepository
import dev.krtirtho.spotube.modules.welcome.WelcomeViewModel
import org.spotube.spotube.core.audioplayer.AudioPlayerQueue
import org.spotube.spotube.core.audioplayer.AudioPlayerQueueRepository
import org.spotube.spotube.core.audioplayer.DeviceAudioPlayerQueue
import org.spotube.spotube.core.audioplayer.QueueStateRepository
import org.spotube.spotube.core.db.Database
import org.spotube.spotube.core.discovery.DeviceDiscoveryService
import org.spotube.spotube.core.discord.DiscordRpcService
import org.spotube.spotube.core.jam.JamRoomClient
import org.spotube.spotube.core.jam.JamRoomService
import org.spotube.spotube.core.navigation.navigationModule
import org.spotube.spotube.core.remote.RemoteControlClient
import org.spotube.spotube.core.remote.RemoteControlHandler
import org.spotube.spotube.core.remote.RemoteControlService
import org.spotube.spotube.core.remote.RemotePlaybackController
import org.spotube.spotube.core.scrobble.ScrobbleManager
import org.spotube.spotube.core.playback.CollectionPlaybackHelper
import org.spotube.spotube.core.server.AlternativeTracksRepository
import org.spotube.spotube.core.server.CacheManager
import org.spotube.spotube.core.server.LocalServer
import org.spotube.spotube.core.server.MatchedTracksRepository
import org.spotube.spotube.core.server.TrackSourceRepository
import org.spotube.spotube.core.server.StreamingUrlRepository
import org.spotube.spotube.core.webview.WebViewController
import org.spotube.spotube.modules.album.AlbumRepository
import org.spotube.spotube.modules.album.AlbumViewModel
import org.spotube.spotube.modules.artist.ArtistRepository
import org.spotube.spotube.modules.artist.ArtistViewModel
import org.spotube.spotube.modules.blacklist.BlacklistRepository
import org.spotube.spotube.modules.blacklist.BlacklistViewModel
import org.spotube.spotube.modules.devices.DevicesViewModel
import org.spotube.spotube.modules.devices.RemoteControlViewModel
import org.spotube.spotube.modules.jam.JamViewModel
import org.spotube.spotube.modules.downloads.DownloadManager
import org.spotube.spotube.modules.downloads.DownloadsViewModel
import org.spotube.spotube.modules.home.HomeScreenRepository
import org.spotube.spotube.modules.home.HomeScreenViewModel
import org.spotube.spotube.modules.plugin.MetadataAuthViewModel
import org.spotube.spotube.modules.library.LibraryRepository
import org.spotube.spotube.modules.library.LibraryState
import org.spotube.spotube.modules.library.album.LibraryAlbumsViewModel
import org.spotube.spotube.modules.library.artist.LibraryArtistsViewModel
import org.spotube.spotube.modules.library.local_tracks.LibraryLocalTracksViewModel
import org.spotube.spotube.modules.library.local_tracks.media.LocalMediaCacheRepository
import org.spotube.spotube.modules.library.local_tracks.media.LocalMediaFoldersConfig
import org.spotube.spotube.modules.library.local_tracks.media.LocalMediaLibraryCoordinator
import org.spotube.spotube.modules.library.playlist.LibraryPlaylistsViewModel
import org.spotube.spotube.modules.lyrics.LyricsViewModel
import org.spotube.spotube.modules.playlist.PlaylistRepository
import org.spotube.spotube.modules.playlist.PlaylistViewModel
import org.spotube.spotube.modules.plugin.AudioPluginSource
import org.spotube.spotube.modules.plugin.PluginManager
import org.spotube.spotube.modules.plugin.PluginProvider
import org.spotube.spotube.modules.plugin.PluginViewModel
import org.spotube.spotube.modules.plugin.guard.MetadataPluginGuardViewModel
import org.spotube.spotube.modules.plugin.ScrobblePluginSource
import org.spotube.spotube.modules.saved_tracks.SavedTracksRepository
import org.spotube.spotube.modules.saved_tracks.SavedTracksViewModel
import org.spotube.spotube.modules.search.SearchRepository
import org.spotube.spotube.modules.search.SearchScreenViewModel
import org.spotube.spotube.modules.update.AppUpdateService
import org.spotube.spotube.modules.update.PluginUpdateService
import org.spotube.spotube.modules.settings.SettingsProvider
import org.spotube.spotube.modules.settings.SettingsRepository
import org.spotube.spotube.modules.settings.UserSettingsSource
import org.spotube.spotube.modules.settings.SettingsViewModel
import org.spotube.spotube.modules.settings.JamSettingsViewModel
import org.spotube.spotube.modules.settings.LocalMediaFoldersViewModel
import org.spotube.spotube.modules.shell.AppShellViewModel
import org.spotube.spotube.modules.shell.PlayerOptionsViewModel
import org.spotube.spotube.modules.shell.alternative_track.AlternativeTrackContentViewModel
import org.spotube.spotube.modules.shell.player_queue.PlayerQueueContentViewModel
import org.spotube.spotube.modules.welcome.WelcomeRepository
import org.spotube.spotube.modules.welcome.WelcomeViewModel
import org.koin.core.module.Module
import org.koin.core.module.dsl.bind
import org.koin.core.module.dsl.createdAtStart

View File

@ -15,12 +15,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.discord
package org.spotube.spotube.core.discord
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerInterface
import dev.krtirtho.spotube.core.audioplayer.PlayerState
import dev.krtirtho.spotube.core.di.injectLogger
import dev.krtirtho.spotube.modules.settings.SettingsProvider
import org.spotube.spotube.core.audioplayer.AudioPlayerInterface
import org.spotube.spotube.core.audioplayer.PlayerState
import org.spotube.spotube.core.di.injectLogger
import org.spotube.spotube.modules.settings.SettingsProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
@ -202,7 +202,7 @@ class DiscordRpcService(
private data class DiscordRpcState(
val enabled: Boolean,
val playerState: PlayerState,
val mediaItem: dev.krtirtho.spotube.core.audioplayer.MediaItem?,
val mediaItem: org.spotube.spotube.core.audioplayer.MediaItem?,
val position: kotlin.time.Duration,
val duration: kotlin.time.Duration)
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.discovery
package org.spotube.spotube.core.discovery
import com.appstractive.dnssd.DiscoveryEvent
import com.appstractive.dnssd.NetService

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.discovery
package org.spotube.spotube.core.discovery
import androidx.compose.runtime.Composable

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.extras
package org.spotube.spotube.core.extras
fun String.kebabToTitleCase(): String {
return this.split("-").joinToString(" ") { it.replaceFirstChar { char -> char.uppercase() } }

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.i18n
package org.spotube.spotube.core.i18n
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@ -23,7 +23,7 @@ import androidx.compose.runtime.ProvidedValue
import androidx.compose.runtime.key
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
import dev.krtirtho.spotube.modules.settings.SupportedLanguages
import org.spotube.spotube.modules.settings.SupportedLanguages
/**
* Points the platform locale (which Compose resources resolve strings from) at [languageTag],

View File

@ -15,11 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.jam
package org.spotube.spotube.core.jam
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import dev.krtirtho.spotube.core.audioplayer.MediaItem
import dev.krtirtho.spotube.core.audioplayer.QueueEntry
import org.spotube.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import org.spotube.spotube.core.audioplayer.MediaItem
import org.spotube.spotube.core.audioplayer.QueueEntry
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@ -168,7 +168,7 @@ data class JamMediaItem(
duration = kotlin.time.Duration.parse("${item.durationMs}ms"),
coverURL = item.coverUrl,
url = item.url,
protocol = dev.krtirtho.plugin_interfaces.plugin_apis.audio.StreamProtocol
protocol = org.spotube.plugin_interfaces.plugin_apis.audio.StreamProtocol
.valueOf(item.protocol.ifBlank { "PROGRESSIVE" }))
}
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.jam
package org.spotube.spotube.core.jam
import co.touchlab.kermit.Logger
import com.ditchoom.buffer.Charset
@ -29,7 +29,7 @@ import com.ditchoom.mqtt.controlpacket.QualityOfService
import com.ditchoom.mqtt.controlpacket.TopicName
import com.ditchoom.mqtt.controlpacket.WillConfig
import com.ditchoom.mqtt5.controlpacket.ConnectionRequest
import dev.krtirtho.spotube.modules.settings.JamBroker
import org.spotube.spotube.modules.settings.JamBroker
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.jam
package org.spotube.spotube.core.jam
import kotlin.random.Random

View File

@ -15,18 +15,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.jam
package org.spotube.spotube.core.jam
import co.touchlab.kermit.Logger
import dev.krtirtho.plugin_interfaces.plugin_apis.audio.StreamProtocol
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.artist.MetadataArtist
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.common.Thumbnail
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerInterface
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueue
import dev.krtirtho.spotube.core.audioplayer.PlayerState
import dev.krtirtho.spotube.core.audioplayer.QueueEntry
import dev.krtirtho.spotube.modules.settings.SettingsRepository
import org.spotube.plugin_interfaces.plugin_apis.audio.StreamProtocol
import org.spotube.plugin_interfaces.plugin_apis.metadata.artist.MetadataArtist
import org.spotube.plugin_interfaces.plugin_apis.metadata.common.Thumbnail
import org.spotube.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import org.spotube.spotube.core.audioplayer.AudioPlayerInterface
import org.spotube.spotube.core.audioplayer.AudioPlayerQueue
import org.spotube.spotube.core.audioplayer.PlayerState
import org.spotube.spotube.core.audioplayer.QueueEntry
import org.spotube.spotube.modules.settings.SettingsRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -481,7 +481,7 @@ class JamRoomService(
return configured.ifBlank { "$fallbackPrefix-${Random.nextInt(1000, 9999)}" }
}
private fun newClientId(broker: dev.krtirtho.spotube.modules.settings.JamBroker): String {
private fun newClientId(broker: org.spotube.spotube.modules.settings.JamBroker): String {
val suffix = buildString(6) {
val chars = "0123456789abcdef"
repeat(6) { append(chars[Random.nextInt(chars.length)]) }

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.navigation
package org.spotube.spotube.core.navigation
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.navigation
package org.spotube.spotube.core.navigation
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.receiveAsFlow

View File

@ -15,27 +15,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.navigation
package org.spotube.spotube.core.navigation
import androidx.navigation3.runtime.NavKey
import dev.krtirtho.spotube.modules.album.AlbumScreen
import dev.krtirtho.spotube.modules.artist.ArtistScreen
import dev.krtirtho.spotube.modules.blacklist.BlacklistScreen
import dev.krtirtho.spotube.modules.devices.DevicesScreen
import dev.krtirtho.spotube.modules.devices.RemoteControlScreen
import dev.krtirtho.spotube.modules.jam.JamScreen
import dev.krtirtho.spotube.modules.home.HomeScreen
import dev.krtirtho.spotube.modules.library.LibraryScreen
import dev.krtirtho.spotube.modules.lyrics.LyricsScreen
import dev.krtirtho.spotube.modules.playlist.PlaylistScreen
import dev.krtirtho.spotube.modules.plugin.PluginScreen
import dev.krtirtho.spotube.modules.plugin.guard.MetadataPluginGuard
import dev.krtirtho.spotube.modules.saved_tracks.SAVED_TRACKS_COLLECTION_ID
import dev.krtirtho.spotube.modules.saved_tracks.SavedTracksScreen
import dev.krtirtho.spotube.modules.search.SearchScreen
import dev.krtirtho.spotube.modules.settings.SettingsScreen
import dev.krtirtho.spotube.modules.settings.JamSettingsScreen
import dev.krtirtho.spotube.modules.welcome.WelcomeScreen
import org.spotube.spotube.modules.album.AlbumScreen
import org.spotube.spotube.modules.artist.ArtistScreen
import org.spotube.spotube.modules.blacklist.BlacklistScreen
import org.spotube.spotube.modules.devices.DevicesScreen
import org.spotube.spotube.modules.devices.RemoteControlScreen
import org.spotube.spotube.modules.jam.JamScreen
import org.spotube.spotube.modules.home.HomeScreen
import org.spotube.spotube.modules.library.LibraryScreen
import org.spotube.spotube.modules.lyrics.LyricsScreen
import org.spotube.spotube.modules.playlist.PlaylistScreen
import org.spotube.spotube.modules.plugin.PluginScreen
import org.spotube.spotube.modules.plugin.guard.MetadataPluginGuard
import org.spotube.spotube.modules.saved_tracks.SAVED_TRACKS_COLLECTION_ID
import org.spotube.spotube.modules.saved_tracks.SavedTracksScreen
import org.spotube.spotube.modules.search.SearchScreen
import org.spotube.spotube.modules.settings.SettingsScreen
import org.spotube.spotube.modules.settings.JamSettingsScreen
import org.spotube.spotube.modules.welcome.WelcomeScreen
import kotlinx.serialization.Serializable
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.navigation
package org.spotube.spotube.core.navigation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
@ -34,7 +34,7 @@ import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
import androidx.savedstate.compose.serialization.serializers.MutableStateSerializer
import androidx.savedstate.serialization.SavedStateConfiguration
import dev.krtirtho.spotube.core.di.injectLogger
import org.spotube.spotube.core.di.injectLogger
import kotlinx.serialization.PolymorphicSerializer
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic

View File

@ -15,9 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.newpipe
package org.spotube.spotube.core.newpipe
import dev.krtirtho.plugin_interfaces.plugin_apis.audio.AudioStream
import org.spotube.plugin_interfaces.plugin_apis.audio.AudioStream
import kotlinx.serialization.Serializable
@Serializable

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.newpipe
package org.spotube.spotube.core.newpipe
enum class SearchKind {
/** YouTube Music "Songs" catalogue. */

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.paths
package org.spotube.spotube.core.paths
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
expect class Paths() {

View File

@ -15,18 +15,18 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.playback
package org.spotube.spotube.core.playback
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueue
import dev.krtirtho.spotube.core.audioplayer.QueueCollectionEntry
import dev.krtirtho.spotube.core.audioplayer.QueueEntry
import dev.krtirtho.spotube.modules.album.AlbumRepository
import dev.krtirtho.spotube.modules.artist.ArtistRepository
import dev.krtirtho.spotube.modules.blacklist.BlacklistRepository
import dev.krtirtho.spotube.modules.playlist.PlaylistRepository
import dev.krtirtho.spotube.modules.saved_tracks.SavedTracksRepository
import dev.krtirtho.spotube.core.remote.RemoteCollectionType
import org.spotube.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import org.spotube.spotube.core.audioplayer.AudioPlayerQueue
import org.spotube.spotube.core.audioplayer.QueueCollectionEntry
import org.spotube.spotube.core.audioplayer.QueueEntry
import org.spotube.spotube.modules.album.AlbumRepository
import org.spotube.spotube.modules.artist.ArtistRepository
import org.spotube.spotube.modules.blacklist.BlacklistRepository
import org.spotube.spotube.modules.playlist.PlaylistRepository
import org.spotube.spotube.modules.saved_tracks.SavedTracksRepository
import org.spotube.spotube.core.remote.RemoteCollectionType
class CollectionPlaybackHelper(
private val albumRepository: AlbumRepository,

View File

@ -15,13 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.remote
package org.spotube.spotube.core.remote
import org.spotube.millennium.composables.MillenniumAlertDialog
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import dev.krtirtho.spotube.core.ui.theming.AppTheme
import org.spotube.spotube.core.ui.theming.AppTheme
import com.composeunstyled.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.remote
package org.spotube.spotube.core.remote
import co.touchlab.kermit.Logger
import io.ktor.client.HttpClient

View File

@ -15,16 +15,16 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.remote
package org.spotube.spotube.core.remote
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerInterface
import dev.krtirtho.spotube.core.audioplayer.AudioPlayerQueue
import dev.krtirtho.spotube.core.audioplayer.LoopState
import dev.krtirtho.spotube.core.audioplayer.PlayerState as AudioPlayerState
import dev.krtirtho.spotube.core.audioplayer.QueueEntry
import dev.krtirtho.spotube.core.di.injectLogger
import dev.krtirtho.spotube.core.playback.CollectionPlaybackHelper
import dev.krtirtho.spotube.modules.settings.SettingsRepository
import org.spotube.spotube.core.audioplayer.AudioPlayerInterface
import org.spotube.spotube.core.audioplayer.AudioPlayerQueue
import org.spotube.spotube.core.audioplayer.LoopState
import org.spotube.spotube.core.audioplayer.PlayerState as AudioPlayerState
import org.spotube.spotube.core.audioplayer.QueueEntry
import org.spotube.spotube.core.di.injectLogger
import org.spotube.spotube.core.playback.CollectionPlaybackHelper
import org.spotube.spotube.modules.settings.SettingsRepository
import io.ktor.server.websocket.WebSocketServerSession
import io.ktor.websocket.CloseReason
import io.ktor.websocket.Frame

View File

@ -15,9 +15,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package dev.krtirtho.spotube.core.remote
package org.spotube.spotube.core.remote
import dev.krtirtho.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import org.spotube.plugin_interfaces.plugin_apis.metadata.track.MetadataTrack
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

Some files were not shown because too many files have changed in this diff Show More