ryanheise / just_audio

Audio Player
1.05k stars 671 forks source link

LockCachingAudioSource may store cache file in a very long filename causing error #1185

Open HandwerSTD opened 8 months ago

HandwerSTD commented 8 months ago

Which API doesn't behave as documented, and how does it misbehave? The LockCachingAudioSource API stores cache files in a very long filename which may cause FileSystemException when the URL itself becomes too long.

Minimal reproduction project Provide a link here using one of two options: Link

To Reproduce (i.e. user steps, not code) Steps to reproduce the behavior: Just play the audio as usual.

Error messages

I/flutter (30730): Proxy request failed: FileSystemException: Cannot create file, path = '/data/user/0/com.myapplication/cache/just_audio_cache/remote/880c9687b7f2f7f7d400ea1a8f72f944853f3bb32a6628b232a6a8b737e7a758.%20%E9%99%A4%E5%A4%95%E6%98%AF%E6%98%A5%E8%8A%82%E7%9A%84%E9%87%8D%E8%A6%81%E7%BB%84%E6%88%90%E9%83%A8%E5%88%86%EF%BC%8C%E6%98%AF%E5%AE%B6%E5%AE%B6%E6%88%B7%E6%88%B7%E5%9B%A2%E5%9C%86%E7%9A%84%E6%97%A5%E5%AD%90%E3%80%82.part' (OS Error: File name too long, errno = 36)
I/flutter (30730): #0      _File.throwIfError (dart:io/file_impl.dart:675:7)
I/flutter (30730): #1      _File.createSync (dart:io/file_impl.dart:306:5)
I/flutter (30730): #2      LockCachingAudioSource._fetch (package:just_audio/just_audio.dart:2939:31)
I/flutter (30730): <asynchronous suspension>

Expected behavior The audio player should work well as usual.

Screenshots N/A

Desktop (please complete the following information): Not running on Desktop / Web

Smartphone (please complete the following information):

Flutter SDK version

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.16.7, on macOS 13.6.3 22G436 darwin-x64, locale zh-Hans-CN)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✗] Xcode - develop for iOS and macOS
    ✗ Xcode installation is incomplete; a full installation is necessary for iOS and macOS development.
      Download at: https://developer.apple.com/xcode/
      Or install Xcode via the App Store.
      Once installed, run:
        sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
        sudo xcodebuild -runFirstLaunch
    ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To install see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.
[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✓] Android Studio (version 2023.1)
[✓] VS Code (version 1.86.0)
[!] Proxy Configuration
    ! NO_PROXY is not set
[✓] Connected device (2 available)
[!] Network resources
    ✗ A network error occurred while checking "https://maven.google.com/": Connection reset by peer
    ✗ A network error occurred while checking "https://github.com/": Connection reset by peer

! Doctor found issues in 4 categories.

Additional context I've looked into this problem and found that it's because there's a . (dot) in my URL, which was recognized as the file extension incorrectly by function _getCacheFile, and thus the very-long URL was wrongly included in the filename. The problem was because of + p.extension(uri.path) in the function.

In short, there's an edge case where the file extension name in the URL becomes too long (more than 192 chars), and then the cache filename will become too long as well, which causes the error.

Personally, I don't get why there's a file extension, because there's no need for humans to read the cache file extension, while machines read by file header, not extension. IMO Removing the extension would be the best choice.

ryanheise commented 8 months ago

Can you provide the URL in order to reproduce the issue? There are instructions on this.

I think the code can be improved if I have an example to test with, although in the meantime, you can pass your preferred cache file name/path into the constructor.

Personally, I don't get why there's a file extension, because there's no need for humans to read the cache file extension, while machines read by file header, not extension. IMO Removing the extension would be the best choice.

On iOS, the correct extension is required in order to play audio from a file directly. Since some people are playing from the file directly after it is downloaded, that would not work if the extension were ignored. What I could do instead of copying the extension from the URL is to infer the extension from the content type.

HandwerSTD commented 8 months ago

Links like "www.example.com/aaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(...more than 192 chars behind the dot)" should reproduce the error. I simply deleted the extension and solved the problem because I only use Android. Maybe it's worth a try to detect the extension from the content type for iOS.