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 />
<!-- TODO: A "shuffle" shortcut -->
<!--
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,
@ -63,7 +65,12 @@
<data android:scheme="content" />
<data android:scheme="file" />
<!-- Normal audio mime types + weird mime types -->
<data android:mimeType="audio/*" />
<data android:mimeType="application/ogg" />
<data android:mimeType="application/x-ogg" />
<data android:mimeType="application/itunes" />
</intent-filter>
</activity>

View file

@ -34,7 +34,6 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.tabs.TabLayoutMediator
import kotlin.math.abs
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.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?) {
fun resolveName(context: Context): String {
// While it would be nice to have more refined mime type names (Layer I/II/III, containers,
// etc.), it's not exactly practical with ExoPlayer. So, we go for the next best thing
// and try to find a good enough readable name to use.
val readableStringRes =
if (fromFormat != null && fromFormat != MimeTypes.AUDIO_RAW) {
// Prefer the extracted mime type, as it properly handles container formats and
// is agnostic to the file extension
when (fromFormat) {
MimeTypes.AUDIO_MPEG,
MimeTypes.AUDIO_MPEG_L1,
MimeTypes.AUDIO_MPEG_L2 -> R.string.cdc_mp3
MimeTypes.AUDIO_AAC -> R.string.cdc_mp4
MimeTypes.AUDIO_VORBIS -> R.string.cdc_ogg_vorbis
MimeTypes.AUDIO_OPUS -> R.string.cdc_ogg_opus
MimeTypes.AUDIO_WAV -> R.string.cdc_wav
else -> -1
}
} else {
// 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
}
// We try our best to produce a more readable name for the common audio formats.
val formatName =
when (fromFormat) {
// We start with the extracted mime types, as they are more consistent. Note that
// we do not include container formats at all with these names. It is only the
// inner codec that we show.
MimeTypes.AUDIO_MPEG,
MimeTypes.AUDIO_MPEG_L1,
MimeTypes.AUDIO_MPEG_L2 -> R.string.cdc_mp3
MimeTypes.AUDIO_AAC -> R.string.cdc_aac
MimeTypes.AUDIO_VORBIS -> R.string.cdc_vorbis
MimeTypes.AUDIO_OPUS -> R.string.cdc_opus
MimeTypes.AUDIO_FLAC -> R.string.cdc_flac
MimeTypes.AUDIO_WAV -> R.string.cdc_wav
// We don't give a name to more unpopular formats.
else -> -1
}
return if (readableStringRes > -1) {
context.getString(readableStringRes)
if (formatName > -1) {
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 {
// Fall back to the extension if we can't find a special name for this format.
MimeTypeMap.getSingleton().getExtensionFromMimeType(fromExtension)?.uppercase()

View file

@ -179,7 +179,11 @@ class Indexer {
private fun indexImpl(context: Context, generation: Long): MusicStore.Library? {
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 =
when {
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.
*
* 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
*/

View file

@ -37,7 +37,8 @@ class MediaButtonReceiver : BroadcastReceiver() {
val playbackManager = PlaybackStateManager.getInstance()
if (playbackManager.song != null) {
// 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)
ContextCompat.startForegroundService(context, intent)
}

View file

@ -9,8 +9,8 @@
<string name="fmt_number" translatable="false">%d</string>
<!-- Codec Namespace | Format names -->
<string name="cdc_ogg_vorbis">Ogg Vorbis</string>
<string name="cdc_ogg_opus">Ogg Opus</string>
<string name="cdc_vorbis">Vorbis</string>
<string name="cdc_opus">Opus</string>
<string name="cdc_wav">Microsoft WAVE</string>
<!-- 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_ogg">Ogg 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 -->
<string name="clr_red">Red</string>