music: default to codecs in format

Only show codecs in the "format" field, if we are able to extract them.

This is primarily for consistency, as there is no way for us to
determine the container format outside of an extension (which could not
be sane).
This commit is contained in:
OxygenCobalt 2022-06-13 09:41:52 -06:00
parent cb8c3306eb
commit e914da4bd1
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 76 additions and 37 deletions

View file

@ -14,6 +14,8 @@
<queries /> <queries />
<!-- TODO: A "shuffle" shortcut -->
<!-- <!--
Note: We have to simultaneously define the fullBackupContent and dataExtractionRules Note: We have to simultaneously define the fullBackupContent and dataExtractionRules
fields, as there is no way to make version-specific manifests. This should be okay, fields, as there is no way to make version-specific manifests. This should be okay,
@ -63,7 +65,12 @@
<data android:scheme="content" /> <data android:scheme="content" />
<data android:scheme="file" /> <data android:scheme="file" />
<!-- Normal audio mime types + weird mime types -->
<data android:mimeType="audio/*" /> <data android:mimeType="audio/*" />
<data android:mimeType="application/ogg" />
<data android:mimeType="application/x-ogg" />
<data android:mimeType="application/itunes" />
</intent-filter> </intent-filter>
</activity> </activity>

View file

@ -34,7 +34,6 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2 import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import kotlin.math.abs import kotlin.math.abs
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
@ -95,8 +94,7 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
binding.homeToolbar.alpha = 1f - (abs(offset.toFloat()) / (range.toFloat() / 2)) binding.homeToolbar.alpha = 1f - (abs(offset.toFloat()) / (range.toFloat() / 2))
binding.homeContent.updatePadding( binding.homeContent.updatePadding(
bottom = binding.homeAppbar.totalScrollRange + offset bottom = binding.homeAppbar.totalScrollRange + offset)
)
} }
} }

View file

@ -75,37 +75,61 @@ sealed class Dir {
*/ */
data class MimeType(val fromExtension: String, val fromFormat: String?) { data class MimeType(val fromExtension: String, val fromFormat: String?) {
fun resolveName(context: Context): String { fun resolveName(context: Context): String {
// While it would be nice to have more refined mime type names (Layer I/II/III, containers, // We try our best to produce a more readable name for the common audio formats.
// etc.), it's not exactly practical with ExoPlayer. So, we go for the next best thing val formatName =
// and try to find a good enough readable name to use. when (fromFormat) {
val readableStringRes = // We start with the extracted mime types, as they are more consistent. Note that
if (fromFormat != null && fromFormat != MimeTypes.AUDIO_RAW) { // we do not include container formats at all with these names. It is only the
// Prefer the extracted mime type, as it properly handles container formats and // inner codec that we show.
// is agnostic to the file extension MimeTypes.AUDIO_MPEG,
when (fromFormat) { MimeTypes.AUDIO_MPEG_L1,
MimeTypes.AUDIO_MPEG, MimeTypes.AUDIO_MPEG_L2 -> R.string.cdc_mp3
MimeTypes.AUDIO_MPEG_L1, MimeTypes.AUDIO_AAC -> R.string.cdc_aac
MimeTypes.AUDIO_MPEG_L2 -> R.string.cdc_mp3 MimeTypes.AUDIO_VORBIS -> R.string.cdc_vorbis
MimeTypes.AUDIO_AAC -> R.string.cdc_mp4 MimeTypes.AUDIO_OPUS -> R.string.cdc_opus
MimeTypes.AUDIO_VORBIS -> R.string.cdc_ogg_vorbis MimeTypes.AUDIO_FLAC -> R.string.cdc_flac
MimeTypes.AUDIO_OPUS -> R.string.cdc_ogg_opus MimeTypes.AUDIO_WAV -> R.string.cdc_wav
MimeTypes.AUDIO_WAV -> R.string.cdc_wav
else -> -1 // We don't give a name to more unpopular formats.
}
} else { else -> -1
// Fall back to the file extension in the case that we have a useless
when (fromExtension) {
"audio/mpeg" -> R.string.cdc_mp3
"audio/mp4" -> R.string.cdc_mp4
"audio/ogg" -> R.string.cdc_ogg
"audio/x-wav" -> R.string.cdc_wav
"audio/x-matroska" -> R.string.cdc_mka
else -> -1
}
} }
return if (readableStringRes > -1) { if (formatName > -1) {
context.getString(readableStringRes) return context.getString(formatName)
}
// Fall back to the file extension in the case that we have no mime type or
// a useless "audio/raw" mime type. Here:
// - We return names for container formats instead of the inner format, as we
// cannot parse the file.
// - We are at the mercy of the Android OS, hence we check for every possible mime
// type for a particular format.
val extensionName =
when (fromExtension) {
"audio/mpeg",
"audio/mp3" -> R.string.cdc_mp3
"audio/mp4",
"audio/mp4a-latm",
"audio/mpeg4-generic" -> R.string.cdc_mp4
"audio/aac",
"audio/aacp",
"audio/3gpp",
"audio/3gpp2" -> R.string.cdc_aac
"audio/ogg",
"application/ogg",
"application/x-ogg" -> R.string.cdc_ogg
"audio/flac" -> R.string.cdc_flac
"audio/wav",
"audio/x-wav",
"audio/wave",
"audio/vnd.wave" -> R.string.cdc_wav
"audio/x-matroska" -> R.string.cdc_mka
else -> -1
}
return if (extensionName > -1) {
context.getString(extensionName)
} else { } else {
// Fall back to the extension if we can't find a special name for this format. // Fall back to the extension if we can't find a special name for this format.
MimeTypeMap.getSingleton().getExtensionFromMimeType(fromExtension)?.uppercase() MimeTypeMap.getSingleton().getExtensionFromMimeType(fromExtension)?.uppercase()

View file

@ -179,7 +179,11 @@ class Indexer {
private fun indexImpl(context: Context, generation: Long): MusicStore.Library? { private fun indexImpl(context: Context, generation: Long): MusicStore.Library? {
emitIndexing(Indexing.Indeterminate, generation) emitIndexing(Indexing.Indeterminate, generation)
// Establish the backend to use when initially loading songs. // Since we have different needs for each version, we determine a "Backend" to use
// when loading music and then leverage that to create the initial song list.
// This is technically dependency injection. Except it doesn't increase your compile
// times by 3x. Isn't that nice.
val mediaStoreBackend = val mediaStoreBackend =
when { when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> Api30MediaStoreBackend() Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> Api30MediaStoreBackend()

View file

@ -40,7 +40,10 @@ import org.oxycblt.auxio.util.newMainPendingIntent
* A [Service] that handles the music loading process. * A [Service] that handles the music loading process.
* *
* Loading music is actually somewhat time-consuming, to the point where it's likely better suited * Loading music is actually somewhat time-consuming, to the point where it's likely better suited
* to a service that is less likely to be * to a service that is less likely to be killed by the OS.
*
* You could probably do the same using WorkManager and the GooberQueue library or whatever, but the
* boilerplate you skip is not worth the insanity of androidx.
* *
* @author OxygenCobalt * @author OxygenCobalt
*/ */

View file

@ -37,7 +37,8 @@ class MediaButtonReceiver : BroadcastReceiver() {
val playbackManager = PlaybackStateManager.getInstance() val playbackManager = PlaybackStateManager.getInstance()
if (playbackManager.song != null) { if (playbackManager.song != null) {
// We have a song, so we can assume that the service will start a foreground state. // We have a song, so we can assume that the service will start a foreground state.
// At least, I hope. // At least, I hope. Again, *this is why we don't do this, I cannot describe how
// stupid this is with the state of foreground services on modern android*
intent.component = ComponentName(context, PlaybackService::class.java) intent.component = ComponentName(context, PlaybackService::class.java)
ContextCompat.startForegroundService(context, intent) ContextCompat.startForegroundService(context, intent)
} }

View file

@ -9,8 +9,8 @@
<string name="fmt_number" translatable="false">%d</string> <string name="fmt_number" translatable="false">%d</string>
<!-- Codec Namespace | Format names --> <!-- Codec Namespace | Format names -->
<string name="cdc_ogg_vorbis">Ogg Vorbis</string> <string name="cdc_vorbis">Vorbis</string>
<string name="cdc_ogg_opus">Ogg Opus</string> <string name="cdc_opus">Opus</string>
<string name="cdc_wav">Microsoft WAVE</string> <string name="cdc_wav">Microsoft WAVE</string>
<!-- Note: These are stopgap measures until we make the path code rely on components! --> <!-- Note: These are stopgap measures until we make the path code rely on components! -->

View file

@ -185,6 +185,8 @@
<string name="cdc_mp4">MPEG-4 Audio</string> <string name="cdc_mp4">MPEG-4 Audio</string>
<string name="cdc_ogg">Ogg Audio</string> <string name="cdc_ogg">Ogg Audio</string>
<string name="cdc_mka">Matroska Audio</string> <string name="cdc_mka">Matroska Audio</string>
<string name="cdc_aac">Advanced Audio Coding (AAC)</string>
<string name="cdc_flac">Free Lossless Audio Codec (FLAC)</string>
<!-- Color Label namespace | Accent names --> <!-- Color Label namespace | Accent names -->
<string name="clr_red">Red</string> <string name="clr_red">Red</string>