Coder Social home page Coder Social logo

hexer10 / youtube_explode_dart Goto Github PK

View Code? Open in Web Editor NEW
284.0 13.0 116.0 1.14 MB

Dart library to interact with many Youtube APIs

Home Page: https://pub.dev/packages/youtube_explode_dart

License: BSD 3-Clause "New" or "Revised" License

Dart 99.86% Kotlin 0.03% Swift 0.10% Objective-C 0.01%
youtubeexplode dart youtube api download closed-captions video video-metadata muxed-streams playlists

youtube_explode_dart's Introduction

YoutubeExplodeDart

This is a port of the YoutubeExplode library from C#, most of the functions, doc comments, readme information, is taken from YoutubeExplode repository.

Pub Version GitHub Workflow Status License Lint

It used to build Youtube Downloader Flutter (A cross-platoform application to download video streams from youtube using this library & flutter)


YoutubeExplode is a library that provides an interface to query metadata of YouTube videos, playlists and channels, as well as to resolve and download video streams and closed caption tracks. Behind a layer of abstraction, the library parses raw page content and uses reverse-engineered AJAX requests to retrieve information. As it doesn't use the official API, there's also no need for an API key and there are no usage quotas.

Features from YoutubeExplode

  • Retrieve metadata on videos, playlists, channels, streams, and closed captions
  • Execute search queries and get resulting videos.
  • Get or download video streams.
  • Get closed captions.
  • Get video comments.
  • All model extend Equatable to easily perform equality checks

Differences from YoutubeExplode

  • The entry point is YoutubeExplode, not YoutubeClient.
  • Download closed captions as srt is not supported yet.
  • Search queries can be fetched from the search page as well (thus fetch Videos, Channels and Playlists).
  • More APIs implemented.

Usage

Install

Add the dependency to the pubspec.yaml (Check for the latest version)

youtube_explode_dart: ^1.10.4

Import the library

import 'package:youtube_explode_dart/youtube_explode_dart.dart';

Getting metadata of a video

The following example shows how you can extract various metadata from a YouTube video:

// You can provide either a video ID or URL as String or an instance of `VideoId`.
var video = yt.videos.get('https://youtube.com/watch?v=Dpp1sIL1m5Q'); // Returns a Video instance.

var title = video.title; // "Scamazon Prime"
var author = video.author; // "Jim Browning"
var duration = video.duration; // Instance of Duration - 0:19:48.00000

Get a list of related videos

var video = yt.videos.get('https://youtube.com/watch?v=Dpp1sIL1m5Q');
var relatedVideos = await yt.videos.getRelatedVideos(video); // video must be a Video instance.
print(relatedVideos); //prints the list of related videos

// to get the next page of related videos
relatedVideos = await relatedVideos.nextPage();

If no related video is found getRelatedVideos or nextPage will return null.

Downloading a video stream

Every YouTube video has a number of streams available. These streams may have different containers, video quality, bitrate, etc.

On top of that, depending on the content of the stream, the streams are further divided into 3 categories:

  • Muxed streams -- contain both video and audio
  • Audio-only streams -- contain only audio -- Video-only streams -- contain only video

You can request the stream manifest to get available streams for a particular video:

var yt = YoutubeExplode();

var manifest = yt.videos.streamsClient.getManifest('Dpp1sIL1m5Q');

Once you get the manifest, you can filter through the streams and choose the one you're interested in downloading:

// Get highest quality muxed stream
var streamInfo = streamManifest.muxed.withHigestVideoQuality();

// ...or highest bitrate audio-only stream
var streamInfo = streamManifest.audioOnly.withHigestBitrate()

// ...or highest quality MP4 video-only stream
var streamInfo.videoOnly.where((e) => e.container == Container)

Finally, you can get the actual Stream object represented by the metadata:

if (streamInfo != null) {
  // Get the actual stream
  var stream = yt.video.streamClient.get(streamInfo);
  
  // Open a file for writing.
  var file = File(filePath);
  var fileStream = file.openWrite();

  // Pipe all the content of the stream into the file.
  await stream.pipe(fileStream);

  // Close the file.
  await fileStream.flush();
  await fileStream.close();
}

While it may be tempting to just always use muxed streams, it's important to note that they are limited in quality. Muxed streams don't go beyond 720p30.

If you want to download the video in maximum quality, you need to download the audio-only and video-only streams separately and then mux them together on your own. There are tools like FFmpeg that let you do that.

Working with playlists

Among other things, YoutubeExplode also supports playlists:

var yt = YoutubeExplode();

// Get playlist metadata.
var playlist = await yt.playlists.get('xxxxx');

var title = playlist.title;
var author = playlist.author;

  await for (var video in yt.playlists.getVideos(playlist.id)) {
    var videoTitle = video.title;
    var videoAuthor = video.author;
  }

var playlistVideos = await yt.playlists.getVideos(playlist.id);

// Get first 20 playlist videos.
var somePlaylistVideos = await yt.playlists.getVideos(playlist.id).take(20);

Extracting closed captions

Similarly, to streams, you can extract closed captions by getting the manifest and choosing the track you're interested in:

  var yt = YoutubeExplode();

  var trackManifest = await yt.videos.closedCaptions.getManifest('_QdPW8JrYzQ')

  var trackInfo = manifest.getByLanguage('en'); // Get english caption.
  
  if (trackInfo != null)
  {
     // Get the actual closed caption track.
     var track = await youtube.videos.closedCaptions.get(trackInfo);
      
    // Get the caption displayed at 1:01
    var caption = track.getByTime(Duration(seconds: 61));
    var text = caption?.text; // "And the game was afoot."
  }

Getting comments

You can easily get the video comments of a given video, the return value of commentsClient.getComments(video) is a list-like object which behaves exactly like a List but has an additional method nextPage() which is used in order to get the next comments, it returns null when there are no comments to be fetched anymore.

var comments = await yt.videos.commentsClient.getComments(video);

var replies = await yt.videos.commentsClient.getReplies(comment); // Fetch the comment replies 

Cleanup

You need to close YoutubeExplode's http client, when done otherwise this could halt the dart process.

yt.close();

Examples:

More examples available on GitHub.


Check the api documentation for additional information. You can find how most APIs can be used in the files inside the test/ folder.

Credits

youtube_explode_dart's People

Contributors

artx-ii avatar bemacized avatar coronon avatar felixgabler avatar hexer10 avatar igormidev avatar itssidhere avatar mitchpk avatar mymikemiller avatar nikosportolos avatar prateekmedia avatar shinyford avatar vi-k avatar wingch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

youtube_explode_dart's Issues

Very slow download?

Bug:

It looks like it's downloading each piece every 10 seconds

Code:

import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:path_provider/path_provider.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';

// Initialize the YoutubeExplode instance.
final yt = YoutubeExplode();

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  print('Type the video id or url: ');

  var url = "https://www.youtube.com/watch?v=I7pBaCorMfM";

  // Save the video to the download directory.
  var dir = await getExternalStorageDirectory();
  Directory(dir.path).createSync();

  // Download the video.
  await download(url);

  yt.close();
  exit(0);
}

Future<void> download(String id) async {
  // Get video metadata.
  var video = await yt.videos.get(id);

  // Get the video manifest.
  var manifest = await yt.videos.streamsClient.getManifest(id);
  var streams = manifest.audioOnly;

  // Get the last audio track (the one with the highest bitrate).
  var audio = streams.last;
  var audioStream = yt.videos.streamsClient.get(audio);

  // Compose the file name removing the unallowed characters in windows.
  var fileName = '${video.title}.${audio.container.name.toString()}'
      .replaceAll('Container.', '')
      .replaceAll(r'\', '')
      .replaceAll('/', '')
      .replaceAll('*', '')
      .replaceAll('?', '')
      .replaceAll('"', '')
      .replaceAll('<', '')
      .replaceAll('>', '')
      .replaceAll('|', '');
  var dir = await getExternalStorageDirectory();
  print(dir.path);
  var file = File('${dir.path}/$fileName');

  // Create the StreamedRequest to track the download status.

  // Open the file in appendMode.
  var output = file.openWrite(mode: FileMode.writeOnlyAppend);

  // Track the file download status.
  var len = audio.size.totalBytes;
  var count = 0;
  var oldProgress = -1;

  // Create the message and set the cursor position.
  var msg = 'Downloading `${video.title}`(.${audio.container.name}):  \n';
  print(msg);
  //  var row = console.cursorPosition.row;
//  var col = msg.length - 2;
//  console.cursorPosition = Coordinate(row, 0);
//  console.write(msg);

  // Listen for data received.
  await for (var data in audioStream) {
    count += data.length;
    var progress = ((count / len) * 100).round();
    if (progress != oldProgress) {
//      console.cursorPosition = Coordinate(row, col);
      print('$progress%');
      oldProgress = progress;
    }
    output.add(data);
  }
  await output.close();
}

Flutter Doctor

    โ€ข Flutter version 1.17.3 at /home/rafael/flutter
    โ€ข Framework revision b041144f83 (2 weeks ago), 2020-06-04 09:26:11 -0700
    โ€ข Engine revision ee76268252
    โ€ข Dart version 2.8.4

[โœ“] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    โ€ข Android SDK at /home/rafael/Android/Sdk
    โ€ข Platform android-29, build-tools 29.0.3
    โ€ข Java binary at: /home/rafael/.local/share/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6325121/jre/bin/java
    โ€ข Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    โ€ข All Android licenses accepted.

[โœ“] Android Studio (version 4.1)
    โ€ข Android Studio at /home/rafael/.local/share/JetBrains/Toolbox/apps/AndroidStudio/ch-0/193.6325121
    โ€ข Flutter plugin version 43.0.3
    โ€ข Dart plugin version 193.5731
    โ€ข Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[!] IntelliJ IDEA Ultimate Edition (version 2019.3)
    โ€ข IntelliJ at /home/rafael/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/193.6911.18
    โœ— Flutter plugin not installed; this adds Flutter specific functionality.
    โœ— Dart plugin not installed; this adds Dart specific functionality.
    โ€ข For information about installing plugins, see
      https://flutter.dev/intellij-setup/#installing-the-plugins

[โœ“] Connected device (1 available)
    โ€ข Redmi Note 5 โ€ข 41e4e3c โ€ข android-arm64 โ€ข Android 9 (API 28)

! Doctor found issues in 1 category.

Is there a way to get a list of videos related to the given videoid?

I am using the plugin, everything works very well, but I have a problem that is getting a list of videos related to the given videoid. I can also get by youtube's api, but it requires usage quota. Can we achieve this through plugins without using apikey? Thanks

https://www.googleapis.com/youtube/v3/search?part=snippet&relatedToVideoId=EWz4fITO5qg&type=video&key=...

[BUG] On channels.getUploads: Bad state: Stream has already been listened to.

Describe the bug
I'm new-ish to Dart so I'm very probably doing something wrong with Streams here, but I figured the following should work, and should re-fetch the stream from the beginning a second time, creating a second list with no problem:

To Reproduce

    final channelId =
        yt_explode.ChannelId.fromString('UC9CuvdOVfMPvKCiwdGKL3cQ');
    final list =
        await _youtubeExplode.channels.getUploads(channelId).toList();
    final list2 =
        await _youtubeExplode.channels.getUploads(channelId).toList();

Instead I get this error on the list2 line: Bad state: Stream has already been listened to. But shouldn't calling getUploads a second time create an entirely new stream? Why, then, is it complaining that the stream has already been listened to?

Enviroment: (please complete the following information):

  • Enviroment: Dart VM
  • Version: 2.8.2 (stable)

NoSuchMethodError: Class 'VideoStreamInfo' has no instance method 'downloadStream'.

I'm using youtube_exploade_dart by following this Code to download youtube video.

// Get the video media stream.
var mediaStream = await yt.getVideoMediaStream(id);
var video = mediaStream.video.last;

// Listen for data received.
await for (var data in video.downloadStream()) {...

So, on this line facing this error

[ERROR:flutter/shell/common/shell.cc(213)] Dart Error: Unhandled exception:
E/flutter (24156): NoSuchMethodError: Class 'VideoStreamInfo' has no instance method 'downloadStream'.
E/flutter (24156): Receiver: Instance of 'VideoStreamInfo'
E/flutter (24156): Tried calling: downloadStream()
E/flutter (24156): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)

Feature request: Return uploads in order

Is your feature request related to a problem? Please describe.
Problem: Uploads are returned in reverse order (newer videos first, older videos last). I need them in the order the user uploaded them in, which currently requires me to fetch the entire list so it can be reversed before doing anything with it.

Describe the solution you'd like
Would be nice to be able to obtain a Stream of uploads in the order they were uploaded, like if you selected "Sort By: Date added (oldest)" on the channel's upload page.

Describe alternatives you've considered
Use .toList().reversed on the Stream. This defeats the purpose of using Streams to avoid unnecessary computation and http requests. The entire list of the user's uploads must be fetched before I can start work on any of them (my work must be performed on the older videos first)

How should this be implemented
Maybe something can be added to the playerlist_response request to get the results to come back in reverse order. I'm not sure how the channel's videos page does it, when the results are sorted oldest to newest.

Unable to open audio stream url on iOS

It seems to work fine for Android, but iOS seems to not be able to open the generated audio stream url from getManifest(). I could be doing something wrong in my code, so I'm not sure.

Fix WatchPage like and dislike getter

As of now they sometimes work and sometimes don't:

  //TODO: Update this to the new "parsing method" w/ regex "label"\s*:\s*"([\d,\.]+) likes"
  int get videoLikeCount => int.parse(_root
          .querySelector('.like-button-renderer-like-button')
          ?.text
          ?.stripNonDigits()
          ?.nullIfWhitespace ??
      '0');

  //TODO: Update this to the new "parsing method" w/ regex "label"\s*:\s*"([\d,\.]+) dislikes"
  int get videoDislikeCount => int.parse(_root
          .querySelector('.like-button-renderer-dislike-button')
          ?.text
          ?.stripNonDigits()
          ?.nullIfWhitespace ??
      '0');

[BUG] Unhandled HttpException when downloading

Describe the bug
I often get an HttpException when downloading videos. Because the exception occurs inside the library's code, my only recourse is to restart the download from the beginning every time the error occurs.

To Reproduce

dependencies:
  youtube_explode_dart: ^1.3.0
import 'package:youtube_explode_dart/youtube_explode_dart.dart' as yt_explode;
final _yt = yt_explode.YoutubeExplode();
var manifest = await _yt.videos.streamsClient.getManifest('Nt6h2EKQE68');
var videoStreamInfo = manifest.muxed.firstWhere((streamInfo) => streamInfo.container == yt_explode.Container.mp4);
var output = file.openWrite(mode: FileMode.writeOnlyAppend);

var success = false;
while (success == false) {
    try {
        final stream = _yt.videos.streamsClient.get(videoStreamInfo);
        await for (var data in stream) {
            output.add(data);
        }
        success = true;
    } catch (e) {
        // We sometimes get the following error from the youtube_explode
        // library, which I'm not sure how to overcome so we just restart the
        // download and hope for the best the next time.
        //
        // _TypeError (type '(HttpException) => Null' is not a subtype of type
        // '(dynamic) => dynamic')
        //
        // See
        // https://stackoverflow.com/questions/62419270/re-trying-last-item-in-stream-and-continuing-from-there
        
        print(e);
        // Clear the file and start over
        await file.writeAsBytes([]);
        output = file.openWrite(mode: FileMode.writeOnlyAppend);
    }
}

Output

Downloading `Down Under - NSP`:
51% [====================================================>                                                    ]
type '(HttpException) => Null' is not a subtype of type '(dynamic) => dynamic'
48% [=================================================>                                                       ]
type '(HttpException) => Null' is not a subtype of type '(dynamic) => dynamic'
48% [=================================================>                                                       ]
type '(HttpException) => Null' is not a subtype of type '(dynamic) => dynamic'
42% [===========================================>                                                             ]

Stacktrace
The error looks like it's happening here. Of course I can't edit this code, but some retry logic around the individual http requests could potentially workaround the issue without requiring me to discard all the data I've already downloaded. With the particular run shown above, it was happening around halfway through the download attempts each time, but it often happens at random times; I haven't noticed any discernible pattern.

Enviroment: (please complete the following information):

  • Enviroment: Dart VM (server app)
  • Version 2.8.2 (stable)

[BUG] some youtube videos show only one quality of mix

Describe the bug
Hello sir your packages is awesome... but i am facing a problem related to mix quality

video url ---> https://youtu.be/zzwRbKI2pn4

sir this video shows only 360p quality and not showing 720p i am using mix (audio and video both)..

but i try for another video also they shows both quality ... i am asking you sir why this happens... please help me sir thanks in advance love from INDIA...

sorry for my bad english...

How to extract auto-generated and auto-translate closed captions?

First of all, thanks for this awesome plugin. Just wondering if we can extract the auto-generated and auto-translate closed captions?

I can extract human-generated closed captions, but when I tried the auto-generated and auto-translate ones, I got the null result. If not supported yet, hope it is possible in the next version. And please keep evolving this plugin. You guys are doing awesome job. Cheers.

NoSuchMethodError: The getter 'attributes' was called on null.

NoSuchMethodError: The getter 'attributes' was called on null.
Receiver: null
Tried calling: attributes
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1      YoutubeExplode.getVideo (package:youtube_explode_dart/src/youtube_explode_base.dart:405:10)
<asynchronous suspension>
#2      <my processor class>
#3      main.<anonymous closure>.<anonymous closure> (<my class>)
#4      Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:172:27)
<asynchronous suspension>
#5      Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
#6      Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:246:15)
#7      _rootRun (dart:async/zone.dart:1184:13)
#8      _CustomZone.run (dart:async/zone.dart:1077:19)
#9      _runZoned (dart:async/zone.dart:1619:10)
#10     runZoned (dart:async/zone.dart:1539:10)
#11     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:243:5)
#12     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:170:33)
#13     _rootRun (dart:async/zone.dart:1184:13)
#14     _CustomZone.run (dart:async/zone.dart:1077:19)
#15     _runZoned (dart:async/zone.dart:1619:10)
#16     runZoned (dart:async/zone.dart:1539:10)
#17     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:13)
#18     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:400:30)
#19     new Future.<anonymous closure> (dart:async/future.dart:176:37)
#20     StackZoneSpecification._run (package:stack_trace/src/stack_zone_specification.dart:209:15)
#21     StackZoneSpecification._registerCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart:119:48)
#22     _rootRun (dart:async/zone.dart:1180:38)
#23     _CustomZone.run (dart:async/zone.dart:1077:19)
#24     _CustomZone.runGuarded (dart:async/zone.dart:979:7)
#25     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1019:23)
#26     StackZoneSpecification._run (package:stack_trace/src/stack_zone_specification.dart:209:15)
#27     StackZoneSpecification._registerCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart:119:48)
#28     _rootRun (dart:async/zone.dart:1184:13)
#29     _CustomZone.run (dart:async/zone.dart:1077:19)
#30     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1003:23)
#31     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:23:15)
#32     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#33     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#34     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
Expected: <true>
  Actual: <false>
#0      fail (package:test_api/src/frontend/expect.dart:154:30)
#1      _expect (package:test_api/src/frontend/expect.dart:148:3)
#2      expect (package:test_api/src/frontend/expect.dart:60:3)
#3      main.<anonymous closure>.<anonymous closure> (<my class>)
<asynchronous suspension>
#4      main.<anonymous closure>.<anonymous closure> (<my class>)
#5      Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:172:27)
<asynchronous suspension>
#6      Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart)
#7      Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:246:15)
#8      _rootRun (dart:async/zone.dart:1184:13)
#9      _CustomZone.run (dart:async/zone.dart:1077:19)
#10     _runZoned (dart:async/zone.dart:1619:10)
#11     runZoned (dart:async/zone.dart:1539:10)
#12     Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:243:5)
#13     Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:170:33)
#14     _rootRun (dart:async/zone.dart:1184:13)
#15     _CustomZone.run (dart:async/zone.dart:1077:19)
#16     _runZoned (dart:async/zone.dart:1619:10)
#17     runZoned (dart:async/zone.dart:1539:10)
#18     Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:13)
#19     Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:400:30)
#20     new Future.<anonymous closure> (dart:async/future.dart:176:37)
#21     StackZoneSpecification._run (package:stack_trace/src/stack_zone_specification.dart:209:15)
#22     StackZoneSpecification._registerCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart:119:48)
#23     _rootRun (dart:async/zone.dart:1180:38)
#24     _CustomZone.run (dart:async/zone.dart:1077:19)
#25     _CustomZone.runGuarded (dart:async/zone.dart:979:7)
#26     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1019:23)
#27     StackZoneSpecification._run (package:stack_trace/src/stack_zone_specification.dart:209:15)
#28     StackZoneSpecification._registerCallback.<anonymous closure> (package:stack_trace/src/stack_zone_specification.dart:119:48)
#29     _rootRun (dart:async/zone.dart:1184:13)
#30     _CustomZone.run (dart:async/zone.dart:1077:19)
#31     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1003:23)
#32     Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:23:15)
#33     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
#34     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
#35     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:168:12)
      var id = YoutubeExplode.parseVideoId(url);

      var video = await YoutubeExplode().getVideo(id);

This is in my test file. This was working with the exact same url for over 50 times before. It suddenly stopped working today without changing any code.

Web support

after version 0.0.10 there's no web support can we get web support in future.

Implement VideoStreamExtension

Right now it is not added to the library but it provides useful functions, such as get the video with the highest quality.

NoSuchMethodError: The method 'split' was called on null.

Tried calling singles('https://www.youtube.com/watch?v=RIuk23XHYj0') but received error:

Unhandled exception: NoSuchMethodError: The method 'split' was called on null. Receiver: null Tried calling: split("&")

Singles Function

Future singles(String myId) async{
  // Intializing
  String id = YoutubeExplode.parseVideoId(myId);
  print('ID: --------------- $id');
  if(id == null){
    return '$id is null';
  }
  var yt = YoutubeExplode();
  var metadata = await yt.getVideo(id); // Returns a Video instance.
  print('METADATA: -------------- $metadata');

  MediaStreamInfoSet mediaStreams = await yt.getVideoMediaStream(id); // Actual downloading here
  var audio = mediaStreams.audio;
  print(audio);

  yt.close();
}

Full stacktrace

youtube_download.dart: Warning: Interpreting this as package URI, 'package:test_download/youtube_download.dart'.
ID: --------------- RIuk23XHYj0
METADATA: -------------- Video(RIuk23XHYj0): JACKBOYS - GANG GANG feat. Sheck Wes, Don Toliver, Luxury Tax 50 & Cactus Jack (Official)
Unhandled exception:
NoSuchMethodError: The method 'split' was called on null.
Receiver: null
Tried calling: split("&")
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1      Uri.splitQueryString (dart:core/uri.dart:1180:18)
#2      decipherUrl (package:youtube_explode_dart/src/cipher/cipher.dart:100:23)
#3      YoutubeExplode.getVideoMediaStream (package:youtube_explode_dart/src/youtube_explode_base.dart:62:23)
<asynchronous suspension>
#4      singles (package:test_download/youtube_download.dart:14:46)
<asynchronous suspension>
#5      main (package:test_download/youtube_download.dart:43:3)
#6      _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:305:32)
#7      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)

[BUG] NoSuchMethodError when downloading: The method 'openUrl' was called on null

Describe the bug
I've resolved the issue (it was my fault), but I wanted to include this here in case someone searches for this error (or, more realistically if I end up searching for it later...)

This error happens when you try to use the YoutubeExplode object after it's been closed.

To Reproduce

Stacktrace

Unhandled exception:
NoSuchMethodError: The method 'openUrl' was called on null.
Receiver: null
Tried calling: openUrl("GET", Instance of '_SimpleUri')
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1      IOClient.send (package:http/src/io_client.dart:31:37)
#2      YoutubeHttpClient.send (package:youtube_explode_dart/src/reverse_engineering/youtube_http_client.dart:129:24)
#3      BaseClient._sendUnstreamed (package:http/src/base_client.dart:176:38)
#4      BaseClient.get (package:http/src/base_client.dart:35:7)
#5      YoutubeHttpClient.get (package:youtube_explode_dart/src/reverse_engineering/youtube_http_client.dart:58:32)
#6      YoutubeHttpClient.getString (package:youtube_explode_dart/src/reverse_engineering/youtube_http_client.dart:46:26)
#7      EmbedPage.get.<anonymous closure> (package:youtube_explode_dart/src/reverse_engineering/responses/embed_page.dart:42:34)
#8      retry (package:youtube_explode_dart/src/retry.dart:15:28)
#9      EmbedPage.get (package:youtube_explode_dart/src/reverse_engineering/responses/embed_page.dart:41:12)
#10     StreamsClient._getStreamContextFromVideoInfo (package:youtube_explode_dart/src/videos/streams/streams_client.dart:36:37)
#11     StreamsClient.getManifest (package:youtube_explode_dart/src/videos/streams/streams_client.dart:222:27)

Enviroment: (please complete the following information):

  • Enviroment: Dart VM
  • Version 2.8.2 (stable)

Does anyone know how to change audio encoding

Just wondering if it's possible to change the encoding to mp3, mp4a etc for this:

 MediaStreamInfoSet mediaStreams = await yt.getVideoMediaStream(id);
 var audio = mediaStreams.audio.last; // Highest bitrate

The encoding is currently sitting at '.webM'

Search youtube

It looks like YoutubExplode can extract a list of youtube videos as if you searched them on youtube.

This functionality is missing in this plugin.

[BUG] Download of stream is not working raises "NoSuchMethodError"

Hello guys,

i wanted to download a youtube video via a given id.

Steps to reproduce the bug:

I am using right now the following lines of code (like it's used in the example):

 
class Downloader {

  YoutubeExplode ytExp;
  VideoId id;

  Downloader(String id) {
    this.ytExp = new YoutubeExplode();
    this.id = new VideoId(id);
  }

  Future<void> downloadVideo(String title) async {
    print(">> Start Download");

    var video = await ytExp.videos.get(this.id);
    
    // Request permission to write in an external directory.
    // (In this case downloads)
    await Permission.storage.request();

    // Get the streams manifest and the audio track.
    var manifest = await ytExp.videos.streamsClient.getManifest(this.id.toString());
    var audio = manifest.audioOnly.last;


    // Build the directory.
    var dir = await DownloadsPathProvider.downloadsDirectory;
    var filePath = path.join(dir.uri.toFilePath(),
        '$title.${audio.container.name}');

    // Open the file to write.
    var file = File(filePath);
    var fileStream = file.openWrite();

    // Pipe all the content of the stream into our file.
    await ytExp.videos.streamsClient.get(audio).pipe(fileStream);

    // Close the file.
    await fileStream.flush();
    await fileStream.close();

    print(">> Download finished");
  }

What is happening:

the line var manifest = await ytExp.videos.streamsClient.getManifest(this.id.toString()); of my code causes the error:

NoSuchMethodError (NoSuchMethodError: The method 'group' was called on null.
Receiver: null
Tried calling: group(0)) 

What is happening in YoutubeExplode:

My Code calls the method (not my code anymore):

Future<StreamManifest> getManifest(dynamic videoId) async {
   videoId = VideoId.fromString(videoId);
   // We can try to extract the manifest from two sources:
   //    get_video_info and the video watch page.
   // In some cases one works, in some cases another does.
   try {
     var context = await _getStreamContextFromVideoInfo(videoId);
     return _getManifest(context);
   } on YoutubeExplodeException {
     var context = await _getStreamContextFromWatchPage(videoId);
     return _getManifest(context);
   }
 }

of the class StreamsClient.

This class can be found in the file: youtube_explode_dart/lib/src/videos/streams/streams_client.dart .


The method getManifest() is calling then _getManifest(content).
The method looks like this:

Future<StreamManifest> _getManifest(StreamContext streamContext) async {
    // To make sure there are no duplicates streams, group them by tag
    var streams = <int, StreamInfo>{};

    for (var streamInfo in streamContext.streamInfoProviders) {
      var tag = streamInfo.tag;
      var url = Uri.parse(streamInfo.url);

      // Signature
      var signature = streamInfo.signature;
      var signatureParameter = streamInfo.signatureParameter ?? "signature";

      if (!signature.isNullOrWhiteSpace) {
        signature = streamContext.cipherOperations.decipher(signature);
        url = url.setQueryParam(signatureParameter, signature);
      }

      // Content length
      var contentLength = streamInfo.contentLength ??
          await _httpClient.getContentLength(url, validate: false) ??
          0;

      if (contentLength <= 0) {
        continue;
      }

...

...

I found out that the line signature = streamContext.cipherOperations.decipher(signature); then is causing the error.


Appreciate every kind of help! :)

Invalid argument (channelId): Invalid YouTube channel id.:

While using getChannelUploads I'm getting Invalid YouTube channel id for most of the channels. Please give me a solution.
The Year, Month, Date of the .uploadDate of all videos fetched from getChannelUploads is 1975-01-08, but the time is correct.

How to change the quality of the iPhone

I'm downloading the video using that source, and the iPhone always uses Muxed Stream to get the video, so I can't change the image quality.
How can I change it?

[BUG] Decipher error

Describe the bug
Can get audio source url correct its return an url that is not playable or the cipher throws exception
This is the url I am trying with and its failing -> https://m.youtube.com/watch?v=cxjvTXo9WWM

Stacktrace
Include here the stacktrace (if applicable).
E/flutter (23429): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The method 'group' was called on null. E/flutter (23429): Receiver: null E/flutter (23429): Tried calling: group(1) E/flutter (23429): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5) E/flutter (23429): #1 PlayerSource._getDeciphererDefinitionBody (package:youtube_explode_dart/src/reverse_engineering/responses/player_source.dart:98:62) E/flutter (23429): #2 PlayerSource.getCiperOperations (package:youtube_explode_dart/src/reverse_engineering/responses/player_source.dart:47:26) E/flutter (23429): #3 _SyncIterator.moveNext (dart:core-patch/core_patch.dart:146:23) E/flutter (23429): #4 ListDecipher.decipher (package:youtube_explode_dart/src/extensions/helpers_extension.dart:38:27) E/flutter (23429): #5 StreamsClient._getManifest (package:youtube_explode_dart/src/videos/streams/streams_client.dart:134:52) E/flutter (23429): #6 StreamsClient.getManifest (package:youtube_explode_dart/src/videos/streams/streams_client.dart:223:14)

Web support with cors

Hello Sir, I'm having this problem:
image

Do you have any idea of โ€‹โ€‹a solution?
Regards.

The README.md file is outdated and wrong

Is your feature request related to a problem? Please describe.
The README.md file is outdated and does not comply with the actual functions to be used with the library.

Describe the solution you'd like
The README.md file needs to be updated according to the latest version,

How should this be implemented
I can contribute to this work as i have successfully implemented this in my device, and know where what modifications are needed. Please assign this to me.
Additional context
image
In this image as you can see that the function provided in the readme file is not an actual function of this library.

Thank You !

Implement more tests

  • Test for channelId method of Video

  • Test for thumbnails for Playlist

  • Test for getUploadsFromPage for ChannelClient

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.