Merge pull request #613 from OxygenCobalt/v3.2.1-cherrypick
Version 3.2.1
This commit is contained in:
commit
d5017f8d38
81 changed files with 2408 additions and 1322 deletions
4
.github/workflows/android.yml
vendored
4
.github/workflows/android.yml
vendored
|
@ -23,8 +23,8 @@ jobs:
|
|||
cache: gradle
|
||||
- name: Grant execute permission for gradlew
|
||||
run: chmod +x gradlew
|
||||
# - name: Test app with Gradle
|
||||
# run: ./gradlew app:testDebug
|
||||
- name: Test app with Gradle
|
||||
run: ./gradlew app:testDebug
|
||||
- name: Build debug APK with Gradle
|
||||
run: ./gradlew app:packageDebug
|
||||
- name: Upload debug APK artifact
|
||||
|
|
20
CHANGELOG.md
20
CHANGELOG.md
|
@ -1,5 +1,21 @@
|
|||
# Changelog
|
||||
|
||||
## dev
|
||||
|
||||
#### What's New
|
||||
- Added ability to rewind/skip tracks by swiping back/forward
|
||||
|
||||
#### What's Improved
|
||||
- Added support for native M4A multi-value tags based on duplicate atoms
|
||||
|
||||
#### What's Fixed
|
||||
- Fixed app restart being required when changing intelligent sorting
|
||||
or music separator settings
|
||||
- Fixed widget/notification actions not working on Android 14
|
||||
- Fixed app crash when using hebrew language
|
||||
- Fixed app crash when adding to a playlist while in the playlist detail view
|
||||
- Fixed music loading failing in some cases on Android 14
|
||||
|
||||
## 3.2.0
|
||||
|
||||
#### What's New
|
||||
|
@ -16,6 +32,10 @@ aspect ratio setting
|
|||
#### What's Fixed
|
||||
- Playlist detail view now respects playback settings
|
||||
|
||||
|
||||
#### Dev/Meta
|
||||
- Revamped navigation backend
|
||||
|
||||
## 3.1.4
|
||||
|
||||
#### What's Fixed
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
|
||||
Auxio is a local music player with a fast, reliable UI/UX without the many useless features present in other music players. Built off of modern media playback libraries, Auxio has superior library support and listening quality compared to other apps that use outdated android functionality. In short, **It plays music.**
|
||||
|
||||
I primarily built Auxio for myself, but you can use it too, I guess.
|
||||
|
||||
**The default branch is the development version of the repository. For a stable version, see the master branch.**
|
||||
|
||||
## Screenshots
|
||||
|
@ -60,12 +58,12 @@ precise/original dates, sort tags, and more
|
|||
- Headset autoplay
|
||||
- Stylish widgets that automatically adapt to their size
|
||||
- Completely private and offline
|
||||
- No rounded album covers (Unless you want them. Then you can.)
|
||||
- No rounded album covers (by default)
|
||||
|
||||
## Permissions
|
||||
|
||||
- Storage (`READ_MEDIA_AUDIO`, `READ_EXTERNAL_STORAGE`) to read and play your media files
|
||||
- Services (`FOREGROUND_SERVICE`, `WAKE_LOCK`) to keep the music playing even if the app itself is in background
|
||||
- Storage (`READ_MEDIA_AUDIO`, `READ_EXTERNAL_STORAGE`) to read and play your music files
|
||||
- Services (`FOREGROUND_SERVICE`, `WAKE_LOCK`) to keep the music playing in the background
|
||||
|
||||
## Building
|
||||
|
||||
|
|
|
@ -21,8 +21,8 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
applicationId namespace
|
||||
versionName "3.2.0"
|
||||
versionCode 35
|
||||
versionName "3.2.1"
|
||||
versionCode 36
|
||||
|
||||
minSdk 24
|
||||
targetSdk 34
|
||||
|
@ -85,9 +85,9 @@ dependencies {
|
|||
// --- SUPPORT ---
|
||||
|
||||
// General
|
||||
implementation "androidx.core:core-ktx:1.10.1"
|
||||
implementation "androidx.core:core-ktx:1.12.0"
|
||||
implementation "androidx.appcompat:appcompat:1.6.1"
|
||||
implementation "androidx.activity:activity-ktx:1.7.2"
|
||||
implementation "androidx.activity:activity-ktx:1.8.0"
|
||||
implementation "androidx.fragment:fragment-ktx:1.6.1"
|
||||
|
||||
// Components
|
||||
|
@ -100,7 +100,7 @@ dependencies {
|
|||
implementation "androidx.viewpager2:viewpager2:1.0.0"
|
||||
|
||||
// Lifecycle
|
||||
def lifecycle_version = "2.6.1"
|
||||
def lifecycle_version = "2.6.2"
|
||||
implementation "androidx.lifecycle:lifecycle-common:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
|
@ -117,7 +117,7 @@ dependencies {
|
|||
implementation "androidx.preference:preference-ktx:1.2.1"
|
||||
|
||||
// Database
|
||||
def room_version = '2.6.0-alpha03'
|
||||
def room_version = '2.6.0-rc01'
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
ksp "androidx.room:room-compiler:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
|
@ -134,7 +134,7 @@ dependencies {
|
|||
// Material
|
||||
// TODO: Exactly figure out the conditions that the 1.7.0 ripple bug occurred so you can just
|
||||
// PR a fix.
|
||||
implementation "com.google.android.material:material:1.10.0-alpha06"
|
||||
implementation "com.google.android.material:material:1.10.0"
|
||||
|
||||
// Dependency Injection
|
||||
implementation "com.google.dagger:dagger:$hilt_version"
|
||||
|
@ -142,9 +142,15 @@ dependencies {
|
|||
implementation "com.google.dagger:hilt-android:$hilt_version"
|
||||
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
|
||||
|
||||
// Logging
|
||||
implementation 'com.jakewharton.timber:timber:5.0.1'
|
||||
|
||||
// Testing
|
||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
|
||||
testImplementation "junit:junit:4.13.2"
|
||||
testImplementation "io.mockk:mockk:1.13.7"
|
||||
testImplementation "org.robolectric:robolectric:4.9"
|
||||
testImplementation 'androidx.test:core-ktx:1.5.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
}
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* StubTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class StubTest {
|
||||
// TODO: Make tests
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("org.oxycblt.auxio.debug", appContext.packageName)
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.oxycblt.auxio.home.HomeSettings
|
|||
import org.oxycblt.auxio.image.ImageSettings
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.ui.UISettings
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* A simple, rational music player for android.
|
||||
|
@ -44,6 +45,10 @@ class Auxio : Application() {
|
|||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
|
||||
// Migrate any settings that may have changed in an app update.
|
||||
imageSettings.migrate()
|
||||
playbackSettings.migrate()
|
||||
|
|
|
@ -68,8 +68,8 @@ class MainActivity : AppCompatActivity() {
|
|||
logD("Activity created")
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
startService(Intent(this, IndexerService::class.java))
|
||||
startService(Intent(this, PlaybackService::class.java))
|
||||
|
|
|
@ -204,6 +204,10 @@ class MainFragment :
|
|||
}
|
||||
|
||||
override fun onPreDraw(): Boolean {
|
||||
// TODO: Due to draw caching even *this* isn't effective enough to avoid the bottom
|
||||
// sheets continually getting stuck. I need something with even more frequent updates,
|
||||
// or otherwise bottom sheets get stuck.
|
||||
|
||||
// We overload CoordinatorLayout far too much to rely on any of it's typical
|
||||
// listener functionality. Just update all transitions before every draw. Should
|
||||
// probably be cheap enough.
|
||||
|
|
|
@ -328,7 +328,11 @@ class PlaylistDetailFragment :
|
|||
logD("Deleting ${decision.playlist}")
|
||||
PlaylistDetailFragmentDirections.deletePlaylist(decision.playlist.uid)
|
||||
}
|
||||
is PlaylistDecision.Add,
|
||||
is PlaylistDecision.Add -> {
|
||||
logD("Adding ${decision.songs.size} songs to a playlist")
|
||||
PlaylistDetailFragmentDirections.addToPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray())
|
||||
}
|
||||
is PlaylistDecision.New -> error("Unexpected playlist decision $decision")
|
||||
}
|
||||
findNavController().navigateSafe(directions)
|
||||
|
|
|
@ -51,7 +51,7 @@ constructor(
|
|||
// Apply the new configuration possibly set in flipTo. This should occur even if
|
||||
// a flip was canceled by a hide.
|
||||
pendingConfig?.run {
|
||||
this@FlipFloatingActionButton.logD("Applying pending configuration")
|
||||
logD("Applying pending configuration")
|
||||
setImageResource(iconRes)
|
||||
contentDescription = context.getString(contentDescriptionRes)
|
||||
setOnClickListener(clickListener)
|
||||
|
|
|
@ -43,7 +43,7 @@ interface MusicSettings : Settings<MusicSettings.Listener> {
|
|||
/** Whether to be actively watching for changes in the music library. */
|
||||
val shouldBeObserving: Boolean
|
||||
/** A [String] of characters representing the desired characters to denote multi-value tags. */
|
||||
var multiValueSeparators: String
|
||||
var separators: String
|
||||
/** Whether to enable more advanced sorting by articles and numbers. */
|
||||
val intelligentSorting: Boolean
|
||||
|
||||
|
@ -85,7 +85,7 @@ class MusicSettingsImpl @Inject constructor(@ApplicationContext context: Context
|
|||
override val shouldBeObserving: Boolean
|
||||
get() = sharedPreferences.getBoolean(getString(R.string.set_key_observing), false)
|
||||
|
||||
override var multiValueSeparators: String
|
||||
override var separators: String
|
||||
// Differ from convention and store a string of separator characters instead of an int
|
||||
// code. This makes it easier to use and more extendable.
|
||||
get() = sharedPreferences.getString(getString(R.string.set_key_separators), "") ?: ""
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.oxycblt.auxio.music.info.Date
|
|||
import org.oxycblt.auxio.music.metadata.correctWhitespace
|
||||
import org.oxycblt.auxio.music.metadata.splitEscaped
|
||||
|
||||
@Database(entities = [CachedSong::class], version = 34, exportSchema = false)
|
||||
@Database(entities = [CachedSong::class], version = 36, exportSchema = false)
|
||||
abstract class CacheDatabase : RoomDatabase() {
|
||||
abstract fun cachedSongsDao(): CachedSongsDao
|
||||
}
|
||||
|
@ -63,9 +63,9 @@ data class CachedSong(
|
|||
/** @see RawSong */
|
||||
var durationMs: Long,
|
||||
/** @see RawSong.replayGainTrackAdjustment */
|
||||
val replayGainTrackAdjustment: Float?,
|
||||
val replayGainTrackAdjustment: Float? = null,
|
||||
/** @see RawSong.replayGainAlbumAdjustment */
|
||||
val replayGainAlbumAdjustment: Float?,
|
||||
val replayGainAlbumAdjustment: Float? = null,
|
||||
/** @see RawSong.musicBrainzId */
|
||||
var musicBrainzId: String? = null,
|
||||
/** @see RawSong.name */
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.oxycblt.auxio.music.MusicSettings
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.fs.contentResolverSafe
|
||||
import org.oxycblt.auxio.music.fs.useQuery
|
||||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.music.metadata.Separators
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
|
@ -107,7 +109,7 @@ interface DeviceLibrary {
|
|||
*/
|
||||
suspend fun create(
|
||||
rawSongs: Channel<RawSong>,
|
||||
processedSongs: Channel<RawSong>
|
||||
processedSongs: Channel<RawSong>,
|
||||
): DeviceLibraryImpl
|
||||
}
|
||||
}
|
||||
|
@ -118,6 +120,9 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
|
|||
rawSongs: Channel<RawSong>,
|
||||
processedSongs: Channel<RawSong>
|
||||
): DeviceLibraryImpl {
|
||||
val nameFactory = Name.Known.Factory.from(musicSettings)
|
||||
val separators = Separators.from(musicSettings)
|
||||
|
||||
val songGrouping = mutableMapOf<Music.UID, SongImpl>()
|
||||
val albumGrouping = mutableMapOf<RawAlbum.Key, Grouping<RawAlbum, SongImpl>>()
|
||||
val artistGrouping = mutableMapOf<RawArtist.Key, Grouping<RawArtist, Music>>()
|
||||
|
@ -127,7 +132,7 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
|
|||
|
||||
// All music information is grouped as it is indexed by other components.
|
||||
for (rawSong in rawSongs) {
|
||||
val song = SongImpl(rawSong, musicSettings)
|
||||
val song = SongImpl(rawSong, nameFactory, separators)
|
||||
// At times the indexer produces duplicate songs, try to filter these. Comparing by
|
||||
// UID is sufficient for something like this, and also prevents collisions from
|
||||
// causing severe issues elsewhere.
|
||||
|
@ -207,7 +212,7 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
|
|||
|
||||
// Now that all songs are processed, also process albums and group them into their
|
||||
// respective artists.
|
||||
val albums = albumGrouping.values.mapTo(mutableSetOf()) { AlbumImpl(it, musicSettings) }
|
||||
val albums = albumGrouping.values.mapTo(mutableSetOf()) { AlbumImpl(it, nameFactory) }
|
||||
for (album in albums) {
|
||||
for (rawArtist in album.rawArtists) {
|
||||
val key = RawArtist.Key(rawArtist)
|
||||
|
@ -243,8 +248,8 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
|
|||
}
|
||||
|
||||
// Artists and genres do not need to be grouped and can be processed immediately.
|
||||
val artists = artistGrouping.values.mapTo(mutableSetOf()) { ArtistImpl(it, musicSettings) }
|
||||
val genres = genreGrouping.values.mapTo(mutableSetOf()) { GenreImpl(it, musicSettings) }
|
||||
val artists = artistGrouping.values.mapTo(mutableSetOf()) { ArtistImpl(it, nameFactory) }
|
||||
val genres = genreGrouping.values.mapTo(mutableSetOf()) { GenreImpl(it, nameFactory) }
|
||||
|
||||
return DeviceLibraryImpl(songGrouping.values.toSet(), albums, artists, genres)
|
||||
}
|
||||
|
@ -253,10 +258,10 @@ class DeviceLibraryFactoryImpl @Inject constructor(private val musicSettings: Mu
|
|||
// TODO: Avoid redundant data creation
|
||||
|
||||
class DeviceLibraryImpl(
|
||||
override val songs: Set<SongImpl>,
|
||||
override val albums: Set<AlbumImpl>,
|
||||
override val artists: Set<ArtistImpl>,
|
||||
override val genres: Set<GenreImpl>
|
||||
override val songs: Collection<SongImpl>,
|
||||
override val albums: Collection<AlbumImpl>,
|
||||
override val artists: Collection<ArtistImpl>,
|
||||
override val genres: Collection<GenreImpl>
|
||||
) : DeviceLibrary {
|
||||
// Use a mapping to make finding information based on it's UID much faster.
|
||||
private val songUidMap = buildMap { songs.forEach { put(it.uid, it.finalize()) } }
|
||||
|
|
|
@ -25,7 +25,6 @@ import org.oxycblt.auxio.music.Album
|
|||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.fs.MimeType
|
||||
|
@ -36,8 +35,8 @@ import org.oxycblt.auxio.music.info.Date
|
|||
import org.oxycblt.auxio.music.info.Disc
|
||||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.music.info.ReleaseType
|
||||
import org.oxycblt.auxio.music.metadata.Separators
|
||||
import org.oxycblt.auxio.music.metadata.parseId3GenreNames
|
||||
import org.oxycblt.auxio.music.metadata.parseMultiValue
|
||||
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
|
||||
import org.oxycblt.auxio.util.positiveOrNull
|
||||
import org.oxycblt.auxio.util.toUuidOrNull
|
||||
|
@ -48,10 +47,15 @@ import org.oxycblt.auxio.util.update
|
|||
* Library-backed implementation of [Song].
|
||||
*
|
||||
* @param rawSong The [RawSong] to derive the member data from.
|
||||
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||
* @param separators The [Separators] to parse multi-value tags with.
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Song {
|
||||
class SongImpl(
|
||||
private val rawSong: RawSong,
|
||||
private val nameFactory: Name.Known.Factory,
|
||||
private val separators: Separators
|
||||
) : Song {
|
||||
override val uid =
|
||||
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
|
||||
rawSong.musicBrainzId?.toUuidOrNull()?.let { Music.UID.musicBrainz(MusicType.SONGS, it) }
|
||||
|
@ -70,67 +74,47 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son
|
|||
update(rawSong.albumArtistNames)
|
||||
}
|
||||
override val name =
|
||||
Name.Known.from(
|
||||
requireNotNull(rawSong.name) { "Invalid raw: No title" },
|
||||
rawSong.sortName,
|
||||
musicSettings)
|
||||
nameFactory.parse(
|
||||
requireNotNull(rawSong.name) { "Invalid raw ${rawSong.fileName}: No title" },
|
||||
rawSong.sortName)
|
||||
|
||||
override val track = rawSong.track
|
||||
override val disc = rawSong.disc?.let { Disc(it, rawSong.subtitle) }
|
||||
override val date = rawSong.date
|
||||
override val uri = requireNotNull(rawSong.mediaStoreId) { "Invalid raw: No id" }.toAudioUri()
|
||||
override val uri =
|
||||
requireNotNull(rawSong.mediaStoreId) { "Invalid raw ${rawSong.fileName}: No id" }
|
||||
.toAudioUri()
|
||||
override val path =
|
||||
Path(
|
||||
name = requireNotNull(rawSong.fileName) { "Invalid raw: No display name" },
|
||||
parent = requireNotNull(rawSong.directory) { "Invalid raw: No parent directory" })
|
||||
name =
|
||||
requireNotNull(rawSong.fileName) {
|
||||
"Invalid raw ${rawSong.fileName}: No display name"
|
||||
},
|
||||
parent =
|
||||
requireNotNull(rawSong.directory) {
|
||||
"Invalid raw ${rawSong.fileName}: No parent directory"
|
||||
})
|
||||
override val mimeType =
|
||||
MimeType(
|
||||
fromExtension =
|
||||
requireNotNull(rawSong.extensionMimeType) { "Invalid raw: No mime type" },
|
||||
requireNotNull(rawSong.extensionMimeType) {
|
||||
"Invalid raw ${rawSong.fileName}: No mime type"
|
||||
},
|
||||
fromFormat = null)
|
||||
override val size = requireNotNull(rawSong.size) { "Invalid raw: No size" }
|
||||
override val durationMs = requireNotNull(rawSong.durationMs) { "Invalid raw: No duration" }
|
||||
override val size = requireNotNull(rawSong.size) { "Invalid raw ${rawSong.fileName}: No size" }
|
||||
override val durationMs =
|
||||
requireNotNull(rawSong.durationMs) { "Invalid raw ${rawSong.fileName}: No duration" }
|
||||
override val replayGainAdjustment =
|
||||
ReplayGainAdjustment(
|
||||
track = rawSong.replayGainTrackAdjustment, album = rawSong.replayGainAlbumAdjustment)
|
||||
|
||||
override val dateAdded = requireNotNull(rawSong.dateAdded) { "Invalid raw: No date added" }
|
||||
override val dateAdded =
|
||||
requireNotNull(rawSong.dateAdded) { "Invalid raw ${rawSong.fileName}: No date added" }
|
||||
|
||||
private var _album: AlbumImpl? = null
|
||||
override val album: Album
|
||||
get() = unlikelyToBeNull(_album)
|
||||
|
||||
private val hashCode = 31 * uid.hashCode() + rawSong.hashCode()
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is SongImpl && uid == other.uid && rawSong == other.rawSong
|
||||
|
||||
override fun toString() = "Song(uid=$uid, name=$name)"
|
||||
|
||||
private val artistMusicBrainzIds = rawSong.artistMusicBrainzIds.parseMultiValue(musicSettings)
|
||||
private val artistNames = rawSong.artistNames.parseMultiValue(musicSettings)
|
||||
private val artistSortNames = rawSong.artistSortNames.parseMultiValue(musicSettings)
|
||||
private val rawIndividualArtists =
|
||||
artistNames.mapIndexed { i, name ->
|
||||
RawArtist(
|
||||
artistMusicBrainzIds.getOrNull(i)?.toUuidOrNull(),
|
||||
name,
|
||||
artistSortNames.getOrNull(i))
|
||||
}
|
||||
|
||||
private val albumArtistMusicBrainzIds =
|
||||
rawSong.albumArtistMusicBrainzIds.parseMultiValue(musicSettings)
|
||||
private val albumArtistNames = rawSong.albumArtistNames.parseMultiValue(musicSettings)
|
||||
private val albumArtistSortNames = rawSong.albumArtistSortNames.parseMultiValue(musicSettings)
|
||||
private val rawAlbumArtists =
|
||||
albumArtistNames.mapIndexed { i, name ->
|
||||
RawArtist(
|
||||
albumArtistMusicBrainzIds.getOrNull(i)?.toUuidOrNull(),
|
||||
name,
|
||||
albumArtistSortNames.getOrNull(i))
|
||||
}
|
||||
|
||||
private val _artists = mutableListOf<ArtistImpl>()
|
||||
override val artists: List<Artist>
|
||||
get() = _artists
|
||||
|
@ -143,40 +127,95 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son
|
|||
* The [RawAlbum] instances collated by the [Song]. This can be used to group [Song]s into an
|
||||
* [Album].
|
||||
*/
|
||||
val rawAlbum =
|
||||
RawAlbum(
|
||||
mediaStoreId = requireNotNull(rawSong.albumMediaStoreId) { "Invalid raw: No album id" },
|
||||
musicBrainzId = rawSong.albumMusicBrainzId?.toUuidOrNull(),
|
||||
name = requireNotNull(rawSong.albumName) { "Invalid raw: No album name" },
|
||||
sortName = rawSong.albumSortName,
|
||||
releaseType = ReleaseType.parse(rawSong.releaseTypes.parseMultiValue(musicSettings)),
|
||||
rawArtists =
|
||||
rawAlbumArtists
|
||||
.ifEmpty { rawIndividualArtists }
|
||||
.distinctBy { it.key }
|
||||
.ifEmpty { listOf(RawArtist(null, null)) })
|
||||
val rawAlbum: RawAlbum
|
||||
|
||||
/**
|
||||
* The [RawArtist] instances collated by the [Song]. The artists of the song take priority,
|
||||
* followed by the album artists. If there are no artists, this field will be a single "unknown"
|
||||
* [RawArtist]. This can be used to group up [Song]s into an [Artist].
|
||||
*/
|
||||
val rawArtists =
|
||||
rawIndividualArtists
|
||||
.ifEmpty { rawAlbumArtists }
|
||||
.distinctBy { it.key }
|
||||
.ifEmpty { listOf(RawArtist()) }
|
||||
val rawArtists: List<RawArtist>
|
||||
|
||||
/**
|
||||
* The [RawGenre] instances collated by the [Song]. This can be used to group up [Song]s into a
|
||||
* [Genre]. ID3v2 Genre names are automatically converted to their resolved names.
|
||||
*/
|
||||
val rawGenres =
|
||||
rawSong.genreNames
|
||||
.parseId3GenreNames(musicSettings)
|
||||
.map { RawGenre(it) }
|
||||
.distinctBy { it.key }
|
||||
.ifEmpty { listOf(RawGenre()) }
|
||||
val rawGenres: List<RawGenre>
|
||||
|
||||
private var hashCode: Int = uid.hashCode()
|
||||
|
||||
init {
|
||||
val artistMusicBrainzIds = separators.split(rawSong.artistMusicBrainzIds)
|
||||
val artistNames = separators.split(rawSong.artistNames)
|
||||
val artistSortNames = separators.split(rawSong.artistSortNames)
|
||||
val rawIndividualArtists =
|
||||
artistNames
|
||||
.mapIndexedTo(mutableSetOf()) { i, name ->
|
||||
RawArtist(
|
||||
artistMusicBrainzIds.getOrNull(i)?.toUuidOrNull(),
|
||||
name,
|
||||
artistSortNames.getOrNull(i))
|
||||
}
|
||||
.toList()
|
||||
|
||||
val albumArtistMusicBrainzIds = separators.split(rawSong.albumArtistMusicBrainzIds)
|
||||
val albumArtistNames = separators.split(rawSong.albumArtistNames)
|
||||
val albumArtistSortNames = separators.split(rawSong.albumArtistSortNames)
|
||||
val rawAlbumArtists =
|
||||
albumArtistNames
|
||||
.mapIndexedTo(mutableSetOf()) { i, name ->
|
||||
RawArtist(
|
||||
albumArtistMusicBrainzIds.getOrNull(i)?.toUuidOrNull(),
|
||||
name,
|
||||
albumArtistSortNames.getOrNull(i))
|
||||
}
|
||||
.toList()
|
||||
|
||||
rawAlbum =
|
||||
RawAlbum(
|
||||
mediaStoreId =
|
||||
requireNotNull(rawSong.albumMediaStoreId) {
|
||||
"Invalid raw ${rawSong.fileName}: No album id"
|
||||
},
|
||||
musicBrainzId = rawSong.albumMusicBrainzId?.toUuidOrNull(),
|
||||
name =
|
||||
requireNotNull(rawSong.albumName) {
|
||||
"Invalid raw ${rawSong.fileName}: No album name"
|
||||
},
|
||||
sortName = rawSong.albumSortName,
|
||||
releaseType = ReleaseType.parse(separators.split(rawSong.releaseTypes)),
|
||||
rawArtists =
|
||||
rawAlbumArtists
|
||||
.ifEmpty { rawIndividualArtists }
|
||||
.ifEmpty { listOf(RawArtist()) })
|
||||
|
||||
rawArtists =
|
||||
rawIndividualArtists.ifEmpty { rawAlbumArtists }.ifEmpty { listOf(RawArtist()) }
|
||||
|
||||
val genreNames =
|
||||
(rawSong.genreNames.parseId3GenreNames() ?: separators.split(rawSong.genreNames))
|
||||
rawGenres =
|
||||
genreNames
|
||||
.mapTo(mutableSetOf()) { RawGenre(it) }
|
||||
.toList()
|
||||
.ifEmpty { listOf(RawGenre()) }
|
||||
|
||||
hashCode = 31 * hashCode + rawSong.hashCode()
|
||||
hashCode = 31 * hashCode + nameFactory.hashCode()
|
||||
}
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
// Since equality on public-facing music models is not identical to the tag equality,
|
||||
// we just compare raw instances and how they are interpreted.
|
||||
override fun equals(other: Any?) =
|
||||
other is SongImpl &&
|
||||
uid == other.uid &&
|
||||
nameFactory == other.nameFactory &&
|
||||
separators == other.separators &&
|
||||
rawSong == other.rawSong
|
||||
|
||||
override fun toString() = "Song(uid=$uid, name=$name)"
|
||||
|
||||
/**
|
||||
* Links this [Song] with a parent [Album].
|
||||
|
@ -211,10 +250,12 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son
|
|||
* @return This instance upcasted to [Song].
|
||||
*/
|
||||
fun finalize(): Song {
|
||||
checkNotNull(_album) { "Malformed song: No album" }
|
||||
checkNotNull(_album) { "Malformed song ${path.name}: No album" }
|
||||
|
||||
check(_artists.isNotEmpty()) { "Malformed song: No artists" }
|
||||
check(_artists.size == rawArtists.size) { "Malformed song: Artist grouping mismatch" }
|
||||
check(_artists.isNotEmpty()) { "Malformed song ${path.name}: No artists" }
|
||||
check(_artists.size == rawArtists.size) {
|
||||
"Malformed song ${path.name}: Artist grouping mismatch"
|
||||
}
|
||||
for (i in _artists.indices) {
|
||||
// Non-destructively reorder the linked artists so that they align with
|
||||
// the artist ordering within the song metadata.
|
||||
|
@ -224,8 +265,10 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son
|
|||
_artists[i] = other
|
||||
}
|
||||
|
||||
check(_genres.isNotEmpty()) { "Malformed song: No genres" }
|
||||
check(_genres.size == rawGenres.size) { "Malformed song: Genre grouping mismatch" }
|
||||
check(_genres.isNotEmpty()) { "Malformed song ${path.name}: No genres" }
|
||||
check(_genres.size == rawGenres.size) {
|
||||
"Malformed song ${path.name}: Genre grouping mismatch"
|
||||
}
|
||||
for (i in _genres.indices) {
|
||||
// Non-destructively reorder the linked genres so that they align with
|
||||
// the genre ordering within the song metadata.
|
||||
|
@ -242,12 +285,12 @@ class SongImpl(private val rawSong: RawSong, musicSettings: MusicSettings) : Son
|
|||
* Library-backed implementation of [Album].
|
||||
*
|
||||
* @param grouping [Grouping] to derive the member data from.
|
||||
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class AlbumImpl(
|
||||
grouping: Grouping<RawAlbum, SongImpl>,
|
||||
musicSettings: MusicSettings,
|
||||
private val nameFactory: Name.Known.Factory
|
||||
) : Album {
|
||||
private val rawAlbum = grouping.raw.inner
|
||||
|
||||
|
@ -261,7 +304,7 @@ class AlbumImpl(
|
|||
update(rawAlbum.name)
|
||||
update(rawAlbum.rawArtists.map { it.name })
|
||||
}
|
||||
override val name = Name.Known.from(rawAlbum.name, rawAlbum.sortName, musicSettings)
|
||||
override val name = nameFactory.parse(rawAlbum.name, rawAlbum.sortName)
|
||||
override val dates: Date.Range?
|
||||
override val releaseType = rawAlbum.releaseType ?: ReleaseType.Album(null)
|
||||
override val coverUri = CoverUri(rawAlbum.mediaStoreId.toCoverUri(), grouping.raw.src.uri)
|
||||
|
@ -311,13 +354,20 @@ class AlbumImpl(
|
|||
dateAdded = earliestDateAdded
|
||||
|
||||
hashCode = 31 * hashCode + rawAlbum.hashCode()
|
||||
hashCode = 31 * hashCode + nameFactory.hashCode()
|
||||
hashCode = 31 * hashCode + songs.hashCode()
|
||||
}
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
// Since equality on public-facing music models is not identical to the tag equality,
|
||||
// we just compare raw instances and how they are interpreted.
|
||||
override fun equals(other: Any?) =
|
||||
other is AlbumImpl && uid == other.uid && rawAlbum == other.rawAlbum && songs == other.songs
|
||||
other is AlbumImpl &&
|
||||
uid == other.uid &&
|
||||
rawAlbum == other.rawAlbum &&
|
||||
nameFactory == other.nameFactory &&
|
||||
songs == other.songs
|
||||
|
||||
override fun toString() = "Album(uid=$uid, name=$name)"
|
||||
|
||||
|
@ -343,9 +393,11 @@ class AlbumImpl(
|
|||
* @return This instance upcasted to [Album].
|
||||
*/
|
||||
fun finalize(): Album {
|
||||
check(songs.isNotEmpty()) { "Malformed album: Empty" }
|
||||
check(_artists.isNotEmpty()) { "Malformed album: No artists" }
|
||||
check(_artists.size == rawArtists.size) { "Malformed album: Artist grouping mismatch" }
|
||||
check(songs.isNotEmpty()) { "Malformed album $name: Empty" }
|
||||
check(_artists.isNotEmpty()) { "Malformed album $name: No artists" }
|
||||
check(_artists.size == rawArtists.size) {
|
||||
"Malformed album $name: Artist grouping mismatch"
|
||||
}
|
||||
for (i in _artists.indices) {
|
||||
// Non-destructively reorder the linked artists so that they align with
|
||||
// the artist ordering within the song metadata.
|
||||
|
@ -362,10 +414,13 @@ class AlbumImpl(
|
|||
* Library-backed implementation of [Artist].
|
||||
*
|
||||
* @param grouping [Grouping] to derive the member data from.
|
||||
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSettings) : Artist {
|
||||
class ArtistImpl(
|
||||
grouping: Grouping<RawArtist, Music>,
|
||||
private val nameFactory: Name.Known.Factory
|
||||
) : Artist {
|
||||
private val rawArtist = grouping.raw.inner
|
||||
|
||||
override val uid =
|
||||
|
@ -373,7 +428,7 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
|
|||
rawArtist.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.ARTISTS, it) }
|
||||
?: Music.UID.auxio(MusicType.ARTISTS) { update(rawArtist.name) }
|
||||
override val name =
|
||||
rawArtist.name?.let { Name.Known.from(it, rawArtist.sortName, musicSettings) }
|
||||
rawArtist.name?.let { nameFactory.parse(it, rawArtist.sortName) }
|
||||
?: Name.Unknown(R.string.def_artist)
|
||||
|
||||
override val songs: Set<Song>
|
||||
|
@ -403,7 +458,7 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
|
|||
music.link(this)
|
||||
albumMap[music] = true
|
||||
}
|
||||
else -> error("Unexpected input music ${music::class.simpleName}")
|
||||
else -> error("Unexpected input music $music in $name ${music::class.simpleName}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,6 +469,7 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
|
|||
durationMs = songs.sumOf { it.durationMs }.positiveOrNull()
|
||||
|
||||
hashCode = 31 * hashCode + rawArtist.hashCode()
|
||||
hashCode = 31 * hashCode + nameFactory.hashCode()
|
||||
hashCode = 31 * hashCode + songs.hashCode()
|
||||
}
|
||||
|
||||
|
@ -421,10 +477,13 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
|
|||
// the same UID but different songs are not equal.
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
// Since equality on public-facing music models is not identical to the tag equality,
|
||||
// we just compare raw instances and how they are interpreted.
|
||||
override fun equals(other: Any?) =
|
||||
other is ArtistImpl &&
|
||||
uid == other.uid &&
|
||||
rawArtist == other.rawArtist &&
|
||||
nameFactory == other.nameFactory &&
|
||||
songs == other.songs
|
||||
|
||||
override fun toString() = "Artist(uid=$uid, name=$name)"
|
||||
|
@ -447,7 +506,7 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
|
|||
* @return This instance upcasted to [Artist].
|
||||
*/
|
||||
fun finalize(): Artist {
|
||||
check(songs.isNotEmpty() || albums.isNotEmpty()) { "Malformed artist: Empty" }
|
||||
check(songs.isNotEmpty() || albums.isNotEmpty()) { "Malformed artist $name: Empty" }
|
||||
genres =
|
||||
Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
|
||||
.genres(songs.flatMapTo(mutableSetOf()) { it.genres })
|
||||
|
@ -459,15 +518,18 @@ class ArtistImpl(grouping: Grouping<RawArtist, Music>, musicSettings: MusicSetti
|
|||
* Library-backed implementation of [Genre].
|
||||
*
|
||||
* @param grouping [Grouping] to derive the member data from.
|
||||
* @param musicSettings [MusicSettings] to for user parsing configuration.
|
||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
class GenreImpl(grouping: Grouping<RawGenre, SongImpl>, musicSettings: MusicSettings) : Genre {
|
||||
class GenreImpl(
|
||||
grouping: Grouping<RawGenre, SongImpl>,
|
||||
private val nameFactory: Name.Known.Factory
|
||||
) : Genre {
|
||||
private val rawGenre = grouping.raw.inner
|
||||
|
||||
override val uid = Music.UID.auxio(MusicType.GENRES) { update(rawGenre.name) }
|
||||
override val name =
|
||||
rawGenre.name?.let { Name.Known.from(it, rawGenre.name, musicSettings) }
|
||||
rawGenre.name?.let { nameFactory.parse(it, rawGenre.name) }
|
||||
?: Name.Unknown(R.string.def_genre)
|
||||
|
||||
override val songs: Set<Song>
|
||||
|
@ -491,13 +553,18 @@ class GenreImpl(grouping: Grouping<RawGenre, SongImpl>, musicSettings: MusicSett
|
|||
durationMs = totalDuration
|
||||
|
||||
hashCode = 31 * hashCode + rawGenre.hashCode()
|
||||
hashCode = 31 * hashCode + nameFactory.hashCode()
|
||||
hashCode = 31 * hashCode + songs.hashCode()
|
||||
}
|
||||
|
||||
override fun hashCode() = hashCode
|
||||
|
||||
override fun equals(other: Any?) =
|
||||
other is GenreImpl && uid == other.uid && rawGenre == other.rawGenre && songs == other.songs
|
||||
other is GenreImpl &&
|
||||
uid == other.uid &&
|
||||
rawGenre == other.rawGenre &&
|
||||
nameFactory == other.nameFactory &&
|
||||
songs == other.songs
|
||||
|
||||
override fun toString() = "Genre(uid=$uid, name=$name)"
|
||||
|
||||
|
@ -519,7 +586,7 @@ class GenreImpl(grouping: Grouping<RawGenre, SongImpl>, musicSettings: MusicSett
|
|||
* @return This instance upcasted to [Genre].
|
||||
*/
|
||||
fun finalize(): Genre {
|
||||
check(songs.isNotEmpty()) { "Malformed genre: Empty" }
|
||||
check(songs.isNotEmpty()) { "Malformed genre $name: Empty" }
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.oxycblt.auxio.music.info
|
|||
|
||||
import android.content.Context
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import java.text.CollationKey
|
||||
import java.text.Collator
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
|
@ -54,36 +55,7 @@ sealed interface Name : Comparable<Name> {
|
|||
abstract val sort: String?
|
||||
|
||||
/** A tokenized version of the name that will be compared. */
|
||||
protected abstract val sortTokens: List<SortToken>
|
||||
|
||||
/** An individual part of a name string that can be compared intelligently. */
|
||||
protected data class SortToken(val collationKey: CollationKey, val type: Type) :
|
||||
Comparable<SortToken> {
|
||||
override fun compareTo(other: SortToken): Int {
|
||||
// Numeric tokens should always be lower than lexicographic tokens.
|
||||
val modeComp = type.compareTo(other.type)
|
||||
if (modeComp != 0) {
|
||||
return modeComp
|
||||
}
|
||||
|
||||
// Numeric strings must be ordered by magnitude, thus immediately short-circuit
|
||||
// the comparison if the lengths do not match.
|
||||
if (type == Type.NUMERIC &&
|
||||
collationKey.sourceString.length != other.collationKey.sourceString.length) {
|
||||
return collationKey.sourceString.length - other.collationKey.sourceString.length
|
||||
}
|
||||
|
||||
return collationKey.compareTo(other.collationKey)
|
||||
}
|
||||
|
||||
/** Denotes the type of comparison to be performed with this token. */
|
||||
enum class Type {
|
||||
/** Compare as a digit string, like "65". */
|
||||
NUMERIC,
|
||||
/** Compare as a standard alphanumeric string, like "65daysofstatic" */
|
||||
LEXICOGRAPHIC
|
||||
}
|
||||
}
|
||||
@VisibleForTesting(VisibleForTesting.PROTECTED) abstract val sortTokens: List<SortToken>
|
||||
|
||||
final override val thumb: String
|
||||
get() =
|
||||
|
@ -108,20 +80,30 @@ sealed interface Name : Comparable<Name> {
|
|||
is Unknown -> 1
|
||||
}
|
||||
|
||||
companion object {
|
||||
interface Factory {
|
||||
/**
|
||||
* Create a new instance of [Name.Known]
|
||||
*
|
||||
* @param raw The raw name obtained from the music item
|
||||
* @param sort The raw sort name obtained from the music item
|
||||
* @param musicSettings [MusicSettings] required for name configuration.
|
||||
*/
|
||||
fun from(raw: String, sort: String?, musicSettings: MusicSettings): Known =
|
||||
if (musicSettings.intelligentSorting) {
|
||||
IntelligentKnownName(raw, sort)
|
||||
} else {
|
||||
SimpleKnownName(raw, sort)
|
||||
}
|
||||
fun parse(raw: String, sort: String?): Known
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Creates a new instance from the **current state** of the given [MusicSettings]'s
|
||||
* user-defined name configuration.
|
||||
*
|
||||
* @param settings The [MusicSettings] to use.
|
||||
* @return A [Factory] instance reflecting the configuration state.
|
||||
*/
|
||||
fun from(settings: MusicSettings) =
|
||||
if (settings.intelligentSorting) {
|
||||
IntelligentKnownName.Factory
|
||||
} else {
|
||||
SimpleKnownName.Factory
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,22 +130,28 @@ sealed interface Name : Comparable<Name> {
|
|||
private val collator: Collator = Collator.getInstance().apply { strength = Collator.PRIMARY }
|
||||
private val punctRegex by lazy { Regex("[\\p{Punct}+]") }
|
||||
|
||||
// TODO: Consider how you want to handle whitespace and "gaps" in names.
|
||||
|
||||
/**
|
||||
* Plain [Name.Known] implementation that is internationalization-safe.
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
private data class SimpleKnownName(override val raw: String, override val sort: String?) :
|
||||
Name.Known() {
|
||||
@VisibleForTesting
|
||||
data class SimpleKnownName(override val raw: String, override val sort: String?) : Name.Known() {
|
||||
override val sortTokens = listOf(parseToken(sort ?: raw))
|
||||
|
||||
private fun parseToken(name: String): SortToken {
|
||||
// Remove excess punctuation from the string, as those usually aren't considered in sorting.
|
||||
val stripped = name.replace(punctRegex, "").ifEmpty { name }
|
||||
val stripped = name.replace(punctRegex, "").trim().ifEmpty { name }
|
||||
val collationKey = collator.getCollationKey(stripped)
|
||||
// Always use lexicographic mode since we aren't parsing any numeric components
|
||||
return SortToken(collationKey, SortToken.Type.LEXICOGRAPHIC)
|
||||
}
|
||||
|
||||
data object Factory : Name.Known.Factory {
|
||||
override fun parse(raw: String, sort: String?) = SimpleKnownName(raw, sort)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -171,7 +159,8 @@ private data class SimpleKnownName(override val raw: String, override val sort:
|
|||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
private data class IntelligentKnownName(override val raw: String, override val sort: String?) :
|
||||
@VisibleForTesting
|
||||
data class IntelligentKnownName(override val raw: String, override val sort: String?) :
|
||||
Name.Known() {
|
||||
override val sortTokens = parseTokens(sort ?: raw)
|
||||
|
||||
|
@ -180,7 +169,8 @@ private data class IntelligentKnownName(override val raw: String, override val s
|
|||
// optimize it
|
||||
val stripped =
|
||||
name
|
||||
// Remove excess punctuation from the string, as those u
|
||||
// Remove excess punctuation from the string, as those usually aren't
|
||||
// considered in sorting.
|
||||
.replace(punctRegex, "")
|
||||
.ifEmpty { name }
|
||||
.run {
|
||||
|
@ -218,7 +208,40 @@ private data class IntelligentKnownName(override val raw: String, override val s
|
|||
}
|
||||
}
|
||||
|
||||
data object Factory : Name.Known.Factory {
|
||||
override fun parse(raw: String, sort: String?) = IntelligentKnownName(raw, sort)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TOKEN_REGEX by lazy { Regex("(\\d+)|(\\D+)") }
|
||||
}
|
||||
}
|
||||
|
||||
/** An individual part of a name string that can be compared intelligently. */
|
||||
@VisibleForTesting(VisibleForTesting.PROTECTED)
|
||||
data class SortToken(val collationKey: CollationKey, val type: Type) : Comparable<SortToken> {
|
||||
override fun compareTo(other: SortToken): Int {
|
||||
// Numeric tokens should always be lower than lexicographic tokens.
|
||||
val modeComp = type.compareTo(other.type)
|
||||
if (modeComp != 0) {
|
||||
return modeComp
|
||||
}
|
||||
|
||||
// Numeric strings must be ordered by magnitude, thus immediately short-circuit
|
||||
// the comparison if the lengths do not match.
|
||||
if (type == Type.NUMERIC &&
|
||||
collationKey.sourceString.length != other.collationKey.sourceString.length) {
|
||||
return collationKey.sourceString.length - other.collationKey.sourceString.length
|
||||
}
|
||||
|
||||
return collationKey.compareTo(other.collationKey)
|
||||
}
|
||||
|
||||
/** Denotes the type of comparison to be performed with this token. */
|
||||
enum class Type {
|
||||
/** Compare as a digit string, like "65". */
|
||||
NUMERIC,
|
||||
/** Compare as a standard alphanumeric string, like "65daysofstatic" */
|
||||
LEXICOGRAPHIC
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* Separators.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.metadata
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
|
||||
/**
|
||||
* Defines the user-specified parsing of multi-value tags. This should be used to parse any tags
|
||||
* that may be delimited with a separator character.
|
||||
*
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*/
|
||||
interface Separators {
|
||||
/**
|
||||
* Parse a separated value from one or more strings. If the value is already composed of more
|
||||
* than one value, nothing is done. Otherwise, it will attempt to split it based on the user's
|
||||
* separator preferences.
|
||||
*
|
||||
* @return A new list of one or more [String]s parsed by the separator configuration
|
||||
*/
|
||||
fun split(strings: List<String>): List<String>
|
||||
|
||||
companion object {
|
||||
const val COMMA = ','
|
||||
const val SEMICOLON = ';'
|
||||
const val SLASH = '/'
|
||||
const val PLUS = '+'
|
||||
const val AND = '&'
|
||||
|
||||
/**
|
||||
* Creates a new instance from the **current state** of the given [MusicSettings]'s
|
||||
* user-defined separator configuration.
|
||||
*
|
||||
* @param settings The [MusicSettings] to use.
|
||||
* @return A new [Separators] instance reflecting the configuration state.
|
||||
*/
|
||||
fun from(settings: MusicSettings) = from(settings.separators)
|
||||
|
||||
@VisibleForTesting
|
||||
fun from(chars: String) =
|
||||
if (chars.isNotEmpty()) {
|
||||
CharSeparators(chars.toSet())
|
||||
} else {
|
||||
NoSeparators
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class CharSeparators(private val chars: Set<Char>) : Separators {
|
||||
override fun split(strings: List<String>) =
|
||||
if (strings.size == 1) splitImpl(strings.first()) else strings
|
||||
|
||||
private fun splitImpl(string: String) =
|
||||
string.splitEscaped { chars.contains(it) }.correctWhitespace()
|
||||
}
|
||||
|
||||
private object NoSeparators : Separators {
|
||||
override fun split(strings: List<String>) = strings
|
||||
}
|
|
@ -52,7 +52,7 @@ class SeparatorsDialog : ViewBindingMaterialDialogFragment<DialogSeparatorsBindi
|
|||
.setTitle(R.string.set_separators)
|
||||
.setNegativeButton(R.string.lbl_cancel, null)
|
||||
.setPositiveButton(R.string.lbl_save) { _, _ ->
|
||||
musicSettings.multiValueSeparators = getCurrentSeparators()
|
||||
musicSettings.separators = getCurrentSeparators()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,7 @@ class SeparatorsDialog : ViewBindingMaterialDialogFragment<DialogSeparatorsBindi
|
|||
// More efficient to do one iteration through the separator list and initialize
|
||||
// the corresponding CheckBox for each character instead of doing an iteration
|
||||
// through the separator list for each CheckBox.
|
||||
(savedInstanceState?.getString(KEY_PENDING_SEPARATORS)
|
||||
?: musicSettings.multiValueSeparators)
|
||||
(savedInstanceState?.getString(KEY_PENDING_SEPARATORS) ?: musicSettings.separators)
|
||||
.forEach {
|
||||
when (it) {
|
||||
Separators.COMMA -> binding.separatorComma.isChecked = true
|
||||
|
@ -102,14 +101,6 @@ class SeparatorsDialog : ViewBindingMaterialDialogFragment<DialogSeparatorsBindi
|
|||
return separators
|
||||
}
|
||||
|
||||
private object Separators {
|
||||
const val COMMA = ','
|
||||
const val SEMICOLON = ';'
|
||||
const val SLASH = '/'
|
||||
const val PLUS = '+'
|
||||
const val AND = '&'
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val KEY_PENDING_SEPARATORS = BuildConfig.APPLICATION_ID + ".key.PENDING_SEPARATORS"
|
||||
}
|
||||
|
|
|
@ -18,29 +18,15 @@
|
|||
|
||||
package org.oxycblt.auxio.music.metadata
|
||||
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
import org.oxycblt.auxio.util.positiveOrNull
|
||||
|
||||
/// --- GENERIC PARSING ---
|
||||
|
||||
/**
|
||||
* Parse a multi-value tag based on the user configuration. If the value is already composed of more
|
||||
* than one value, nothing is done. Otherwise, this function will attempt to split it based on the
|
||||
* user's separator preferences.
|
||||
*
|
||||
* @param settings [MusicSettings] required to obtain user separator configuration.
|
||||
* @return A new list of one or more [String]s.
|
||||
*/
|
||||
fun List<String>.parseMultiValue(settings: MusicSettings) =
|
||||
if (size == 1) {
|
||||
first().maybeParseBySeparators(settings)
|
||||
} else {
|
||||
// Nothing to do.
|
||||
this
|
||||
}
|
||||
|
||||
// TODO: Remove the escaping checks, it's too expensive to do this for every single tag.
|
||||
|
||||
// TODO: I want to eventually be able to move a lot of this into TagWorker once I no longer have
|
||||
// to deal with the cross-module dependencies of MediaStoreExtractor.
|
||||
|
||||
/**
|
||||
* Split a [String] by the given selector, automatically handling escaped characters that satisfy
|
||||
* the selector.
|
||||
|
@ -101,17 +87,6 @@ fun String.correctWhitespace() = trim().ifBlank { null }
|
|||
*/
|
||||
fun List<String>.correctWhitespace() = mapNotNull { it.correctWhitespace() }
|
||||
|
||||
/**
|
||||
* Attempt to parse a string by the user's separator preferences.
|
||||
*
|
||||
* @param settings [MusicSettings] required to obtain user separator configuration.
|
||||
* @return A list of one or more [String]s that were split up by the user-defined separators.
|
||||
*/
|
||||
private fun String.maybeParseBySeparators(settings: MusicSettings): List<String> {
|
||||
if (settings.multiValueSeparators.isEmpty()) return listOf(this)
|
||||
return splitEscaped { settings.multiValueSeparators.contains(it) }.correctWhitespace()
|
||||
}
|
||||
|
||||
/// --- ID3v2 PARSING ---
|
||||
|
||||
/**
|
||||
|
@ -165,12 +140,12 @@ fun transformPositionField(pos: Int?, total: Int?) =
|
|||
* representations of genre fields into their named counterparts, and split up singular ID3v2-style
|
||||
* integer genre fields into one or more genres.
|
||||
*
|
||||
* @param settings [MusicSettings] required to obtain user separator configuration.
|
||||
* @return A list of one or more genre names..
|
||||
* @return A list of one or more genre names, or null if this multi-value list has no valid
|
||||
* formatting.
|
||||
*/
|
||||
fun List<String>.parseId3GenreNames(settings: MusicSettings) =
|
||||
fun List<String>.parseId3GenreNames() =
|
||||
if (size == 1) {
|
||||
first().parseId3MultiValueGenre(settings)
|
||||
first().parseId3MultiValueGenre()
|
||||
} else {
|
||||
// Nothing to split, just map any ID3v1 genres to their name counterparts.
|
||||
map { it.parseId3v1Genre() ?: it }
|
||||
|
@ -179,11 +154,10 @@ fun List<String>.parseId3GenreNames(settings: MusicSettings) =
|
|||
/**
|
||||
* Parse a single ID3v1/ID3v2 integer genre field into their named representations.
|
||||
*
|
||||
* @param settings [MusicSettings] required to obtain user separator configuration.
|
||||
* @return A list of one or more genre names.
|
||||
* @return list of one or more genre names, or null if this is not in ID3v2 format.
|
||||
*/
|
||||
private fun String.parseId3MultiValueGenre(settings: MusicSettings) =
|
||||
parseId3v1Genre()?.let { listOf(it) } ?: parseId3v2Genre() ?: maybeParseBySeparators(settings)
|
||||
private fun String.parseId3MultiValueGenre() =
|
||||
parseId3v1Genre()?.let { listOf(it) } ?: parseId3v2Genre()
|
||||
|
||||
/**
|
||||
* Parse an ID3v1 integer genre field.
|
||||
|
|
|
@ -77,7 +77,6 @@ private class TagWorkerImpl(
|
|||
private val rawSong: RawSong,
|
||||
private val future: Future<TrackGroupArray>
|
||||
) : TagWorker {
|
||||
|
||||
override fun poll(): RawSong? {
|
||||
if (!future.isDone) {
|
||||
// Not done yet, nothing to do.
|
||||
|
|
|
@ -28,11 +28,9 @@ import androidx.media3.extractor.metadata.vorbis.VorbisComment
|
|||
*
|
||||
* @param metadata The [Metadata] to wrap.
|
||||
* @author Alexander Capehart (OxygenCobalt)
|
||||
*
|
||||
* TODO: Merge with TagWorker
|
||||
*/
|
||||
class TextTags(metadata: Metadata) {
|
||||
private val _id3v2 = mutableMapOf<String, List<String>>()
|
||||
private val _id3v2 = mutableMapOf<String, MutableList<String>>()
|
||||
/** The ID3v2 text identification frames found in the file. Can have more than one value. */
|
||||
val id3v2: Map<String, List<String>>
|
||||
get() = _id3v2
|
||||
|
@ -53,7 +51,11 @@ class TextTags(metadata: Metadata) {
|
|||
?: tag.id.sanitize()
|
||||
val values = tag.values.map { it.sanitize() }.correctWhitespace()
|
||||
if (values.isNotEmpty()) {
|
||||
_id3v2[id] = values
|
||||
// Normally, duplicate ID3v2 frames are forbidden. But since MP4 atoms,
|
||||
// which can also have duplicates, are mapped to ID3v2 frames by ExoPlayer,
|
||||
// we must drop this invariant and gracefully treat duplicates as if they
|
||||
// are another way of specfiying multi-value tags.
|
||||
_id3v2.getOrPut(id) { mutableListOf() }.addAll(values)
|
||||
}
|
||||
}
|
||||
is InternalFrame -> {
|
||||
|
@ -62,7 +64,7 @@ class TextTags(metadata: Metadata) {
|
|||
val id = "TXXX:${tag.description.sanitize().lowercase()}"
|
||||
val value = tag.text
|
||||
if (value.isNotEmpty()) {
|
||||
_id3v2[id] = listOf(value)
|
||||
_id3v2.getOrPut(id) { mutableListOf() }.add(value)
|
||||
}
|
||||
}
|
||||
is VorbisComment -> {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package org.oxycblt.auxio.music.user
|
||||
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
|
@ -51,10 +50,10 @@ private constructor(
|
|||
* Clone the data in this instance to a new [PlaylistImpl] with the given [name].
|
||||
*
|
||||
* @param name The new name to use.
|
||||
* @param musicSettings [MusicSettings] required for name configuration.
|
||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||
*/
|
||||
fun edit(name: String, musicSettings: MusicSettings) =
|
||||
PlaylistImpl(uid, Name.Known.from(name, null, musicSettings), songs)
|
||||
fun edit(name: String, nameFactory: Name.Known.Factory) =
|
||||
PlaylistImpl(uid, nameFactory.parse(name, null), songs)
|
||||
|
||||
/**
|
||||
* Clone the data in this instance to a new [PlaylistImpl] with the given [Song]s.
|
||||
|
@ -76,29 +75,26 @@ private constructor(
|
|||
*
|
||||
* @param name The name of the playlist.
|
||||
* @param songs The songs to initially populate the playlist with.
|
||||
* @param musicSettings [MusicSettings] required for name configuration.
|
||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||
*/
|
||||
fun from(name: String, songs: List<Song>, musicSettings: MusicSettings) =
|
||||
PlaylistImpl(
|
||||
Music.UID.auxio(MusicType.PLAYLISTS),
|
||||
Name.Known.from(name, null, musicSettings),
|
||||
songs)
|
||||
fun from(name: String, songs: List<Song>, nameFactory: Name.Known.Factory) =
|
||||
PlaylistImpl(Music.UID.auxio(MusicType.PLAYLISTS), nameFactory.parse(name, null), songs)
|
||||
|
||||
/**
|
||||
* Populate a new instance from a read [RawPlaylist].
|
||||
*
|
||||
* @param rawPlaylist The [RawPlaylist] to read from.
|
||||
* @param deviceLibrary The [DeviceLibrary] to initialize from.
|
||||
* @param musicSettings [MusicSettings] required for name configuration.
|
||||
* @param nameFactory The [Name.Known.Factory] to interpret name information with.
|
||||
*/
|
||||
fun fromRaw(
|
||||
rawPlaylist: RawPlaylist,
|
||||
deviceLibrary: DeviceLibrary,
|
||||
musicSettings: MusicSettings
|
||||
nameFactory: Name.Known.Factory
|
||||
) =
|
||||
PlaylistImpl(
|
||||
rawPlaylist.playlistInfo.playlistUid,
|
||||
Name.Known.from(rawPlaylist.playlistInfo.name, null, musicSettings),
|
||||
nameFactory.parse(rawPlaylist.playlistInfo.name, null),
|
||||
rawPlaylist.songs.mapNotNull { deviceLibrary.findSong(it.songUid) })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.oxycblt.auxio.music.MusicSettings
|
|||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
||||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
|
||||
|
@ -144,7 +145,9 @@ constructor(private val playlistDao: PlaylistDao, private val musicSettings: Mus
|
|||
UserLibrary.Factory {
|
||||
override suspend fun query() =
|
||||
try {
|
||||
playlistDao.readRawPlaylists()
|
||||
val rawPlaylists = playlistDao.readRawPlaylists()
|
||||
logD("Successfully read ${rawPlaylists.size} playlists")
|
||||
rawPlaylists
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to read playlists: $e")
|
||||
listOf()
|
||||
|
@ -154,11 +157,10 @@ constructor(private val playlistDao: PlaylistDao, private val musicSettings: Mus
|
|||
rawPlaylists: List<RawPlaylist>,
|
||||
deviceLibrary: DeviceLibrary
|
||||
): MutableUserLibrary {
|
||||
logD("Successfully read ${rawPlaylists.size} playlists")
|
||||
// Convert the database playlist information to actual usable playlists.
|
||||
val nameFactory = Name.Known.Factory.from(musicSettings)
|
||||
val playlistMap = mutableMapOf<Music.UID, PlaylistImpl>()
|
||||
for (rawPlaylist in rawPlaylists) {
|
||||
val playlistImpl = PlaylistImpl.fromRaw(rawPlaylist, deviceLibrary, musicSettings)
|
||||
val playlistImpl = PlaylistImpl.fromRaw(rawPlaylist, deviceLibrary, nameFactory)
|
||||
playlistMap[playlistImpl.uid] = playlistImpl
|
||||
}
|
||||
return UserLibraryImpl(playlistDao, playlistMap, musicSettings)
|
||||
|
@ -184,7 +186,7 @@ private class UserLibraryImpl(
|
|||
override fun findPlaylist(name: String) = playlistMap.values.find { it.name.raw == name }
|
||||
|
||||
override suspend fun createPlaylist(name: String, songs: List<Song>): Playlist? {
|
||||
val playlistImpl = PlaylistImpl.from(name, songs, musicSettings)
|
||||
val playlistImpl = PlaylistImpl.from(name, songs, Name.Known.Factory.from(musicSettings))
|
||||
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
|
||||
val rawPlaylist =
|
||||
RawPlaylist(
|
||||
|
@ -207,7 +209,9 @@ private class UserLibraryImpl(
|
|||
val playlistImpl =
|
||||
synchronized(this) {
|
||||
requireNotNull(playlistMap[playlist.uid]) { "Cannot rename invalid playlist" }
|
||||
.also { playlistMap[it.uid] = it.edit(name, musicSettings) }
|
||||
.also {
|
||||
playlistMap[it.uid] = it.edit(name, Name.Known.Factory.from(musicSettings))
|
||||
}
|
||||
}
|
||||
|
||||
return try {
|
||||
|
|
|
@ -338,8 +338,7 @@ constructor(
|
|||
song,
|
||||
object : BitmapProvider.Target {
|
||||
override fun onCompleted(bitmap: Bitmap?) {
|
||||
this@MediaSessionComponent.logD(
|
||||
"Bitmap loaded, applying media session and posting notification")
|
||||
logD("Bitmap loaded, applying media session and posting notification")
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmap)
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
|
||||
val metadata = builder.build()
|
||||
|
|
|
@ -166,7 +166,7 @@ class PlaybackService :
|
|||
}
|
||||
|
||||
ContextCompat.registerReceiver(
|
||||
this, systemReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED)
|
||||
this, systemReceiver, intentFilter, ContextCompat.RECEIVER_EXPORTED)
|
||||
|
||||
logD("Service created")
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
|
||||
if (!launchedKeyboard) {
|
||||
// Auto-open the keyboard when this view is shown
|
||||
this@SearchFragment.logD("Keyboard is not shown yet")
|
||||
logD("Keyboard is not shown yet")
|
||||
showKeyboard(this)
|
||||
launchedKeyboard = true
|
||||
}
|
||||
|
|
|
@ -18,27 +18,24 @@
|
|||
|
||||
package org.oxycblt.auxio.util
|
||||
|
||||
import android.util.Log
|
||||
import org.oxycblt.auxio.BuildConfig
|
||||
|
||||
// Shortcut functions for logging.
|
||||
// Yes, I know timber exists but this does what I need.
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Log an object to the debug channel. Automatically handles tags.
|
||||
*
|
||||
* @param obj The object to log.
|
||||
*/
|
||||
fun Any.logD(obj: Any?) = logD("$obj")
|
||||
inline fun logD(obj: Any?) = logD("$obj")
|
||||
|
||||
/**
|
||||
* Log a string message to the debug channel. Automatically handles tags.
|
||||
*
|
||||
* @param msg The message to log.
|
||||
*/
|
||||
fun Any.logD(msg: String) {
|
||||
inline fun logD(msg: String) {
|
||||
if (BuildConfig.DEBUG && !copyleftNotice()) {
|
||||
Log.d(autoTag, msg)
|
||||
Timber.d(msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,31 +44,24 @@ fun Any.logD(msg: String) {
|
|||
*
|
||||
* @param msg The message to log.
|
||||
*/
|
||||
fun Any.logW(msg: String) = Log.w(autoTag, msg)
|
||||
inline fun logW(msg: String) = Timber.w(msg)
|
||||
|
||||
/**
|
||||
* Log a string message to the error channel. Automatically handles tags.
|
||||
*
|
||||
* @param msg The message to log.
|
||||
*/
|
||||
fun Any.logE(msg: String) = Log.e(autoTag, msg)
|
||||
|
||||
/**
|
||||
* The LogCat-suitable tag for this string. Consists of the object's name, or "Anonymous Object" if
|
||||
* the object does not exist.
|
||||
*/
|
||||
private val Any.autoTag: String
|
||||
get() = "Auxio.${this::class.simpleName ?: "Anonymous Object"}"
|
||||
inline fun logE(msg: String) = Timber.e(msg)
|
||||
|
||||
/**
|
||||
* Please don't plagiarize Auxio! You are free to remove this as long as you continue to keep your
|
||||
* source open.
|
||||
*/
|
||||
@Suppress("KotlinConstantConditions")
|
||||
private fun copyleftNotice(): Boolean {
|
||||
fun copyleftNotice(): Boolean {
|
||||
if (BuildConfig.APPLICATION_ID != "org.oxycblt.auxio" &&
|
||||
BuildConfig.APPLICATION_ID != "org.oxycblt.auxio.debug") {
|
||||
Log.d(
|
||||
Timber.d(
|
||||
"Auxio Project",
|
||||
"Friendly reminder: Auxio is licensed under the " +
|
||||
"GPLv3 and all derivative apps must be made open source!")
|
||||
|
|
|
@ -154,4 +154,4 @@
|
|||
|
||||
</org.oxycblt.auxio.playback.ui.ForcedLTRFrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -157,4 +157,4 @@
|
|||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</org.oxycblt.auxio.playback.ui.ForcedLTRFrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -159,4 +159,4 @@
|
|||
</org.oxycblt.auxio.playback.ui.ForcedLTRFrameLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -379,6 +379,9 @@
|
|||
<action
|
||||
android:id="@+id/delete_playlist"
|
||||
app:destination="@id/delete_playlist_dialog" />
|
||||
<action
|
||||
android:id="@+id/add_to_playlist"
|
||||
app:destination="@id/add_to_playlist_dialog" />
|
||||
<action
|
||||
android:id="@+id/play_from_artist"
|
||||
app:destination="@id/play_from_artist_dialog" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<!-- Info namespace | App labels -->
|
||||
<string name="info_app_desc">مشغل موسيقى بسيط ومعقول للأندرويد</string>
|
||||
<string name="info_app_desc">مشغل موسيقى بسيط ومعقول للأندرويد.</string>
|
||||
<string name="lng_widget">عرض وتحكم بشتغيل الموسيقى</string>
|
||||
<!-- Label Namespace | Static Labels -->
|
||||
<string name="lbl_retry">إعادة المحاولة</string>
|
||||
|
@ -40,7 +40,7 @@
|
|||
<string name="lbl_version">الإصدار</string>
|
||||
<string name="lbl_code">عرض على الكود في Github</string>
|
||||
<string name="lbl_licenses">التراخيص</string>
|
||||
<string name="lng_author">تمت برمجة التطبيق من قبل OxygenCobalt</string>
|
||||
<string name="lng_author">تمت برمجة التطبيق من قبل الكساندر كابيهارت</string>
|
||||
<!-- Settings namespace | Settings-related labels -->
|
||||
<string name="set_root_title">الإعدادات</string>
|
||||
<string name="set_ui">المظهر</string>
|
||||
|
@ -192,4 +192,27 @@
|
|||
<string name="lbl_mixes">مزيج</string>
|
||||
<string name="lbl_wiki">Wiki</string>
|
||||
<string name="lbl_song">أغنية</string>
|
||||
<string name="lbl_sort_direction">أتجاه</string>
|
||||
<string name="lbl_selection">أختيار</string>
|
||||
<string name="lbl_playlists">قوائم التشغيل</string>
|
||||
<string name="lbl_playlist">قائمة التشغيل</string>
|
||||
<string name="lng_playlist_created">تم خلق قائمة التشغيل</string>
|
||||
<string name="lbl_show_error_info">المزيد</string>
|
||||
<string name="lbl_delete">حذف</string>
|
||||
<string name="lbl_copied">تم النسخ</string>
|
||||
<string name="lbl_playlist_add">إضافة إلى قائمة التشغيل</string>
|
||||
<string name="lbl_share">مشاركة</string>
|
||||
<string name="lbl_edit">تعديل</string>
|
||||
<string name="lbl_rename">إعادة التسمية</string>
|
||||
<string name="lng_playlist_added">تمت الإضافة إلى قائمة التشغيل</string>
|
||||
<string name="lbl_sort_mode">رتب حسب</string>
|
||||
<string name="lbl_parent_detail">مشاهدة</string>
|
||||
<string name="lbl_confirm_delete_playlist">حذف قائمة التشغيل؟</string>
|
||||
<string name="lng_playlist_deleted">تم حذف قائمة التشغيل</string>
|
||||
<string name="lbl_report">تقرير</string>
|
||||
<string name="lbl_new_playlist">قائمة تشغيل جديدة</string>
|
||||
<string name="lbl_error_info">معلومات خاطئة</string>
|
||||
<string name="lng_playlist_renamed">تم إعادة تسمية قائمة التشغيل</string>
|
||||
<string name="lbl_rename_playlist">إعادة تسمية قائمة التشغيل</string>
|
||||
<string name="lbl_appears_on">يظهر على</string>
|
||||
</resources>
|
|
@ -300,4 +300,8 @@
|
|||
<string name="lbl_sort_direction">Напрамак</string>
|
||||
<string name="desc_selection_image">Абярыце малюнак</string>
|
||||
<string name="lbl_selection">Абярыце</string>
|
||||
<string name="lbl_show_error_info">Дадаткова</string>
|
||||
<string name="lbl_copied">Скапіравана</string>
|
||||
<string name="lbl_error_info">Інфармацыя пра памылку</string>
|
||||
<string name="lbl_report">Справаздача пра памылку</string>
|
||||
</resources>
|
|
@ -311,4 +311,8 @@
|
|||
<string name="lbl_sort_mode">Seřadit podle</string>
|
||||
<string name="desc_selection_image">Výběr obrázku</string>
|
||||
<string name="lbl_selection">Výběr</string>
|
||||
<string name="lbl_show_error_info">Další</string>
|
||||
<string name="lbl_error_info">Informace o chybě</string>
|
||||
<string name="lbl_copied">Zkopírovat</string>
|
||||
<string name="lbl_report">Nahlásit</string>
|
||||
</resources>
|
|
@ -300,4 +300,10 @@
|
|||
<string name="set_play_song_by_itself">Lied selbst spielen</string>
|
||||
<string name="lbl_sort_direction">Richtung</string>
|
||||
<string name="lbl_sort_mode">Sortieren nach</string>
|
||||
<string name="desc_selection_image">Auswahl-Bild</string>
|
||||
<string name="lbl_selection">Auswahl</string>
|
||||
<string name="lbl_show_error_info">Mehr</string>
|
||||
<string name="lbl_copied">Kopiert</string>
|
||||
<string name="lbl_report">Melden</string>
|
||||
<string name="lbl_error_info">Fehlerinformation</string>
|
||||
</resources>
|
|
@ -306,4 +306,8 @@
|
|||
<string name="lbl_sort_direction">Dirección</string>
|
||||
<string name="desc_selection_image">Selección de imágenes</string>
|
||||
<string name="lbl_selection">Selección</string>
|
||||
<string name="lbl_show_error_info">Más</string>
|
||||
<string name="lbl_error_info">Información sobre el error</string>
|
||||
<string name="lbl_copied">Copiado</string>
|
||||
<string name="lbl_report">Informar</string>
|
||||
</resources>
|
|
@ -271,4 +271,7 @@
|
|||
<string name="set_rescan_desc">Tyhjennä tunnistevälimuisti ja lataa musiikkikirjasto kokonaan uudelleen (hitaampi mutta kattavampi)</string>
|
||||
<string name="lbl_song">Kappale</string>
|
||||
<string name="lbl_parent_detail">Näytä</string>
|
||||
<string name="lbl_show_error_info">Lisää</string>
|
||||
<string name="lbl_copied">Kopioitu</string>
|
||||
<string name="lbl_report">Ilmoita virheestä</string>
|
||||
</resources>
|
|
@ -242,7 +242,7 @@
|
|||
<string name="lbl_playlist_add">Ajouter à la liste de lecture</string>
|
||||
<string name="desc_new_playlist">Créer une nouvelle liste de lecture</string>
|
||||
<string name="cdc_mka">Audio Matroska</string>
|
||||
<string name="fmt_lib_artist_count">Artistes chargés&nbsp;: %d</string>
|
||||
<string name="fmt_lib_artist_count">Artistes chargés : %d</string>
|
||||
<string name="set_rewind_prev">Rembobiner avant de revenir en arrière</string>
|
||||
<string name="desc_artist_image">Image d\'artiste pour %s</string>
|
||||
<string name="def_track">Aucune piste</string>
|
||||
|
@ -253,8 +253,8 @@
|
|||
<string name="lbl_rename">Renommer</string>
|
||||
<string name="err_did_not_wipe">Impossible d\'effacer l\'état</string>
|
||||
<string name="desc_change_repeat">Modifier le mode de répétition</string>
|
||||
<string name="fmt_lib_album_count">Albums chargés&nbsp;: %d</string>
|
||||
<string name="fmt_lib_total_duration">Durée totale&nbsp;: %s</string>
|
||||
<string name="fmt_lib_album_count">Albums chargés : %d</string>
|
||||
<string name="fmt_lib_total_duration">Durée totale : %s</string>
|
||||
<string name="desc_clear_search">Effacer la requête de recherche</string>
|
||||
<string name="desc_playlist_image">Image de la liste de lecture pour %s</string>
|
||||
<string name="fmt_disc_no">Disque %d</string>
|
||||
|
@ -288,7 +288,7 @@
|
|||
<string name="err_did_not_save">Impossible de sauvegarder l\'état</string>
|
||||
<string name="def_song_count">Aucune chanson</string>
|
||||
<string name="fmt_editing">Modification de %s</string>
|
||||
<string name="fmt_lib_genre_count">Genres chargés&nbsp;: %d</string>
|
||||
<string name="fmt_lib_genre_count">Genres chargés : %d</string>
|
||||
<string name="desc_genre_image">Image de genre pour %s</string>
|
||||
<string name="cdc_flac">Codec audio gratuit sans perte (FLAC)</string>
|
||||
<string name="fmt_selected">%d sélectionnés</string>
|
||||
|
@ -300,4 +300,12 @@
|
|||
<string name="lbl_song">Chanson</string>
|
||||
<string name="lbl_parent_detail">Voir</string>
|
||||
<string name="set_play_song_by_itself">Jouer la chanson par elle-même</string>
|
||||
<string name="desc_selection_image">Image de sélection</string>
|
||||
<string name="lbl_sort_mode">Trier par</string>
|
||||
<string name="lbl_sort_direction">Direction</string>
|
||||
<string name="lbl_selection">Sélection</string>
|
||||
<string name="lbl_show_error_info">En savoir plus</string>
|
||||
<string name="lbl_copied">Copié</string>
|
||||
<string name="lbl_report">Signaler</string>
|
||||
<string name="lbl_error_info">Info sur l\'erreur</string>
|
||||
</resources>
|
|
@ -299,4 +299,10 @@
|
|||
<string name="set_play_song_by_itself">इसी गीत को चलाएं</string>
|
||||
<string name="lbl_sort_direction">दिशा</string>
|
||||
<string name="lbl_sort_mode">के अनुसार क्रमबद्ध करें</string>
|
||||
<string name="lbl_selection">संग्रह</string>
|
||||
<string name="desc_selection_image">चयन छवि</string>
|
||||
<string name="lbl_error_info">त्रुटि की जानकारी</string>
|
||||
<string name="lbl_report">रिपोर्ट करें</string>
|
||||
<string name="lbl_copied">कापी किया गया</string>
|
||||
<string name="lbl_show_error_info">और</string>
|
||||
</resources>
|
|
@ -297,4 +297,8 @@
|
|||
<string name="lbl_sort_direction">Smjer</string>
|
||||
<string name="desc_selection_image">Slika odabira</string>
|
||||
<string name="lbl_selection">Odabir</string>
|
||||
<string name="lbl_show_error_info">Više</string>
|
||||
<string name="lbl_error_info">Podaci greške</string>
|
||||
<string name="lbl_report">Prijavi grešku</string>
|
||||
<string name="lbl_copied">Kopirano</string>
|
||||
</resources>
|
|
@ -301,4 +301,8 @@
|
|||
<string name="lbl_sort_mode">Rendezés</string>
|
||||
<string name="lbl_selection">Kiválasztás</string>
|
||||
<string name="desc_selection_image">Kép kiválasztás</string>
|
||||
<string name="lbl_show_error_info">További</string>
|
||||
<string name="lbl_copied">Másolva</string>
|
||||
<string name="lbl_report">Jelentés</string>
|
||||
<string name="lbl_error_info">Hiba információ</string>
|
||||
</resources>
|
|
@ -211,4 +211,26 @@
|
|||
<string name="set_library">Pustaka</string>
|
||||
<string name="set_playback">Pemutaran</string>
|
||||
<string name="set_separators_and">Ampersand (&)</string>
|
||||
<string name="lbl_compilations">Kompilasi</string>
|
||||
<string name="lbl_compilation_remix">Kompilasi remix</string>
|
||||
<string name="lbl_eps">EP</string>
|
||||
<string name="lbl_ep_live">EP Live</string>
|
||||
<string name="lbl_compilation">Kompilasi</string>
|
||||
<string name="lbl_mixtapes">Kaset campuran</string>
|
||||
<string name="lbl_show_error_info">Lainnya</string>
|
||||
<string name="lbl_soundtracks">Soundtrack</string>
|
||||
<string name="lbl_album_live">Album live</string>
|
||||
<plurals name="fmt_artist_count">
|
||||
<item quantity="other">%d artis</item>
|
||||
</plurals>
|
||||
<string name="lbl_single_live">Single Live</string>
|
||||
<string name="lbl_ep">EP</string>
|
||||
<string name="lbl_mixtape">Kaset campuran</string>
|
||||
<string name="lbl_single_remix">Single remix</string>
|
||||
<string name="lbl_song">Lagu</string>
|
||||
<string name="lbl_single">Single</string>
|
||||
<string name="lbl_soundtrack">Soundtrek</string>
|
||||
<string name="lbl_compilation_live">Kompilasi live</string>
|
||||
<string name="lbl_ep_remix">EP Remix</string>
|
||||
<string name="lbl_singles">Single</string>
|
||||
</resources>
|
|
@ -176,12 +176,12 @@
|
|||
<string name="err_did_not_save">לא ניתן לשמור את המצב</string>
|
||||
<string name="err_no_perms"> Auxio צריך הרשאות על מנת לקרוא את ספריית המוזיקה שלך</string>
|
||||
<string name="desc_queue_bar">פתיחת התור</string>
|
||||
<string name="fmt_lib_total_duration">סך הכל משך: %s</string>
|
||||
<string name="fmt_lib_total_duration">משך כולל: %s</string>
|
||||
<string name="fmt_def_playlist">רשימת השמעה %d</string>
|
||||
<string name="fmt_lib_artist_count">אומנים טעונים: %d</string>
|
||||
<string name="fmt_lib_song_count">שירים טעונים: %d</string>
|
||||
<string name="fmt_lib_album_count">אלבומים טעונים: %d</string>
|
||||
<string name="fmt_lib_genre_count">סוגות טעונות: %d</string>
|
||||
<string name="fmt_lib_genre_count">ז\'אנרים טעונים: %d</string>
|
||||
<string name="lbl_state_wiped">המצב נוקה</string>
|
||||
<string name="set_library">ספריה</string>
|
||||
<string name="set_save_desc">שמירת מצב הנגינה הנוכחי כעת</string>
|
||||
|
@ -197,15 +197,15 @@
|
|||
<string name="desc_artist_image">תמונת אומן עבור %s</string>
|
||||
<string name="desc_genre_image">יצירת תמונה עבור %s</string>
|
||||
<string name="def_artist">אומן לא ידוע</string>
|
||||
<string name="def_genre">סוגה לא ידועה</string>
|
||||
<string name="def_genre">ז\'אנר לא ידוע</string>
|
||||
<string name="def_date">אין תאריך</string>
|
||||
<string name="def_track">אין רצועה</string>
|
||||
<string name="def_playback">אך מוזיקה אינה מתנגנת</string>
|
||||
<string name="def_playback">מוזיקה לא מתנגנת</string>
|
||||
<string name="clr_blue">כחול</string>
|
||||
<string name="clr_deep_blue">כחול עמוק</string>
|
||||
<string name="clr_grey">אפור</string>
|
||||
<string name="clr_dynamic">דינמי</string>
|
||||
<string name="fmt_indexing">המוזיקה שלך בטעינה (%1$d/%2$d)…</string>
|
||||
<string name="fmt_indexing">המוזיקה שלך בטעינה… (%1$d/%2$d)</string>
|
||||
<string name="fmt_disc_no">דיסק %d</string>
|
||||
<string name="set_dirs_desc">ניהול המקומות שמהם תיטען מוזיקה</string>
|
||||
<string name="def_song_count">אין שירים</string>
|
||||
|
@ -215,7 +215,7 @@
|
|||
<plurals name="fmt_artist_count">
|
||||
<item quantity="one">אומן אחד</item>
|
||||
<item quantity="two">שני אומנים</item>
|
||||
<item quantity="many">%d אומנים</item>
|
||||
<item quantity="other">%d אומנים</item>
|
||||
</plurals>
|
||||
<string name="set_dirs_mode_include">לכלול</string>
|
||||
<string name="set_reindex">רענון מוזיקה</string>
|
||||
|
@ -226,12 +226,12 @@
|
|||
<plurals name="fmt_song_count">
|
||||
<item quantity="one">שיר אחד</item>
|
||||
<item quantity="two">שני שירים</item>
|
||||
<item quantity="many">%d שירים</item>
|
||||
<item quantity="other">%d שירים</item>
|
||||
</plurals>
|
||||
<plurals name="fmt_album_count">
|
||||
<item quantity="one">אלבום אחד</item>
|
||||
<item quantity="two">שני אלבומים</item>
|
||||
<item quantity="many">%d אלבומים</item>
|
||||
<item quantity="other">%d אלבומים</item>
|
||||
</plurals>
|
||||
<string name="lng_playlist_renamed">שונה שם רשימת ההשמעה</string>
|
||||
<string name="lng_playlist_deleted">רשימת השמעה נמחקה</string>
|
||||
|
@ -242,7 +242,7 @@
|
|||
<string name="desc_playlist_image">תמונת רשימת השמעה עבור %s</string>
|
||||
<string name="clr_red">אדום</string>
|
||||
<string name="clr_green">ירוק</string>
|
||||
<string name="lbl_relative_path">נתיב הורה</string>
|
||||
<string name="lbl_relative_path">נתיב ראשי</string>
|
||||
<string name="err_did_not_restore">לא ניתן לשחזר את המצב</string>
|
||||
<string name="desc_track_number">רצועה %d</string>
|
||||
<string name="desc_new_playlist">יצירת רשימת השמעה חדשה</string>
|
||||
|
@ -257,7 +257,7 @@
|
|||
<string name="def_disc">אין דיסק</string>
|
||||
<string name="clr_deep_green">ירוק עמוק</string>
|
||||
<string name="clr_yellow">צהוב</string>
|
||||
<string name="fmt_deletion_info">מחיקת %s\? פעולה זו לא ניתן לביטול.</string>
|
||||
<string name="fmt_deletion_info">למחוק את %s\? פעולה זו לא ניתן לביטול.</string>
|
||||
<string name="lbl_song">שיר</string>
|
||||
<string name="set_intelligent_sorting">מיון חכם</string>
|
||||
<string name="lbl_parent_detail">הצגה</string>
|
||||
|
@ -271,6 +271,34 @@
|
|||
<string name="set_dirs_mode_include_desc">מוזיקה תיטען <b>רק</b> מהתיקיות שנוספו.</string>
|
||||
<string name="lbl_appears_on">מופיע~ה ב-</string>
|
||||
<string name="set_play_song_by_itself">ניגון השיר בלבד</string>
|
||||
<string name="set_pre_amp_warning">אזהרה: שינוי המגבר לערך חיובי גבוה עלול לגרום לשיאים בחלק מרצועות האודיו</string>
|
||||
<string name="set_pre_amp_warning">אזהרה: שינוי המגבר לערך חיובי גבוה עלול לגרום לעיוות (דיסטורשן) בחלק מרצועות האודיו.</string>
|
||||
<string name="set_restore_state">שחזור מצב נגינה</string>
|
||||
<string name="clr_indigo">אינדיגו</string>
|
||||
<string name="cdc_mp3">אודיו MPEG-1</string>
|
||||
<string name="cdc_mp4">אודיו MPEG-4</string>
|
||||
<string name="cdc_ogg">אודיו Ogg</string>
|
||||
<string name="clr_cyan">ציאן</string>
|
||||
<string name="clr_teal">טורקיז</string>
|
||||
<string name="clr_brown">חום</string>
|
||||
<string name="fmt_selected">%d נבחרו</string>
|
||||
<string name="set_state">התמדה</string>
|
||||
<string name="lbl_show_error_info">עוד</string>
|
||||
<string name="lbl_selection">בחירה</string>
|
||||
<string name="lbl_error_info">מידע על השגיאה</string>
|
||||
<string name="lbl_report">דיווח</string>
|
||||
<string name="desc_selection_image">תמונה נבחרת</string>
|
||||
<string name="cdc_flac">קודק אודיו חופשי ללא איבוד נתונים (FLAC)</string>
|
||||
<string name="clr_purple">סגול</string>
|
||||
<string name="clr_deep_purple">סגול עמוק</string>
|
||||
<string name="fmt_db_pos">+%.1f דציבלים (dB)</string>
|
||||
<string name="fmt_db_neg">-%.1f דציבלים (dB)</string>
|
||||
<string name="fmt_sample_rate">%d הרץ (Hz)</string>
|
||||
<string name="fmt_bitrate">%d קילוביטים לשנייה (kbps)</string>
|
||||
<string name="lbl_copied">מועתק</string>
|
||||
<string name="set_restore_desc">שחזור מצב הנגינה שנשמר קודם (אם קיים)</string>
|
||||
<string name="cdc_mka">אודיו Matroska</string>
|
||||
<string name="cdc_aac">קידוד אודיו מתקדם (AAC)</string>
|
||||
<string name="fmt_list">%1$s, %2$s</string>
|
||||
<string name="clr_lime">ליים</string>
|
||||
<string name="fmt_editing">%s נערך</string>
|
||||
</resources>
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
|
||||
<!-- Info namespace | App labels -->
|
||||
<string name="info_app_desc">단순하고, 실용적인 안드로이드용 뮤직 플레이어입니다.</string>
|
||||
<string name="info_app_desc">단순하고, 실용적인 안드로이드용 음악 플레이어입니다.</string>
|
||||
<string name="lng_widget">음악 재생 제어 및 상태 확인</string>
|
||||
<!-- Label Namespace | Static Labels -->
|
||||
<string name="lbl_retry">재시도</string>
|
||||
<string name="lbl_grant">허가</string>
|
||||
<string name="lbl_retry">다시 시도</string>
|
||||
<string name="lbl_grant">허용</string>
|
||||
<string name="lbl_genres">장르</string>
|
||||
<string name="lbl_artists">아티스트</string>
|
||||
<string name="lbl_albums">앨범</string>
|
||||
|
@ -26,14 +26,14 @@
|
|||
<string name="lbl_sort_asc">오름차순</string>
|
||||
<string name="lbl_playback">지금 재생 중</string>
|
||||
<string name="lbl_play">재생</string>
|
||||
<string name="lbl_shuffle">셔플</string>
|
||||
<string name="lbl_shuffle">무작위 재생</string>
|
||||
<string name="set_play_song_from_all">모든 곡에서 재생</string>
|
||||
<string name="set_play_song_from_album">앨범에서 재생</string>
|
||||
<string name="set_play_song_from_artist">아티스트에서 재생</string>
|
||||
<string name="lbl_queue">대기열</string>
|
||||
<string name="lbl_play_next">다음 곡 재생</string>
|
||||
<string name="lbl_queue_add">대기열에 추가</string>
|
||||
<string name="lng_queue_added">대기열에 추가됨</string>
|
||||
<string name="lng_queue_added">대기열에 추가했습니다.</string>
|
||||
<string name="lbl_artist_details">아티스트로 이동</string>
|
||||
<string name="lbl_album_details">앨범으로 이동</string>
|
||||
<string name="lbl_state_saved">상태 저장됨</string>
|
||||
|
@ -46,24 +46,24 @@
|
|||
<string name="lbl_about">정보</string>
|
||||
<string name="lbl_version">버전</string>
|
||||
<string name="lbl_code">소스 코드</string>
|
||||
<string name="lbl_licenses">라이센스</string>
|
||||
<string name="lbl_licenses">라이선스</string>
|
||||
<string name="lng_author">Alexander Capehart가 개발</string>
|
||||
<string name="lbl_library_counts">라이브러리 통계</string>
|
||||
<!-- Settings namespace | Settings-related labels -->
|
||||
<string name="set_root_title">설정</string>
|
||||
<string name="set_ui">보고 느낌</string>
|
||||
<string name="set_ui">모양과 느낌</string>
|
||||
<string name="set_theme">테마</string>
|
||||
<string name="set_theme_auto">자동</string>
|
||||
<string name="set_theme_day">밝음</string>
|
||||
<string name="set_theme_night">어두움</string>
|
||||
<string name="set_theme_day">라이트 테마</string>
|
||||
<string name="set_theme_night">다크 테마</string>
|
||||
<string name="set_accent">배색</string>
|
||||
<string name="set_black_mode">검정 테마</string>
|
||||
<string name="set_black_mode_desc">어두운 테마에 검정색 사용</string>
|
||||
<string name="set_black_mode_desc">다크 테마에 검정색 사용</string>
|
||||
<string name="set_display">화면</string>
|
||||
<string name="set_lib_tabs">라이브러리 탭</string>
|
||||
<string name="set_lib_tabs_desc">라이브러리 탭의 순서 및 표시할 탭 변경</string>
|
||||
<string name="set_lib_tabs_desc">라이브러리 탭 순서 및 표시할 탭 변경</string>
|
||||
<string name="set_round_mode">둥근 UI 모드</string>
|
||||
<string name="set_round_mode_desc">기타 UI 요소 가장자리를 둥글게 표시 (앨범 커버도 둥글어짐)</string>
|
||||
<string name="set_round_mode_desc">앨범 커버를 포함한 기타 UI의 가장자리를 둥글게 표시합니다.</string>
|
||||
<string name="set_notif_action">알림 동작 사용자 정의</string>
|
||||
<string name="set_audio">소리</string>
|
||||
<string name="set_headset_autoplay">헤드셋 자동 재생</string>
|
||||
|
@ -71,32 +71,32 @@
|
|||
<string name="set_replay_gain_mode">ReplayGain 계획</string>
|
||||
<string name="set_replay_gain_mode_track">트랙 선호</string>
|
||||
<string name="set_replay_gain_mode_album">앨범 선호</string>
|
||||
<string name="set_replay_gain_mode_dynamic">앨법 재생 중인 경우 앨범 선호</string>
|
||||
<string name="set_replay_gain_mode_dynamic">앨범 재생 중인 경우 앨범 선호</string>
|
||||
<string name="set_pre_amp">ReplayGain 프리앰프</string>
|
||||
<string name="set_pre_amp_desc">재생 중에 프리앰프를 적용하여 조정</string>
|
||||
<string name="set_pre_amp_with">태그로 조정</string>
|
||||
<string name="set_pre_amp_without">태그 없이 조정</string>
|
||||
<string name="set_pre_amp_warning">주의: 프리앰프를 높게 설정하면 일부 소리 트랙이 왜곡될 수 있습니다.</string>
|
||||
<string name="set_personalize">동작</string>
|
||||
<string name="set_pre_amp_warning">주의: 프리앰프를 높게 설정하면 일부 오디오 트랙이 왜곡될 수 있습니다.</string>
|
||||
<string name="set_personalize">개인화</string>
|
||||
<string name="set_play_in_list_with">라이브러리에서 재생할 때</string>
|
||||
<string name="set_keep_shuffle">무작위 재생 기억</string>
|
||||
<string name="set_keep_shuffle_desc">새로운 곡을 재생할 때 무작위 재생 유지</string>
|
||||
<string name="set_keep_shuffle_desc">새로운 곡을 재생할 때 무작위 재생 모드 유지</string>
|
||||
<string name="set_rewind_prev">이전 곡으로 가기 전에 되감기</string>
|
||||
<string name="set_rewind_prev_desc">이전 곡으로 건너뛰기 전에 먼저 현재 트랙을 되감기</string>
|
||||
<string name="set_repeat_pause">반복 재생 시 일시 중지</string>
|
||||
<string name="set_repeat_pause_desc">곡이 반복 재생될 때 일시 중지</string>
|
||||
<string name="set_content">내용</string>
|
||||
<string name="set_save_state">재생 상태 저장</string>
|
||||
<string name="set_save_desc">현재 재생 상태를 즉시 저장</string>
|
||||
<string name="set_save_desc">현재 재생 상태를 지금 저장합니다.</string>
|
||||
<string name="set_reindex">음악 새로고침</string>
|
||||
<string name="set_reindex_desc">이미 저장된 태그를 가능한 활용하여 음악 라이브러리를 다시 만들기</string>
|
||||
<string name="set_reindex_desc">캐시된 태그를 사용하여 음악 라이브러리를 다시 불러옵니다.</string>
|
||||
<!-- Error Namespace | Error Labels -->
|
||||
<string name="err_no_music">음악 없음</string>
|
||||
<string name="err_index_failed">음악 불러오기 실패</string>
|
||||
<string name="err_no_perms">Auxio가 음악 라이브러리를 읽을 수 있는 권한이 필요함</string>
|
||||
<string name="err_no_app">이 작업을 처리할 수 있는 앱을 찾지 못함</string>
|
||||
<string name="err_no_perms">앱에서 음악 라이브러리를 읽을 수 있는 권한이 필요합니다.</string>
|
||||
<string name="err_no_app">이 작업을 처리할 수 있는 앱을 찾을 수 없습니다.</string>
|
||||
<string name="err_no_dirs">폴더 없음</string>
|
||||
<string name="err_bad_dir">이 폴더는 지원되지 않음</string>
|
||||
<string name="err_bad_dir">지원하지 않는 폴더입니다.</string>
|
||||
<!-- Hint Namespace | EditText Hints -->
|
||||
<string name="lng_search_library">라이브러리에서 검색…</string>
|
||||
<!-- Description Namespace | Accessibility Strings -->
|
||||
|
@ -107,8 +107,8 @@
|
|||
<string name="desc_change_repeat">반복 방식 변경</string>
|
||||
<string name="desc_shuffle">무작위 재생 켜기 또는 끄기</string>
|
||||
<string name="desc_shuffle_all">모든 곡 무작위 재생</string>
|
||||
<string name="desc_remove_song">이 대기열의 곡 제거</string>
|
||||
<string name="desc_song_handle">이 대기열의 곡 이동</string>
|
||||
<string name="desc_remove_song">이 곡 제거</string>
|
||||
<string name="desc_song_handle">이 곡 이동</string>
|
||||
<string name="desc_tab_handle">이 탭 이동</string>
|
||||
<string name="desc_clear_search">검색 기록 삭제</string>
|
||||
<string name="desc_music_dir_delete">폴더 제거</string>
|
||||
|
@ -157,8 +157,8 @@
|
|||
<item quantity="other">%d 앨범</item>
|
||||
</plurals>
|
||||
<string name="cdc_mp4">MPEG-4 오디오</string>
|
||||
<string name="cdc_flac">자유 무손실 오디오 코덱 (FLAC)</string>
|
||||
<string name="set_wipe_desc">이전에 저장된 재생 상태 지우기 (있는 경우)</string>
|
||||
<string name="cdc_flac">Free Lossless Audio Codec (FLAC)</string>
|
||||
<string name="set_wipe_desc">이전에 저장된 재생 상태 초기화</string>
|
||||
<string name="set_dirs_mode_exclude">제외</string>
|
||||
<string name="set_dirs_mode_include_desc"><b>추가한 폴더에서만</b> 음악을 불러옵니다.</string>
|
||||
<string name="lbl_props">곡 속성</string>
|
||||
|
@ -167,34 +167,34 @@
|
|||
<string name="lbl_sample_rate">샘플 속도</string>
|
||||
<string name="lbl_bitrate">전송 속도</string>
|
||||
<string name="lbl_size">크기</string>
|
||||
<string name="lbl_shuffle_shortcut_long">모두 셔플</string>
|
||||
<string name="lbl_shuffle_shortcut_long">모두 무작위 재생</string>
|
||||
<string name="desc_exit">재생 중지</string>
|
||||
<string name="cdc_ogg">Ogg 오디오</string>
|
||||
<string name="cdc_mka">마트로스카 오디오</string>
|
||||
<string name="cdc_mka">Matroska 오디오</string>
|
||||
<string name="fmt_sample_rate">%d Hz</string>
|
||||
<string name="lbl_mix">DJ믹스</string>
|
||||
<string name="lbl_compilation_live">라이브 컴필레이션</string>
|
||||
<string name="lbl_compilation_remix">리믹스 편집</string>
|
||||
<string name="lbl_mixes">DJ믹스</string>
|
||||
<string name="lbl_equalizer">이퀄라이저</string>
|
||||
<string name="lbl_shuffle_shortcut_short">셔플</string>
|
||||
<string name="lbl_shuffle_shortcut_short">무작위 재생</string>
|
||||
<string name="set_play_song_none">표시된 항목에서 재생</string>
|
||||
<string name="lng_indexing">음악 라이브러리를 불러오는 중…</string>
|
||||
<string name="lng_indexing">음악 라이브러리 불러오는 중…</string>
|
||||
<string name="set_wipe_state">재생 상태 지우기</string>
|
||||
<string name="set_restore_state">재생 상태 복원</string>
|
||||
<string name="set_dirs">음악 폴더</string>
|
||||
<string name="set_dirs_desc">음악을 불러오는 위치 관리</string>
|
||||
<string name="set_dirs_mode_exclude_desc">추가한 폴더에서 음악을 <b>불러오지 않습니다</b>.</string>
|
||||
<string name="set_dirs_mode_include">포함</string>
|
||||
<string name="set_separators">다중값 구분자</string>
|
||||
<string name="set_separators_desc">여러 태그 값을 나타낼때의 구분자 설정</string>
|
||||
<string name="set_separators">다중 값 구분 기호</string>
|
||||
<string name="set_separators_desc">태그 값이 여러 개일 때 태그를 구분할 기호를 설정합니다.</string>
|
||||
<string name="set_separators_comma">콤마 (,)</string>
|
||||
<string name="set_separators_semicolon">세미콜론 (;)</string>
|
||||
<string name="set_separators_slash">슬래쉬 (/)</string>
|
||||
<string name="set_separators_slash">슬래시 (/)</string>
|
||||
<string name="set_separators_plus">플러스 (+)</string>
|
||||
<string name="set_separators_and">앰퍼샌드 (&)</string>
|
||||
<string name="cdc_mp3">MPEG-1 오디오</string>
|
||||
<string name="lbl_date_added">추가된 날짜</string>
|
||||
<string name="lbl_date_added">추가한 날짜</string>
|
||||
<string name="lbl_relative_path">상위 경로</string>
|
||||
<string name="set_bar_action">맞춤형 재생 동작 버튼</string>
|
||||
<string name="set_action_mode_repeat">반복 방식</string>
|
||||
|
@ -208,20 +208,20 @@
|
|||
<string name="lbl_compilations">컴필레이션</string>
|
||||
<string name="lbl_live_group">라이브</string>
|
||||
<string name="lbl_format">형식</string>
|
||||
<string name="set_exclude_non_music">음악 아닌 것 제외</string>
|
||||
<string name="set_exclude_non_music">음악이 아닌 항목 제외</string>
|
||||
<string name="fmt_bitrate">%d kbps</string>
|
||||
<string name="cdc_aac">고급 오디오 코딩 (AAC)</string>
|
||||
<string name="cdc_aac">Advanced Audio Coding (AAC)</string>
|
||||
<string name="set_cover_mode">앨범 커버</string>
|
||||
<string name="set_cover_mode_off">끔</string>
|
||||
<string name="set_cover_mode_media_store">빠름</string>
|
||||
<string name="set_cover_mode_quality">고품질</string>
|
||||
<string name="set_restore_desc">이전에 저장된 재생 상태 복원 (있는 경우)</string>
|
||||
<string name="err_did_not_restore">재생상태를 복원할 수 없음</string>
|
||||
<string name="set_restore_desc">이전에 저장된 재생 상태 복원</string>
|
||||
<string name="err_did_not_restore">재생 상태를 복원할 수 없습니다.</string>
|
||||
<string name="set_observing_desc">음악 라이브러리가 변경될 때마다 새로고침 (고정 알림 필요)</string>
|
||||
<string name="lbl_state_wiped">상태 지워짐</string>
|
||||
<string name="lbl_indexing">음악 불러오기 중</string>
|
||||
<string name="lbl_indexer">음악 불러오기 중</string>
|
||||
<string name="lbl_observing">음악 라이브러리 추적중</string>
|
||||
<string name="lbl_indexing">음악 불러오는 중</string>
|
||||
<string name="lbl_indexer">음악 불러오는 중</string>
|
||||
<string name="lbl_observing">음악 라이브러리 모니터링 중</string>
|
||||
<string name="lbl_state_restored">상태 복원됨</string>
|
||||
<string name="lbl_eps">EP 앨범</string>
|
||||
<string name="lbl_ep">EP 앨범</string>
|
||||
|
@ -234,72 +234,76 @@
|
|||
<string name="lbl_mixtape">믹스테이프</string>
|
||||
<string name="lbl_remix_group">리믹스</string>
|
||||
<string name="set_observing">자동 새로고침</string>
|
||||
<string name="set_dirs_mode">처리방식</string>
|
||||
<string name="set_dirs_mode">모드</string>
|
||||
<string name="fmt_indexing">음악 라이브러리를 불러오는 중… (%1$d/%2$d)</string>
|
||||
<string name="lbl_genre">장르</string>
|
||||
<string name="set_separators_warning">경고: 이 설정을 사용하면 일부 태그가 여러 값을 갖는 것으로 잘못 해석될 수 있습니다. 구분자로 읽히지 않도록 하려면 해당 구분자 앞에 백슬래시 (\\)를 붙입니다.</string>
|
||||
<string name="set_separators_warning">경고: 이 설정을 사용하면 몇몇 태그가 다중 값을 가진 것으로 잘못 나타날 수 있습니다. 태그에서 구분 기호 앞에 백슬래시(\\)를 붙이면 구분 기호로 인식하지 않습니다.</string>
|
||||
<string name="set_play_in_parent_with">항목 세부 정보에서 재생할 때</string>
|
||||
<string name="lng_observing">음악 라이브러리의 변경사항을 추적하는 중…</string>
|
||||
<string name="lng_observing">음악 라이브러리 변경 사항 모니터링 중…</string>
|
||||
<string name="set_action_mode_next">다음 곡으로 건너뛰기</string>
|
||||
<string name="set_exclude_non_music_desc">팟캐스트와 같이 음악이 아닌 소리 파일 무시</string>
|
||||
<string name="set_hide_collaborators">공동작업자 숨기기</string>
|
||||
<string name="set_exclude_non_music_desc">팟캐스트 등 음악이 아닌 오디오 파일 무시</string>
|
||||
<string name="set_hide_collaborators">공동 작업자 숨기기</string>
|
||||
<string name="set_hide_collaborators_desc">앨범에 등장하는 아티스트만 표시 (자세히 태그된 라이브러리에 최적화)</string>
|
||||
<string name="err_did_not_wipe">재생상태를 지울 수 없음</string>
|
||||
<string name="err_did_not_save">재생상태를 저장할 수 없음</string>
|
||||
<string name="err_did_not_wipe">재생 상태를 지울 수 없습니다.</string>
|
||||
<string name="err_did_not_save">재생 상태를 저장할 수 없습니다.</string>
|
||||
<string name="set_rescan">음악 재탐색</string>
|
||||
<plurals name="fmt_artist_count">
|
||||
<item quantity="other">%d 아티스트</item>
|
||||
</plurals>
|
||||
<string name="set_rescan_desc">태그 정보를 지우고 음악 라이브러리를 재생성함(느림, 더 완전함)</string>
|
||||
<string name="set_rescan_desc">태그 캐시를 지우고 음악 라이브러리를 처음부터 다시 생성합니다. 느리지만 더 완벽한 방식입니다.</string>
|
||||
<string name="fmt_selected">%d 선택됨</string>
|
||||
<string name="lbl_reset">재설정</string>
|
||||
<string name="lbl_wiki">위키</string>
|
||||
<string name="set_play_song_from_genre">장르에서 재생</string>
|
||||
<string name="fmt_list">%1$s, %2$s</string>
|
||||
<string name="set_replay_gain">리플레이게인</string>
|
||||
<string name="set_replay_gain">ReplayGain</string>
|
||||
<string name="set_audio_desc">사운드 및 재생 동작 구성</string>
|
||||
<string name="set_playback">재생</string>
|
||||
<string name="set_dirs_list">폴더</string>
|
||||
<string name="set_ui_desc">앱의 테마 및 색상 변경</string>
|
||||
<string name="set_ui_desc">앱 테마 및 색상 변경</string>
|
||||
<string name="set_music">음악</string>
|
||||
<string name="set_library">라이브러리</string>
|
||||
<string name="set_images">이미지</string>
|
||||
<string name="set_content_desc">음악 및 이미지 불러오기 방법 제어</string>
|
||||
<string name="set_content_desc">음악 및 이미지 불러오기 방식 설정</string>
|
||||
<string name="set_state">지속</string>
|
||||
<string name="set_behavior">동작</string>
|
||||
<string name="set_personalize_desc">UI 제어 및 동작 커스텀</string>
|
||||
<string name="set_personalize_desc">UI 제어 및 동작 사용자 정의</string>
|
||||
<string name="lbl_sort_dsc">내림차순</string>
|
||||
<string name="lbl_playlist">재생목록</string>
|
||||
<string name="lbl_playlists">재생목록</string>
|
||||
<string name="lbl_playlist">재생 목록</string>
|
||||
<string name="lbl_playlists">재생 목록</string>
|
||||
<string name="desc_playlist_image">%s의 재생 목록 이미지</string>
|
||||
<string name="set_intelligent_sorting">정렬할 때 기사 무시</string>
|
||||
<string name="set_intelligent_sorting_desc">이름으로 정렬할 때 \"the\"와 같은 단어 무시(영어 음악에서 가장 잘 작동함)</string>
|
||||
<string name="set_intelligent_sorting">적응형 정렬</string>
|
||||
<string name="set_intelligent_sorting_desc">정렬할 때 숫자나 \"the\"와 같은 단어를 무시합니다. 태그가 영어로 되어 있을 때 가장 잘 작동합니다.</string>
|
||||
<string name="desc_new_playlist">새 재생 목록 만들기</string>
|
||||
<string name="lbl_new_playlist">새 재생목록</string>
|
||||
<string name="lbl_playlist_add">재생목록에 추가</string>
|
||||
<string name="lng_playlist_created">생성된 재생목록</string>
|
||||
<string name="lng_playlist_added">재생목록에 추가됨</string>
|
||||
<string name="fmt_def_playlist">재생목록 %d</string>
|
||||
<string name="lbl_new_playlist">새 재생 목록</string>
|
||||
<string name="lbl_playlist_add">재생 목록에 추가</string>
|
||||
<string name="lng_playlist_created">재생 목록을 만들었습니다.</string>
|
||||
<string name="lng_playlist_added">재생 목록에 추가했습니다.</string>
|
||||
<string name="fmt_def_playlist">재생 목록 %d</string>
|
||||
<string name="def_song_count">노래 없음</string>
|
||||
<string name="lbl_delete">삭제</string>
|
||||
<string name="fmt_deletion_info">%s를 삭제하시겠습니까\? 이 취소 할 수 없습니다.</string>
|
||||
<string name="fmt_deletion_info">%s 항목을 삭제하시겠습니까\? 이 작업은 취소할 수 없습니다.</string>
|
||||
<string name="lbl_rename">이름 바꾸기</string>
|
||||
<string name="lbl_rename_playlist">재생목록 이름 바꾸기</string>
|
||||
<string name="lbl_confirm_delete_playlist">재생목록을 삭제하시겠습니까\?</string>
|
||||
<string name="lbl_edit">편집하다</string>
|
||||
<string name="lbl_rename_playlist">재생 목록 이름 바꾸기</string>
|
||||
<string name="lbl_confirm_delete_playlist">재생 목록을 삭제하시겠습니까\?</string>
|
||||
<string name="lbl_edit">편집</string>
|
||||
<string name="lbl_appears_on">에 나타납니다</string>
|
||||
<string name="lbl_share">공유하다</string>
|
||||
<string name="lng_playlist_renamed">재생목록의 이름이 변경됨</string>
|
||||
<string name="lbl_share">공유</string>
|
||||
<string name="lng_playlist_renamed">재생 목록의 이름을 바꿨습니다.</string>
|
||||
<string name="def_disc">디스크 없음</string>
|
||||
<string name="lng_playlist_deleted">재생목록이 삭제되었습니다</string>
|
||||
<string name="fmt_editing">%s 수정 중</string>
|
||||
<string name="lng_playlist_deleted">재생 목록을 삭제했습니다.</string>
|
||||
<string name="fmt_editing">%s 편집 중</string>
|
||||
<string name="lbl_song">노래</string>
|
||||
<string name="lbl_parent_detail">보다</string>
|
||||
<string name="set_square_covers">포스 스퀘어 앨범 커버</string>
|
||||
<string name="set_square_covers_desc">모든 앨범 표지를 1:1 가로세로 비율로 자르기</string>
|
||||
<string name="lbl_parent_detail">보기</string>
|
||||
<string name="set_square_covers">정사각형 앨범 커버 강제</string>
|
||||
<string name="set_square_covers_desc">모든 앨범 커버를 가로세로 1:1 비율로 자릅니다.</string>
|
||||
<string name="set_play_song_by_itself">노래 따로 재생</string>
|
||||
<string name="lbl_sort_direction">방향</string>
|
||||
<string name="lbl_sort_mode">정렬 기준</string>
|
||||
<string name="desc_selection_image">선택 이미지</string>
|
||||
<string name="lbl_selection">선택</string>
|
||||
<string name="lbl_show_error_info">더 보기</string>
|
||||
<string name="lbl_copied">복사했습니다.</string>
|
||||
<string name="lbl_report">오류 보고</string>
|
||||
<string name="lbl_error_info">오류 정보</string>
|
||||
</resources>
|
|
@ -2,10 +2,10 @@
|
|||
<resources>
|
||||
<string name="lbl_songs">Dainos</string>
|
||||
<string name="lbl_all_songs">Visos dainos</string>
|
||||
<string name="lbl_search">Ieškoti</string>
|
||||
<string name="lbl_search">Paieška</string>
|
||||
<string name="lbl_filter">Filtruoti</string>
|
||||
<string name="lbl_filter_all">Visos</string>
|
||||
<string name="lbl_sort">Rūšiuoti</string>
|
||||
<string name="lbl_sort">Rūšiavimas</string>
|
||||
<string name="lbl_name">Pavadinimas</string>
|
||||
<string name="lbl_date">Metai</string>
|
||||
<string name="lbl_duration">Trukmė</string>
|
||||
|
@ -34,7 +34,7 @@
|
|||
<string name="lbl_play">Groti</string>
|
||||
<string name="lbl_licenses">Licencijos</string>
|
||||
<string name="lbl_shuffle">Maišyti</string>
|
||||
<string name="lng_queue_added">Pridėta į eilę</string>
|
||||
<string name="lng_queue_added">Pridėtas į eilę</string>
|
||||
<string name="lbl_props">Dainų ypatybės</string>
|
||||
<string name="lbl_file_name">Failo pavadinimas</string>
|
||||
<string name="lbl_save">Išsaugoti</string>
|
||||
|
@ -47,7 +47,7 @@
|
|||
<string name="set_theme">Tema</string>
|
||||
<string name="set_black_mode_desc">Naudoti grynai juodą tamsią temą</string>
|
||||
<string name="info_app_desc">Paprastas, racionalus Android muzikos grotuvas.</string>
|
||||
<string name="lbl_indexer">Muzika kraunama</string>
|
||||
<string name="lbl_indexer">Muzikos pakraunimas</string>
|
||||
<string name="lng_widget">Peržiūrėk ir valdyk muzikos grojimą</string>
|
||||
<string name="lbl_genres">Žanrai</string>
|
||||
<string name="lbl_retry">Pakartoti</string>
|
||||
|
@ -72,7 +72,7 @@
|
|||
<string name="desc_no_cover">Albumo viršelis</string>
|
||||
<string name="clr_deep_purple">Giliai violetinė</string>
|
||||
<string name="lbl_observing">Stebėjimas muzikos biblioteka</string>
|
||||
<string name="lng_observing">Stebima tavo muzikos biblioteko dėl pakeitimų…</string>
|
||||
<string name="lng_observing">Stebimas tavo muzikos biblioteka dėl pakeitimų…</string>
|
||||
<string name="lbl_shuffle_shortcut_short">Maišyti</string>
|
||||
<string name="lbl_shuffle_shortcut_long">Maišyti viską</string>
|
||||
<string name="lbl_state_restored">Atkurta būsena</string>
|
||||
|
@ -123,7 +123,7 @@
|
|||
<string name="lbl_live_group">Gyvai</string>
|
||||
<string name="set_headset_autoplay_desc">Visada pradėti groti, kai ausinės yra prijungtos (gali neveikti visuose įrenginiuose)</string>
|
||||
<string name="cdc_ogg">Ogg garsas</string>
|
||||
<string name="lng_author">Sukūrė Alexanderis Capehartas</string>
|
||||
<string name="lng_author">Sukūrė Alexanderis Capehartas (angl. Alexander Capehart)</string>
|
||||
<string name="set_replay_gain_mode_track">Pageidauti takelį</string>
|
||||
<string name="err_no_dirs">Jokių aplankų</string>
|
||||
<string name="err_bad_dir">Šis aplankas nepalaikomas</string>
|
||||
|
@ -159,7 +159,7 @@
|
|||
<string name="set_play_in_parent_with">Kai grojant iš elemento detalių</string>
|
||||
<string name="desc_music_dir_delete">Pašalinti aplanką</string>
|
||||
<string name="lbl_genre">Žanras</string>
|
||||
<string name="lng_search_library">Ieškok savo bibliotekoje…</string>
|
||||
<string name="lng_search_library">Ieškoti savo bibliotekoje…</string>
|
||||
<string name="lbl_equalizer">Ekvalaizeris</string>
|
||||
<string name="set_dirs_mode">Režimas</string>
|
||||
<string name="set_observing">Automatinis įkrovimas</string>
|
||||
|
@ -171,7 +171,7 @@
|
|||
<string name="set_action_mode_repeat">Kartojimo režimas</string>
|
||||
<string name="desc_queue_bar">Atidaryti eilę</string>
|
||||
<string name="desc_clear_search">Išvalyti paieškos paraišką</string>
|
||||
<string name="set_dirs_mode_exclude_desc">Muzika <b>nebus</b> įkeliama iš pridėtų aplankų, kurių tu pridėsi.</string>
|
||||
<string name="set_dirs_mode_exclude_desc">Muzika <b>nebus</b> kraunama iš pridėtų aplankų, kurių tu pridėsi.</string>
|
||||
<string name="set_dirs_mode_include">Įtraukti</string>
|
||||
<string name="desc_remove_song">Pašalinti šią dainą</string>
|
||||
<string name="set_play_song_from_all">Groti iš visų dainų</string>
|
||||
|
@ -180,17 +180,17 @@
|
|||
<string name="set_play_song_from_artist">Groti iš atlikėjo</string>
|
||||
<string name="lbl_state_wiped">Išvalyta būsena</string>
|
||||
<string name="set_dirs_mode_exclude">Neįtraukti</string>
|
||||
<string name="set_dirs_mode_include_desc">Muzika <b>bus</b> įkeliama iš aplankų, kurių tu pridėsi.</string>
|
||||
<string name="set_dirs_mode_include_desc">Muzika <b>bus</b> kraunama iš aplankų, kurių tu pridėsi.</string>
|
||||
<string name="fmt_sample_rate">%d Hz</string>
|
||||
<string name="set_observing_desc">Perkrauti muzikos biblioteką, kai ji pasikeičia (reikia nuolatinio pranešimo)</string>
|
||||
<string name="fmt_lib_song_count">Įkeltos dainos: %d</string>
|
||||
<string name="fmt_lib_genre_count">Įkeltos žanrai: %d</string>
|
||||
<string name="fmt_lib_album_count">Įkeltos albumai: %d</string>
|
||||
<string name="fmt_lib_artist_count">Įkeltos atlikėjai: %d</string>
|
||||
<string name="fmt_indexing">Kraunamas tavo muzikos biblioteka… (%1$d/%2$d)</string>
|
||||
<string name="fmt_lib_song_count">Pakrautos dainos: %d</string>
|
||||
<string name="fmt_lib_genre_count">Pakrautos žanros: %d</string>
|
||||
<string name="fmt_lib_album_count">Pakrauti albumai: %d</string>
|
||||
<string name="fmt_lib_artist_count">Pakrauti atlikėjai: %d</string>
|
||||
<string name="fmt_indexing">Kraunama tavo muzikos biblioteka… (%1$d/%2$d)</string>
|
||||
<string name="desc_shuffle_all">Maišyti visas dainas</string>
|
||||
<string name="set_personalize">Personalizuotas</string>
|
||||
<string name="set_pre_amp_warning">Įspėjimas: Keičiant išankstinį stiprintuvą į didelę teigiamą vertę, kai kuriuose garso takeliuose gali atsirasti tarpų.</string>
|
||||
<string name="set_pre_amp_warning">Įspėjimas: keičiant išankstinį stiprintuvą į didelę teigiamą vertę, kai kuriuose garso takeliuose gali atsirasti tarpų.</string>
|
||||
<string name="desc_album_cover">Albumo viršelis %s</string>
|
||||
<string name="desc_artist_image">Atlikėjo vaizdas %s</string>
|
||||
<string name="def_playback">Nėra grojančio muzikos</string>
|
||||
|
@ -214,7 +214,7 @@
|
|||
<string name="lbl_mix">DJ miksas</string>
|
||||
<string name="lbl_compilation_live">Gyvai kompiliacija</string>
|
||||
<string name="lbl_compilation_remix">Remikso kompiliacija</string>
|
||||
<string name="lbl_relative_path">Pagrindinis aplankas</string>
|
||||
<string name="lbl_relative_path">Pirminis kelias</string>
|
||||
<string name="set_wipe_desc">Išvalyti anksčiau išsaugotą grojimo būseną (jei yra)</string>
|
||||
<string name="set_separators">Daugiareikšmiai separatoriai</string>
|
||||
<string name="set_separators_slash">Pasvirasis brūkšnys (/)</string>
|
||||
|
@ -228,7 +228,7 @@
|
|||
<string name="set_separators_desc">Konfigūruoti simbolius, kurie nurodo kelias žymių reikšmes</string>
|
||||
<string name="set_separators_comma">Kablelis (,)</string>
|
||||
<string name="set_pre_amp_without">Reguliavimas be žymų</string>
|
||||
<string name="set_separators_warning">Įspėjimas: Naudojant šį nustatymą, kai kurios žymos gali būti neteisingai interpretuojamos kaip turinčios kelias reikšmes. Tai galima išspręsti prieš nepageidaujamus skiriamuosius ženklus naudojant atgalinį brūkšnį (\\).</string>
|
||||
<string name="set_separators_warning">Įspėjimas: naudojant šį nustatymą, kai kurios žymos gali būti neteisingai interpretuojamos kaip turinčios kelias reikšmes. Tai galima išspręsti prieš nepageidaujamus skiriamuosius ženklus su agalinių brūkšniu (\\).</string>
|
||||
<string name="set_separators_semicolon">Kabliataškis (;)</string>
|
||||
<string name="set_cover_mode_quality">Aukštos kokybės</string>
|
||||
<string name="set_restore_state">Atkurti grojimo būseną</string>
|
||||
|
@ -245,6 +245,7 @@
|
|||
<item quantity="one">%d atlikėjas (-a)</item>
|
||||
<item quantity="few">%d atlikėjai</item>
|
||||
<item quantity="other">%d atlikėjų</item>
|
||||
<item quantity="many">%d atlikėjų</item>
|
||||
</plurals>
|
||||
<string name="set_rescan">Perskenuoti muziką</string>
|
||||
<string name="set_rescan_desc">Išvalyti žymių talpyklą ir pilnai perkrauti muzikos biblioteką (lėčiau, bet labiau išbaigta)</string>
|
||||
|
@ -297,4 +298,10 @@
|
|||
<string name="set_play_song_by_itself">Groti dainą pačią</string>
|
||||
<string name="lbl_sort_mode">Rūšiuoti pagal</string>
|
||||
<string name="lbl_sort_direction">Kryptis</string>
|
||||
<string name="desc_selection_image">Pasirinkimo vaizdas</string>
|
||||
<string name="lbl_selection">Pasirinkimas</string>
|
||||
<string name="lbl_error_info">Klaidos informacija</string>
|
||||
<string name="lbl_copied">Nukopijuota</string>
|
||||
<string name="lbl_show_error_info">Daugiau</string>
|
||||
<string name="lbl_report">Pranešti</string>
|
||||
</resources>
|
|
@ -93,11 +93,11 @@
|
|||
<string name="set_ui_desc">ਐਪ ਦਾ ਥੀਮ ਅਤੇ ਰੰਗ ਬਦਲੋ</string>
|
||||
<string name="set_theme">ਥੀਮ</string>
|
||||
<string name="set_theme_auto">ਸਵੈਚਾਲਿਤ</string>
|
||||
<string name="set_theme_day">ਹਲਕਾ</string>
|
||||
<string name="set_theme_day">ਸਫ਼ੈਦ</string>
|
||||
<string name="set_theme_night">ਗੂੜ੍ਹਾ</string>
|
||||
<string name="set_accent">ਰੰਗ ਸਕੀਮ</string>
|
||||
<string name="set_black_mode">ਕਾਲ੍ਹਾ ਥੀਮ</string>
|
||||
<string name="set_black_mode_desc">ਇੱਕ ਸ਼ੁੱਧ-ਕਾਲ੍ਹਾ ਗੂੜ੍ਹਾ ਥੀਮ ਵਰਤੋ</string>
|
||||
<string name="set_black_mode_desc">ਸ਼ਾਹ-ਕਾਲ਼ਾ ਥੀਮ ਵਰਤੋ</string>
|
||||
<string name="set_round_mode">ਗੋਲ ਮੋਡ</string>
|
||||
<string name="set_round_mode_desc">ਵਾਧੂ UI ਤੱਤਾਂ \'ਤੇ ਗੋਲ ਕੋਨਿਆਂ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ (ਗੋਲਾਕਾਰ ਕਰਨ ਲਈ ਐਲਬਮ ਕਵਰਾਂ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ )</string>
|
||||
<string name="set_personalize">ਵਿਅਕਤੀਗਤ ਬਣਾਓ</string>
|
||||
|
@ -292,4 +292,10 @@
|
|||
<string name="set_play_song_by_itself">ਇਸੇ ਗੀਤ ਨੂੰ ਚਲਾਓ</string>
|
||||
<string name="lbl_sort_mode">ਸੌਰਟ ਕਰੋ</string>
|
||||
<string name="lbl_sort_direction">ਦਿਸ਼ਾ</string>
|
||||
<string name="lbl_selection">ਚੋਣ</string>
|
||||
<string name="desc_selection_image">ਚੋਣ ਚਿੱਤਰ</string>
|
||||
<string name="lbl_show_error_info">ਹੋਰ</string>
|
||||
<string name="lbl_error_info">ਤਰੁੱਟੀ ਦੀ ਜਾਣਕਾਰੀ</string>
|
||||
<string name="lbl_copied">ਕਾਪੀ ਕੀਤਾ ਗਿਆ</string>
|
||||
<string name="lbl_report">ਰਿਪੋਰਟ ਕਰੋ</string>
|
||||
</resources>
|
|
@ -11,12 +11,12 @@
|
|||
<string name="lbl_search">Pesquisar</string>
|
||||
<string name="lbl_filter">Filtro</string>
|
||||
<string name="lbl_filter_all">Tudo</string>
|
||||
<string name="lbl_sort">Classificar</string>
|
||||
<string name="lbl_sort">Organizar</string>
|
||||
<string name="lbl_play">Reproduzir</string>
|
||||
<string name="lbl_shuffle">Aleatório</string>
|
||||
<string name="lbl_playback">Tocando agora</string>
|
||||
<string name="lbl_queue">Fila</string>
|
||||
<string name="lbl_play_next">Reproduzir próxima</string>
|
||||
<string name="lbl_play_next">Reproduzir a seguir</string>
|
||||
<string name="lbl_queue_add">Adicionar à fila</string>
|
||||
<string name="lng_queue_added">Adicionada à fila</string>
|
||||
<string name="lbl_artist_details">Ir para o artista</string>
|
||||
|
@ -145,7 +145,7 @@
|
|||
<string name="cdc_mp4">Áudio MPEG-4</string>
|
||||
<string name="cdc_ogg">Áudio Ogg</string>
|
||||
<string name="cdc_mka">Áudio Matroska</string>
|
||||
<string name="cdc_aac">Codificação de Audio Avançada (AAC)</string>
|
||||
<string name="cdc_aac">Advanced Audio Coding (AAC)</string>
|
||||
<string name="cdc_flac">Free Lossless Audio Codec (FLAC)</string>
|
||||
<string name="desc_song_handle">Mover esta música da fila</string>
|
||||
<string name="clr_dynamic">Dinâmico</string>
|
||||
|
@ -273,4 +273,27 @@
|
|||
<string name="lbl_sort_dsc">Descendente</string>
|
||||
<string name="set_intelligent_sorting">Ignorar artigos ao classificar</string>
|
||||
<string name="set_intelligent_sorting_desc">Ignore palavras como \"the\" ao classificar por nome (funciona melhor com músicas em inglês)</string>
|
||||
<string name="lbl_playlists">Playlists</string>
|
||||
<string name="fmt_def_playlist">Playlist %d</string>
|
||||
<string name="lbl_playlist">Playlist</string>
|
||||
<string name="lng_playlist_created">Playlist criada</string>
|
||||
<string name="lbl_show_error_info">Mais</string>
|
||||
<string name="lbl_delete">Apagar</string>
|
||||
<string name="lbl_copied">Copiado</string>
|
||||
<string name="lbl_playlist_add">Adicionar à playlist</string>
|
||||
<string name="lbl_share">Compartilhar</string>
|
||||
<string name="lbl_edit">Editar</string>
|
||||
<string name="lbl_rename">Renomear</string>
|
||||
<string name="lng_playlist_added">Adicionada à playlist</string>
|
||||
<string name="fmt_editing">Editando %s</string>
|
||||
<string name="lbl_sort_mode">Organizar por</string>
|
||||
<string name="lbl_song">Música</string>
|
||||
<string name="lbl_confirm_delete_playlist">Apagar playlist\?</string>
|
||||
<string name="desc_new_playlist">Criar uma nova playlist</string>
|
||||
<string name="lng_playlist_deleted">Playlist deletada</string>
|
||||
<string name="lbl_new_playlist">Nova playlist</string>
|
||||
<string name="lng_playlist_renamed">Playlist renomeada</string>
|
||||
<string name="lbl_rename_playlist">Renomear playlist</string>
|
||||
<string name="lbl_appears_on">Aparece em</string>
|
||||
<string name="fmt_deletion_info">Apagar %s\? Esta ação não pode ser desfeita.</string>
|
||||
</resources>
|
|
@ -3,19 +3,19 @@
|
|||
<!-- Label Namespace | Static Labels -->
|
||||
<string name="lbl_retry">Tentar novamente</string>
|
||||
<string name="lbl_grant">Permitir</string>
|
||||
<string name="lbl_genres">Gêneros</string>
|
||||
<string name="lbl_genres">Géneros</string>
|
||||
<string name="lbl_artists">Artistas</string>
|
||||
<string name="lbl_albums">Álbuns</string>
|
||||
<string name="lbl_songs">Músicas</string>
|
||||
<string name="lbl_all_songs">Todas as músicas</string>
|
||||
<string name="lbl_search">Pesquisar</string>
|
||||
<string name="lbl_search">Procurar</string>
|
||||
<string name="lbl_filter">Filtrar</string>
|
||||
<string name="lbl_filter_all">Tudo</string>
|
||||
<string name="lbl_sort">Classificação</string>
|
||||
<string name="lbl_sort">Organizar</string>
|
||||
<string name="lbl_sort_asc">Ascendente</string>
|
||||
<string name="lbl_play">Reproduzir</string>
|
||||
<string name="lbl_shuffle">Embaralhar</string>
|
||||
<string name="lbl_playback">Tocando agora</string>
|
||||
<string name="lbl_shuffle">Misturar</string>
|
||||
<string name="lbl_playback">A tocar agora</string>
|
||||
<string name="lbl_queue">Fila</string>
|
||||
<string name="lbl_play_next">Reproduzir a próxima</string>
|
||||
<string name="lbl_queue_add">Adicionar à fila</string>
|
||||
|
@ -34,10 +34,10 @@
|
|||
<string name="set_theme_day">Claro</string>
|
||||
<string name="set_theme_night">Escuro</string>
|
||||
<string name="set_theme_auto">Automático</string>
|
||||
<string name="set_accent">Cor de realce</string>
|
||||
<string name="set_accent">Esquema de cores</string>
|
||||
<string name="set_audio">Áudio</string>
|
||||
<string name="set_personalize">Comportamento</string>
|
||||
<string name="set_keep_shuffle">Memorizar aleatorização</string>
|
||||
<string name="set_personalize">Personalizar</string>
|
||||
<string name="set_keep_shuffle">Memorizar musica misturada</string>
|
||||
<!-- Error Namespace | Error Labels -->
|
||||
<string name="err_no_music">Nenhuma música encontrada</string>
|
||||
<!-- Description Namespace | Accessibility Strings -->
|
||||
|
@ -79,19 +79,19 @@
|
|||
<string name="cdc_mp4">Áudio MPEG-4</string>
|
||||
<string name="fmt_lib_artist_count">Artistas carregados: %d</string>
|
||||
<string name="fmt_lib_total_duration">Duração total: %s</string>
|
||||
<string name="err_index_failed">Falha no carregamento da música</string>
|
||||
<string name="err_index_failed">Falha ao carregar música</string>
|
||||
<string name="lbl_name">Nome</string>
|
||||
<string name="set_replay_gain_mode_dynamic">Prefira o álbum se estiver tocando</string>
|
||||
<string name="err_no_app">Nenhuma aplicação encontrada que possa lidar com esta tarefa</string>
|
||||
<string name="set_replay_gain_mode_dynamic">Prefira o álbum se estiver a tocar</string>
|
||||
<string name="err_no_app">Nenhuma aplicação encontrada que possa executar esta tarefa</string>
|
||||
<string name="clr_cyan">Ciano</string>
|
||||
<string name="lbl_song_count">Contagem de músicas</string>
|
||||
<string name="lbl_format">Formato</string>
|
||||
<string name="lbl_library_counts">Estatísticas da biblioteca</string>
|
||||
<string name="desc_no_cover">Capa do álbum</string>
|
||||
<string name="lbl_date">Ano</string>
|
||||
<string name="lbl_date">Data</string>
|
||||
<string name="set_cover_mode_media_store">Rápido</string>
|
||||
<string name="set_cover_mode_quality">Qualidade alta</string>
|
||||
<string name="set_bar_action">Ação da barra de reprodução personalizada</string>
|
||||
<string name="set_bar_action">Personalizar a barra de reprodução</string>
|
||||
<string name="set_action_mode_repeat">Modo de repetição</string>
|
||||
<string name="set_play_song_from_artist">Reproduzir do artista</string>
|
||||
<string name="set_repeat_pause">Pausar na repetição</string>
|
||||
|
@ -100,29 +100,29 @@
|
|||
<string name="err_bad_dir">Esta pasta não é compatível</string>
|
||||
<string name="desc_song_handle">Mover esta música da fila</string>
|
||||
<string name="desc_music_dir_delete">Remover pasta</string>
|
||||
<string name="lbl_compilation_remix">Compilações de remix</string>
|
||||
<string name="lbl_compilation_remix">Mistura de compilações</string>
|
||||
<string name="lbl_compilation_live">Compilação ao vivo</string>
|
||||
<string name="lbl_disc">Disco</string>
|
||||
<string name="lbl_track">Faixa</string>
|
||||
<string name="lbl_bitrate">Taxa de bits</string>
|
||||
<string name="set_action_mode_next">Pular para o próximo</string>
|
||||
<string name="set_action_mode_next">Avançar para o próximo</string>
|
||||
<string name="set_pre_amp_warning">Aviso: Alterar o pré-amplificador para um valor positivo alto pode resultar em picos em algumas faixas de áudio.</string>
|
||||
<string name="set_pre_amp_with">Ajuste com etiquetas</string>
|
||||
<string name="set_pre_amp_with">Ajustar com etiquetas</string>
|
||||
<string name="set_separators_slash">Barra (/)</string>
|
||||
<string name="set_separators_plus">Mais (+)</string>
|
||||
<string name="cdc_ogg">Áudio Ogg</string>
|
||||
<string name="lbl_date_added">Data adicionada</string>
|
||||
<string name="lbl_sample_rate">Taxa de amostragem</string>
|
||||
<string name="lbl_save">Gravar</string>
|
||||
<string name="lbl_save">Salvar</string>
|
||||
<string name="set_separators">Separadores multi-valor</string>
|
||||
<string name="lbl_file_name">Nome do ficheiro</string>
|
||||
<string name="lbl_size">Tamanho</string>
|
||||
<string name="lbl_song_detail">Ver propriedades</string>
|
||||
<string name="lbl_song_detail">Propriedades</string>
|
||||
<string name="lbl_props">Propriedades da música</string>
|
||||
<string name="lbl_ok">OK</string>
|
||||
<string name="lbl_add">Adicionar</string>
|
||||
<string name="lbl_state_saved">Estado salvo</string>
|
||||
<string name="lbl_state_wiped">Estado liberado</string>
|
||||
<string name="lbl_state_wiped">Estado limpo</string>
|
||||
<string name="set_black_mode">Tema preto</string>
|
||||
<string name="desc_clear_search">Limpar consulta de pesquisa</string>
|
||||
<string name="desc_genre_image">Imagem de gênero para %s</string>
|
||||
|
@ -139,8 +139,8 @@
|
|||
<string name="lbl_live_group">Ao vivo</string>
|
||||
<string name="lbl_duration">Duração</string>
|
||||
<string name="lbl_cancel">Cancelar</string>
|
||||
<string name="lng_indexing">A carregar a sua biblioteca de músicas…</string>
|
||||
<string name="set_dirs_desc">Gira de onde a música deve ser carregada</string>
|
||||
<string name="lng_indexing">A carregar biblioteca de músicas…</string>
|
||||
<string name="set_dirs_desc">Configurar onde a música deve ser carregada</string>
|
||||
<string name="lbl_genre">Gênero</string>
|
||||
<string name="set_keep_shuffle_desc">Mantenha a reprodução aleatória ao reproduzir uma nova música</string>
|
||||
<string name="desc_skip_next">Pular para a próxima música</string>
|
||||
|
@ -152,7 +152,7 @@
|
|||
<string name="set_dirs_mode_exclude">Excluir</string>
|
||||
<string name="set_dirs_mode_exclude_desc">A música <b>não</b> será carregada das pastas que adicionar.</string>
|
||||
<string name="set_dirs_mode_include">Incluir</string>
|
||||
<string name="set_dirs_mode_include_desc">A música <b>somente</b> será carregada das pastas que adicionar.</string>
|
||||
<string name="set_dirs_mode_include_desc">A música será <b>somente</b> carregada das pastas que adicionar.</string>
|
||||
<string name="set_exclude_non_music">Excluir não-música</string>
|
||||
<string name="set_exclude_non_music_desc">Ignorar ficheiros de áudio que não são música, tal como podcasts</string>
|
||||
<string name="set_separators_desc">Configurar caracteres que denotam múltiplos valores de etiqueta</string>
|
||||
|
@ -167,30 +167,30 @@
|
|||
<string name="clr_dynamic">Dinâmico</string>
|
||||
<string name="fmt_disc_no">Disco %d</string>
|
||||
<string name="desc_album_cover">Capa do álbum para %s</string>
|
||||
<string name="set_pre_amp_without">Ajuste sem etiquetas</string>
|
||||
<string name="set_pre_amp_without">Ajustar sem etiquetas</string>
|
||||
<string name="set_content">Conteúdo</string>
|
||||
<string name="fmt_lib_genre_count">Gêneros carregados: %d</string>
|
||||
<string name="lbl_indexer">A carregar música</string>
|
||||
<string name="lbl_indexing">A carregar música</string>
|
||||
<string name="lbl_observing">A monitorar a biblioteca de música</string>
|
||||
<string name="lbl_observing">A monitorizar a biblioteca de música</string>
|
||||
<string name="lbl_equalizer">Equalizador</string>
|
||||
<string name="info_app_desc">Um reprodutor de música simples e racional para Android.</string>
|
||||
<string name="lbl_state_restored">Estado restaurado</string>
|
||||
<string name="set_display">Exibição</string>
|
||||
<string name="set_display">Mostrar</string>
|
||||
<string name="set_lib_tabs">Abas da biblioteca</string>
|
||||
<string name="set_lib_tabs_desc">Altere a visibilidade e a ordem das abas da biblioteca</string>
|
||||
<string name="set_cover_mode">Capas de álbuns</string>
|
||||
<string name="set_cover_mode_off">Desligado</string>
|
||||
<string name="set_round_mode">Modo redondo</string>
|
||||
<string name="set_notif_action">Usar ação de notificação alternativa</string>
|
||||
<string name="set_headset_autoplay">Reprodução automática do fone de ouvido</string>
|
||||
<string name="set_headset_autoplay_desc">Sempre comece a tocar quando um fone de ouvido estiver conectado (pode não funcionar em todos os aparelhos)</string>
|
||||
<string name="set_notif_action">Personalizar notificações</string>
|
||||
<string name="set_headset_autoplay">Reprodução automática dos auscultadores</string>
|
||||
<string name="set_headset_autoplay_desc">Iniciar música quando os auscultadores forem conectados (pode não funcionar em todos os aparelhos)</string>
|
||||
<string name="set_replay_gain_mode">Estratégia do ganho de repetição</string>
|
||||
<string name="set_replay_gain_mode_album">Preferir álbum</string>
|
||||
<string name="set_pre_amp_desc">O pré-amplificador é aplicado ao ajuste existente durante a reprodução</string>
|
||||
<string name="set_play_song_from_all">Reproduzir de todas as músicas</string>
|
||||
<string name="set_repeat_pause_desc">Pausa quando uma música se repete</string>
|
||||
<string name="set_wipe_desc">Limpe o estado de reprodução salvo anteriormente (se houver)</string>
|
||||
<string name="set_repeat_pause_desc">Pausar quando uma música é repetida</string>
|
||||
<string name="set_wipe_desc">Limpar o estado de reprodução salvo anteriormente (se houver)</string>
|
||||
<string name="set_restore_state">Restaurar o estado de reprodução</string>
|
||||
<string name="set_restore_desc">Restaurar o estado de reprodução salvo anteriormente (se houver)</string>
|
||||
<string name="desc_shuffle">Ativar ou desativar a reprodução aleatória</string>
|
||||
|
@ -207,8 +207,8 @@
|
|||
<string name="lbl_mixtape">Mixtape</string>
|
||||
<string name="lbl_remix_group">Remixes</string>
|
||||
<string name="lbl_artist">Artista</string>
|
||||
<string name="set_save_state">Gravar estado de reprodução</string>
|
||||
<string name="set_save_desc">Salve o estado de reprodução atual agora</string>
|
||||
<string name="set_save_state">Gravar estado da reprodução</string>
|
||||
<string name="set_save_desc">Salvar o estado de reprodução atual</string>
|
||||
<string name="set_wipe_state">Limpar estado de reprodução</string>
|
||||
<string name="lbl_album_live">Álbum ao vivo</string>
|
||||
<string name="fmt_db_neg">-%.1f dB</string>
|
||||
|
@ -220,20 +220,20 @@
|
|||
<string name="lbl_relative_path">Caminho principal</string>
|
||||
<string name="set_round_mode_desc">Ativar cantos arredondados em elementos adicionais da interface do utilizador (requer que as capas dos álbuns sejam arredondadas)</string>
|
||||
<string name="fmt_selected">%d Selecionadas</string>
|
||||
<string name="lbl_mixes">Mixes</string>
|
||||
<string name="lbl_mix">Mix</string>
|
||||
<string name="lbl_mixes">Misturas DJ</string>
|
||||
<string name="lbl_mix">DJ Mix</string>
|
||||
<string name="lbl_shuffle_shortcut_short">Aleatório</string>
|
||||
<string name="set_hide_collaborators">Ocultar artistas colaboradores</string>
|
||||
<string name="set_hide_collaborators">Ocultar colaboradores</string>
|
||||
<string name="set_rescan_desc">Limpa os metadados em cache e recarrega totalmente a biblioteca de música (lento, porém mais completo)</string>
|
||||
<string name="lbl_ep_remix">Álbum de Remix</string>
|
||||
<string name="lbl_single_live">Single ao vivo</string>
|
||||
<string name="lbl_single_remix">Single remix</string>
|
||||
<string name="lng_observing">Monitorando alterações na sua biblioteca de músicas…</string>
|
||||
<string name="lng_observing">A Monitorizar alterações na sua biblioteca de músicas…</string>
|
||||
<string name="set_observing_desc">Recarrega a biblioteca de músicas sempre que ela mudar (requer notificação fixa)</string>
|
||||
<string name="lbl_reset">Redefinir</string>
|
||||
<string name="lbl_reset">Repor</string>
|
||||
<string name="lbl_wiki">Wiki</string>
|
||||
<string name="lng_widget">Visualize e controle a reprodução de música</string>
|
||||
<string name="set_black_mode_desc">Use um tema preto</string>
|
||||
<string name="lng_widget">Vêr e controlar a reprodução da música</string>
|
||||
<string name="set_black_mode_desc">Utilizar tema preto puro</string>
|
||||
<string name="set_hide_collaborators_desc">Mostrar apenas artistas que foram creditados diretamente no álbum (funciona melhor em músicas com metadados completos)</string>
|
||||
<string name="set_replay_gain_mode_track">Preferir faixa</string>
|
||||
<string name="set_pre_amp">Pré-amplificação da normalização de volume</string>
|
||||
|
@ -244,10 +244,10 @@
|
|||
<string name="fmt_list">%1$s, %2$s</string>
|
||||
<string name="err_did_not_wipe">Não foi possível limpar a lista</string>
|
||||
<string name="err_did_not_save">Não foi possível gravar a lista</string>
|
||||
<string name="set_rescan">Re-escanear músicas</string>
|
||||
<string name="set_rescan">Procurar músicas novamente</string>
|
||||
<string name="err_did_not_restore">Nenhuma lista pode ser restaurada</string>
|
||||
<string name="desc_auxio_icon">Ícone do Auxio</string>
|
||||
<string name="lbl_shuffle_shortcut_long">Aleatorizar tudo</string>
|
||||
<string name="lbl_shuffle_shortcut_long">Misturar tudo</string>
|
||||
<string name="set_play_in_list_with">Ao tocar da biblioteca</string>
|
||||
<string name="lbl_singles">Singles</string>
|
||||
<string name="lbl_single">Single</string>
|
||||
|
@ -257,20 +257,55 @@
|
|||
<item quantity="many">%d artistas</item>
|
||||
<item quantity="other">%d artistas</item>
|
||||
</plurals>
|
||||
<string name="set_replay_gain">Equalização de volume ReplayGain</string>
|
||||
<string name="set_replay_gain">Configurar ganho de repetição</string>
|
||||
<string name="lbl_sort_dsc">Descendente</string>
|
||||
<string name="set_ui_desc">Mude o tema e as cores do app</string>
|
||||
<string name="set_personalize_desc">Personalize os controles e o comportamento da interface do usuário</string>
|
||||
<string name="set_content_desc">Controle como a música e as imagens são carregadas</string>
|
||||
<string name="set_ui_desc">Mudar o tema e cores da app</string>
|
||||
<string name="set_personalize_desc">Personalize os controlos e o comportamento do interface do utilizador</string>
|
||||
<string name="set_content_desc">Controlar como a música e as imagens são carregadas</string>
|
||||
<string name="set_music">Música</string>
|
||||
<string name="set_images">Imagens</string>
|
||||
<string name="set_audio_desc">Configurar som e comportamento de reprodução</string>
|
||||
<string name="set_audio_desc">Configurar o som e comportamento da reprodução</string>
|
||||
<string name="set_playback">Reprodução</string>
|
||||
<string name="set_dirs_list">Pastas</string>
|
||||
<string name="set_library">Biblioteca</string>
|
||||
<string name="set_state">Estado de reprodução</string>
|
||||
<string name="set_state">Estado da reprodução</string>
|
||||
<string name="set_separators_and">E comercial (&)</string>
|
||||
<string name="set_behavior">Comportamento</string>
|
||||
<string name="set_intelligent_sorting">Ignorar artigos ao classificar</string>
|
||||
<string name="set_intelligent_sorting">Classificação inteligente</string>
|
||||
<string name="set_intelligent_sorting_desc">Ignore palavras como \"the\" ao classificar por nome (funciona melhor com músicas em inglês)</string>
|
||||
<string name="lbl_sort_direction">Direção</string>
|
||||
<string name="desc_selection_image">Seleção de imagem</string>
|
||||
<string name="lbl_selection">Seleção</string>
|
||||
<string name="set_play_song_by_itself">Tocar música sozinha</string>
|
||||
<string name="lbl_playlists">Listas de reprodução</string>
|
||||
<string name="fmt_def_playlist">Lista de reprodução %d</string>
|
||||
<string name="lbl_playlist">Lista de reprodução</string>
|
||||
<string name="lng_playlist_created">Lista de reprodução criada</string>
|
||||
<string name="lbl_show_error_info">Mais</string>
|
||||
<string name="desc_playlist_image">Imagem da lista de reprodução de %s</string>
|
||||
<string name="lbl_delete">Eliminar</string>
|
||||
<string name="def_disc">Nenhum disco</string>
|
||||
<string name="lbl_copied">Copiado</string>
|
||||
<string name="lbl_playlist_add">Adicionar à lista de reprodução</string>
|
||||
<string name="lbl_share">Partilhar</string>
|
||||
<string name="lbl_edit">Editar</string>
|
||||
<string name="lbl_rename">Renomear</string>
|
||||
<string name="lng_playlist_added">Adicionado à lista de reprodução</string>
|
||||
<string name="def_song_count">Nenhuma música</string>
|
||||
<string name="set_square_covers_desc">Recortar à capa dos álbuns numa proporção de 1:1</string>
|
||||
<string name="fmt_editing">A editar %s</string>
|
||||
<string name="lbl_sort_mode">Ordenar por</string>
|
||||
<string name="lbl_parent_detail">Visualizar</string>
|
||||
<string name="lbl_song">Música</string>
|
||||
<string name="lbl_confirm_delete_playlist">Eliminar lista de reprodução</string>
|
||||
<string name="desc_new_playlist">Criar nova lista de reprodução</string>
|
||||
<string name="lng_playlist_deleted">Lista de reprodução eliminada</string>
|
||||
<string name="lbl_report">Relatório</string>
|
||||
<string name="lbl_new_playlist">Nova lista de reprodução</string>
|
||||
<string name="lbl_error_info">Informações de erro</string>
|
||||
<string name="set_square_covers">Forçar capas em formato quadrado</string>
|
||||
<string name="lng_playlist_renamed">Lista de reprodução renomeada</string>
|
||||
<string name="lbl_rename_playlist">Renomear lista de reprodução</string>
|
||||
<string name="fmt_deletion_info">Excluir %s\? Não pode ser desfeito.</string>
|
||||
<string name="lbl_appears_on">Só aparecer</string>
|
||||
</resources>
|
2
app/src/main/res/values-pt/strings.xml
Normal file
2
app/src/main/res/values-pt/strings.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources />
|
|
@ -157,4 +157,38 @@
|
|||
<string name="set_play_song_from_album">Redă din album</string>
|
||||
<string name="set_play_in_parent_with">În timpul redării de la detaliile articolului</string>
|
||||
<string name="set_behavior">Comportament</string>
|
||||
<string name="lbl_new_playlist">Listă de redare nouă</string>
|
||||
<string name="set_exclude_non_music_desc">Ignoră fișiere audio care nu sunt muzică, precum podcasturi</string>
|
||||
<string name="set_separators_plus">Plus (+)</string>
|
||||
<string name="lbl_song">Melodie</string>
|
||||
<string name="lng_playlist_created">Listă de redare creată</string>
|
||||
<string name="lbl_delete">Șterge</string>
|
||||
<string name="set_hide_collaborators">Ascunde colaboratori</string>
|
||||
<string name="set_cover_mode_off">Oprit</string>
|
||||
<string name="set_square_covers_desc">Taie toate coperțile de album la raportul de aspect 1:1</string>
|
||||
<string name="set_intelligent_sorting">Sortare inteligentă</string>
|
||||
<string name="lbl_rename_playlist">Redenumiți lista da redare</string>
|
||||
<string name="lbl_confirm_delete_playlist">Șterge lista de redare\?</string>
|
||||
<string name="lbl_rename">Redenumiți</string>
|
||||
<string name="set_content_desc">Controlează cum muzica și imaginile sunt încărcate</string>
|
||||
<string name="lbl_sort_mode">Sortează după</string>
|
||||
<string name="set_intelligent_sorting_desc">Sortare corectă pentru nume care incep cu numere sau cuvinte precum \"the\" (funcționează cel mai bine cu melodii în limba engleză)</string>
|
||||
<string name="set_square_covers">Forțează coperți de album pătrate</string>
|
||||
<string name="set_cover_mode_media_store">Rapid</string>
|
||||
<string name="set_cover_mode_quality">Calitate mare</string>
|
||||
<string name="set_separators_semicolon">Punct și virgulă (;)</string>
|
||||
<string name="lbl_edit">Editează</string>
|
||||
<string name="set_exclude_non_music">Exclude non-muzică</string>
|
||||
<string name="lng_playlist_added">Adaugat către lista de redare</string>
|
||||
<string name="set_observing">Reîncărcare automată</string>
|
||||
<string name="set_separators_comma">Virgulă (,)</string>
|
||||
<string name="set_observing_desc">Reîncărcați biblioteca de muzică oricând se schimbă (Necesită notificare persistentă)</string>
|
||||
<string name="set_images">Imagini</string>
|
||||
<string name="lbl_appears_on">Apare în</string>
|
||||
<string name="lbl_share">Partajați</string>
|
||||
<string name="lng_playlist_renamed">Listă de redare redenumită</string>
|
||||
<string name="lng_playlist_deleted">Listă de redare ștearsă</string>
|
||||
<string name="set_cover_mode">Coperți de album</string>
|
||||
<string name="lbl_playlist_add">Adaugă către listă de redare</string>
|
||||
<string name="lbl_sort_direction">Direcție</string>
|
||||
</resources>
|
|
@ -309,4 +309,8 @@
|
|||
<string name="lbl_sort_direction">Направление</string>
|
||||
<string name="lbl_selection">Выберите</string>
|
||||
<string name="desc_selection_image">Выберите изображение</string>
|
||||
<string name="lbl_show_error_info">Дополнительно</string>
|
||||
<string name="lbl_error_info">Информация об ошибке</string>
|
||||
<string name="lbl_report">Отчёт об ошибке</string>
|
||||
<string name="lbl_copied">Скопировано</string>
|
||||
</resources>
|
307
app/src/main/res/values-sl/strings.xml
Normal file
307
app/src/main/res/values-sl/strings.xml
Normal file
|
@ -0,0 +1,307 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="clr_grey">Siva</string>
|
||||
<string name="set_intelligent_sorting">Pametno sortiranje</string>
|
||||
<string name="lbl_compilations">Zbirke</string>
|
||||
<string name="lbl_albums">Albumi</string>
|
||||
<string name="lbl_compilation_remix">Zbirka remiksov</string>
|
||||
<string name="set_wipe_state">Počisti stanje predvajanja</string>
|
||||
<string name="lbl_album_details">Pojdi na album</string>
|
||||
<string name="desc_artist_image">Slika izvajalca za %s</string>
|
||||
<string name="lbl_sort_direction">Smer</string>
|
||||
<string name="lng_queue_added">Dodano v čakalno vrsto</string>
|
||||
<string name="set_theme_day">Svetlo</string>
|
||||
<string name="lbl_album_remix">Remiks album</string>
|
||||
<string name="lbl_wiki">Wiki</string>
|
||||
<string name="set_theme_auto">Samodejno</string>
|
||||
<string name="desc_selection_image">Slika izbire</string>
|
||||
<string name="lbl_selection">Izbira</string>
|
||||
<string name="desc_skip_next">Preskoči na naslednjo pesem</string>
|
||||
<string name="lbl_name">Ime</string>
|
||||
<string name="set_black_mode">Črna tema</string>
|
||||
<string name="set_hide_collaborators_desc">Prikaži samo izvajalce, ki so neposredno navedeni na albumu (najbolje deluje v dobro označenih knjižnicah)</string>
|
||||
<string name="set_lib_tabs">Zavihki knjižnice</string>
|
||||
<string name="clr_deep_purple">Temna vijolična</string>
|
||||
<string name="set_play_song_by_itself">Predvajaj pesem samostojno</string>
|
||||
<string name="set_replay_gain_mode_album">Prednost albumu</string>
|
||||
<string name="set_play_song_none">Predvajaj iz prikazanega elementa</string>
|
||||
<string name="set_observing">Samodejno ponovno nalaganje</string>
|
||||
<string name="err_did_not_wipe">Ni mogoče počistiti stanja</string>
|
||||
<string name="lbl_eps">Podaljšane</string>
|
||||
<string name="lbl_props">Lastnosti pesmi</string>
|
||||
<string name="desc_change_repeat">Spremenite način ponavljanja</string>
|
||||
<string name="clr_orange">Oranžna</string>
|
||||
<string name="lbl_add">Dodaj</string>
|
||||
<string name="lbl_shuffle">Naključno predvajanje</string>
|
||||
<string name="lbl_mix">DJ Miks</string>
|
||||
<string name="set_replay_gain_mode_track">Prednost pesmi</string>
|
||||
<string name="def_playback">Glasba ni v predavanju</string>
|
||||
<string name="lbl_genres">Žanri</string>
|
||||
<string name="info_app_desc">Preprost, racionalen predvajalnik glasbe za Android.</string>
|
||||
<string name="lng_indexing">Nalaganje vaše glasbene knjižnice…</string>
|
||||
<string name="set_rewind_prev_desc">Previj nazaj pred skokom na prejšnjo pesem</string>
|
||||
<string name="fmt_bitrate">%d kbps</string>
|
||||
<string name="lng_observing">Spremljanje vaše glasbene knjižnice za spremembe…</string>
|
||||
<string name="set_replay_gain_mode_dynamic">Prednost albumu če se album predvaja</string>
|
||||
<string name="lbl_playlists">Seznami predvajanja</string>
|
||||
<string name="lng_search_library">Išči v knjižnici…</string>
|
||||
<string name="set_play_in_parent_with">Ko se predvaja iz podrobnosti elementa</string>
|
||||
<string name="set_reindex">Ponovno naloži glasbo</string>
|
||||
<string name="lbl_remix_group">Remiksi</string>
|
||||
<string name="set_save_state">Shrani stanje predvajanja</string>
|
||||
<string name="set_pre_amp_warning">Opozorilo: Sprememba pred-ojačevalca na visoko pozitivno vrednost lahko privede do preseganja na nekaterih avdio posnetkih.</string>
|
||||
<string name="def_date">Ni datuma</string>
|
||||
<string name="set_reindex_desc">Ponovno naloži glasbeno knjižnico, uporabi predpomnjene oznake, kadar je mogoče</string>
|
||||
<string name="err_no_app">Najdena ni bila nobena aplikacija, ki bi lahko opravila to nalogo</string>
|
||||
<string name="lbl_cancel">Prekliči</string>
|
||||
<string name="set_dirs_mode_include">Vključi</string>
|
||||
<string name="fmt_def_playlist">Seznam predvajanja %d</string>
|
||||
<string name="set_save_desc">Shrani trenutno stanje predvajanja zdaj</string>
|
||||
<string name="desc_skip_prev">Preskoči na zadnjo pesem</string>
|
||||
<string name="set_observing_desc">Ponovno naloži glasbeno knjižnico vsakič, ko se zazna sprememba (zahteva vztrajno obvestilo)</string>
|
||||
<string name="lbl_relative_path">Pot do datoteke</string>
|
||||
<plurals name="fmt_song_count">
|
||||
<item quantity="one">%d pesem</item>
|
||||
<item quantity="two">%d pesmi</item>
|
||||
<item quantity="few">%d pesmi</item>
|
||||
<item quantity="other">%d pesmi</item>
|
||||
</plurals>
|
||||
<string name="lbl_ep_live">Podaljšano v živo</string>
|
||||
<string name="lbl_playlist">Seznam predvajanja</string>
|
||||
<string name="lbl_compilation">Zbirka</string>
|
||||
<string name="set_hide_collaborators">Skrij soustvarjalce</string>
|
||||
<string name="set_keep_shuffle_desc">Obdrži naključno predvajanje pri predvajanju nove pesmi</string>
|
||||
<string name="set_behavior">Obnašanje</string>
|
||||
<string name="set_cover_mode_off">Izklopljeno</string>
|
||||
<string name="cdc_mp4">MPEG-4 Audio</string>
|
||||
<string name="lbl_save">Shrani</string>
|
||||
<string name="desc_queue_bar">Odpri čakalno vrsto</string>
|
||||
<string name="lbl_mixtapes">Mešanice</string>
|
||||
<string name="lbl_artist">Izvajalec</string>
|
||||
<string name="set_intelligent_sorting_desc">Pravilno razvrsti imena, ki se začnejo z številkami ali besedami, kot so \'the\' (najbolje deluje z angleško glasbo)</string>
|
||||
<string name="lbl_file_name">Ime datoteke</string>
|
||||
<string name="clr_teal">Zelenkasto modra</string>
|
||||
<string name="set_state">Vztrajnost</string>
|
||||
<string name="desc_shuffle_all">Premešaj vse pesmi</string>
|
||||
<string name="lng_playlist_created">Seznam predavanja ustvarjen</string>
|
||||
<string name="fmt_lib_total_duration">Celoten čas predvajanja: %s</string>
|
||||
<string name="err_did_not_save">Ni mogoče shraniti stanja</string>
|
||||
<string name="set_repeat_pause">Pavza ob ponavljanju</string>
|
||||
<string name="set_dirs">Mape za glasbo</string>
|
||||
<string name="set_keep_shuffle">Zapomni si naključno predvajanje</string>
|
||||
<string name="lbl_artist_details">Pojdi na izvajalca</string>
|
||||
<string name="fmt_lib_song_count">Naloženih pesmi: %d</string>
|
||||
<string name="desc_song_handle">Premakni to pesem</string>
|
||||
<string name="lbl_observing">Spremljanje glasbene knjižnice</string>
|
||||
<string name="lbl_show_error_info">Pokaži več</string>
|
||||
<string name="clr_cyan">Ciano modra</string>
|
||||
<string name="set_accent">Barvna shema</string>
|
||||
<string name="desc_playlist_image">Slika seznama predvajanja za %s</string>
|
||||
<string name="lbl_delete">Odstrani</string>
|
||||
<string name="set_rewind_prev">Previj nazaj preden se preskoči nazaj</string>
|
||||
<string name="fmt_lib_genre_count">Naloženih žanrov: %d</string>
|
||||
<string name="lbl_playback">Se predvaja</string>
|
||||
<string name="desc_remove_song">Odstrani to pesem</string>
|
||||
<string name="lbl_state_saved">Stanje predvajanja shranjeno</string>
|
||||
<string name="def_disc">Ni diska</string>
|
||||
<string name="lbl_search">Išči</string>
|
||||
<string name="set_headset_autoplay_desc">Vedno začnite predvajati, ko se slušalke priključijo (morda ne deluje na vseh napravah)</string>
|
||||
<string name="lbl_soundtracks">Glasbene podlage</string>
|
||||
<string name="lbl_shuffle_shortcut_long">Premešaj vse</string>
|
||||
<string name="lbl_queue_add">Dodaj v čakalno vrsto</string>
|
||||
<string name="set_pre_amp">Pred-ojačevalnik ReplayGain</string>
|
||||
<string name="cdc_mp3">MPEG-1 Audio</string>
|
||||
<string name="err_did_not_restore">Ni mogoče obnoviti stanja</string>
|
||||
<string name="set_ui_desc">Spremenite temo in barve aplikacije</string>
|
||||
<string name="lbl_retry">Poskusi znova</string>
|
||||
<string name="set_audio_desc">Prilagodi zvok in obnašanje predvajanja</string>
|
||||
<string name="set_content_desc">Nadzorujte kako se glasba in slike nalagajo</string>
|
||||
<string name="set_ui">Izgled in občutek</string>
|
||||
<string name="set_dirs_mode_exclude">Izključi</string>
|
||||
<string name="cdc_mka">Matroska Audio</string>
|
||||
<string name="set_repeat_pause_desc">Začasna prekinitev ob ponavljanju</string>
|
||||
<string name="lbl_play">Predvajaj</string>
|
||||
<string name="lbl_indexing">Nalaganje glasbe</string>
|
||||
<string name="err_no_music">Ni najdenih pesmi</string>
|
||||
<string name="lbl_date">Datum</string>
|
||||
<string name="set_rescan_desc">Izprazni predpomnilnik oznak in popolnoma ponovno naloži glasbeno knjižnico (počasneje, vendar bolj popolno)</string>
|
||||
<string name="set_pre_amp_desc">Pred-ojačevalec se uporablja na obstoječi prilagoditvi med predvajanjem</string>
|
||||
<string name="set_play_song_from_album">Predvajaj iz albuma</string>
|
||||
<string name="set_music">Glasba</string>
|
||||
<string name="err_bad_dir">Ta mapa ni podprta</string>
|
||||
<string name="set_restore_desc">Obnovi prej shranjeno stanje predvajanja (če obstaja)</string>
|
||||
<string name="lng_author">Razvil Alexander Capehart</string>
|
||||
<string name="desc_music_dir_delete">Odstrani mapo</string>
|
||||
<string name="lbl_copied">Kopirano</string>
|
||||
<string name="err_index_failed">Nalaganje glasbe ni uspelo</string>
|
||||
<string name="lbl_album">Album</string>
|
||||
<string name="set_play_in_list_with">Ko se predvaja iz knjižnice</string>
|
||||
<string name="set_cover_mode_quality">Visoka kvaliteta</string>
|
||||
<string name="set_pre_amp_without">Prilagoditev brez oznak</string>
|
||||
<string name="lbl_playlist_add">Dodaj na seznam predvajanja</string>
|
||||
<string name="lbl_date_added">Datum vnosa</string>
|
||||
<string name="lbl_share">Deli</string>
|
||||
<string name="lbl_album_live">Album v živo</string>
|
||||
<string name="lbl_edit">Uredi</string>
|
||||
<string name="desc_no_cover">Naslovnica albuma</string>
|
||||
<string name="lbl_rename">Preimenuj</string>
|
||||
<string name="set_separators_plus">Plus (+)</string>
|
||||
<string name="lbl_state_restored">Stanje predvajanja obnovljeno</string>
|
||||
<string name="fmt_selected">%d Izbrano</string>
|
||||
<string name="def_artist">Neznan izvajatelj</string>
|
||||
<string name="set_images">Slike</string>
|
||||
<plurals name="fmt_artist_count">
|
||||
<item quantity="one">%d izvajalec</item>
|
||||
<item quantity="two">%d izvajalca</item>
|
||||
<item quantity="few">%d izvajalci</item>
|
||||
<item quantity="other">%d izvajalcev</item>
|
||||
</plurals>
|
||||
<string name="lbl_state_wiped">Stanje predvajanja počiščeno</string>
|
||||
<string name="set_display">Prikaz</string>
|
||||
<string name="fmt_list">%1$s, %2$s</string>
|
||||
<string name="cdc_ogg">Ogg Audio</string>
|
||||
<string name="lbl_filter_all">Vse</string>
|
||||
<string name="set_separators_slash">Poševnica (/)</string>
|
||||
<string name="lng_playlist_added">Dodano na seznam predvajanja</string>
|
||||
<string name="lbl_single_live">Singl v živo</string>
|
||||
<string name="def_song_count">Ni pesmi</string>
|
||||
<string name="lbl_ep">Podaljšano</string>
|
||||
<string name="lbl_songs">Pesmi</string>
|
||||
<string name="set_dirs_list">Mape</string>
|
||||
<string name="set_square_covers_desc">Prireži vse naslovnice albumov v razmerje 1:1</string>
|
||||
<string name="set_bar_action">Prilagojeno dejanje na vrstici za predvajanje</string>
|
||||
<string name="clr_indigo">Indigo modra</string>
|
||||
<string name="fmt_db_neg">-%.1f dB</string>
|
||||
<string name="lbl_indexer">Nalaganje glasbe</string>
|
||||
<string name="set_separators_and">In (&)</string>
|
||||
<string name="lbl_song_count">Število pesmi</string>
|
||||
<string name="lbl_sort">Sortiraj</string>
|
||||
<string name="clr_purple">Vijolična</string>
|
||||
<string name="cdc_flac">Brezplačni format brez izgub zvoka (FLAC)</string>
|
||||
<string name="def_genre">Neznan žanr</string>
|
||||
<string name="fmt_db_pos">+%.1f dB</string>
|
||||
<string name="set_personalize">Prilagodi</string>
|
||||
<string name="fmt_editing">Urejanje %s</string>
|
||||
<string name="set_action_mode_next">Preskoči na naslednjo</string>
|
||||
<string name="set_action_mode_repeat">Način ponavljanja</string>
|
||||
<plurals name="fmt_album_count">
|
||||
<item quantity="one">%d album</item>
|
||||
<item quantity="two">%d albuma</item>
|
||||
<item quantity="few">%d albumi</item>
|
||||
<item quantity="other">%d albumov</item>
|
||||
</plurals>
|
||||
<string name="lbl_disc">Disk</string>
|
||||
<string name="fmt_indexing">Nalaganje vaše glasbene knjižnice… (%1$d/%2$d)</string>
|
||||
<string name="desc_clear_search">Počisti iskalno poizvedbo</string>
|
||||
<string name="lbl_sort_asc">Naraščajoče</string>
|
||||
<string name="clr_pink">Roza</string>
|
||||
<string name="lbl_all_songs">Vse pesmi</string>
|
||||
<string name="lbl_about">O aplikaciji</string>
|
||||
<string name="fmt_disc_no">Disk %d</string>
|
||||
<string name="set_round_mode_desc">Omogočite zaobljene robove na dodatnih elementih uporabniškega vmesnika (zahteva zaobljene naslovnice albumov)</string>
|
||||
<string name="desc_album_cover">Naslovnica albuma za %s</string>
|
||||
<string name="lbl_live_group">V živo</string>
|
||||
<string name="set_lib_tabs_desc">Spremenite vidnost in vrstni red zavihkov knjižnice</string>
|
||||
<string name="set_wipe_desc">Počisti shranjeno stanje predvajanja (če obstaja)</string>
|
||||
<string name="lbl_sort_mode">Sortiraj po</string>
|
||||
<string name="lbl_parent_detail">Ogled</string>
|
||||
<string name="desc_exit">Ustavi predvajanje</string>
|
||||
<string name="lbl_mixtape">Mežanica</string>
|
||||
<string name="set_dirs_mode_include_desc">Glasba se bo nalagala <b>samo</b> iz map, ki jih dodate.</string>
|
||||
<string name="set_dirs_mode">Način</string>
|
||||
<string name="lbl_single_remix">Remiks singla</string>
|
||||
<string name="err_no_perms">Auxio potrebuje dovoljenje za branje vaše glasbene knjižnice</string>
|
||||
<string name="set_theme">Tema</string>
|
||||
<string name="set_library">Knjižnica</string>
|
||||
<string name="lbl_library_counts">Statistika knjižnice</string>
|
||||
<string name="lbl_equalizer">Izenačevalnik</string>
|
||||
<string name="desc_tab_handle">Premakni ta zavihek</string>
|
||||
<string name="lbl_song">Pesem</string>
|
||||
<string name="desc_genre_image">Slika žanra za %s</string>
|
||||
<string name="set_dirs_desc">Nastavitev virov za nalaganje glasbe</string>
|
||||
<string name="lbl_mixes">DJ Miksi</string>
|
||||
<string name="lbl_confirm_delete_playlist">Odstrani seznam predvajanja\?</string>
|
||||
<string name="clr_blue">Modra</string>
|
||||
<string name="clr_deep_blue">Temno modra</string>
|
||||
<string name="set_round_mode">Zaobljen način</string>
|
||||
<string name="fmt_lib_artist_count">Naloženih izvajalcev: %d</string>
|
||||
<string name="set_audio">Zvok</string>
|
||||
<string name="set_dirs_mode_exclude_desc">Glasba se <b>ne</b> bo nalagala iz the map, ki jih dodate.</string>
|
||||
<string name="clr_red">Rdeča</string>
|
||||
<string name="clr_dynamic">Dinamično</string>
|
||||
<string name="set_theme_night">Temno</string>
|
||||
<string name="desc_shuffle">Vklopite ali izklopite naključno predvajanje</string>
|
||||
<string name="lbl_genre">Žanr</string>
|
||||
<string name="set_playback">Predvajanje</string>
|
||||
<string name="lbl_ok">Vredu</string>
|
||||
<string name="desc_new_playlist">Ustvari nov seznam predvajanja</string>
|
||||
<string name="lbl_single">Singl</string>
|
||||
<string name="lng_playlist_deleted">Seznam predvajanja odstranjen</string>
|
||||
<string name="lbl_grant">Dovoli</string>
|
||||
<string name="set_play_song_from_all">Predvajaj iz vseh pesmi</string>
|
||||
<string name="set_restore_state">Obnovi stanje predvajanja</string>
|
||||
<string name="set_pre_amp_with">Prilagoditev z oznakami</string>
|
||||
<string name="set_headset_autoplay">Predvajanje ob priključitvi slušalk</string>
|
||||
<string name="set_separators_comma">Vejica (,)</string>
|
||||
<string name="desc_auxio_icon">Auxio ikona</string>
|
||||
<string name="desc_track_number">Skladba %d</string>
|
||||
<string name="lbl_filter">Filtriraj</string>
|
||||
<string name="set_exclude_non_music_desc">Prezri avdio datoteke, ki niso glasba, na primer podkaste</string>
|
||||
<string name="lbl_soundtrack">Glasbena podlaga</string>
|
||||
<string name="set_notif_action">Prilagojeno dejanje v obvestilu</string>
|
||||
<string name="lbl_reset">Ponastavi nastavitve</string>
|
||||
<string name="lbl_report">Prijavi napako</string>
|
||||
<string name="set_exclude_non_music">Izključi ne-glasbo</string>
|
||||
<string name="lbl_play_next">Predvajaj naslednje</string>
|
||||
<string name="lbl_artists">Izvajalci</string>
|
||||
<string name="lbl_track">Skladba</string>
|
||||
<string name="fmt_lib_album_count">Naloženih albumov: %d</string>
|
||||
<string name="lbl_new_playlist">Nov seznam predvajanja</string>
|
||||
<string name="lbl_error_info">Informacije napake</string>
|
||||
<string name="lbl_shuffle_shortcut_short">Premešaj</string>
|
||||
<string name="cdc_aac">Napredno avdio kodiranje (AAC)</string>
|
||||
<string name="set_square_covers">Prisilite uporabo kvadratnih naslovnic albumov</string>
|
||||
<string name="lbl_compilation_live">Zbirka pesmi v živo</string>
|
||||
<string name="set_cover_mode">Naslovnice albumov</string>
|
||||
<string name="clr_yellow">Rumena</string>
|
||||
<string name="clr_green">Zelena</string>
|
||||
<string name="lbl_version">Različica</string>
|
||||
<string name="lbl_song_detail">Ogled lastnosti</string>
|
||||
<string name="lbl_size">Velikost</string>
|
||||
<string name="lbl_sort_dsc">Padajoče</string>
|
||||
<string name="lbl_ep_remix">Podaljšan remiks</string>
|
||||
<string name="set_separators_semicolon">Podpičje (;)</string>
|
||||
<string name="set_cover_mode_media_store">Hitro</string>
|
||||
<string name="lng_playlist_renamed">Seznam predvajanja preimenovan</string>
|
||||
<string name="desc_play_pause">Predvajaj ali začasno ustavi</string>
|
||||
<string name="clr_brown">Rjava</string>
|
||||
<string name="set_replay_gain_mode">ReplayGain strategija</string>
|
||||
<string name="lbl_code">Izvorna koda</string>
|
||||
<string name="set_play_song_from_artist">Predvajaj iz izvajalca</string>
|
||||
<string name="err_no_dirs">Ni map</string>
|
||||
<string name="set_personalize_desc">Prilagoditev kontrol uporabniškega vmesnika in obnašanja</string>
|
||||
<string name="lbl_sample_rate">Hitrost vzorčenja</string>
|
||||
<string name="lbl_queue">Čakalna vrsta</string>
|
||||
<string name="set_separators">Ločila za več vrednosti</string>
|
||||
<string name="set_replay_gain">ReplayGain Tehnologija</string>
|
||||
<string name="lbl_singles">Singli</string>
|
||||
<string name="lng_widget">Pregled in nadzor predvajanja glasbe</string>
|
||||
<string name="set_black_mode_desc">Uporabite čisto črno temo</string>
|
||||
<string name="set_rescan">Ponovno preglej glasbeno knjižnico</string>
|
||||
<string name="lbl_licenses">Licence</string>
|
||||
<string name="lbl_format">Format</string>
|
||||
<string name="set_content">Vsebina</string>
|
||||
<string name="lbl_rename_playlist">Preimenuj seznam predvajanja</string>
|
||||
<string name="lbl_bitrate">Bitna hitrost</string>
|
||||
<string name="fmt_deletion_info">Odstraniti %s\? Tega ni mogoče razveljaviti.</string>
|
||||
<string name="set_root_title">Nastavitve</string>
|
||||
<string name="set_separators_desc">Konfigurirajte znake, ki označujejo več vrednosti zaporedoma</string>
|
||||
<string name="def_track">Ni skladbe</string>
|
||||
<string name="set_separators_warning">Opozorilo: Uporaba te nastavitve lahko povzroči, da se nekatere oznake napačno interpretirajo kot oznake z več vrednostmi. To lahko rešite tako, da neželene ločevalne znake predhodno označite z vzvratno poševnico (\\).</string>
|
||||
<string name="clr_deep_green">Temno zelena</string>
|
||||
<string name="set_play_song_from_genre">Predvajaj iz žanra</string>
|
||||
<string name="lbl_duration">Trajanje</string>
|
||||
<string name="clr_lime">Limeta</string>
|
||||
<string name="lbl_appears_on">Sodeloval pri</string>
|
||||
<string name="fmt_sample_rate">%d Hz</string>
|
||||
</resources>
|
|
@ -3,7 +3,7 @@
|
|||
<string name="lbl_retry">Försök igen</string>
|
||||
<string name="lbl_indexer">Musik laddar</string>
|
||||
<string name="lbl_indexing">Laddar musik</string>
|
||||
<string name="lbl_all_songs">Alla låtar</string>
|
||||
<string name="lbl_all_songs">Alla spår</string>
|
||||
<string name="lbl_albums">Album</string>
|
||||
<string name="lbl_album">Albumet</string>
|
||||
<string name="lbl_album_remix">Remix-album</string>
|
||||
|
@ -23,7 +23,7 @@
|
|||
<string name="lbl_remix_group">Remixar</string>
|
||||
<string name="lbl_appears_on">Framträder på</string>
|
||||
<string name="lbl_artist">Konstnär</string>
|
||||
<string name="lbl_artists">Konstnär</string>
|
||||
<string name="lbl_artists">Konstnärer</string>
|
||||
<string name="lbl_genres">Genrer</string>
|
||||
<string name="lbl_playlist">Spellista</string>
|
||||
<string name="lbl_playlists">Spellistor</string>
|
||||
|
@ -68,11 +68,11 @@
|
|||
<string name="lbl_licenses">Licenser</string>
|
||||
<string name="lng_widget">Visa och kontrollera musikuppspelning</string>
|
||||
<string name="lng_indexing">Laddar ditt musikbibliotek…</string>
|
||||
<string name="lng_observing">Övervakning ditt musikbibliotek för ändringar…</string>
|
||||
<string name="lng_queue_added">Tillagd till kö</string>
|
||||
<string name="lng_observing">Overvåker ditt musikbibliotek för ändringar…</string>
|
||||
<string name="lng_queue_added">Tillagd i kö</string>
|
||||
<string name="lng_playlist_created">Spellista skapade</string>
|
||||
<string name="lng_playlist_added">Tillagd till spellista</string>
|
||||
<string name="lng_search_library">Sök ditt musikbibliotek…</string>
|
||||
<string name="lng_search_library">Sök i ditt musikbibliotek…</string>
|
||||
<string name="set_root_title">Inställningar</string>
|
||||
<string name="set_ui">Utseende</string>
|
||||
<string name="set_ui_desc">Ändra tema och färger på appen</string>
|
||||
|
@ -83,7 +83,7 @@
|
|||
<string name="lbl_grant">Bevilja</string>
|
||||
<string name="info_app_desc">En enkel, rationell musikspelare för Android.</string>
|
||||
<string name="lbl_observing">Övervakar musikbiblioteket</string>
|
||||
<string name="lbl_songs">Låtar</string>
|
||||
<string name="lbl_songs">Spår</string>
|
||||
<string name="lbl_album_live">Live-album</string>
|
||||
<string name="lbl_delete">Ta bort</string>
|
||||
<string name="lbl_compilation_live">Live-sammanställning</string>
|
||||
|
@ -107,7 +107,7 @@
|
|||
<string name="lbl_state_saved">Tillstånd sparat</string>
|
||||
<string name="lbl_version">Version</string>
|
||||
<string name="lbl_library_counts">Statistik över beroende</string>
|
||||
<string name="lng_playlist_renamed">Bytt namn av spellista</string>
|
||||
<string name="lng_playlist_renamed">Byt namn av spellista</string>
|
||||
<string name="lng_playlist_deleted">Spellista tog bort</string>
|
||||
<string name="lng_author">Utvecklad av Alexander Capeheart</string>
|
||||
<string name="set_theme">Tema</string>
|
||||
|
@ -125,7 +125,7 @@
|
|||
<string name="set_play_in_parent_with">När spelar från artikeluppgifter</string>
|
||||
<string name="set_play_song_from_genre">Spela från genre</string>
|
||||
<string name="set_keep_shuffle">Komma ihåg blandningsstatus</string>
|
||||
<string name="set_keep_shuffle_desc">Behåll blandning på när spelar en ny låt</string>
|
||||
<string name="set_keep_shuffle_desc">Behåll blandning på när en ny låt spelas</string>
|
||||
<string name="set_content">Kontent</string>
|
||||
<string name="set_content_desc">Kontrollera hur musik och bilar laddas</string>
|
||||
<string name="set_music">Musik</string>
|
||||
|
@ -151,4 +151,146 @@
|
|||
<string name="set_separators_desc">Konfigurera tecken som separerar flera värden i taggar</string>
|
||||
<string name="set_separators_warning">Advarsel: Denna inställning kan leda till att vissa taggar separeras felaktigt. För att åtgärda detta, prefixa oönskade separatortecken med ett backslash (\\).</string>
|
||||
<string name="set_personalize_desc">Anpassa UI-kontroller och beteende</string>
|
||||
<string name="set_cover_mode_off">Av</string>
|
||||
<string name="set_headset_autoplay">Hörlurar-autouppspelning</string>
|
||||
<string name="set_repeat_pause_desc">Pausa när en låt upprepas</string>
|
||||
<string name="set_dirs_mode_exclude_desc">Musik laddas <b>inte</b> från mapparna som ni lägger till.</string>
|
||||
<string name="desc_queue_bar">Öppna kö</string>
|
||||
<string name="clr_dynamic">Dynamisk</string>
|
||||
<string name="fmt_lib_artist_count">%d konstnärer som laddats</string>
|
||||
<plurals name="fmt_artist_count">
|
||||
<item quantity="one">%d konstnär</item>
|
||||
<item quantity="other">%d konstnärer</item>
|
||||
</plurals>
|
||||
<string name="set_images">Bildar</string>
|
||||
<string name="set_audio">Ljud</string>
|
||||
<string name="set_audio_desc">Konfigurera ljud- och uppspelningsbeteende</string>
|
||||
<string name="set_rewind_prev">Spola tillbaka innan spår hoppar tillbaka</string>
|
||||
<string name="set_replay_gain_mode">ReplayGain-strategi</string>
|
||||
<string name="set_wipe_desc">Rensa det tidigare sparade uppspelningsläget om det finns</string>
|
||||
<string name="set_restore_state">Återställ uppspelningsläge</string>
|
||||
<string name="fmt_db_neg">-%.1f dB</string>
|
||||
<string name="fmt_deletion_info">Radera %s\? Detta kan inte ångras.</string>
|
||||
<string name="set_hide_collaborators_desc">Endast visa artister som är direkt krediterade på ett album (funkar bäst på välmärkta bibliotek)</string>
|
||||
<string name="set_cover_mode">Albumomslag</string>
|
||||
<string name="set_cover_mode_media_store">Snabbt</string>
|
||||
<string name="set_library">Bibliotek</string>
|
||||
<string name="set_dirs_mode_include">Inkludera</string>
|
||||
<string name="set_reindex">Uppdatera musik</string>
|
||||
<string name="set_reindex_desc">Ladda musikbiblioteket om och använd cachad taggar när det är möjligt</string>
|
||||
<string name="set_state">Uthållighet</string>
|
||||
<string name="set_wipe_state">Rensa uppspelningsläge</string>
|
||||
<string name="set_restore_desc">Återställ det tidigare lagrade uppspelningsläget om det finns</string>
|
||||
<string name="err_did_not_save">Misslyckades att spara uppspelningsläget</string>
|
||||
<string name="desc_shuffle_all">Blanda alla spår</string>
|
||||
<string name="desc_clear_search">Rensa sökfrågan</string>
|
||||
<string name="desc_music_dir_delete">Radera mappen</string>
|
||||
<string name="desc_genre_image">Genrebild för %s</string>
|
||||
<string name="desc_playlist_image">Spellistabild för %s</string>
|
||||
<string name="cdc_mp3">MPEG-1-ljud</string>
|
||||
<string name="cdc_mp4">MPEG-4-ljud</string>
|
||||
<string name="cdc_ogg">OGG-ljud</string>
|
||||
<string name="cdc_mka">Matroska-ljud</string>
|
||||
<string name="clr_blue">Blå</string>
|
||||
<string name="clr_deep_blue">Mörkblå</string>
|
||||
<string name="clr_cyan">Cyanblå</string>
|
||||
<string name="clr_teal">Blågrön</string>
|
||||
<string name="clr_green">Grön</string>
|
||||
<string name="clr_deep_green">Mörkgrön</string>
|
||||
<string name="clr_lime">Limegrön</string>
|
||||
<string name="clr_yellow">Gul</string>
|
||||
<string name="clr_grey">Grå</string>
|
||||
<string name="fmt_list">%1$s, %2$s</string>
|
||||
<string name="fmt_editing">Redigerar %s</string>
|
||||
<string name="set_playback">Uppspelning</string>
|
||||
<string name="clr_orange">Orange</string>
|
||||
<string name="clr_brown">Brun</string>
|
||||
<string name="set_headset_autoplay_desc">Alltid börja uppspelning när hörlurar kopplas till (kanske inte fungerar på alla enheter)</string>
|
||||
<string name="set_repeat_pause">Pausa vid upprepa</string>
|
||||
<string name="set_pre_amp">ReplayGain förförstärkare</string>
|
||||
<string name="set_pre_amp_without">Justering utan taggar</string>
|
||||
<string name="set_dirs">Musikmappar</string>
|
||||
<string name="set_pre_amp_warning">Varning: Om man ändrar förförstärkaren till ett högt positivt värde kan det leda till toppning på vissa ljudspår.</string>
|
||||
<string name="set_dirs_desc">Hantera var musik bör laddas in från</string>
|
||||
<string name="set_dirs_list">Mappar</string>
|
||||
<string name="set_dirs_mode">Modus</string>
|
||||
<string name="set_dirs_mode_exclude">Utesluta</string>
|
||||
<string name="set_dirs_mode_include_desc">Musik laddas <b>endast</b> från mapparna som ni lägger till.</string>
|
||||
<string name="set_save_desc">Spara det aktuella uppspelningsläget</string>
|
||||
<string name="set_rescan">Skanna musik om</string>
|
||||
<string name="set_rescan_desc">Rensa tagbiblioteket och ladda komplett om musikbiblioteket (långsammare, men mer komplett)</string>
|
||||
<string name="err_no_music">Ingen musik på gång</string>
|
||||
<string name="err_index_failed">Laddning av musik misslyckades</string>
|
||||
<string name="err_no_perms">Auxio behöver tillstånd för att läsa ditt musikbibliotek</string>
|
||||
<string name="err_no_app">Ingen app på gång som kan hantera denna uppgift</string>
|
||||
<string name="err_bad_dir">Denna mapp stöds inte</string>
|
||||
<string name="err_did_not_restore">Misslyckades att återställa uppspelningsläget</string>
|
||||
<string name="desc_track_number">Spår %d</string>
|
||||
<string name="desc_play_pause">Spela eller pausa</string>
|
||||
<string name="desc_song_handle">Flytta detta spår</string>
|
||||
<string name="def_artist">Okänd konstnär</string>
|
||||
<string name="def_genre">Okänd genre</string>
|
||||
<string name="cdc_aac">Avancerad audio-koding (AAC)</string>
|
||||
<string name="fmt_selected">%d utvalda</string>
|
||||
<string name="fmt_def_playlist">Spellista %d</string>
|
||||
<string name="fmt_db_pos">+%.1f dB</string>
|
||||
<plurals name="fmt_song_count">
|
||||
<item quantity="one">%d spår</item>
|
||||
<item quantity="other">%d spår</item>
|
||||
</plurals>
|
||||
<plurals name="fmt_album_count">
|
||||
<item quantity="one">%d album</item>
|
||||
<item quantity="other">%d album</item>
|
||||
</plurals>
|
||||
<string name="fmt_lib_song_count">%d spår som laddats</string>
|
||||
<string name="fmt_lib_total_duration">Total längd: %s</string>
|
||||
<string name="lbl_copied">Kopierade</string>
|
||||
<string name="lbl_selection">Urval</string>
|
||||
<string name="lbl_error_info">Felinformation</string>
|
||||
<string name="lbl_report">Rapportera</string>
|
||||
<string name="def_date">Ingen datum</string>
|
||||
<string name="def_disc">Ingen disk</string>
|
||||
<string name="def_track">Inget spår</string>
|
||||
<string name="def_song_count">Inga spår</string>
|
||||
<string name="clr_purple">Lilla</string>
|
||||
<string name="fmt_bitrate">%d kbps</string>
|
||||
<string name="fmt_sample_rate">%d Hz</string>
|
||||
<string name="fmt_lib_album_count">%d album som laddats</string>
|
||||
<string name="fmt_lib_genre_count">%d genrer som laddats</string>
|
||||
<string name="set_play_song_by_itself">Spela upp låten själv</string>
|
||||
<string name="set_cover_mode_quality">Hög kvalitet</string>
|
||||
<string name="set_square_covers">Tvinga fyrkantiga skivomslag</string>
|
||||
<string name="set_square_covers_desc">Beskär alla albumomslag till en 1:1 sidförhållande</string>
|
||||
<string name="set_rewind_prev_desc">Spola tillbaka innan att hoppa till föregående låt</string>
|
||||
<string name="set_pre_amp_with">Justering med taggar</string>
|
||||
<string name="err_no_dirs">Inga mappar</string>
|
||||
<string name="err_did_not_wipe">Misslyckades att rensa uppspelningsläget</string>
|
||||
<string name="desc_new_playlist">Skapa en ny spellista</string>
|
||||
<string name="desc_exit">Stoppa uppspelning</string>
|
||||
<string name="desc_remove_song">Radera detta spår</string>
|
||||
<string name="desc_auxio_icon">Auxio-ikon</string>
|
||||
<string name="desc_tab_handle">Flytta denna flik</string>
|
||||
<string name="desc_no_cover">Albumomslag</string>
|
||||
<string name="desc_selection_image">Urvalbild</string>
|
||||
<string name="clr_deep_purple">Mörklila</string>
|
||||
<string name="clr_indigo">Indigo</string>
|
||||
<string name="fmt_disc_no">Disk %d</string>
|
||||
<string name="set_save_state">Spara uppspelningsläge</string>
|
||||
<string name="desc_skip_next">Hoppa till nästa spår</string>
|
||||
<string name="desc_skip_prev">Hoppa till sista spår</string>
|
||||
<string name="desc_change_repeat">Ändra upprepningsläge</string>
|
||||
<string name="desc_shuffle">Slå på eller av blandningen</string>
|
||||
<string name="desc_album_cover">Albumomslag för %s</string>
|
||||
<string name="desc_artist_image">Konstnärbild för %s</string>
|
||||
<string name="def_playback">Ingen musik spelas</string>
|
||||
<string name="cdc_flac">Fritt tapsfritt ljudkodek (FLAC)</string>
|
||||
<string name="clr_pink">Rosa</string>
|
||||
<string name="fmt_indexing">Laddar ditt musikbibliotek… (%1$d/%2$d)</string>
|
||||
<string name="set_separators_and">Ampersand (&)</string>
|
||||
<string name="set_replay_gain">ReplayGain</string>
|
||||
<string name="set_replay_gain_mode_track">Föredra spår</string>
|
||||
<string name="set_replay_gain_mode_album">Föredra album</string>
|
||||
<string name="set_replay_gain_mode_dynamic">Föredra album om ett album spelar</string>
|
||||
<string name="set_pre_amp_desc">Förförstarkning användas för befintliga justeringar vid uppspelning</string>
|
||||
<string name="clr_red">Röd</string>
|
||||
</resources>
|
|
@ -197,7 +197,7 @@
|
|||
<string name="lbl_single">Tekli</string>
|
||||
<string name="lbl_mixtape">Karışık kaset</string>
|
||||
<string name="lbl_compilation_live">Canlı derleme</string>
|
||||
<string name="lbl_compilation_remix">Remiks derlemeler</string>
|
||||
<string name="lbl_compilation_remix">Remiks derlemesi</string>
|
||||
<string name="lbl_equalizer">Ekolayzır</string>
|
||||
<string name="lbl_ep_live">Canlı EP</string>
|
||||
<string name="lbl_ep_remix">Remiks EP</string>
|
||||
|
@ -228,8 +228,8 @@
|
|||
<item quantity="one">%d sanatçı</item>
|
||||
<item quantity="other">%d sanatçılar</item>
|
||||
</plurals>
|
||||
<string name="lbl_mixes">Karmalar</string>
|
||||
<string name="lbl_mix">Karma</string>
|
||||
<string name="lbl_mixes">DJ Miksleri</string>
|
||||
<string name="lbl_mix">DJ Mix</string>
|
||||
<string name="set_rescan_desc">Etiket önbelleğini temizleyin ve müzik kitaplığını tamamen yeniden yükleyin (daha yavaş, ancak daha eksiksiz)</string>
|
||||
<string name="set_separators">Çok değerli ayırıcılar</string>
|
||||
<string name="set_separators_desc">Birden fazla etiket değerini ifade eden karakterleri yapılandırın</string>
|
||||
|
@ -278,4 +278,30 @@
|
|||
<string name="lbl_rename">Yeniden Adlandır</string>
|
||||
<string name="lbl_rename_playlist">Oynatma Listesini Yeniden Adlandır</string>
|
||||
<string name="lbl_confirm_delete_playlist">Oynatma listesini silmek istiyor musun\?</string>
|
||||
<string name="lbl_sort_direction">Yön</string>
|
||||
<string name="desc_selection_image">Seçim görüntüsü</string>
|
||||
<string name="lbl_selection">Seçim</string>
|
||||
<string name="set_play_song_by_itself">Şarkıyı kendi kendine çal</string>
|
||||
<string name="fmt_def_playlist">Çalma listesi %d</string>
|
||||
<string name="lng_playlist_created">Oynatma listesi oluşturuldu</string>
|
||||
<string name="lbl_show_error_info">Daha fazla</string>
|
||||
<string name="def_disc">Disk yok</string>
|
||||
<string name="lbl_copied">Kopyalandı</string>
|
||||
<string name="lbl_playlist_add">Çalma listesine ekle</string>
|
||||
<string name="lbl_share">Paylaş</string>
|
||||
<string name="lbl_edit">Düzenle</string>
|
||||
<string name="lng_playlist_added">Çalma listesine eklendi</string>
|
||||
<string name="def_song_count">Şarkı yok</string>
|
||||
<string name="set_square_covers_desc">Tüm albüm kapaklarını 1:1 en boy oranına kırp</string>
|
||||
<string name="fmt_editing">%s düzenleniyor</string>
|
||||
<string name="lbl_sort_mode">Göre sırala</string>
|
||||
<string name="lbl_parent_detail">Görünüm</string>
|
||||
<string name="lbl_song">Şarkı</string>
|
||||
<string name="lng_playlist_deleted">Çalma listesi silindi</string>
|
||||
<string name="lbl_report">Rapor</string>
|
||||
<string name="lbl_error_info">Hata bilgisi</string>
|
||||
<string name="set_square_covers">Kare albüm kapaklarına zorla</string>
|
||||
<string name="lng_playlist_renamed">Çalma listesi yeniden adlandırıldı</string>
|
||||
<string name="fmt_deletion_info">%s silinsin mi\? Geri alınamaz.</string>
|
||||
<string name="lbl_appears_on">Üzerinde görünür</string>
|
||||
</resources>
|
|
@ -306,4 +306,8 @@
|
|||
<string name="lbl_sort_direction">Напрямок</string>
|
||||
<string name="lbl_selection">Вибрати</string>
|
||||
<string name="desc_selection_image">Вибрати зображення</string>
|
||||
<string name="lbl_show_error_info">Докладніше</string>
|
||||
<string name="lbl_error_info">Інформація про помилку</string>
|
||||
<string name="lbl_copied">Скопійовано</string>
|
||||
<string name="lbl_report">Звіт</string>
|
||||
</resources>
|
|
@ -300,4 +300,8 @@
|
|||
<string name="lbl_sort_direction">说明</string>
|
||||
<string name="lbl_selection">选择</string>
|
||||
<string name="desc_selection_image">选择图片</string>
|
||||
<string name="lbl_report">报告</string>
|
||||
<string name="lbl_show_error_info">更多</string>
|
||||
<string name="lbl_copied">已复制</string>
|
||||
<string name="lbl_error_info">错误信息</string>
|
||||
</resources>
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* FakeMusic.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import android.net.Uri
|
||||
import org.oxycblt.auxio.music.fs.MimeType
|
||||
import org.oxycblt.auxio.music.fs.Path
|
||||
import org.oxycblt.auxio.music.info.Date
|
||||
import org.oxycblt.auxio.music.info.Disc
|
||||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.music.info.ReleaseType
|
||||
|
||||
open class FakeSong : Song {
|
||||
override val name: Name
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val date: Date?
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val dateAdded: Long
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val disc: Disc?
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val mimeType: MimeType
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val track: Int?
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val path: Path
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val size: Long
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val uri: Uri
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val album: Album
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val durationMs: Long
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val uid: Music.UID
|
||||
get() = throw NotImplementedError()
|
||||
}
|
||||
|
||||
open class FakeAlbum : Album {
|
||||
override val name: Name
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val coverUri: Uri
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val dateAdded: Long
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val dates: Date.Range?
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val releaseType: ReleaseType
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val durationMs: Long
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val songs: List<Song>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val uid: Music.UID
|
||||
get() = throw NotImplementedError()
|
||||
}
|
||||
|
||||
open class FakeArtist : Artist {
|
||||
override val name: Name
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val albums: List<Album>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val explicitAlbums: List<Album>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val implicitAlbums: List<Album>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val durationMs: Long
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val songs: List<Song>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val uid: Music.UID
|
||||
get() = throw NotImplementedError()
|
||||
}
|
||||
|
||||
open class FakeGenre : Genre {
|
||||
override val name: Name
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val durationMs: Long
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val songs: List<Song>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val uid: Music.UID
|
||||
get() = throw NotImplementedError()
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* FakeMusicRepository.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import kotlinx.coroutines.Job
|
||||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
||||
import org.oxycblt.auxio.music.user.UserLibrary
|
||||
|
||||
open class FakeMusicRepository : MusicRepository {
|
||||
override val indexingState: IndexingState?
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val deviceLibrary: DeviceLibrary?
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val userLibrary: UserLibrary?
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override fun addUpdateListener(listener: MusicRepository.UpdateListener) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun removeUpdateListener(listener: MusicRepository.UpdateListener) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun addIndexingListener(listener: MusicRepository.IndexingListener) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun removeIndexingListener(listener: MusicRepository.IndexingListener) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun registerWorker(worker: MusicRepository.IndexingWorker) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun unregisterWorker(worker: MusicRepository.IndexingWorker) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun find(uid: Music.UID): Music? {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override suspend fun createPlaylist(name: String, songs: List<Song>) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override suspend fun renamePlaylist(playlist: Playlist, name: String) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override suspend fun deletePlaylist(playlist: Playlist) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override suspend fun addToPlaylist(songs: List<Song>, playlist: Playlist) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun requestIndex(withCache: Boolean) {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun index(worker: MusicRepository.IndexingWorker, withCache: Boolean): Job {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* FakeMusicSettings.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import org.oxycblt.auxio.list.sort.Sort
|
||||
import org.oxycblt.auxio.music.fs.MusicDirectories
|
||||
|
||||
open class FakeMusicSettings : MusicSettings {
|
||||
override fun registerListener(listener: MusicSettings.Listener) = throw NotImplementedError()
|
||||
|
||||
override fun unregisterListener(listener: MusicSettings.Listener) = throw NotImplementedError()
|
||||
|
||||
override var musicDirs: MusicDirectories
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override val excludeNonMusic: Boolean
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val shouldBeObserving: Boolean
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override var multiValueSeparators: String
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override val intelligentSorting: Boolean
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override var songSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override var albumSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override var artistSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override var genreSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override var playlistSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override var albumSongSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override var artistSongSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
|
||||
override var genreSongSort: Sort
|
||||
get() = throw NotImplementedError()
|
||||
set(_) = throw NotImplementedError()
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* MusicModeTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class MusicModeTest {
|
||||
@Test
|
||||
fun intCode() {
|
||||
assertEquals(MusicType.SONGS, MusicType.fromIntCode(MusicType.SONGS.intCode))
|
||||
assertEquals(MusicType.ALBUMS, MusicType.fromIntCode(MusicType.ALBUMS.intCode))
|
||||
assertEquals(MusicType.ARTISTS, MusicType.fromIntCode(MusicType.ARTISTS.intCode))
|
||||
assertEquals(MusicType.GENRES, MusicType.fromIntCode(MusicType.GENRES.intCode))
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* MusicViewModelTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
||||
import org.oxycblt.auxio.music.device.FakeDeviceLibrary
|
||||
import org.oxycblt.auxio.util.forceClear
|
||||
|
||||
class MusicViewModelTest {
|
||||
@Test
|
||||
fun indexerState() {
|
||||
val indexer =
|
||||
TestMusicRepository().apply {
|
||||
indexingState = IndexingState.Indexing(IndexingProgress.Indeterminate)
|
||||
}
|
||||
val musicViewModel = MusicViewModel(indexer, FakeMusicSettings())
|
||||
assertTrue(indexer.updateListener is MusicViewModel)
|
||||
assertTrue(indexer.indexingListener is MusicViewModel)
|
||||
assertEquals(
|
||||
IndexingProgress.Indeterminate,
|
||||
(musicViewModel.indexingState.value as IndexingState.Indexing).progress)
|
||||
indexer.indexingState = null
|
||||
assertEquals(null, musicViewModel.indexingState.value)
|
||||
musicViewModel.forceClear()
|
||||
assertTrue(indexer.indexingListener == null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun statistics() {
|
||||
val musicRepository = TestMusicRepository()
|
||||
val musicViewModel = MusicViewModel(musicRepository, FakeMusicSettings())
|
||||
assertEquals(null, musicViewModel.statistics.value)
|
||||
musicRepository.deviceLibrary = TestDeviceLibrary()
|
||||
assertEquals(
|
||||
MusicViewModel.Statistics(
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
161616 * 2,
|
||||
),
|
||||
musicViewModel.statistics.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun requests() {
|
||||
val indexer = TestMusicRepository()
|
||||
val musicViewModel = MusicViewModel(indexer, FakeMusicSettings())
|
||||
musicViewModel.refresh()
|
||||
musicViewModel.rescan()
|
||||
assertEquals(listOf(true, false), indexer.requests)
|
||||
}
|
||||
|
||||
private class TestMusicRepository : FakeMusicRepository() {
|
||||
override var deviceLibrary: DeviceLibrary? = null
|
||||
set(value) {
|
||||
field = value
|
||||
updateListener?.onMusicChanges(
|
||||
MusicRepository.Changes(deviceLibrary = true, userLibrary = false))
|
||||
}
|
||||
|
||||
override var indexingState: IndexingState? = null
|
||||
set(value) {
|
||||
field = value
|
||||
indexingListener?.onIndexingStateChanged()
|
||||
}
|
||||
|
||||
var updateListener: MusicRepository.UpdateListener? = null
|
||||
var indexingListener: MusicRepository.IndexingListener? = null
|
||||
val requests = mutableListOf<Boolean>()
|
||||
|
||||
override fun addUpdateListener(listener: MusicRepository.UpdateListener) {
|
||||
listener.onMusicChanges(
|
||||
MusicRepository.Changes(deviceLibrary = true, userLibrary = false))
|
||||
this.updateListener = listener
|
||||
}
|
||||
|
||||
override fun removeUpdateListener(listener: MusicRepository.UpdateListener) {
|
||||
this.updateListener = null
|
||||
}
|
||||
|
||||
override fun addIndexingListener(listener: MusicRepository.IndexingListener) {
|
||||
listener.onIndexingStateChanged()
|
||||
this.indexingListener = listener
|
||||
}
|
||||
|
||||
override fun removeIndexingListener(listener: MusicRepository.IndexingListener) {
|
||||
this.indexingListener = null
|
||||
}
|
||||
|
||||
override fun requestIndex(withCache: Boolean) {
|
||||
requests.add(withCache)
|
||||
}
|
||||
}
|
||||
|
||||
private class TestDeviceLibrary : FakeDeviceLibrary() {
|
||||
override val songs: List<Song>
|
||||
get() = listOf(TestSong(), TestSong())
|
||||
|
||||
override val albums: List<Album>
|
||||
get() = listOf(FakeAlbum(), FakeAlbum(), FakeAlbum())
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = listOf(FakeArtist(), FakeArtist(), FakeArtist(), FakeArtist())
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = listOf(FakeGenre())
|
||||
}
|
||||
|
||||
private class TestSong : FakeSong() {
|
||||
override val durationMs: Long
|
||||
get() = 161616
|
||||
}
|
||||
}
|
266
app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt
vendored
Normal file
266
app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt
vendored
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* CacheRepositoryTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.cache
|
||||
|
||||
import io.mockk.Runs
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerifyAll
|
||||
import io.mockk.coVerifySequence
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import java.lang.IllegalStateException
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.oxycblt.auxio.music.device.RawSong
|
||||
import org.oxycblt.auxio.music.info.Date
|
||||
|
||||
class CacheRepositoryTest {
|
||||
@Test
|
||||
fun cache_read_noInvalidate() {
|
||||
val dao =
|
||||
mockk<CachedSongsDao> {
|
||||
coEvery { readSongs() }.returnsMany(listOf(CACHED_SONG_A, CACHED_SONG_B))
|
||||
}
|
||||
val cacheRepository = CacheRepositoryImpl(dao)
|
||||
val cache = requireNotNull(runBlocking { cacheRepository.readCache() })
|
||||
coVerifyAll { dao.readSongs() }
|
||||
assertFalse(cache.invalidated)
|
||||
|
||||
val songA = RawSong(mediaStoreId = 0, dateAdded = 1, dateModified = 2)
|
||||
assertTrue(cache.populate(songA))
|
||||
assertEquals(RAW_SONG_A, songA)
|
||||
|
||||
assertFalse(cache.invalidated)
|
||||
|
||||
val songB = RawSong(mediaStoreId = 9, dateAdded = 10, dateModified = 11)
|
||||
assertTrue(cache.populate(songB))
|
||||
assertEquals(RAW_SONG_B, songB)
|
||||
|
||||
assertFalse(cache.invalidated)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cache_read_invalidate() {
|
||||
val dao =
|
||||
mockk<CachedSongsDao> {
|
||||
coEvery { readSongs() }.returnsMany(listOf(CACHED_SONG_A, CACHED_SONG_B))
|
||||
}
|
||||
val cacheRepository = CacheRepositoryImpl(dao)
|
||||
val cache = requireNotNull(runBlocking { cacheRepository.readCache() })
|
||||
coVerifyAll { dao.readSongs() }
|
||||
assertFalse(cache.invalidated)
|
||||
|
||||
val nullStart = RawSong(mediaStoreId = 0, dateAdded = 0, dateModified = 0)
|
||||
val nullEnd = RawSong(mediaStoreId = 0, dateAdded = 0, dateModified = 0)
|
||||
assertFalse(cache.populate(nullStart))
|
||||
assertEquals(nullStart, nullEnd)
|
||||
|
||||
assertTrue(cache.invalidated)
|
||||
|
||||
val songB = RawSong(mediaStoreId = 9, dateAdded = 10, dateModified = 11)
|
||||
assertTrue(cache.populate(songB))
|
||||
assertEquals(RAW_SONG_B, songB)
|
||||
|
||||
assertTrue(cache.invalidated)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cache_read_crashes() {
|
||||
val dao = mockk<CachedSongsDao> { coEvery { readSongs() } throws IllegalStateException() }
|
||||
val cacheRepository = CacheRepositoryImpl(dao)
|
||||
assertEquals(null, runBlocking { cacheRepository.readCache() })
|
||||
coVerifyAll { dao.readSongs() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cache_write() {
|
||||
var currentlyStoredSongs = listOf<CachedSong>()
|
||||
val insertSongsArg = slot<List<CachedSong>>()
|
||||
val dao =
|
||||
mockk<CachedSongsDao> {
|
||||
coEvery { nukeSongs() } answers { currentlyStoredSongs = listOf() }
|
||||
|
||||
coEvery { insertSongs(capture(insertSongsArg)) } answers
|
||||
{
|
||||
currentlyStoredSongs = insertSongsArg.captured
|
||||
}
|
||||
}
|
||||
|
||||
val cacheRepository = CacheRepositoryImpl(dao)
|
||||
|
||||
val rawSongs = listOf(RAW_SONG_A, RAW_SONG_B)
|
||||
runBlocking { cacheRepository.writeCache(rawSongs) }
|
||||
|
||||
val cachedSongs = listOf(CACHED_SONG_A, CACHED_SONG_B)
|
||||
coVerifySequence {
|
||||
dao.nukeSongs()
|
||||
dao.insertSongs(cachedSongs)
|
||||
}
|
||||
assertEquals(cachedSongs, currentlyStoredSongs)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cache_write_nukeCrashes() {
|
||||
val dao =
|
||||
mockk<CachedSongsDao> {
|
||||
coEvery { nukeSongs() } throws IllegalStateException()
|
||||
coEvery { insertSongs(listOf()) } just Runs
|
||||
}
|
||||
val cacheRepository = CacheRepositoryImpl(dao)
|
||||
runBlocking { cacheRepository.writeCache(listOf()) }
|
||||
coVerifyAll { dao.nukeSongs() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cache_write_insertCrashes() {
|
||||
val dao =
|
||||
mockk<CachedSongsDao> {
|
||||
coEvery { nukeSongs() } just Runs
|
||||
coEvery { insertSongs(listOf()) } throws IllegalStateException()
|
||||
}
|
||||
val cacheRepository = CacheRepositoryImpl(dao)
|
||||
runBlocking { cacheRepository.writeCache(listOf()) }
|
||||
coVerifySequence {
|
||||
dao.nukeSongs()
|
||||
dao.insertSongs(listOf())
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val CACHED_SONG_A =
|
||||
CachedSong(
|
||||
mediaStoreId = 0,
|
||||
dateAdded = 1,
|
||||
dateModified = 2,
|
||||
size = 3,
|
||||
durationMs = 4,
|
||||
replayGainTrackAdjustment = 5.5f,
|
||||
replayGainAlbumAdjustment = 6.6f,
|
||||
musicBrainzId = "Song MBID A",
|
||||
name = "Song Name A",
|
||||
sortName = "Song Sort Name A",
|
||||
track = 7,
|
||||
disc = 8,
|
||||
subtitle = "Subtitle A",
|
||||
date = Date.from("2020-10-10"),
|
||||
albumMusicBrainzId = "Album MBID A",
|
||||
albumName = "Album Name A",
|
||||
albumSortName = "Album Sort Name A",
|
||||
releaseTypes = listOf("Release Type A"),
|
||||
artistMusicBrainzIds = listOf("Artist MBID A"),
|
||||
artistNames = listOf("Artist Name A"),
|
||||
artistSortNames = listOf("Artist Sort Name A"),
|
||||
albumArtistMusicBrainzIds = listOf("Album Artist MBID A"),
|
||||
albumArtistNames = listOf("Album Artist Name A"),
|
||||
albumArtistSortNames = listOf("Album Artist Sort Name A"),
|
||||
genreNames = listOf("Genre Name A"),
|
||||
)
|
||||
|
||||
val RAW_SONG_A =
|
||||
RawSong(
|
||||
mediaStoreId = 0,
|
||||
dateAdded = 1,
|
||||
dateModified = 2,
|
||||
size = 3,
|
||||
durationMs = 4,
|
||||
replayGainTrackAdjustment = 5.5f,
|
||||
replayGainAlbumAdjustment = 6.6f,
|
||||
musicBrainzId = "Song MBID A",
|
||||
name = "Song Name A",
|
||||
sortName = "Song Sort Name A",
|
||||
track = 7,
|
||||
disc = 8,
|
||||
subtitle = "Subtitle A",
|
||||
date = Date.from("2020-10-10"),
|
||||
albumMusicBrainzId = "Album MBID A",
|
||||
albumName = "Album Name A",
|
||||
albumSortName = "Album Sort Name A",
|
||||
releaseTypes = listOf("Release Type A"),
|
||||
artistMusicBrainzIds = listOf("Artist MBID A"),
|
||||
artistNames = listOf("Artist Name A"),
|
||||
artistSortNames = listOf("Artist Sort Name A"),
|
||||
albumArtistMusicBrainzIds = listOf("Album Artist MBID A"),
|
||||
albumArtistNames = listOf("Album Artist Name A"),
|
||||
albumArtistSortNames = listOf("Album Artist Sort Name A"),
|
||||
genreNames = listOf("Genre Name A"),
|
||||
)
|
||||
|
||||
val CACHED_SONG_B =
|
||||
CachedSong(
|
||||
mediaStoreId = 9,
|
||||
dateAdded = 10,
|
||||
dateModified = 11,
|
||||
size = 12,
|
||||
durationMs = 13,
|
||||
replayGainTrackAdjustment = 14.14f,
|
||||
replayGainAlbumAdjustment = 15.15f,
|
||||
musicBrainzId = "Song MBID B",
|
||||
name = "Song Name B",
|
||||
sortName = "Song Sort Name B",
|
||||
track = 16,
|
||||
disc = 17,
|
||||
subtitle = "Subtitle B",
|
||||
date = Date.from("2021-11-11"),
|
||||
albumMusicBrainzId = "Album MBID B",
|
||||
albumName = "Album Name B",
|
||||
albumSortName = "Album Sort Name B",
|
||||
releaseTypes = listOf("Release Type B"),
|
||||
artistMusicBrainzIds = listOf("Artist MBID B"),
|
||||
artistNames = listOf("Artist Name B"),
|
||||
artistSortNames = listOf("Artist Sort Name B"),
|
||||
albumArtistMusicBrainzIds = listOf("Album Artist MBID B"),
|
||||
albumArtistNames = listOf("Album Artist Name B"),
|
||||
albumArtistSortNames = listOf("Album Artist Sort Name B"),
|
||||
genreNames = listOf("Genre Name B"),
|
||||
)
|
||||
|
||||
val RAW_SONG_B =
|
||||
RawSong(
|
||||
mediaStoreId = 9,
|
||||
dateAdded = 10,
|
||||
dateModified = 11,
|
||||
size = 12,
|
||||
durationMs = 13,
|
||||
replayGainTrackAdjustment = 14.14f,
|
||||
replayGainAlbumAdjustment = 15.15f,
|
||||
musicBrainzId = "Song MBID B",
|
||||
name = "Song Name B",
|
||||
sortName = "Song Sort Name B",
|
||||
track = 16,
|
||||
disc = 17,
|
||||
subtitle = "Subtitle B",
|
||||
date = Date.from("2021-11-11"),
|
||||
albumMusicBrainzId = "Album MBID B",
|
||||
albumName = "Album Name B",
|
||||
albumSortName = "Album Sort Name B",
|
||||
releaseTypes = listOf("Release Type B"),
|
||||
artistMusicBrainzIds = listOf("Artist MBID B"),
|
||||
artistNames = listOf("Artist Name B"),
|
||||
artistSortNames = listOf("Artist Sort Name B"),
|
||||
albumArtistMusicBrainzIds = listOf("Album Artist MBID B"),
|
||||
albumArtistNames = listOf("Album Artist Name B"),
|
||||
albumArtistSortNames = listOf("Album Artist Sort Name B"),
|
||||
genreNames = listOf("Genre Name B"),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* DeviceMusicImplTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.device
|
||||
|
||||
import java.util.UUID
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class DeviceMusicImplTest {
|
||||
@Test
|
||||
fun albumRaw_equals_inconsistentCase() {
|
||||
val a =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = null,
|
||||
name = "Paraglow",
|
||||
sortName = null,
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Parannoul"), RawArtist(name = "Asian Glow")))
|
||||
val b =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = null,
|
||||
name = "paraglow",
|
||||
sortName = null,
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Parannoul"), RawArtist(name = "Asian glow")))
|
||||
assertTrue(a == b)
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun albumRaw_equals_withMbids() {
|
||||
val a =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = UUID.fromString("c7b245c9-8099-32ea-af95-893acedde2cf"),
|
||||
name = "Weezer",
|
||||
sortName = "Blue Album",
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Weezer")))
|
||||
val b =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = UUID.fromString("923d5ba6-7eee-3bce-bcb2-c913b2bd69d4"),
|
||||
name = "Weezer",
|
||||
sortName = "Green Album",
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Weezer")))
|
||||
assertTrue(a != b)
|
||||
assertTrue(a.hashCode() != b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun albumRaw_equals_inconsistentMbids() {
|
||||
val a =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = UUID.fromString("c7b245c9-8099-32ea-af95-893acedde2cf"),
|
||||
name = "Weezer",
|
||||
sortName = "Blue Album",
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Weezer")))
|
||||
val b =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = null,
|
||||
name = "Weezer",
|
||||
sortName = "Green Album",
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Weezer")))
|
||||
assertTrue(a != b)
|
||||
assertTrue(a.hashCode() != b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun albumRaw_equals_withArtists() {
|
||||
val a =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = null,
|
||||
name = "Album",
|
||||
sortName = null,
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Artist A")))
|
||||
val b =
|
||||
RawAlbum(
|
||||
mediaStoreId = -1,
|
||||
musicBrainzId = null,
|
||||
name = "Album",
|
||||
sortName = null,
|
||||
releaseType = null,
|
||||
rawArtists = listOf(RawArtist(name = "Artist B")))
|
||||
assertTrue(a != b)
|
||||
assertTrue(a.hashCode() != b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun artistRaw_equals_inconsistentCase() {
|
||||
val a = RawArtist(musicBrainzId = null, name = "Parannoul")
|
||||
val b = RawArtist(musicBrainzId = null, name = "parannoul")
|
||||
assertTrue(a == b)
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun artistRaw_equals_withMbids() {
|
||||
val a =
|
||||
RawArtist(
|
||||
musicBrainzId = UUID.fromString("677325ef-d850-44bb-8258-0d69bbc0b3f7"),
|
||||
name = "Artist")
|
||||
val b =
|
||||
RawArtist(
|
||||
musicBrainzId = UUID.fromString("6b625592-d88d-48c8-ac1a-c5b476d78bcc"),
|
||||
name = "Artist")
|
||||
assertTrue(a != b)
|
||||
assertTrue(a.hashCode() != b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun artistRaw_equals_inconsistentMbids() {
|
||||
val a =
|
||||
RawArtist(
|
||||
musicBrainzId = UUID.fromString("677325ef-d850-44bb-8258-0d69bbc0b3f7"),
|
||||
name = "Artist")
|
||||
val b = RawArtist(musicBrainzId = null, name = "Artist")
|
||||
assertTrue(a != b)
|
||||
assertTrue(a.hashCode() != b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun artistRaw_equals_missingNames() {
|
||||
val a = RawArtist(name = null)
|
||||
val b = RawArtist(name = null)
|
||||
assertTrue(a == b)
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun artistRaw_equals_inconsistentNames() {
|
||||
val a = RawArtist(name = null)
|
||||
val b = RawArtist(name = "Parannoul")
|
||||
assertTrue(a != b)
|
||||
assertTrue(a.hashCode() != b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun genreRaw_equals_inconsistentCase() {
|
||||
val a = RawGenre("Future Garage")
|
||||
val b = RawGenre("future garage")
|
||||
assertTrue(a == b)
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun genreRaw_equals_missingNames() {
|
||||
val a = RawGenre(name = null)
|
||||
val b = RawGenre(name = null)
|
||||
assertTrue(a == b)
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun genreRaw_equals_inconsistentNames() {
|
||||
val a = RawGenre(name = null)
|
||||
val b = RawGenre(name = "Future Garage")
|
||||
assertTrue(a != b)
|
||||
assertTrue(a.hashCode() != b.hashCode())
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* FakeDeviceLibrary.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.device
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Song
|
||||
|
||||
open class FakeDeviceLibrary : DeviceLibrary {
|
||||
override val songs: List<Song>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val albums: List<Album>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val artists: List<Artist>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override val genres: List<Genre>
|
||||
get() = throw NotImplementedError()
|
||||
|
||||
override fun findSong(uid: Music.UID): Song? {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun findSongForUri(context: Context, uri: Uri): Song? {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun findAlbum(uid: Music.UID): Album? {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun findArtist(uid: Music.UID): Artist? {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
|
||||
override fun findGenre(uid: Music.UID): Genre? {
|
||||
throw NotImplementedError()
|
||||
}
|
||||
}
|
|
@ -88,32 +88,4 @@ class DateTest {
|
|||
assertEquals(null, Date.from("2016-08-16:00:01:02"))
|
||||
assertEquals("2016-11", Date.from("2016-11-32 25:43:01").toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dateRange_from_correct() {
|
||||
val range =
|
||||
requireNotNull(
|
||||
Date.Range.from(
|
||||
listOf(
|
||||
requireNotNull(Date.from("2016-08-16T00:01:02")),
|
||||
requireNotNull(Date.from("2016-07-16")),
|
||||
requireNotNull(Date.from("2014-03-12T00")),
|
||||
requireNotNull(Date.from("2022-12-22T22:22:22")))))
|
||||
assertEquals("2014-03-12T00Z", range.min.toString())
|
||||
assertEquals("2022-12-22T22:22:22Z", range.max.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dateRange_from_one() {
|
||||
val range =
|
||||
requireNotNull(
|
||||
Date.Range.from(listOf(requireNotNull(Date.from("2016-08-16T00:01:02")))))
|
||||
assertEquals("2016-08-16T00:01:02Z", range.min.toString())
|
||||
assertEquals("2016-08-16T00:01:02Z", range.max.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dateRange_from_none() {
|
||||
assertEquals(null, Date.Range.from(listOf()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,30 +19,36 @@
|
|||
package org.oxycblt.auxio.music.info
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class DiscTest {
|
||||
@Test
|
||||
fun disc_compare() {
|
||||
val a = Disc(1, "Part I")
|
||||
val b = Disc(2, "Part II")
|
||||
fun disc_equals_byNum() {
|
||||
val a = Disc(0, null)
|
||||
val b = Disc(0, null)
|
||||
assertEquals(a, b)
|
||||
assertEquals(a.hashCode(), b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun disc_equals_bySubtitle() {
|
||||
val a = Disc(0, "z subtitle")
|
||||
val b = Disc(0, "a subtitle")
|
||||
assertEquals(a, b)
|
||||
assertEquals(a.hashCode(), b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun disc_compareTo_byNum() {
|
||||
val a = Disc(0, null)
|
||||
val b = Disc(1, null)
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun disc_equals_correct() {
|
||||
val a = Disc(1, "Part I")
|
||||
val b = Disc(1, "Part I")
|
||||
assertTrue(a == b)
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun disc_equals_inconsistentNames() {
|
||||
val a = Disc(1, "Part I")
|
||||
val b = Disc(1, null)
|
||||
assertTrue(a == b)
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
fun disc_compareTo_bySubtitle() {
|
||||
val a = Disc(0, "z subtitle")
|
||||
val b = Disc(1, "a subtitle")
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
}
|
||||
}
|
||||
|
|
453
app/src/test/java/org/oxycblt/auxio/music/info/NameTest.kt
Normal file
453
app/src/test/java/org/oxycblt/auxio/music/info/NameTest.kt
Normal file
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* NameTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.info
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
|
||||
class NameTest {
|
||||
@Test
|
||||
fun name_simple_from_settings() {
|
||||
val musicSettings = mockk<MusicSettings> { every { intelligentSorting } returns false }
|
||||
assertTrue(Name.Known.Factory.from(musicSettings) is SimpleKnownName.Factory)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_from_settings() {
|
||||
val musicSettings = mockk<MusicSettings> { every { intelligentSorting } returns true }
|
||||
assertTrue(Name.Known.Factory.from(musicSettings) is IntelligentKnownName.Factory)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_simple_withoutPunct() {
|
||||
val name = SimpleKnownName("Loveless", null)
|
||||
assertEquals("Loveless", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("L", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("Loveless", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_simple_withPunct() {
|
||||
val name = SimpleKnownName("alt-J", null)
|
||||
assertEquals("alt-J", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("A", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("altJ", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_simple_oopsAllPunct() {
|
||||
val name = SimpleKnownName("!!!", null)
|
||||
assertEquals("!!!", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("!", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("!!!", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_simple_spacedPunct() {
|
||||
val name = SimpleKnownName("& Yet & Yet", null)
|
||||
assertEquals("& Yet & Yet", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("Y", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Yet Yet", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_simple_withSort() {
|
||||
val name = SimpleKnownName("The Smile", "Smile")
|
||||
assertEquals("The Smile", name.raw)
|
||||
assertEquals("Smile", name.sort)
|
||||
assertEquals("S", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("Smile", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withoutArticle_withoutNumerics() {
|
||||
val name = IntelligentKnownName("Loveless", null)
|
||||
assertEquals("Loveless", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("L", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("Loveless", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withoutArticle_withSpacedStartNumerics() {
|
||||
val name = IntelligentKnownName("15 Step", null)
|
||||
assertEquals("15 Step", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("#", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("15", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals("Step", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, second.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withoutArticle_withPackedStartNumerics() {
|
||||
val name = IntelligentKnownName("23Kid", null)
|
||||
assertEquals("23Kid", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("#", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("23", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals("Kid", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, second.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withoutArticle_withSpacedMiddleNumerics() {
|
||||
val name = IntelligentKnownName("Foo 1 2 Bar", null)
|
||||
assertEquals("Foo 1 2 Bar", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("F", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Foo", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals("1", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, second.type)
|
||||
val third = name.sortTokens[2]
|
||||
assertEquals(" ", third.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, third.type)
|
||||
val fourth = name.sortTokens[3]
|
||||
assertEquals("2", fourth.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, fourth.type)
|
||||
val fifth = name.sortTokens[4]
|
||||
assertEquals("Bar", fifth.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, fifth.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withoutArticle_withPackedMiddleNumerics() {
|
||||
val name = IntelligentKnownName("Foo12Bar", null)
|
||||
assertEquals("Foo12Bar", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("F", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Foo", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals("12", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, second.type)
|
||||
val third = name.sortTokens[2]
|
||||
assertEquals("Bar", third.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, third.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withoutArticle_withSpacedEndNumerics() {
|
||||
val name = IntelligentKnownName("Foo 1", null)
|
||||
assertEquals("Foo 1", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("F", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Foo", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals("1", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, second.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withoutArticle_withPackedEndNumerics() {
|
||||
val name = IntelligentKnownName("Error404", null)
|
||||
assertEquals("Error404", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("E", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Error", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals("404", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, second.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withThe_withoutNumerics() {
|
||||
val name = IntelligentKnownName("The National Anthem", null)
|
||||
assertEquals("The National Anthem", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("N", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("National Anthem", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withAn_withoutNumerics() {
|
||||
val name = IntelligentKnownName("An Eagle in Your Mind", null)
|
||||
assertEquals("An Eagle in Your Mind", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("E", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Eagle in Your Mind", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_withA_withoutNumerics() {
|
||||
val name = IntelligentKnownName("A Song For Our Fathers", null)
|
||||
assertEquals("A Song For Our Fathers", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("S", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Song For Our Fathers", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withPunct_withoutArticle_withoutNumerics() {
|
||||
val name = IntelligentKnownName("alt-J", null)
|
||||
assertEquals("alt-J", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("A", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("altJ", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_oopsAllPunct_withoutArticle_withoutNumerics() {
|
||||
val name = IntelligentKnownName("!!!", null)
|
||||
assertEquals("!!!", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("!", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("!!!", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withoutPunct_shortArticle_withNumerics() {
|
||||
val name = IntelligentKnownName("the 1", null)
|
||||
assertEquals("the 1", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("#", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("1", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, first.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_spacedPunct_withoutArticle_withoutNumerics() {
|
||||
val name = IntelligentKnownName("& Yet & Yet", null)
|
||||
assertEquals("& Yet & Yet", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("Y", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Yet Yet", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withPunct_withoutArticle_withNumerics() {
|
||||
val name = IntelligentKnownName("Design : 2 : 3", null)
|
||||
assertEquals("Design : 2 : 3", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("D", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("Design", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals("2", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, second.type)
|
||||
val third = name.sortTokens[2]
|
||||
assertEquals(" ", third.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, third.type)
|
||||
val fourth = name.sortTokens[3]
|
||||
assertEquals("3", fourth.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, fourth.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_oopsAllPunct_withoutArticle_oopsAllNumerics() {
|
||||
val name = IntelligentKnownName("2 + 2 = 5", null)
|
||||
assertEquals("2 + 2 = 5", name.raw)
|
||||
assertEquals(null, name.sort)
|
||||
assertEquals("#", name.thumb)
|
||||
val first = name.sortTokens[0]
|
||||
assertEquals("2", first.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, first.type)
|
||||
val second = name.sortTokens[1]
|
||||
assertEquals(" ", second.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, second.type)
|
||||
val third = name.sortTokens[2]
|
||||
assertEquals("2", third.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, third.type)
|
||||
val fourth = name.sortTokens[3]
|
||||
assertEquals(" ", fourth.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, fourth.type)
|
||||
val fifth = name.sortTokens[4]
|
||||
assertEquals("5", fifth.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.NUMERIC, fifth.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_intelligent_withSort() {
|
||||
val name = IntelligentKnownName("The Smile", "Smile")
|
||||
assertEquals("The Smile", name.raw)
|
||||
assertEquals("Smile", name.sort)
|
||||
assertEquals("S", name.thumb)
|
||||
val only = name.sortTokens.single()
|
||||
assertEquals("Smile", only.collationKey.sourceString)
|
||||
assertEquals(SortToken.Type.LEXICOGRAPHIC, only.type)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_equals_simple() {
|
||||
val a = SimpleKnownName("The Same", "Same")
|
||||
val b = SimpleKnownName("The Same", "Same")
|
||||
assertEquals(a, b)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_equals_differentSort() {
|
||||
val a = SimpleKnownName("The Same", "Same")
|
||||
val b = SimpleKnownName("The Same", null)
|
||||
assertNotEquals(a, b)
|
||||
assertNotEquals(a.hashCode(), b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_equals_intelligent_differentTokens() {
|
||||
val a = IntelligentKnownName("The Same", "Same")
|
||||
val b = IntelligentKnownName("Same", "Same")
|
||||
assertNotEquals(a, b)
|
||||
assertNotEquals(a.hashCode(), b.hashCode())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_simple_withoutSort_withoutArticle_withoutNumeric() {
|
||||
val a = SimpleKnownName("A", null)
|
||||
val b = SimpleKnownName("B", null)
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_simple_withoutSort_withArticle_withoutNumeric() {
|
||||
val a = SimpleKnownName("A Brain in a Bottle", null)
|
||||
val b = SimpleKnownName("Acid Rain", null)
|
||||
val c = SimpleKnownName("Boralis / Contrastellar", null)
|
||||
val d = SimpleKnownName("Breathe In", null)
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
assertEquals(-1, a.compareTo(c))
|
||||
assertEquals(-1, a.compareTo(d))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_simple_withSort_withoutArticle_withNumeric() {
|
||||
val a = SimpleKnownName("15 Step", null)
|
||||
val b = SimpleKnownName("128 Harps", null)
|
||||
val c = SimpleKnownName("1969", null)
|
||||
assertEquals(1, a.compareTo(b))
|
||||
assertEquals(-1, a.compareTo(c))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_simple_withPartialSort() {
|
||||
val a = SimpleKnownName("A", "C")
|
||||
val b = SimpleKnownName("B", null)
|
||||
assertEquals(1, a.compareTo(b))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_simple_withSort() {
|
||||
val a = SimpleKnownName("D", "A")
|
||||
val b = SimpleKnownName("C", "B")
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_intelligent_withoutSort_withoutArticle_withoutNumeric() {
|
||||
val a = IntelligentKnownName("A", null)
|
||||
val b = IntelligentKnownName("B", null)
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_intelligent_withoutSort_withArticle_withoutNumeric() {
|
||||
val a = IntelligentKnownName("A Brain in a Bottle", null)
|
||||
val b = IntelligentKnownName("Acid Rain", null)
|
||||
val c = IntelligentKnownName("Boralis / Contrastellar", null)
|
||||
val d = IntelligentKnownName("Breathe In", null)
|
||||
assertEquals(1, a.compareTo(b))
|
||||
assertEquals(1, a.compareTo(c))
|
||||
assertEquals(-1, a.compareTo(d))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_intelligent_withoutSort_withoutArticle_withNumeric() {
|
||||
val a = IntelligentKnownName("15 Step", null)
|
||||
val b = IntelligentKnownName("128 Harps", null)
|
||||
val c = IntelligentKnownName("1969", null)
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
assertEquals(-1, b.compareTo(c))
|
||||
assertEquals(-2, a.compareTo(c))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_intelligent_withPartialSort_withoutArticle_withoutNumeric() {
|
||||
val a = SimpleKnownName("A", "C")
|
||||
val b = SimpleKnownName("B", null)
|
||||
assertEquals(1, a.compareTo(b))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_intelligent_withSort_withoutArticle_withoutNumeric() {
|
||||
val a = IntelligentKnownName("D", "A")
|
||||
val b = IntelligentKnownName("C", "B")
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_unknown() {
|
||||
val a = Name.Unknown(0)
|
||||
assertEquals("?", a.thumb)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun name_compareTo_mixed() {
|
||||
val a = Name.Unknown(0)
|
||||
val b = IntelligentKnownName("A", null)
|
||||
assertEquals(-1, a.compareTo(b))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* SeparatorsTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.metadata
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class SeparatorsTest {
|
||||
@Test
|
||||
fun separators_split_withString_withSingleChar() {
|
||||
assertEquals(listOf("a", "b", "c"), Separators.from(",").split(listOf("a,b,c")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun separators_split_withMultiple_withSingleChar() {
|
||||
assertEquals(listOf("a,b", "c", "d"), Separators.from(",").split(listOf("a,b", "c", "d")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun separators_split_withString_withMultipleChar() {
|
||||
assertEquals(
|
||||
listOf("a", "b", "c", "d", "e", "f"),
|
||||
Separators.from(",;/+&").split(listOf("a,b;c/d+e&f")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun separators_split_withList_withMultipleChar() {
|
||||
assertEquals(
|
||||
listOf("a,b;c/d", "e&f"), Separators.from(",;/+&").split(listOf("a,b;c/d", "e&f")))
|
||||
}
|
||||
}
|
|
@ -20,27 +20,8 @@ package org.oxycblt.auxio.music.metadata
|
|||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.oxycblt.auxio.music.FakeMusicSettings
|
||||
|
||||
class TagUtilTest {
|
||||
@Test
|
||||
fun parseMultiValue_single() {
|
||||
assertEquals(listOf("a", "b", "c"), listOf("a,b,c").parseMultiValue(TestMusicSettings(",")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseMultiValue_many() {
|
||||
assertEquals(
|
||||
listOf("a", "b", "c"), listOf("a", "b", "c").parseMultiValue(TestMusicSettings(",")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseMultiValue_several() {
|
||||
assertEquals(
|
||||
listOf("a", "b", "c", "d", "e", "f"),
|
||||
listOf("a,b;c/d+e&f").parseMultiValue(TestMusicSettings(",;/+&")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun splitEscaped_correct() {
|
||||
assertEquals(listOf("a", "b", "c"), "a,b,c".splitEscaped { it == ',' })
|
||||
|
@ -131,43 +112,30 @@ class TagUtilTest {
|
|||
fun parseId3v2Genre_multi() {
|
||||
assertEquals(
|
||||
listOf("Post-Rock", "Shoegaze", "Glitch"),
|
||||
listOf("Post-Rock", "Shoegaze", "Glitch").parseId3GenreNames(TestMusicSettings(",")))
|
||||
listOf("Post-Rock", "Shoegaze", "Glitch").parseId3GenreNames())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseId3v2Genre_multiId3v1() {
|
||||
assertEquals(
|
||||
listOf("Post-Rock", "Shoegaze", "Glitch"),
|
||||
listOf("176", "178", "Glitch").parseId3GenreNames(TestMusicSettings(",")))
|
||||
listOf("176", "178", "Glitch").parseId3GenreNames())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseId3v2Genre_wackId3() {
|
||||
assertEquals(listOf("2941"), listOf("2941").parseId3GenreNames(TestMusicSettings(",")))
|
||||
assertEquals(null, listOf("2941").parseId3GenreNames())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseId3v2Genre_singleId3v23() {
|
||||
assertEquals(
|
||||
listOf("Post-Rock", "Shoegaze", "Remix", "Cover", "Glitch"),
|
||||
listOf("(176)(178)(RX)(CR)Glitch").parseId3GenreNames(TestMusicSettings(",")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseId3v2Genre_singleSeparated() {
|
||||
assertEquals(
|
||||
listOf("Post-Rock", "Shoegaze", "Glitch"),
|
||||
listOf("Post-Rock, Shoegaze, Glitch").parseId3GenreNames(TestMusicSettings(",")))
|
||||
listOf("(176)(178)(RX)(CR)Glitch").parseId3GenreNames())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parsId3v2Genre_singleId3v1() {
|
||||
assertEquals(listOf("Post-Rock"), listOf("176").parseId3GenreNames(TestMusicSettings(",")))
|
||||
}
|
||||
|
||||
class TestMusicSettings(private val separators: String) : FakeMusicSettings() {
|
||||
override var multiValueSeparators: String
|
||||
get() = separators
|
||||
set(_) = throw NotImplementedError()
|
||||
assertEquals(listOf("Post-Rock"), listOf("176").parseId3GenreNames())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ class TextTagsTest {
|
|||
assertEquals(listOf("2022"), textTags.vorbis["date"])
|
||||
assertEquals(listOf("ep"), textTags.vorbis["releasetype"])
|
||||
assertEquals(listOf("+2 dB"), textTags.vorbis["replaygain_track_gain"])
|
||||
assertEquals(null, textTags.id3v2["APIC"])
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -51,10 +52,24 @@ class TextTagsTest {
|
|||
assertEquals(listOf("2022"), textTags.id3v2["TDRC"])
|
||||
assertEquals(listOf("ep"), textTags.id3v2["TXXX:musicbrainz album type"])
|
||||
assertEquals(listOf("+2 dB"), textTags.id3v2["TXXX:replaygain_track_gain"])
|
||||
assertEquals(null, textTags.id3v2["metadata_block_picture"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun textTags_combined() {
|
||||
fun textTags_mp4() {
|
||||
val textTags = TextTags(MP4_METADATA)
|
||||
assertTrue(textTags.vorbis.isEmpty())
|
||||
assertEquals(listOf("Wheel"), textTags.id3v2["TIT2"])
|
||||
assertEquals(listOf("Paraglow"), textTags.id3v2["TALB"])
|
||||
assertEquals(listOf("Parannoul", "Asian Glow"), textTags.id3v2["TPE1"])
|
||||
assertEquals(listOf("2022"), textTags.id3v2["TDRC"])
|
||||
assertEquals(listOf("ep"), textTags.id3v2["TXXX:musicbrainz album type"])
|
||||
assertEquals(listOf("+2 dB"), textTags.id3v2["TXXX:replaygain_track_gain"])
|
||||
assertEquals(null, textTags.id3v2["metadata_block_picture"])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun textTags_id3v2_vorbis_combined() {
|
||||
val textTags = TextTags(VORBIS_METADATA.copyWithAppendedEntriesFrom(ID3V2_METADATA))
|
||||
assertEquals(listOf("Wheel"), textTags.vorbis["title"])
|
||||
assertEquals(listOf("Paraglow"), textTags.vorbis["album"])
|
||||
|
@ -62,10 +77,13 @@ class TextTagsTest {
|
|||
assertEquals(listOf("2022"), textTags.vorbis["date"])
|
||||
assertEquals(listOf("ep"), textTags.vorbis["releasetype"])
|
||||
assertEquals(listOf("+2 dB"), textTags.vorbis["replaygain_track_gain"])
|
||||
assertEquals(null, textTags.id3v2["metadata_block_picture"])
|
||||
|
||||
assertEquals(listOf("Wheel"), textTags.id3v2["TIT2"])
|
||||
assertEquals(listOf("Paraglow"), textTags.id3v2["TALB"])
|
||||
assertEquals(listOf("Parannoul", "Asian Glow"), textTags.id3v2["TPE1"])
|
||||
assertEquals(listOf("2022"), textTags.id3v2["TDRC"])
|
||||
assertEquals(null, textTags.id3v2["APIC"])
|
||||
assertEquals(listOf("ep"), textTags.id3v2["TXXX:musicbrainz album type"])
|
||||
assertEquals(listOf("+2 dB"), textTags.id3v2["TXXX:replaygain_track_gain"])
|
||||
}
|
||||
|
@ -90,6 +108,19 @@ class TextTagsTest {
|
|||
TextInformationFrame("TPE1", null, listOf("Parannoul", "Asian Glow")),
|
||||
TextInformationFrame("TDRC", null, listOf("2022")),
|
||||
TextInformationFrame("TXXX", "MusicBrainz Album Type", listOf("ep")),
|
||||
TextInformationFrame("TXXX", "replaygain_track_gain", listOf("+2 dB")),
|
||||
ApicFrame("", "", 0, byteArrayOf()))
|
||||
|
||||
// MP4 atoms are mapped to ID3v2 text information frames by ExoPlayer, but can
|
||||
// duplicate frames and have ---- mapped to InternalFrame.
|
||||
private val MP4_METADATA =
|
||||
Metadata(
|
||||
TextInformationFrame("TIT2", null, listOf("Wheel")),
|
||||
TextInformationFrame("TALB", null, listOf("Paraglow")),
|
||||
TextInformationFrame("TPE1", null, listOf("Parannoul")),
|
||||
TextInformationFrame("TPE1", null, listOf("Asian Glow")),
|
||||
TextInformationFrame("TDRC", null, listOf("2022")),
|
||||
TextInformationFrame("TXXX", "MusicBrainz Album Type", listOf("ep")),
|
||||
InternalFrame("com.apple.iTunes", "replaygain_track_gain", "+2 dB"),
|
||||
ApicFrame("", "", 0, byteArrayOf()))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* DeviceLibraryTest.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.music.user
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Test
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.music.device.AlbumImpl
|
||||
import org.oxycblt.auxio.music.device.ArtistImpl
|
||||
import org.oxycblt.auxio.music.device.DeviceLibraryImpl
|
||||
import org.oxycblt.auxio.music.device.GenreImpl
|
||||
import org.oxycblt.auxio.music.device.SongImpl
|
||||
|
||||
class DeviceLibraryTest {
|
||||
|
||||
@Test
|
||||
fun deviceLibrary_withSongs() {
|
||||
val songUidA = Music.UID.auxio(MusicType.SONGS)
|
||||
val songUidB = Music.UID.auxio(MusicType.SONGS)
|
||||
val songA =
|
||||
mockk<SongImpl> {
|
||||
every { uid } returns songUidA
|
||||
every { durationMs } returns 0
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val songB =
|
||||
mockk<SongImpl> {
|
||||
every { uid } returns songUidB
|
||||
every { durationMs } returns 1
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val deviceLibrary = DeviceLibraryImpl(listOf(songA, songB), listOf(), listOf(), listOf())
|
||||
verify {
|
||||
songA.finalize()
|
||||
songB.finalize()
|
||||
}
|
||||
val foundSongA = deviceLibrary.findSong(songUidA)!!
|
||||
assertEquals(songUidA, foundSongA.uid)
|
||||
assertEquals(0L, foundSongA.durationMs)
|
||||
val foundSongB = deviceLibrary.findSong(songUidB)!!
|
||||
assertEquals(songUidB, foundSongB.uid)
|
||||
assertEquals(1L, foundSongB.durationMs)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceLibrary_withAlbums() {
|
||||
val albumUidA = Music.UID.auxio(MusicType.ALBUMS)
|
||||
val albumUidB = Music.UID.auxio(MusicType.ALBUMS)
|
||||
val albumA =
|
||||
mockk<AlbumImpl> {
|
||||
every { uid } returns albumUidA
|
||||
every { durationMs } returns 0
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val albumB =
|
||||
mockk<AlbumImpl> {
|
||||
every { uid } returns albumUidB
|
||||
every { durationMs } returns 1
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val deviceLibrary = DeviceLibraryImpl(listOf(), listOf(albumA, albumB), listOf(), listOf())
|
||||
verify {
|
||||
albumA.finalize()
|
||||
albumB.finalize()
|
||||
}
|
||||
val foundAlbumA = deviceLibrary.findAlbum(albumUidA)!!
|
||||
assertEquals(albumUidA, foundAlbumA.uid)
|
||||
assertEquals(0L, foundAlbumA.durationMs)
|
||||
val foundAlbumB = deviceLibrary.findAlbum(albumUidB)!!
|
||||
assertEquals(albumUidB, foundAlbumB.uid)
|
||||
assertEquals(1L, foundAlbumB.durationMs)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceLibrary_withArtists() {
|
||||
val artistUidA = Music.UID.auxio(MusicType.ARTISTS)
|
||||
val artistUidB = Music.UID.auxio(MusicType.ARTISTS)
|
||||
val artistA =
|
||||
mockk<ArtistImpl> {
|
||||
every { uid } returns artistUidA
|
||||
every { durationMs } returns 0
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val artistB =
|
||||
mockk<ArtistImpl> {
|
||||
every { uid } returns artistUidB
|
||||
every { durationMs } returns 1
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val deviceLibrary =
|
||||
DeviceLibraryImpl(listOf(), listOf(), listOf(artistA, artistB), listOf())
|
||||
verify {
|
||||
artistA.finalize()
|
||||
artistB.finalize()
|
||||
}
|
||||
val foundArtistA = deviceLibrary.findArtist(artistUidA)!!
|
||||
assertEquals(artistUidA, foundArtistA.uid)
|
||||
assertEquals(0L, foundArtistA.durationMs)
|
||||
val foundArtistB = deviceLibrary.findArtist(artistUidB)!!
|
||||
assertEquals(artistUidB, foundArtistB.uid)
|
||||
assertEquals(1L, foundArtistB.durationMs)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceLibrary_withGenres() {
|
||||
val genreUidA = Music.UID.auxio(MusicType.GENRES)
|
||||
val genreUidB = Music.UID.auxio(MusicType.GENRES)
|
||||
val genreA =
|
||||
mockk<GenreImpl> {
|
||||
every { uid } returns genreUidA
|
||||
every { durationMs } returns 0
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val genreB =
|
||||
mockk<GenreImpl> {
|
||||
every { uid } returns genreUidB
|
||||
every { durationMs } returns 1
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val deviceLibrary = DeviceLibraryImpl(listOf(), listOf(), listOf(), listOf(genreA, genreB))
|
||||
verify {
|
||||
genreA.finalize()
|
||||
genreB.finalize()
|
||||
}
|
||||
val foundGenreA = deviceLibrary.findGenre(genreUidA)!!
|
||||
assertEquals(genreUidA, foundGenreA.uid)
|
||||
assertEquals(0L, foundGenreA.durationMs)
|
||||
val foundGenreB = deviceLibrary.findGenre(genreUidB)!!
|
||||
assertEquals(genreUidB, foundGenreB.uid)
|
||||
assertEquals(1L, foundGenreB.durationMs)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun deviceLibrary_equals() {
|
||||
val songA =
|
||||
mockk<SongImpl> {
|
||||
every { uid } returns Music.UID.auxio(MusicType.SONGS)
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val songB =
|
||||
mockk<SongImpl> {
|
||||
every { uid } returns Music.UID.auxio(MusicType.SONGS)
|
||||
every { finalize() } returns this
|
||||
}
|
||||
val album =
|
||||
mockk<AlbumImpl> {
|
||||
every { uid } returns mockk()
|
||||
every { finalize() } returns this
|
||||
}
|
||||
|
||||
val deviceLibraryA = DeviceLibraryImpl(listOf(songA), listOf(album), listOf(), listOf())
|
||||
val deviceLibraryB = DeviceLibraryImpl(listOf(songA), listOf(), listOf(), listOf())
|
||||
val deviceLibraryC = DeviceLibraryImpl(listOf(songB), listOf(album), listOf(), listOf())
|
||||
assertEquals(deviceLibraryA, deviceLibraryB)
|
||||
assertEquals(deviceLibraryA.hashCode(), deviceLibraryA.hashCode())
|
||||
assertNotEquals(deviceLibraryA, deviceLibraryC)
|
||||
assertNotEquals(deviceLibraryA.hashCode(), deviceLibraryC.hashCode())
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Auxio Project
|
||||
* TestingUtil.kt is part of Auxio.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.oxycblt.auxio.util
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
private val VM_CLEAR_METHOD =
|
||||
ViewModel::class.java.getDeclaredMethod("clear").apply { isAccessible = true }
|
||||
|
||||
fun ViewModel.forceClear() {
|
||||
VM_CLEAR_METHOD.invoke(this)
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
buildscript {
|
||||
ext {
|
||||
kotlin_version = '1.9.0'
|
||||
kotlin_version = '1.9.10'
|
||||
navigation_version = "2.5.3"
|
||||
hilt_version = '2.47'
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ buildscript {
|
|||
}
|
||||
|
||||
plugins {
|
||||
id "com.android.application" version "8.1.0" apply false
|
||||
id "com.android.application" version '8.1.2' apply false
|
||||
id "androidx.navigation.safeargs.kotlin" version "$navigation_version" apply false
|
||||
id "org.jetbrains.kotlin.android" version "$kotlin_version" apply false
|
||||
id "com.google.devtools.ksp" version '1.9.0-1.0.12' apply false
|
||||
id "com.google.devtools.ksp" version '1.9.10-1.0.13' apply false
|
||||
id "com.diffplug.spotless" version "6.20.0" apply false
|
||||
}
|
||||
|
||||
|
|
3
fastlane/metadata/android/en-US/changelogs/36.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/36.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
Auxio 3.2.0 refreshes the item management experience, with a new menu UI and playback options.
|
||||
This release fixes several critical issues identified in the previous version.
|
||||
For more information, see https://github.com/OxygenCobalt/Auxio/releases/tag/v3.2.0.
|
|
@ -20,4 +20,4 @@ precise/original dates, sort tags, and more
|
|||
- Headset autoplay
|
||||
- Stylish widgets that automatically adapt to their size
|
||||
- Completely private and offline
|
||||
- No rounded album covers (Unless you want them. Then you can.)
|
||||
- No rounded album covers (by default)
|
23
fastlane/metadata/android/fr-FR/full_description.txt
Normal file
23
fastlane/metadata/android/fr-FR/full_description.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
Auxio est un lecteur de musique local doté d'une UI/UX rapide et sûre, sans les fonctions inutiles de la plupart des autres lecteurs. Construit sur les bases d'une librairie moderne de lecture de media, Auxio supporte une libaririe et propose une qualité d'écoute supérieurs comparé aux autres applications qui utilisent des fonctionnalités d'android dépassées. Pour faire simple, <b>il joue votre musique .</b>
|
||||
|
||||
<b>Fonctionnalités</b>
|
||||
|
||||
- Lecture basée sur l'ExoPlayer Media3
|
||||
- UI réactive dérivée des dernières lignes directrices en Material Design
|
||||
- UX orientée qui mets l'accent sur la facilité d'utilisation plutôt que sur les usages
|
||||
- Comportement personnalisable
|
||||
- Reconnaît les numéros de disque, les artistes multiples, les types de support,
|
||||
les dates précises/originales, le classement par tags, and plus encore
|
||||
- Système de reconaissance d'artistes avancé qui unifie artistes et artistes de l'album
|
||||
- Carte SD reconnue par le système de dossiers
|
||||
- Fonction de liste de lecture efficace
|
||||
- Statut de lecture persistant
|
||||
- Support complet de ReplayGain (pour les fichiers MP3, FLAC, OGG, OPUS, et MP4)
|
||||
- Support pour égaliseur externe (ex. Wavelet)
|
||||
- Navigation bord-à-bord
|
||||
- Couvertures intégrées reconnues
|
||||
- Recherche intégrée
|
||||
- Lecture automatique pour les casques
|
||||
- Widgets stylisés qui s'adaptent automatiquement à leur taille
|
||||
- Complètement privé et hors-ligne
|
||||
- On arrondit pas les couvertures d'albums (Sauf si vous le voulez. Dans ce cas c'est possible.)
|
|
@ -6,10 +6,9 @@
|
|||
- ממשק משתמש מהיר שנגזר מהנחיות Material Design האחרונות ביותר
|
||||
- חוויית משתמש שמתעדפת נוחות שימוש על פני מקרי קיצון
|
||||
- התנהגות מותאמת אישית
|
||||
- תמיכה במספרי דיסק, אומנים מרובים, סוגי שחרור,
|
||||
- תמיכה במספרי דיסק, אומנים מרובים, סוגי שחרור,
|
||||
תאריכים מדוייקים/מקוריים, תגיות מיון, ועוד
|
||||
- מערכת אומנים מתקדמת שמאחדת אומנים ואומני אלבום
|
||||
|
||||
- ניהול תיקיות מודע לכרטיסי SD
|
||||
- פונקציונליות פלייליסטים אמינה
|
||||
- התמדה במצב ההשמעה
|
||||
|
@ -21,5 +20,4 @@
|
|||
- ניגון אוטומטי באוזניות
|
||||
- ווידג'טים אלגנטיים שמתאימים את עצמם לגודלם אוטומטית
|
||||
- פרטי לגמרי ולא מקוון
|
||||
|
||||
- ללא עטיפות אלבום מעוגלות (אלא אם את.ה מעוניינ.ת בהם. אחרת אפשר.)
|
||||
- ללא עטיפות אלבום מעוגלות (אלא אם את.ה מעוניינ.ת בהם. אז זה אפשרי.)
|
||||
|
|
21
fastlane/metadata/android/pt-PT/full_description.txt
Normal file
21
fastlane/metadata/android/pt-PT/full_description.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
Auxio é um leitor de música local com uma UI/UX rápida e fiável sem as muitas funcionalidades inúteis presentes noutros leitores de música. Construído a partir de bibliotecas de reprodução de mídia modernas, Auxio tem suporte de biblioteca superior e qualidade de audição em comparação com outras aplicações que usam funcionalidade Android desatualizadas. Em suma, <b>toca música.</b>
|
||||
|
||||
<b>Caraterísticas</b>
|
||||
|
||||
- Reprodução baseada em Media3 ExoPlayer
|
||||
- Snappy UI derivada das mais recentes diretrizes de Material Design
|
||||
- UX opinativa que prioriza a facilidade de uso sobre casos de borda
|
||||
- Comportamento personalizável
|
||||
- Suporte para números de disco, vários artistas, tipos de lançamento,
|
||||
datas precisas/originais, tags de classificação e muito mais
|
||||
- Sistema avançado de artistas que unifica artistas e artistas de álbuns
|
||||
- Gerenciamento de pastas com reconhecimento de cartão SD
|
||||
- Funcionalidade de playlisting confiável
|
||||
- Persistência do estado de reprodução
|
||||
- Suporte completo ReplayGain (em arquivos MP3, FLAC, OGG, OPUS e MP4)
|
||||
- Suporte de equalizador externo (ex. Wavelet)
|
||||
- De ponta a ponta
|
||||
- Suporte de capas embutidas
|
||||
- Funcionalidade de pesquisa
|
||||
- Reprodução automática de auscultadores
|
||||
- Elegante
|
1
fastlane/metadata/android/pt-PT/short_description.txt
Normal file
1
fastlane/metadata/android/pt-PT/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Um leitor de música simples
|
22
fastlane/metadata/android/sl/full_description.txt
Normal file
22
fastlane/metadata/android/sl/full_description.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
Auxio je lokalni predvajalnik glasbe z hitrim in zanesljivim uporabniškim vmesnikom brez večino nepotrebnih funkcij, ki jih najdete v drugih predvajalnikih glasbe. Zgrajen na sodobnih knjižnicah za predvajanje medijskih vsebin, Auxio ponuja izjemno podporo za knjižnico in kakovost poslušanja v primerjavi z aplikacijami, ki uporabljajo zastarelo funkcionalnost Androida. Skratka, <b>predvaja glasbo</b>.
|
||||
|
||||
<b>Lastnosti</b>
|
||||
|
||||
- Predvajanje temelji na Media3 ExoPlayer predvajalniku
|
||||
- Hiter uporabniški vmesnik, izpeljan iz najnovejših smernic oblikovanja gradiva (Material Design)
|
||||
- Samostojno premišljena uporabniška izkušnja, ki postavlja enostavnost uporabe pred izjemne primere, ki se zelo redko zgodijo
|
||||
- Prilagodljivo obnašanje
|
||||
- Podpora za številke diskov, več izvajalcev, vrste izdaj, natančne/izvirne datume, razvrščalne oznake in še več
|
||||
- Napreden sistem izvajalcev, ki združuje izvajalce in izvajalce albumov
|
||||
- Upravljanje map na SD kartici
|
||||
- Zanesljiva funkcionalnost ustvarjanja seznama predvajanja
|
||||
- Trajnost stanja predvajanja
|
||||
- Popolna podpora za ReplayGain tehnologijo (za MP3, FLAC, OGG, OPUS in MP4 datoteke)
|
||||
- Podpora za zunanje izenačevalnike (npr. Wavelet)
|
||||
- Od roba do roba
|
||||
- Podpora za vdelane naslovnice albumov
|
||||
- Funkcionalnost iskanja
|
||||
- Avtomatski zagon ob priključitvi slušalk
|
||||
- Elegantni pripomočki, ki se samodejno prilagajajo svoji velikosti
|
||||
- Popolnoma zasebno in brez povezave
|
||||
- Brez zaobljenih naslovnic albumov (če jih ne želite; če pa želite, jih lahko omogočite)
|
1
fastlane/metadata/android/sl/short_description.txt
Normal file
1
fastlane/metadata/android/sl/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Preprost, racionalen predvajalnik glasbe
|
|
@ -1,19 +1,23 @@
|
|||
Auxio, diğer müzik oynatıcılarda bulunan birçok gereksiz özellik olmadan hızlı, güvenilir bir kullanıcı arayüzüne ve deneyimine sahip yerel bir müzik çalardır. <a href="https://exoplayer.dev/">Exoplayer</a> üzerine inşa edilen Auxio, yerel MediaPlayer API'sini kullanan diğer uygulamalara kıyasla çok daha iyi bir dinleme deneyimine sahiptir. Kısaca, <b>Müzik çalar.</b>
|
||||
Auxio, diğer müzik çalarlarda bulunan birçok gereksiz özellik olmadan hızlı, güvenilir bir UI / UX'a sahip yerel bir müzik oynatıcıdır. Modern medya oynatma kütüphaneleri üzerine inşa edilen Auxio, eski android işlevselliğini kullanan diğer uygulamalara kıyasla üstün kütüphane desteği ve dinleme kalitesine sahiptir. Kısacası, <b>Müzik çalar.</b>
|
||||
|
||||
<b>Özellikler</b>
|
||||
|
||||
- ExoPlayer tabanlı oynatma
|
||||
- Media3 ExoPlayer tabanlı oynatma
|
||||
- En son Materyal Tasarım yönergelerinden türetilen hızlı kullanıcı arayüzü
|
||||
- Uç durumlardan ziyade kullanım kolaylığına öncelik veren fikir sahibi kullanıcı deneyimi
|
||||
- Özelleştirilebilir davranış
|
||||
- Doğru meta verilere öncelik veren gelişmiş medya indeksleyici
|
||||
- Disk numaraları, çoklu sanatçılar, sürüm türleri için destek,
|
||||
kesin/orijinal tarihler, sıralama etiketleri ve daha fazlası
|
||||
- Sanatçıları ve albüm sanatçılarını birleştiren gelişmiş sanatçı sistemi
|
||||
- SD Card-aware klasör yönetimi
|
||||
- Güvenilir oynatma durumu kalıcılığı
|
||||
- Tam ReplayGain desteği (MP3, MP4, FLAC, OGG ve OPUS'ta)
|
||||
- Güvenilir çalma listesi işlevi
|
||||
- Oynatma durumu kalıcılığı
|
||||
- Tam ReplayGain desteği (MP3, FLAC, OGG, OPUS ve MP4 dosyalarında)
|
||||
- Harici ekolayzer desteği (örn. Wavelet)
|
||||
- Kenardan kenara
|
||||
- Gömülü kapak desteği
|
||||
- Arama İşlevselliği
|
||||
- Arama işlevi
|
||||
- Kulaklık otomatik oynatma
|
||||
- Boyutlarına otomatik olarak uyum sağlayan şık widget'lar
|
||||
- Tamamen özel ve çevrimdışı
|
||||
- Yuvarlak albüm kapakları yok (İstediğiniz zaman açıp kapatabilirsiniz.)
|
||||
- Yuvarlak albüm kapakları yok (İstemediğiniz sürece. O zaman yapabilirsiniz.)
|
||||
|
|
Loading…
Reference in a new issue