Tyrrrz / YoutubeExplode

Abstraction layer over YouTube's internal API
MIT License
2.95k stars 493 forks source link

Infinite waiting #126

Closed darkdoctor closed 6 years ago

darkdoctor commented 6 years ago

Hi Tyrrrz.

Hope you re doing fine.

I am trying to get mediastreaminfo for some videos and the Task will never return a result.

Video id : 8GKIKwAHOuc mediaStreamInfo = new YoutubeExplode.YoutubeClient().GetVideoMediaStreamInfosAsync(videoInfo.YoutubeId).Result;

I keep waiting for minutes ...

Tyrrrz commented 6 years ago

Hi It's probably a deadlock, make sure you await the task and not call .Result.

darkdoctor commented 6 years ago

Hi.

It works only sometime, very rare. the other stuff is reached very rare... idk y. Task.Run(async () => { mediaStreamInfo = await Youtube.Explode.Search(videoInfo.YoutubeId); ... other stuff ... });

internal static class Explode
{
    private static readonly YoutubeClient _client;

    static Explode() => _client = new YoutubeClient();

    internal static async Task<MediaStreamInfoSet> Search(string videoId) => await _client.GetVideoMediaStreamInfosAsync(videoId);
}
Tyrrrz commented 6 years ago

Nothing has changed. A lot of people had reported having similar issue and it was always because of deadlock.

e.g. #88 #92

darkdoctor commented 6 years ago

Hi.

So how I can avoid Deadlock? Is it safe to use one YoutubeClient for different Requests?

Tyrrrz commented 6 years ago

Yes it's safe. Can you show the code where you call Explode.Search(videoId) method?

darkdoctor commented 6 years ago

Hi Tyrrrz.


           if (mediaStreamInfo == null)
            {
                Toast.MakeText(activity, $"{activity.Resources.GetString(Resource.String.please_wait_c)}",
                    ToastLength.Long).Show();

                Youtube.Explode.Search(videoInfo.YoutubeId).ContinueWith(x =>
                {
                    mediaStreamInfo = x.Result;

                    if (mediaStreamInfo == null) return;

                    activity.RunOnUiThread(() =>
                    {
                        Download(activity, mediaStreamInfo, videoInfo);
                    });
                });
            }```

```c#   internal static class Explode
    {
        // Static client makes some operations to not repeat, which makes loading faster.
        private static readonly YoutubeClient _client;

        static Explode() => _client = new YoutubeClient();

        internal static async Task<MediaStreamInfoSet> Search(string videoId) => await _client.GetVideoMediaStreamInfosAsync(videoId).ConfigureAwait(false);
    }```
Tyrrrz commented 6 years ago

You are calling x.Result within the same context, which causes deadlock. You need to rewrite your code while making use of the away/async pattern instead of Wait() and Result. Read here: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/

darkdoctor commented 6 years ago

70% of videos are fine, the rest just does not work. Like this video: "JYGZV5FiCUM"

:/

So you think that I have only to rewrite the x.REsult and not the rest of code right?

Tyrrrz commented 6 years ago

Ah. JYGZV5FiCUM throws an exception and because it doesn't happen on the main thread you don't see it. This is related to #125

darkdoctor commented 6 years ago

YoutubeExplode.Exceptions.VideoUnavailableException: Video [JYGZV5FiCUM] is not available and cannot be processed. Error code: 150

Yes, just saw it now,

Tyrrrz commented 6 years ago

I'll mark it as duplicate, please wait until #125 is fixed.