Has anyone found a better way to stream file?
Here is what I came up with:
//http://localhost:5000/Youtube/Download/bcQQwYKkj_s
[Route("Youtube")]
public class YoutubeController : ControllerBase {
[HttpGet("Download/{id}")]
public async Task DownloadAudio(string id) {
var client = new YoutubeClient();
var mediaInfoSet = await client.GetVideoMediaStreamInfosAsync(id);
var mediaStreamInfo = mediaInfoSet.Audio.WithHighestBitrate();
var contentType = mediaStreamInfo is AudioStreamInfo ? "audio" : "video"; //With this example just put "audio" I use custom query parameters ;)
HttpContext.Response.Headers.Add("Content-Disposition", $"attachment;filename={id}.{mediaStreamInfo.Container}");
HttpContext.Response.Headers.Add("Content-Type", $"{contentType}/{mediaStreamInfo.Container}");
await client.DownloadMediaStreamAsync(mediaStreamInfo, HttpContext.Response.Body, null);
}
}
Maybe among you there is an AspNet Core guru and knows better way to do this? If No I would probably put this into examples (so I could find this later myself 馃槃).
I couldn't work it out with Task<ActionResult<FileStreamResult>> so had to do all header stuff manually.
Edit: I found a better solution for this, which allows returning IActionResult, this allows return BadRequest(...) if you do for example:
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
Here is my better solution:
[Route("Youtube")]
public class YoutubeController : ControllerBase {
[HttpGet("Download/{id}")]
public IActionResult DownloadAudio(string id) {
//TODO: validate id
var client = new YoutubeClient(); //This should be initialized in YoutubeController constructor.
return new StreamYoutubeVideo(client, id);
}
}
public class StreamYoutubeVideo : ActionResult {
private readonly IYoutubeClient _client;
private readonly string _videoId;
public StreamYoutubeVideo(IYoutubeClient client, string videoId) {
_client = client;
_videoId = videoId;
}
public override async Task ExecuteResultAsync(ActionContext context) {
var mediaInfoSet = await _client.GetVideoMediaStreamInfosAsync(_videoId);
var mediaStreamInfo = mediaInfoSet.Audio.WithHighestBitrate();
context.HttpContext.Response.Headers.Add("Content-Disposition", $"attachment;filename={_videoId}.{mediaStreamInfo.Container.GetFileExtension()}");
context.HttpContext.Response.Headers.Add("Content-Type", $"audio/{mediaStreamInfo.Container.GetFileExtension()}");
await _client.DownloadMediaStreamAsync(mediaStreamInfo, context.HttpContext.Response.Body);
}
}
Regarding your edited version, I recommend using mediaStreamInfo.Container.GetFileExtension(), this will return the actual extension instead of enum name (which can theoretically change).
Since I don't have access to Edit Wiki, I uploaded this example: https://gist.github.com/SlowLogicBoy/54200343ce3a08b5ac15555641ad4a9b
@Tyrrrz you can add this to wiki or readme :) or put a link to this gist like you always do. If you find this useful of course.
I will close this since this pollutes issue list.
Pretty cool, will give this a try sometime.
Do you have a full working example? 馃槢
My fully working solution is quite a bit different, I made this as simple as possible.
Mine has quite a few wrappers, model validations, is separated to quite a few libraries:
Model, Repository, Repository Implementation, Controller which is loaded dynamically, and quite a few DI happens so.. I could of course make this bare bones solution as an example.
Full Blown Example:
https://github.com/SlowLogicBoy/YoutubeExplode.AspNetCore.Mvc
vscode, noice 馃槑
Added to wiki :+1: