Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting only audio to file/AssetReader ? #61

Open
chnbr opened this issue Nov 14, 2024 · 6 comments
Open

Getting only audio to file/AssetReader ? #61

chnbr opened this issue Nov 14, 2024 · 6 comments

Comments

@chnbr
Copy link

chnbr commented Nov 14, 2024

I need to extract the audio part and save it to a file. Currently my code works like this:

// get the stream
let stream = try await YouTube(url: inUrl).streams
  .filterAudioOnly()
  .filter { $0.fileExtension == .m4a }
  .highestAudioBitrateStream()

// download stream url to locale file
(localeUrl, _) = try await URLSession.shared.download(from: stream?.url, delegate: self)

// copy downloaded file to mpeg4audio conforming file
let copyURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0].appendingPathComponent("tmpfile", conformingTo: .mpeg4Audio)
try? FileManager.default.removeItem(at: copyURL)
try FileManager.default.moveItem(at: localeUrl, to: copyURL)

// use AssetReader to read it
let asset = AVURLAsset(url: copyURL)
let assetReader = try AVAssetReader(asset: asset)

Now my problem is that I am restricting to m4a audio files which I don't want to. However, if I remove the filter modifier I can get audio which is not coded in MPEG4 audio. Obviously I can't copy such a file with "conformingTo: .mpeg4audio".

How can I download ALL audio coding types and feed this into AssetReader ? (I think AssetReader needs a correct file extension to work properly. How do I get the audio coding file type of a correct filetype extension for the stream ?)

Thanks !

@alexeichhorn
Copy link
Owner

I usually do it via .filter { $0.isNativelyPlayable }, which ensures AVAssetReader can handle it.
You can use the .fileExtension.rawValue property to get the file extension for the cache file.
But maybe it's a good idea to first be sure that the AVAssetReader actually requires a file extension - would make it easier without of course.

@chnbr
Copy link
Author

chnbr commented Nov 15, 2024

Thanks for your response, very helpful !

In my experience nearly all YT audio is coded as "m4a". Are you aware of any other codings ? If so, can you provide a test link to a video that has audio coded other than m4a ?

@alexeichhorn
Copy link
Owner

Yes, usually you see m4a and webm audio files. For example, for video 2lAe1cqCOXo, you get:

print(streams.filter { $0.includesAudioTrack }.map { $0.fileExtension })
// → [YouTubeKit.FileExtension.m4a, YouTubeKit.FileExtension.m4a, YouTubeKit.FileExtension.mp4, YouTubeKit.FileExtension.webm, YouTubeKit.FileExtension.webm, YouTubeKit.FileExtension.webm]

@chnbr
Copy link
Author

chnbr commented Dec 26, 2024

Hi,

currently with the code segment:

let stream = try await YouTube(url: inUrl).streams
    .filterAudioOnly()
    .filter { $0.isNativelyPlayable }
    .highestAudioBitrateStream()

I get an exception and find those logs.

Is YTKit currently broken due to a change at YT ?

inURL: https://www.youtube.com/watch?v=u_LaF1L-EEs
Skipping player response from client 1. Got player response for nil instead of u_LaF1L-EEs
applying descrambler
finding initial function name
Failed to decode object from given start point: Die Daten konnten nicht geöffnet werden, da sie nicht das korrekte Format haben.
pattern (ytplayer.config\s*=\s*) failed: Der Vorgang konnte nicht abgeschlossen werden. (YouTubeKit.YouTubeKitError-Fehler 1.)
-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID. inputModality = Keyboard, inputOperation = , customInfoType = UIEmojiSearchOperations
-[RTIInputSystemClient remoteTextInputSessionWithID:performInputOperation:] perform input operation requires a valid sessionID. inputModality = Keyboard, inputOperation = , customInfoType = UIEmojiSearchOperations
applying descrambler
finding initial function name
finished regex search, matched \b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+.set([^,]+\s*,\s*([a-zA-Z0-9$]+)(
getting transform plan
finding initial function name
Failed to decode object from given start point: Die Daten konnten nicht geöffnet werden, da sie nicht das korrekte Format haben.
pattern (ytplayer.config\s*=\s*) failed: Der Vorgang konnte nicht abgeschlossen werden. (YouTubeKit.YouTubeKitError-Fehler 1.)
finding initial function name
finished regex search, matched \b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+.set([^,]+\s*,\s*([a-zA-Z0-9$]+)(
getting transform plan

@chnbr
Copy link
Author

chnbr commented Jan 14, 2025

The problem is fixed. Thanks for this project !

@chnbr
Copy link
Author

chnbr commented Jan 16, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants