GithubHelp home page GithubHelp logo

Comments (30)

MrYossu avatar MrYossu commented on May 28, 2024 1

@Tyrrrz Thanks for the reply. However, I'm stuck, as your code is basically the same as mine, with just the progress indicator removed, but when I run your code, I get the same as with my code, ie audio but no video.

Any ideas? Thanks again.

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

Hi. I was not able to reproduce this. With the following code I got both audio and video:

// Arrange
var youtube = new YoutubeClient();

using var dir = TempDir.Create();
var filePath = Path.Combine(dir.Path, "video.mp4");

// Act
await youtube.Videos.DownloadAsync(
    "tllygkj0czw",
    filePath,
    o =>
        o.SetFFmpegPath(FFmpeg.FilePath)
            .SetContainer("mp4")
            .SetPreset(ConversionPreset.UltraFast)
);

// Assert
MediaFormat.IsMp4File(filePath).Should().BeTrue();

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

By the way, I had to remove the last line as MediaFormat wasn't resolved. Didn't matter, as I checked it by playing the video, which is what's actually important.

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

That sounds weird. My only guess is that YouTube serves as different stream manifests for whatever reason. They tend to do regional-based A/B testing so it might be something like that.

Can you try to resolve the manifest and inspect the streams it provides? Using this:

https://github.com/Tyrrrz/YoutubeExplode#downloading-video-streams

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Thanks for the suggestion. What exactly am I looking for in there? I don't really know much about how the YouTube stuff works.

Please clarify what info I need to look at to see what's being provided.

Thanks again

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

If you can just dump the contents of StreamManifest as JSON, it would be nice. I'll compare it to what I get locally. You might want to scrub your IP address from the URLs, or just remove the URLs completely because they are not useful for this comparison.

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz How is this...

{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":19530951,"kiloBytes":19073.195,"megaBytes":18.626167,"gigaBytes":0.018189617},"bitrate":{"bitsPerSecond":264572,"kiloBitsPerSecond":258.3711,"megaBitsPerSecond":0.25231552,"gigaBitsPerSecond":0.00024640188}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":22408301,"kiloBytes":21883.105,"megaBytes":21.370222,"gigaBytes":0.020869358},"bitrate":{"bitsPerSecond":303561,"kiloBitsPerSecond":296.4463,"megaBitsPerSecond":0.28949833,"gigaBitsPerSecond":0.0002827132}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":127598404,"kiloBytes":124607.81,"megaBytes":121.687325,"gigaBytes":0.11883527},"bitrate":{"bitsPerSecond":4753127,"kiloBitsPerSecond":4641.7256,"megaBitsPerSecond":4.532935,"gigaBitsPerSecond":0.0044266945}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":72878255,"kiloBytes":71170.17,"megaBytes":69.50212,"gigaBytes":0.067873165},"bitrate":{"bitsPerSecond":2788605,"kiloBitsPerSecond":2723.247,"megaBitsPerSecond":2.659421,"gigaBitsPerSecond":0.0025970908}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":32270546,"kiloBytes":31514.205,"megaBytes":30.77559,"gigaBytes":0.030054288},"bitrate":{"bitsPerSecond":1102430,"kiloBitsPerSecond":1076.5918,"megaBitsPerSecond":1.0513592,"gigaBitsPerSecond":0.001026718}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":33954609,"kiloBytes":33158.797,"megaBytes":32.381638,"gigaBytes":0.031622693},"bitrate":{"bitsPerSecond":1005292,"kiloBitsPerSecond":981.73047,"megaBitsPerSecond":0.95872116,"gigaBitsPerSecond":0.00093625113}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":27429214,"kiloBytes":26786.342,"megaBytes":26.158537,"gigaBytes":0.025545446},"bitrate":{"bitsPerSecond":717750,"kiloBitsPerSecond":700.92773,"megaBitsPerSecond":0.68449974,"gigaBitsPerSecond":0.0006684568}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":18836732,"kiloBytes":18395.246,"megaBytes":17.964108,"gigaBytes":0.017543074},"bitrate":{"bitsPerSecond":695478,"kiloBitsPerSecond":679.17773,"megaBitsPerSecond":0.6632595,"gigaBitsPerSecond":0.00064771436}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":23236899,"kiloBytes":22692.285,"megaBytes":22.160433,"gigaBytes":0.021641048},"bitrate":{"bitsPerSecond":628605,"kiloBitsPerSecond":613.8721,"megaBitsPerSecond":0.59948444,"gigaBitsPerSecond":0.000585434}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":15872988,"kiloBytes":15500.965,"megaBytes":15.137661,"gigaBytes":0.014782872},"bitrate":{"bitsPerSecond":445312,"kiloBitsPerSecond":434.875,"megaBitsPerSecond":0.42468262,"gigaBitsPerSecond":0.00041472912}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":5112007,"kiloBytes":4992.1943,"megaBytes":4.87519,"gigaBytes":0.0047609275},"bitrate":{"bitsPerSecond":217592,"kiloBitsPerSecond":212.49219,"megaBitsPerSecond":0.2075119,"gigaBitsPerSecond":0.00020264834}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":11011709,"kiloBytes":10753.622,"megaBytes":10.501584,"gigaBytes":0.010255453},"bitrate":{"bitsPerSecond":398125,"kiloBitsPerSecond":388.79395,"megaBitsPerSecond":0.3796816,"gigaBitsPerSecond":0.0003707828}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":7323937,"kiloBytes":7152.282,"megaBytes":6.9846506,"gigaBytes":0.006820948},"bitrate":{"bitsPerSecond":211049,"kiloBitsPerSecond":206.10254,"megaBitsPerSecond":0.20127201,"gigaBitsPerSecond":0.0001965547}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":3540560,"kiloBytes":3457.5781,"megaBytes":3.3765411,"gigaBytes":0.0032974035},"bitrate":{"bitsPerSecond":137350,"kiloBitsPerSecond":134.13086,"megaBitsPerSecond":0.13098717,"gigaBitsPerSecond":0.00012791716}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":7495959,"kiloBytes":7320.2725,"megaBytes":7.1487036,"gigaBytes":0.006981156},"bitrate":{"bitsPerSecond":262139,"kiloBitsPerSecond":255.99512,"megaBitsPerSecond":0.24999523,"gigaBitsPerSecond":0.00024413597}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":4663921,"kiloBytes":4554.6104,"megaBytes":4.4478617,"gigaBytes":0.004343615},"bitrate":{"bitsPerSecond":127771,"kiloBitsPerSecond":124.77637,"megaBitsPerSecond":0.12185192,"gigaBitsPerSecond":0.00011899602}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":2115995,"kiloBytes":2066.4014,"megaBytes":2.01797,"gigaBytes":0.001970674},"bitrate":{"bitsPerSecond":71380,"kiloBitsPerSecond":69.70703,"megaBitsPerSecond":0.06807327,"gigaBitsPerSecond":6.6477805E-05}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":3921409,"kiloBytes":3829.501,"megaBytes":3.739747,"gigaBytes":0.0036520967},"bitrate":{"bitsPerSecond":144970,"kiloBitsPerSecond":141.57227,"megaBitsPerSecond":0.13825417,"gigaBitsPerSecond":0.00013501383}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":2683298,"kiloBytes":2620.4082,"megaBytes":2.5589924,"gigaBytes":0.002499016},"bitrate":{"bitsPerSecond":65930,"kiloBitsPerSecond":64.384766,"megaBitsPerSecond":0.06287575,"gigaBitsPerSecond":6.14021E-05}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":1211961,"kiloBytes":1183.5557,"megaBytes":1.1558161,"gigaBytes":0.0011287266},"bitrate":{"bitsPerSecond":30023,"kiloBitsPerSecond":29.319336,"megaBitsPerSecond":0.028632164,"gigaBitsPerSecond":2.7961098E-05}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":3054518,"kiloBytes":2982.9277,"megaBytes":2.9130154,"gigaBytes":0.0028447416},"bitrate":{"bitsPerSecond":70321,"kiloBitsPerSecond":68.67285,"megaBitsPerSecond":0.06706333,"gigaBitsPerSecond":6.5491535E-05}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":2547774,"kiloBytes":2488.0605,"megaBytes":2.4297466,"gigaBytes":0.0023727994},"bitrate":{"bitsPerSecond":53243,"kiloBitsPerSecond":51.995117,"megaBitsPerSecond":0.05077648,"gigaBitsPerSecond":4.9586408E-05}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":3603036,"kiloBytes":3518.5898,"megaBytes":3.436123,"gigaBytes":0.0033555888},"bitrate":{"bitsPerSecond":50166,"kiloBitsPerSecond":48.990234,"megaBitsPerSecond":0.047842026,"gigaBitsPerSecond":4.672073E-05}}
{"container":{"name":"mp4","isAudioOnly":false},"size":{"bytes":9559707,"kiloBytes":9335.651,"megaBytes":9.116847,"gigaBytes":0.008903171},"bitrate":{"bitsPerSecond":130741,"kiloBitsPerSecond":127.67676,"megaBitsPerSecond":0.124684334,"gigaBitsPerSecond":0.000121762045}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":3762110,"kiloBytes":3673.9355,"megaBytes":3.5878277,"gigaBytes":0.003503738},"bitrate":{"bitsPerSecond":53219,"kiloBitsPerSecond":51.97168,"megaBitsPerSecond":0.050753593,"gigaBitsPerSecond":4.9564056E-05}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":4809493,"kiloBytes":4696.7705,"megaBytes":4.58669,"gigaBytes":0.0044791894},"bitrate":{"bitsPerSecond":68507,"kiloBitsPerSecond":66.90137,"megaBitsPerSecond":0.06533337,"gigaBitsPerSecond":6.3802116E-05}}
{"container":{"name":"webm","isAudioOnly":false},"size":{"bytes":8582174,"kiloBytes":8381.029,"megaBytes":8.184599,"gigaBytes":0.007992772},"bitrate":{"bitsPerSecond":123760,"kiloBitsPerSecond":120.859375,"megaBitsPerSecond":0.11802673,"gigaBitsPerSecond":0.00011526048}}

Thanks again

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

Hmm seems like it's lacking a lot of data. As an alternative, can just call ToString() on every stream info and copy-paste it here? It should probably give me enough info.

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Tried ToString, but it gave even less info!

Muxed (360p | mp4)
Muxed (720p | mp4)
Video-only (1440p60 | webm)
Video-only (1440p60 | mp4)
Video-only (1080p60 | mp4)
Video-only (1080p60 | webm)
Video-only (1080p60 | mp4)
Video-only (720p60 | mp4)
Video-only (720p60 | webm)
Video-only (720p60 | mp4)
Video-only (480p | mp4)
Video-only (480p | webm)
Video-only (480p | mp4)
Video-only (360p | mp4)
Video-only (360p | webm)
Video-only (360p | mp4)
Video-only (240p | mp4)
Video-only (240p | webm)
Video-only (240p | mp4)
Video-only (144p | mp4)
Video-only (144p | webm)
Video-only (144p | mp4)
Audio-only (mp4)
Audio-only (mp4)
Audio-only (webm)
Audio-only (webm)
Audio-only (webm)

Any other suggestions? Thanks again for the help.

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

Looks fine to me. If you do a manual selection of streams, does anything change?

https://github.com/Tyrrrz/YoutubeExplode/tree/master/YoutubeExplode.Converter#manually-selecting-streams

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Failed to start ffmpeg. Where do I specify the path to it? The previous code had an extension method .SetFFmpegPath("path/to/ffmpeg"), but I can't see an overload for youtube.Videos.DownloadAsync that accepts both a ConversionRequestBuilder and the options needed to set the path to ffmpeg.

Thanks again

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024
await youtube.Videos.DownloadAsync(streamInfos, new ConversionRequestBuilder("video.mp4").SetFFmpegPath(FFmpeg.FilePath).Build());

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Thanks, that worked fine.

Is there any disadvantage to downloading this way? The page you linked says that stream muxing is a resource-intensive process, which concerns me. The previous method has worked for all videos I've tried, except for ones from this author. Is there some way of telling if the previous method will be OK, and only switching to this method if needed?

Thanks again for all the help.

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

Also, can I guarantee that there will always be a stream with label "1080p60", or do I have to loop through them all and pick the best one by parsing the label?

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

@Tyrrrz Thanks, that worked fine.

Is there any disadvantage to downloading this way? The page you linked says that stream muxing is a resource-intensive process, which concerns me. The previous method has worked for all videos I've tried, except for ones from this author. Is there some way of telling if the previous method will be OK, and only switching to this method if needed?

Thanks again for all the help.

There is no inherent disadvantage because the original approach uses this under the hood:

private static async IAsyncEnumerable<IStreamInfo> GetOptimalStreamInfosAsync(
this VideoClient videoClient,
VideoId videoId,
Container container,
[EnumeratorCancellation] CancellationToken cancellationToken = default
)
{
var streamManifest = await videoClient.Streams.GetManifestAsync(videoId, cancellationToken);
if (
streamManifest.GetAudioOnlyStreams().Any() && streamManifest.GetVideoOnlyStreams().Any()
)
{
// Include audio stream
// Priority: transcoding -> bitrate
yield return streamManifest
.GetAudioOnlyStreams()
.OrderByDescending(s => s.Container == container)
.ThenByDescending(s => s.Bitrate)
.First();
// Include video stream
if (!container.IsAudioOnly)
{
// Priority: video quality -> transcoding
yield return streamManifest
.GetVideoOnlyStreams()
.OrderByDescending(s => s.VideoQuality)
.ThenByDescending(s => s.Container == container)
.First();
}
}
// Use single muxed stream if adaptive streams are not available
else
{
// Priority: video quality -> transcoding
yield return streamManifest
.GetMuxedStreams()
.OrderByDescending(s => s.VideoQuality)
.ThenByDescending(s => s.Container == container)
.First();
}
}

When selecting streams manually, you have to account for a few different things. Reading the method implementation I linked should give more context.

I don't know why the original approach didn't work for you and I can't reproduce it. The streams you receive seem fine. If you can get a video-less output with the manual approach as well, it could provide more info. But I don't have a guess right now.

Also, can I guarantee that there will always be a stream with label "1080p60", or do I have to loop through them all and pick the best one by parsing the label?

No, you can't, that was just an example.

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Thanks again.

I dumped out the VideoQuality.Label for each of the streams, and got the following...

360p
720p
1440p60
1080p60
1080p60
720p60
720p60
480p
480p
360p
360p
240p
240p
144p
144p

I tried the same code as before, but used "1440p60" to select the stream. This gave an audio-only file again. The same happened if I used GetWithHighestBitrate instead of First(s => s.VideoQuality.Label == "1080p60"), which I guess is consistent.

However, this leaves me with a problem. How do I know which stream to pick? I can't pick the highest resolution, as that fails as you can see here. Is there a way of telling which stream will give the video as well?

Any advice? Thanks again.

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

Hmm. Can you download the 1440p60 stream by itself (using youtube.Video.Streams.DownloadAsync(...)) and see if it has any video data in itself?

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Tried the following...

string _path = @"C:\Users\Public\Downloads\";
var youtube = new YoutubeClient();
var videoUrl = "https://youtube.com/watch?v=tllygkj0czw";
var streamManifest = await youtube.Videos.Streams.GetManifestAsync(videoUrl);
var videoStreamInfo = streamManifest
    .GetVideoStreams()
    .Where(s => s.Container == Container.Mp4)
    .First(s => s.VideoQuality.Label == "1440p60");
await youtube.Videos.Streams.DownloadAsync(videoStreamInfo, $"{_path}video.mp4");

...but the file that was downloaded wouldn't play. Media Player gave an error "We can't open video. It's encoded in AVI format which isn't supported."

Does that help? Thanks again.

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

It really looks like YouTube just has a corrupted/broken stream for some reason.

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

It's odd, as it seems to happen with all of the videos from that author, but I've not noticed it with any other author.

So, I'm still left with my previous question, is there any way of telling whether a stream is going to have video or not? If I could detect that, I could choose the right stream. Otherwise I'm stuck.

Thanks again

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

What's the VideoEncoding of that stream? If you open the stream URL in the browser, can you play it? Does it return a non-zero Content-Length header?

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Not exactly sure how to find the VideoEncoding or Content-Length, but the following code...

var videoStreamInfo = streamManifest
    .GetVideoStreams()
    .Where(s => s.Container == Container.Mp4)
    .First(s => s.VideoQuality.Label == "1440p60");

Console.WriteLine($"Codec: {videoStreamInfo.VideoCodec}");
Console.WriteLine($"Bit rate: {videoStreamInfo.Bitrate.ToString()}");
Console.WriteLine($"Size: {videoStreamInfo.Size.Bytes} bytes");
Console.WriteLine($"Container: {videoStreamInfo.Container.Name}");
Console.WriteLine($"Url: {videoStreamInfo.Url}");

...gave the following output...

Codec: av01.0.12M.08
Bit rate: 2.66 Mbit/s
Size: 72878255 bytes
Container: mp4
Url: https://rr5---sn-aigzrn7z.googlevideo.com/videoplayback?expire=1709096353&ei=QWneZerOCaSXhcIP8u6h8AU&ip=81.174.251.160&id=o-AHskOsEvrhb4KeMjuZX8vadBKFVUcFZinosRLNZ0Hs5x&itag=400&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&mh=u_&mm=31%2C26&mn=sn-aigzrn7z%2Csn-5hne6nzk&ms=au%2Conr&mv=m&mvi=5&pl=21&initcwndbps=1763750&vprv=1&mime=video%2Fmp4&gir=yes&clen=72878255&dur=590.583&lmt=1707491729003654&mt=1709074385&fvip=3&keepalive=yes&fexp=24007246&c=ANDROID_TESTSUITE&txp=5532434&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cvprv%2Cmime%2Cgir%2Cclen%2Cdur%2Clmt&sig=AJfQdSswRQIhALe-uq9ymT39LJJphCPh5GMvo7kDpBuAya894bGKSbQvAiBY8vbQ190QtO-ZJkV4yhw4cVdlNq5F3SLlc3eCDGrwvg%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=APTiJQcwRQIgIMmMeg_TwO4TLJcsTrtK3qAW3O8SyZ4WZoIRLPy-YfMCIQCeOamYR73Nts5oydHYh7Js-r1A0nVVz36-PHAU59Zspw%3D%3D

Pasting that URL into a browser played the video without any audio.

Does that help? If not, please can you give me more precise instructions how to get the info you want.

Thanks again

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

Can you download that stream and upload it here?

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Short answer - no I don't seem to be able to download it. I have tried a few ways, but all time out.

I used the URL returned by the code above (regenerated as they only last a short while), but whatever C# I try, it just times out.

I first tried this...

HttpClient client=new();
var bytes = await client.GetByteArrayAsync(url)
File.WriteAllBytes(@"C:\Users\Public\Downloads\stream.mp4", bytes);

I then tried the old method...

WebRequest r=WebRequest.Create(url);
using WebResponse res=r.GetResponse();
using Stream s=res.GetResponseStream();
string file=@"C:\Users\Public\Downloads\stream.mp4";
using var fs = new FileStream(file, FileMode.OpenOrCreate);
s.CopyTo(fs);

...but had the same time-out issue both ways. The code shown earlier downloaded the file fairly quickly, so it's not the size that's a problem.

Am I doing something wrong here? Any suggestions? Thanks again

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

What if you try to download it in your browser? You said you could get it to play there, right?

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz Silly me. Forgot that I could just paste the URL into a browser and download from there 😁

Too big to upload here, so I put it on my blog.

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

The stream looks actually fine so I'm not sure what's wrong then

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

Do you have any advice as to what I can do then? I've asked a few times if there is a way of checking a stream to see if it contains the data I need, but you've not answered that one, which makes me think it can't be done.

I really need a way of getting the full audio and video, so any advice would be appreciated.

from youtubeexplode.

Tyrrrz avatar Tyrrrz commented on May 28, 2024

Yeah, I was trying to figure out if there's anything special about that stream that could let you identify it early and skip, but it doesn't appear like it's special in any way. So I unfortunately don't have any recommendations for that.

As an interim solution, I would specifically skip this combination of video quality + video codec + container for this YouTube creator. I wish I could assist you help more but I don't have the time to investigate this further.

from youtubeexplode.

MrYossu avatar MrYossu commented on May 28, 2024

@Tyrrrz OK, thanks for all the help.

from youtubeexplode.

Related Issues (20)

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.