omansak / libvideo

A lightweight .NET library to download YouTube videos.
BSD 2-Clause "Simplified" License
553 stars 163 forks source link

Download Videos with Chunks does not work #214

Closed Areoxy closed 3 years ago

Areoxy commented 3 years ago

Hey,

i want to download Video with chunks, but it doesn't work. The application stop working when the Run() function is called

My Code:

# Download Video 

public async void download_video(string url, string format, int resolution)
        {
            string path = GetDefaultFolder();

            if (format == "Mp3")
            {

                Run(url);

            }

# Chunks 

        public async void Run(string url)
        {
            string path = GetDefaultFolder();

            var youtube = new CustomYouTube();

            var videos = youtube.GetAllVideosAsync(url).GetAwaiter().GetResult();
            var maxBitrate = videos.First(i => i.AudioBitrate == videos.Max(j => j.AudioBitrate));
            label7.Hide();
            label3.Text = maxBitrate.Title;
            label1.Text = $"{maxBitrate.AudioBitrate}";
            circularProgressBar1.Value = 0;
            circularProgressBar1.Show();
            youtube
                .CreateDownloadAsync(
                new Uri(maxBitrate.Uri),
                path + "/" + maxBitrate.Title + "mp4",
                new Progress<Tuple<long, long>>((Tuple<long, long> v) =>
                {
                    var percent = (int)((v.Item1 * 100) / v.Item2);
                    Console.Write(string.Format("Downloading.. ( % {0} ) {1} / {2} MB\r", percent, (v.Item1 / (double)(1024 * 1024)).ToString("N"), (v.Item2 / (double)(1024 * 1024)).ToString("N")));
                }))
                .GetAwaiter().GetResult();
        }

    }

    class CustomHandler
    {
        public HttpMessageHandler GetHandler()
        {
            CookieContainer cookieContainer = new CookieContainer();
            cookieContainer.Add(new Cookie("CONSENT", "YES+cb", "/", "youtube.com"));
            return new HttpClientHandler
            {
                UseCookies = true,
                CookieContainer = cookieContainer
            };

        }
    }

    public class CustomHandlers
    {
        public HttpMessageHandler GetHandler()
        {
            CookieContainer cookieContainer = new CookieContainer();
            cookieContainer.Add(new Cookie("CONSENT", "YES+cb", "/", "youtube.com"));
            return new HttpClientHandler
            {
                UseCookies = true,
                CookieContainer = cookieContainer
            };

        }
    }
    public class CustomYouTube : YouTube
    {
        private long chunkSize = 10_485_760;
        private long _fileSize = 0L;
        private HttpClient _client = new HttpClient();
        protected override HttpClient MakeClient(HttpMessageHandler handler)
        {
            return base.MakeClient(handler);
        }
        protected override HttpMessageHandler MakeHandler()
        {
            return new CustomHandlers().GetHandler();
        }
        public async Task CreateDownloadAsync(Uri uri, string filePath, IProgress<Tuple<long, long>> progress)
        {
            var totalBytesCopied = 0L;
            _fileSize = await GetContentLengthAsync(uri.AbsoluteUri) ?? 0;
            if (_fileSize == 0)
            {
                throw new Exception("File has no any content !");
            }
            using (Stream output = File.OpenWrite(filePath))
            {
                var segmentCount = (int)Math.Ceiling(1.0 * _fileSize / chunkSize);
                for (var i = 0; i < segmentCount; i++)
                {
                    var from = i * chunkSize;
                    var to = (i + 1) * chunkSize - 1;
                    var request = new HttpRequestMessage(HttpMethod.Get, uri);
                    request.Headers.Range = new RangeHeaderValue(from, to);
                    using (request)
                    {
                        // Download Stream
                        var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
                        if (response.IsSuccessStatusCode)
                            response.EnsureSuccessStatusCode();
                        var stream = await response.Content.ReadAsStreamAsync();
                        //File Steam
                        var buffer = new byte[81920];
                        int bytesCopied;
                        do
                        {
                            bytesCopied = await stream.ReadAsync(buffer, 0, buffer.Length);
                            output.Write(buffer, 0, bytesCopied);
                            totalBytesCopied += bytesCopied;
                            progress.Report(new Tuple<long, long>(totalBytesCopied, _fileSize));
                        } while (bytesCopied > 0);
                    }
                }
            }
        }
        private async Task<long?> GetContentLengthAsync(string requestUri, bool ensureSuccess = true)
        {
            using (var request = new HttpRequestMessage(HttpMethod.Head, requestUri))
            {
                var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
                if (ensureSuccess)
                    response.EnsureSuccessStatusCode();
                return response.Content.Headers.ContentLength;
            }
        }
    }
omansak commented 3 years ago

your run function is async did u use .GetAwaiter().GetResult();or await btw i tested your codei works perfect.

Areoxy commented 3 years ago

In the Run() function i used .GetAwaiter().GetResult(); if you mean that

omansak commented 3 years ago

use in download_video