all: remove immature comments

Remove childish wording/diatribes from the codebase that were added
when I was younger.

I'm an adult now. I have to make this repository at least somewhat
professional.
This commit is contained in:
Alexander Capehart 2022-12-15 14:21:21 -07:00
parent 381286802d
commit 873f15ff40
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
17 changed files with 68 additions and 185 deletions

View file

@ -144,9 +144,9 @@ class MainFragment :
}
override fun onPreDraw(): Boolean {
// CoordinatorLayout is insane and thus makes bottom sheet callbacks insane. Do our
// checks before every draw, which is not ideal in the slightest but also has minimal
// performance impact since we are only mutating attributes used during drawing.
// We overload CoordinatorLayout far too much to rely on any of it's typical
// callback functionality. Just update all transitions before every draw. Should
// probably be cheap *enough.*
val binding = requireBinding()
val playbackSheetBehavior =

View file

@ -26,7 +26,6 @@ import org.oxycblt.auxio.home.tabs.Tab
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.MusicMode
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song

View file

@ -33,9 +33,9 @@ import org.oxycblt.auxio.util.getColorCompat
import org.oxycblt.auxio.util.getDrawableCompat
/**
* View that displays the playback indicator. Nominally emulates [StyledImageView], but is much
* different internally as an animated icon can't be wrapped within StyledDrawable without causing
* insane issues.
* View that displays the playback indicator. Nominally emulates [StyledImageView], but
* relies on the existing ImageView infrastructure to achieve the same result while also
* allowing animation to work.
* @author OxygenCobalt
*/
class IndicatorView

View file

@ -83,10 +83,8 @@ abstract class BaseFetcher : Fetcher {
// First try MediaMetadataRetriever. We will always do this first, as it supports
// a variety of formats, has multiple levels of fault tolerance, and is pretty fast
// for a manual parser.
// However, Samsung seems to cripple this class as to force people to use their ad-infested
// music app which relies on proprietary OneUI extensions instead of AOSP. That means
// we have to add even more layers of redundancy to make sure we can extract a cover.
// Thanks Samsung. Prick.
// However, this does not seem to work on some devices (Notably Samsung), so we
// have to have redundancy.
fetchAospMetadataCovers(context, album)
?: fetchExoplayerCover(context, album) ?: fetchMediaStoreCovers(context, album)
@ -109,12 +107,12 @@ abstract class BaseFetcher : Fetcher {
// future.get is a blocking call that makes us spin until the future is done.
// This is bad for a co-routine, as it prevents cancellation and by extension
// messes with the image loading process and causes frustrating bugs.
// messes with the image loading process and causes annoying bugs.
// To fix this we wrap this around in a withContext call to make it suspend and make
// sure that the runner can do other coroutines.
@Suppress("BlockingMethodInNonBlockingContext")
val tracks =
withContext(Dispatchers.IO) {
withContext(Dispatchers.Default) {
try {
future.get()
} catch (e: Exception) {

View file

@ -14,7 +14,7 @@
* 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.extractor
import android.content.Context
@ -39,62 +39,6 @@ import org.oxycblt.auxio.util.contentResolverSafe
import org.oxycblt.auxio.util.getSystemServiceCompat
import org.oxycblt.auxio.util.logD
/*
* This file acts as the base for most the black magic required to get a remotely sensible music
* indexing system from MediaStore while still optimizing for time. I would recommend you leave
* this file now before you lose your sanity trying to understand the hoops I had to jump through
* for this system, but if you really want to stay, here's a debrief on why this code is so awful.
*
* MediaStore is not a good API. It is not even a bad API. Calling it a bad API is an insult to
* other bad android APIs, like CoordinatorLayout or InputMethodManager. No. MediaStore is a crime
* against humanity and probably a way to summon Zalgo if you look at it the wrong way.
*
* You think that if you wanted to query a song's genre from a media database, you could just put
* "genre" in the query and it would return it, right? But not with MediaStore! No, that's too
* straightforward for this database that was dropped on it's head as a baby. So instead, you have
* to query for each genre, query all the songs in each genre, and then iterate through those songs
* to link every song with their genre. This is not documented anywhere, and the O(mom im scared)
* algorithm you have to run to get it working single-handedly DOUBLES Auxio's query times. At no
* point have the devs considered that this system is absolutely insane, and instead focused on
* adding infuriat- I mean nice proprietary extensions to MediaStore for their own Google Play
* Music, and of course every Google Play Music user knew how great that turned out!
*
* It's not even ergonomics that makes this API bad. It's base implementation is completely borked
* as well. Did you know that MediaStore doesn't accept dates that aren't from ID3v2.3 MP3 files? I
* sure didn't, until I decided to upgrade my music collection to ID3v2.4 and FLAC only to see that
* the metadata parser has a brain aneurysm the moment it stumbles upon a dreaded TRDC or DATE tag.
* Once again, this is because internally android uses an ancient in-house metadata parser to get
* everything indexed, and so far they have not bothered to modernize this parser or even switch it
* to something that actually works, not even in Android 12. ID3v2.4 has been around for *21
* years.* *It can drink now.*
*
* Not to mention all the other infuriating quirks. Pretty much every OEM has added some extension
* or quirk to MediaStore that I cannot reproduce, with some OEMs (COUGHSAMSUNGCOUGH) crippling the
* normal tables so that you're railroaded into their music app. I have to use a semi-deprecated
* field to work with file paths, and the supposedly "modern" method is SLOWER and causes even more
* problems since some devices just don't expose those fields for some insane reason. Sometimes
* music will have a deformed clone that I can't filter out, sometimes Genres will just break for
* no reason, and sometimes tags encoded in UTF-8 will be interpreted as anything from UTF-16 to
* Latin-1 to *Shift JIS* WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY WHY
*
* Is there anything we can do about it? No. Google has routinely shut down issues that begged
* google to fix glaring issues with MediaStore or to just take the API behind the woodshed and
* shoot it. Largely because they have zero incentive to improve it given how "obscure" local music
* listening is. As a result, I am forced to write my own extractor (Which is the contents of the
* rest of this module) based on ExoPlayer that at least tries to correct the insane metadata that
* this API returns, but not only is that system horrifically slow and bug-prone, it also faces the
* even larger issue of how google keeps trying to kill the filesystem and force you into their
* ContentResolver API. In the future MediaStore could be the only system we have, which is also
* the day that greenland melts and birthdays stop happening forever.
*
* I'm pretty sure nothing is going to happen and MediaStore will continue to be neglected and
* probably deprecated eventually for a "new" API that just coincidentally excludes music indexing.
* Because go screw yourself for wanting to listen to music you own. Be a good consoomer and listen
* to your AlgoPop StreamMix.
*
* I wish I was born in the neolithic.
*/
/**
* The layer that loads music from the MediaStore database. This is an intermediate step in the
* music loading process.
@ -205,7 +149,8 @@ abstract class MediaStoreExtractor(
// Since we can't obtain the genre tag from a song query, we must construct
// our own equivalent from genre database queries. Theoretically, this isn't
// needed since MetadataLayer will fill this in for us, but I'd imagine there
// are some obscure formats where genre support is only really covered by this.
// are some obscure formats where genre support is only really covered by this,
// so we are forced to bite the O(n^2) complexity here.
context.contentResolverSafe.useQuery(
MediaStore.Audio.Genres.EXTERNAL_CONTENT_URI,
arrayOf(MediaStore.Audio.Genres._ID, MediaStore.Audio.Genres.NAME)) { genreCursor ->

View file

@ -33,9 +33,9 @@ import org.oxycblt.auxio.util.logW
/**
* The layer that leverages ExoPlayer's metadata retrieval system to index metadata.
*
* Normally, leveraging ExoPlayer's metadata system would be a terrible idea, as it is horrifically
* slow. However, if we parallelize it, we can get similar throughput to other metadata extractors,
* which is nice as it means we don't have to bundle a redundant metadata library like JAudioTagger.
* Normally, ExoPlayer's metadata system is quite slow. However, if we parallelize it, we can get
* similar throughput to other metadata extractors, which is nice as it means we don't have to
* bundle a redundant metadata library like JAudioTagger.
*
* Now, ExoPlayer's metadata API is not the best. It's opaque, undocumented, and prone to weird
* pitfalls given ExoPlayer's cozy relationship with native code. However, this backend should do
@ -312,16 +312,8 @@ class Task(context: Context, private val raw: Song.Raw) {
}
/**
* Copies and sanitizes this string under the assumption that it is UTF-8.
*
* Sometimes ExoPlayer emits weird UTF-8. Worse still, sometimes it emits strings backed by data
* allocated by some native function. This could easily cause a terrible crash if you even look
* at the malformed string the wrong way.
*
* This function mitigates it by first encoding the string as UTF-8 bytes (replacing malformed
* characters with the replacement in the process), and then re-interpreting it as a new string,
* which hopefully fixes encoding insanity while also copying the string out of dodgy native
* memory.
* Copies and sanitizes this string under the assumption that it is UTF-8. This should
* launder away any weird UTF-8 issues that ExoPlayer may cause.
*/
private fun String.sanitize() = String(encodeToByteArray())
}

View file

@ -25,8 +25,8 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.PlaybackStateManager
/**
* Class enabling more advanced queue list functionality and queue editing.
* TODO: Allow editing previous parts of the queue
* Class enabling more advanced queue list functionality and queue editing. TODO: Allow editing
* previous parts of the queue
* @author OxygenCobalt
*/
class QueueViewModel : ViewModel(), PlaybackStateManager.Callback {

View file

@ -34,11 +34,10 @@ import org.oxycblt.auxio.util.logE
import org.oxycblt.auxio.util.logW
/**
* Master class (and possible god object) for the playback state.
* Core playback controller class.
*
* Whereas other apps centralize the playback state around the MediaSession, Auxio does not, as
* MediaSession is a terrible API that prevents nice features like better album cover loading or a
* reasonable queue system.
* MediaSession is poorly designed. We use our own playback state system instead.
*
* This should ***NOT*** be used outside of the playback module.
* - If you want to use the playback state in the UI, use

View file

@ -40,20 +40,10 @@ import org.oxycblt.auxio.settings.Settings
import org.oxycblt.auxio.util.logD
/**
* The component managing the [MediaSessionCompat] instance, alongside the [NotificationComponent]
* The component managing the [MediaSessionCompat] instance, alongside the [NotificationComponent].
*
* MediaSession is easily one of the most poorly thought out APIs in Android. It tries to hard to be
* hElpfUl and implement so many fundamental behaviors into a one-size-fits-all package that it only
* ends up causing bugs and frustration. The queue system is horribly designed, the playback state
* system has unending coherency issues, and the overstretched abstractions result in god-awful
* performance bottlenecks and insane state bugs.
*
* The sheer absurdity of the hoops we have jump through to get this working in an okay manner is
* the reason why Auxio only mirrors a saner playback state to the media session instead of relying
* on it. I thought that Android 13 would at least try to make the state more coherent, but NOPE.
* You still have to do a delicate dance of posting notifications and updating the session state
* while also keeping in mind the absurd rate limiting system in place just to have a sort-of
* coherent state. And even then it will break if you skip too much.
* Auxio does not directly rely on MediaSession, as it is extremely poorly designed. We instead
* just mirror the playback state into the media session.
*
* @author OxygenCobalt
*/
@ -165,17 +155,9 @@ class MediaSessionComponent(private val context: Context, private val callback:
song.date?.let { builder.putString(MediaMetadataCompat.METADATA_KEY_DATE, it.toString()) }
// Cover loading is a mess. Android expects you to provide a clean, easy URI for it to
// leverage, but Auxio cannot do that as quality-of-life features like scaling or
// 1:1 cropping could not be used.
//
// Thus, we have two options to handle album art:
// 1. Load the bitmap, then post the notification
// 2. Post the notification with text metadata, then post it with the bitmap when it's
// loaded.
//
// Neither of these are good, but 1 is the only one that will work on all versions
// without the notification being eaten by rate-limiting.
// We are normally supposed to use URIs for album art, but that removes some of the
// nice things we can do like square cropping or high quality covers. Instead,
// we load a full-size bitmap into the media session and take the performance hit.
provider.load(
song,
object : BitmapProvider.Target {

View file

@ -27,17 +27,8 @@ import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.logD
/**
* A wrapper around [Slider] that shows not only position and duration values, but also basically
* hacks in behavior consistent with a normal SeekBar in a way that will not crash the app.
*
* SeekBar, like most android OS components, is a version-specific mess that requires constant hacks
* on older versions. Instead, we use the more "modern" [Slider] component, but it is not designed
* for the job that Auxio's progress bar has. It does not gracefully degrade when positions don't
* make sense (which happens incredibly often), it just crashes the entire app, which is insane but
* also checks out for something more meant for configuration than seeking.
*
* Instead, we wrap it in a safe class that hopefully implements enough sanity checks to not crash
* the app or result in blatantly janky behavior. Mostly.
* A wrapper around [Slider] that shows not only position and duration values, but also hacks
* in bounds checking to avoid app crashes if bad position input comes in.
*
* @author OxygenCobalt
*/

View file

@ -79,15 +79,8 @@ class PreferenceFragment : PreferenceFragmentCompat() {
override fun onDisplayPreferenceDialog(preference: Preference) {
when (preference) {
is IntListPreference -> {
// Creating our own preference dialog is hilariously difficult. For one, we need
// to override this random method within the class in order to launch the dialog in
// the first (because apparently you can't just implement some interface that
// automatically provides this behavior), then we also need to use a deprecated
// method to adequately supply a "target fragment" (otherwise we will crash since
// the dialog requires one), and then we need to actually show the dialog, making
// sure we use the parent FragmentManager as again, it will crash if we don't.
//
// Fragments were a mistake.
// Copy the built-in preference dialog launching code into our project so
// we can automatically use the provided preference class.
val dialog = IntListPreferenceDialog.from(preference)
dialog.setTargetFragment(this, 0)
dialog.show(parentFragmentManager, IntListPreferenceDialog.TAG)

View file

@ -1,3 +1,20 @@
/*
* Copyright (c) 2022 Auxio Project
*
* 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.ui
import androidx.lifecycle.ViewModel
@ -23,4 +40,4 @@ class SelectionViewModel : ViewModel() {
_selected.value = items
}
}
}
}

View file

@ -199,12 +199,13 @@ val AndroidViewModel.application: Application
fun <R> SQLiteDatabase.queryAll(tableName: String, block: (Cursor) -> R) =
query(tableName, null, null, null, null, null, null)?.use(block)
// Note: WindowInsetsCompat and it's related methods are an over-engineered mess that does not
// work for Auxio's use-case. Use our own compat methods instead.
// Note: WindowInsetsCompat and it's related methods cause too many issues.
// Use our own compat methods instead.
/**
* Resolve system bar insets in a version-aware manner. This can be used to apply padding to a view
* that properly follows all the frustrating changes that were made between Android 8-11.
* that properly follows all the changes that were made between Android 8-11.
*/
val WindowInsets.systemBarInsetsCompat: Insets
get() =
@ -217,8 +218,8 @@ val WindowInsets.systemBarInsetsCompat: Insets
/**
* Resolve gesture insets in a version-aware manner. This can be used to apply padding to a view
* that properly follows all the frustrating changes that were made between Android 8-11. Note that
* if the gesture insets are not present (i.e zeroed), the bar insets will be used instead.
* that properly follows all the changes that were made between Android 8-11. Note that if the
* gesture insets are not present (i.e zeroed), the bar insets will be used instead.
*/
val WindowInsets.systemGestureInsetsCompat: Insets
get() =
@ -241,7 +242,7 @@ val WindowInsets.systemGestureInsetsCompat: Insets
}
@Suppress("DEPRECATION")
fun WindowInsets.getSystemWindowCompatInsets() =
private fun WindowInsets.getSystemWindowCompatInsets() =
Insets.of(
systemWindowInsetLeft,
systemWindowInsetTop,
@ -250,14 +251,14 @@ fun WindowInsets.getSystemWindowCompatInsets() =
@Suppress("DEPRECATION")
@RequiresApi(Build.VERSION_CODES.Q)
fun WindowInsets.getSystemGestureCompatInsets() = Insets.toCompatInsets(systemGestureInsets)
private fun WindowInsets.getSystemGestureCompatInsets() = Insets.toCompatInsets(systemGestureInsets)
@RequiresApi(Build.VERSION_CODES.R)
fun WindowInsets.getCompatInsets(typeMask: Int) = Insets.toCompatInsets(getInsets(typeMask))
private fun WindowInsets.getCompatInsets(typeMask: Int) = Insets.toCompatInsets(getInsets(typeMask))
/**
* Replaces the system bar insets in a version-aware manner. This can be used to modify the insets
* for child views in a way that follows all of the frustrating changes that were made between 8-11.
* for child views in a way that follows all of the changes that were made between 8-11.
*/
fun WindowInsets.replaceSystemBarInsetsCompat(
left: Int,

View file

@ -34,7 +34,7 @@ fun Any.logD(obj: Any?) = logD("$obj")
* objects
*/
fun Any.logD(msg: String) {
if (BuildConfig.DEBUG && !basedCopyleftNotice()) {
if (BuildConfig.DEBUG && !copyleftNotice()) {
Log.d(autoTag, msg)
}
}
@ -50,37 +50,11 @@ private val Any.autoTag: String
get() = "Auxio.${this::class.simpleName ?: "Anonymous Object"}"
/**
* Note: If you are politely forking this project while keeping the source open, you can ignore the
* following passage. If not, give me a moment of your time.
*
* Consider what you are doing with your life, plagiarizers. Do you want to live a fulfilling
* existence on this planet? Or do you want to spend your life taking work others did and making it
* objectively worse so you could arbitrage a fraction of a penny on every AdMob impression you get?
* You could do so many great things if you simply had the courage to come up with an idea of your
* own.
*
* If you still want to go on, I guess the only thing I can say is this:
*
* JUNE 1989 TIANAMEN SQUARE PROTESTS AND MASSACRE / 六四事件
*
* 2022 RUSSIAN INVASION OF UKRAINE / ВТОРЖЕНИЕ РОССИИ НА УКРАИНУ
*
* WOMEN'S RIGHTS IN THE ISLAMIC REPUBLIC OF IRAN / حقوق زنان در ایران
*
* UYGHUR GENOCIDE/XINJIANG INTERNMENT CAMPS / 新疆种族灭绝指控/新疆再教育營
*
* KASHMIR INDEPENDENCE MOVEMENT
*
* FREE TIBET / 西藏自由
*
* 1915-1916 ARMENIAN GENOCIDE / ERMENI KIRIMI
*
* 2018 TORTURE AND ASSASSINATION OF JAMAL KHASHOGGI / مقتل جمال خاشقجي
*
* UNITED ARAB EMIRATES ENSLAVED MIGRANT WORKERS
* 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 basedCopyleftNotice(): Boolean {
private fun copyleftNotice(): Boolean {
if (BuildConfig.APPLICATION_ID != "org.oxycblt.auxio" &&
BuildConfig.APPLICATION_ID != "org.oxycblt.auxio.debug") {
Log.d(

View file

@ -4,13 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
app:startDestination="@id/home_fragment">
<!--
Now, it would be quite cool if we could implement shared element transitions
between elements in this navigation web. Sadly though, the shared element transition
system is filled with so many bugs and visual errors to make this a terrible idea.
Just use the boring, yet sane and functional axis transitions.
-->
<fragment
android:id="@+id/artist_detail_fragment"
android:name="org.oxycblt.auxio.detail.ArtistDetailFragment"

View file

@ -155,7 +155,7 @@ Monitoring the loading progress (Internally called the indexing state) should be
and is best done with `MusicViewModel`.
#### Playback System
The android/androidx media state APIs are terrible, and are often the cause of the strange queue
The android/androidx media state APIs are poorly designed, and are often the cause of the strange queue
behavior and jank you see in other apps. So, Auxio does not use it, instead implementing it's own
playback engine that is more controllable and sensible and simply mirroring it to the android APIs.
@ -246,7 +246,7 @@ playing indicator and one custom view.
#### `.music`
This package contains all `Music` implementations, the music loading implementation, and the music
folder system. This is the second most complicated package in the app, as loading music in a sane
way is horribly difficult.
way is quite difficult.
The major classes are:
- `MusicStore`, which is the container for a `Library` instance. Any code wanting to access the
@ -314,8 +314,7 @@ default implementations.
- `ForegroundManager` and `ServiceNotification`, which remove boilerplate regarding service
foreground instantiation.
- The `RecyclerView` adapter framework described previously.
- `BottomSheetLayout`, which implements a bottom sheet in a way that is not completely broken and
insane.
- `BottomSheetLayout`, which implements a bottom sheet in a way that is not completely broken.
- Standard `ViewHolder` implementations that can be used for common datatypes.
- `NavigationViewModel`, which acts as an interface to control navigation to a particular item and
navigation within `MainFragment`

View file

@ -47,7 +47,7 @@ metadata parser is stuck in 2008.
**Some files with accented/symbolic characters have corrupted tags:** When Android extracts metadata, at some point it tries to convert the bytes it extracted to a
java string, which apparently involves detecting the encoding of the data dynamically and then converting it to Java's Unicode dialect. Of course, trying to detect
codings on the fly like that is a [terrible idea](https://en.wikipedia.org/wiki/Bush_hid_the_facts), and more often than not it results in UTF-8 tags (Seen on
codings on the fly like that is a [bad idea](https://en.wikipedia.org/wiki/Bush_hid_the_facts), and more often than not it results in UTF-8 tags (Seen on
FLAC/OGG/OPUS files most often) being corrupted. It also affects MP3 files with ID3v2.4.0 tags that use the UTF-8 encoding in text-based tags.
**I have a large library and Auxio takes really long to load it:** This is expected since reading from the audio database takes awhile, especially with libraries