SimpleStorage
SimpleStorage copied to clipboard
Downloading/manipulating M4B file adds a .MP3 file extension
Library version: 1.0.0+ OS version: Android 11 & 12 Device model: OnePlus6 & Pixel 6
Describe the bug In debugging this issue https://github.com/advplyr/audiobookshelf-app/issues/292 I found that starting at release v1.0.0 downloading .M4B audiobooks will add a .MP3 extension at the end.
I am able to resolve this issue by using v0.14.0
To Reproduce Download or move a .m4b file on v1.0.0 or above
What's the mime type you're using when saving the M4B files? Are you using audio/mp4a-latm or audio/mpeg?
Listed on this website:
audio/mp4a-latmfor M4Baudio/mpegfor MP3
The server was using node-express sendFile to serve the files which was setting the mime type based on the file extension.
I found out that M4B was not listed in the mime type db they use (https://github.com/jshttp/mime-db/blob/master/db.json)
so the mime type was application/octet-stream, which explains some other issues we've had.
I updated the server to use our internal set of mime types that uses audio/mp4 for M4B
I'm not positive but I think audio/mp4 is the best mime type for M4A and M4B files
Both M4A and M4B format are basically an audio file extension of MP4 codec, and encoded by AAC (Advanced Audio Coding)
https://www.tunefab.com/tutorials/m4a-vs-m4b.html
Will SimpleStorage handle M4B correctly with audio/mp4?
SimpleStorage relies on OS level android.webkit.MimeTypeMap to retrieve the file extension, which is statically hardcoded by the system. For example, the following code will return *.bin on OS 10+, but no extension on older OS level:
val fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType("application/octet-stream")
I will make a feature that can handle file extensions globally, regardless of the API levels by using the mime type DB you suggested. Thanks for the idea! I'll let this issue open until the feature is merged.
BTW, you had better to use SimpleStorage v1.4.1, because it contains many bugfixes. Since current Android OS does not handle M4B yet, then just use mime type */* explicitly to create M4B with v1.4.1. SimpleStorage v0.14.0 uses */* implicitly, that's why it worked.
Is there a way I can set this from the android app without having to serve the file with mime type */*?
The server is serving files to many different clients and not just the android app so I would like to keep the mime type audio/mp4 coming from the server.
The mime type DB I shared is just what node-express uses, but it is missing the mime type for the file extension I actually need so if you do use it I hope you would add M4B in there.
Update: I'm not sure I understand correctly. If the server uses audio/mp4 for M4B or M4A files will this cause a problem?
Is there a way I can set this from the android app without having to serve the file with mime type /?
No. It is the limitation from the OS itself. Nothing we can do. Using */* is the only way. To check if you can use mime type audio/mp4, simply:
val fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType("audio/mp4") ?: "*/*"
I hope you would add M4B in there.
Sure. I just need to find more reliable online mime type database out there. Please tell me if you know something better.
If the server uses audio/mp4 for M4B or M4A files will this cause a problem?
Use */* if the received mime type from the server is not recognized by android.webkit.MimeTypeMap, for example:
val mimeTypeFromServer = ...
val fileExtension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeTypeFromServer) ?: "*/*"
Use / if the received mime type from the server is not recognized by android.webkit.MimeTypeMap
I'm not sure what you mean by this. How do I use a different mime type after the file has been downloaded?
I don't think this explains why .mp3 was being appended to the M4B file with mime type application/octet-stream.
SimpleStorage was appending a file extension even though the file already had a file extension. That is the reason I'm asking if I use audio/mp4 as the mime type for a file with extension .m4b is SimpleStorage going to append .mp4?
How do I use a different mime type after the file has been downloaded?
I think I know what you mean. It is caused by extension function moveFileTo(). I have to check & reproduce it.
What is the previous file location before you moving the files? Maybe in /storage/emulated/0/Android/data/<packageName>/files?
The user selects a folder on their device where they want the audio files to go.
Downloading directly to their selected folder was crashing on certain devices (something with permissions) so I set it up to first download everything to the downloads folder:
val tempFolderPath = mainActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
then after all the audio files are downloaded they are moved into the folder the user selected. This resolved the issue with downloading files directly into their folder but might not be necessary if I figure out what the underlying issue was.
So to answer your question the files are downloaded to DIRECTORY_DOWNLOADS