private void InitPlayer(string videoUri, NetworkCredential account, Size size = default(Size)) { hostedPlayer = new HostedPlayer(); playerDisposables.Add(hostedPlayer); if (size != default(Size)) { videoBuffer = new VideoBuffer(size.Width, size.Height, PixFrmt.bgra32); } else { videoBuffer = new VideoBuffer(720, 576, PixFrmt.bgra32); } hostedPlayer.SetVideoBuffer(videoBuffer); MediaStreamInfo.Transport transport = MediaStreamInfo.Transport.Tcp; MediaStreamInfo streamInfo = null; if (account != null) { streamInfo = new MediaStreamInfo(videoUri, transport, new UserNameToken(account.UserName, account.Password)); } else { streamInfo = new MediaStreamInfo(videoUri, transport); } playerDisposables.Add( hostedPlayer.Play(streamInfo, this) ); InitPlayback(videoBuffer, true); }
/// <inheritdoc /> public async Task DownloadMediaStreamAsync(MediaStreamInfo info, Stream output, IProgress <double>?progress = null, CancellationToken cancellationToken = default) { using var input = await GetMediaStreamAsync(info).ConfigureAwait(false); await input.CopyToAsync(output, progress, cancellationToken).ConfigureAwait(false); }
/// <summary> /// Returns the file extension for specified video type. /// To avoid conflicting file names, the codec extension must be different than the final extension. /// </summary> /// <param name="video">The video type to get file extension for.</param> /// <returns>The file extension.</returns> public static string GetFinalExtension(MediaStreamInfo video, AudioStreamInfo audio) { if ((video == null || video.Container == Container.WebM) && (audio == null || audio.Container == Container.WebM)) { return(".webm"); } else if ((video == null || video.Container == Container.Mp4) && (audio == null || audio.Container == Container.Mp4 || audio.Container == Container.M4A)) { return(".mp4"); } else if (video != null && (video.Container == Container.Mp4 || video.Container == Container.WebM)) { return(".mkv"); } else if (video != null) { return(GetCodecExtension(video.Container)); } else if (audio != null) { return(GetCodecExtension(audio.Container)); } else { return(""); } }
public async Task <string> Download(string url, Action <int> progressCallback, string newPath, bool onlyMusic) { string result = null; var streamInfoSet = await client.GetVideoMediaStreamInfosAsync(url); MediaStreamInfo stream = null; if (onlyMusic) { stream = streamInfoSet.Audio.WithHighestBitrate(); } else { stream = streamInfoSet.Muxed.WithHighestVideoQuality(); } var fileExtension = stream.Container.GetFileExtension(); result = newPath + "." + fileExtension; var fileStream = File.Create(result); var progress = new DownladProgress(progressCallback); await client.DownloadMediaStreamAsync(stream, fileStream, progress); return(result); }
/// <summary> /// Gets the actual media stream associated with given metadata /// and downloads it to a file. /// </summary> public async Task DownloadMediaStreamAsync(MediaStreamInfo info, string filePath, IProgress <double> progress, CancellationToken cancellationToken) { info.GuardNotNull(nameof(info)); filePath.GuardNotNull(nameof(filePath)); // Save to file using (var input = await GetMediaStreamAsync(info).ConfigureAwait(false)) using (var output = File.Create(filePath)) { var buffer = new byte[4 * 1024]; int bytesRead; long totalBytesRead = 0; do { // Read totalBytesRead += bytesRead = await input.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false); // Write await output.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); // Report progress progress?.Report(1.0 * totalBytesRead / input.Length); } while (bytesRead > 0); } }
public MediaStreamInfo ToStreamInfo() { MediaStreamInfo stream = null; if (CodecType == "audio") { stream = new AudioStreamInfo { ChannelLayout = this.ChannelLayout, ChannelCount = this.ChannelCount, SampleFormat = FfmpegHelper.ParseSampleFormat(SampleFormat), SampleRate = SampleRate, }; } else if (CodecType == "video") { stream = new VideoStreamInfo { PixelFormat = PixelFormatHelper.Parse(PixelFormat), Width = this.Width, Height = this.Height }; if (Tags != null && Tags.TryGetValue("rotate", out var rotate)) { ((VideoStreamInfo)stream).Rotate = (int)rotate; } } else if (CodecType == "subtitle") { stream = new SubtitleStreamInfo { }; } else if (CodecType == "data") { stream = new DataStreamInfo { }; } else { stream = new MediaStreamInfo(); } stream.Codec = Profile != null?CodecInfo.Create(CodecIdHelper.Parse(CodecName), Profile).Name : CodecName; if (TimeBase != null && Rational.TryParse(TimeBase, out var timeBase)) { stream.TimeBase = timeBase; } stream.Duration = Duration ?? TimeSpan.Zero; stream.StartTime = StartTime ?? TimeSpan.Zero; stream.FrameCount = FrameCount; return(stream); }
/// <inheritdoc /> public async Task DownloadMediaStreamAsync(MediaStreamInfo info, string filePath, IProgress <double> progress = null, CancellationToken cancellationToken = default(CancellationToken)) { filePath.GuardNotNull(nameof(filePath)); using (var output = File.Create(filePath)) await DownloadMediaStreamAsync(info, output, progress, cancellationToken).ConfigureAwait(false); }
/// <inheritdoc /> public MediaStream GetMediaStreamAsync(MediaStreamInfo info) { info.GuardNotNull(nameof(info)); // Get stream var stream = _httpClient.GetStreamAsync(info.Url).Result; //.ConfigureAwait(false); return(new MediaStream(info, stream)); }
/// <summary> /// Downloads video and saves it to the provided videoPath folder /// </summary> /// <param name="id">ID of the video to download</param> /// <param name="quality">Choosen quality of the video</param> /// <param name="videoPath">Path where file should be saved and what file should be named with extension at the end (.mp4/.mp3).</param> /// <returns></returns> public async Task DownloadVideoAsync(string id, string quality, string videoPath) { MediaStreamInfoSet streamInfoSet = await client.GetVideoMediaStreamInfosAsync(id); var audioStreamInfo = streamInfoSet.Audio.WithHighestBitrate(); var videoStreamInfo = streamInfoSet.Video.FirstOrDefault(c => c.VideoQualityLabel == quality); var mediaStreamInfos = new MediaStreamInfo[] { audioStreamInfo, videoStreamInfo }; await converter.DownloadAndProcessMediaStreamsAsync(mediaStreamInfos, videoPath, "mp4"); }
/// <inheritdoc /> public async Task DownloadMediaStreamAsync(MediaStreamInfo info, Stream output, IProgress <double> progress = null, CancellationToken cancellationToken = default(CancellationToken)) { info.GuardNotNull(nameof(info)); output.GuardNotNull(nameof(output)); using (var input = await GetMediaStreamAsync(info).ConfigureAwait(false)) await input.CopyToAsync(output, progress, cancellationToken).ConfigureAwait(false); }
/// <summary> /// Gets the actual media stream associated with given metadata. /// </summary> public async Task <MediaStream> GetMediaStreamAsync(MediaStreamInfo info) { info.GuardNotNull(nameof(info)); // Get stream var stream = await _httpService.GetStreamAsync(info.Url).ConfigureAwait(false); return(new MediaStream(info, stream)); }
private async Task ResolveAdaptiveStreamInfosAsync(PlayerContext context, string encodedData, ICollection <AudioStreamInfo> audioStreamInfos, ICollection <VideoStreamInfo> videoStreamInfos) { foreach (var streamEncoded in encodedData.Split(",")) { var streamInfoDic = UrlHelper.GetDictionaryFromUrlQuery(streamEncoded); var itag = streamInfoDic.Get("itag").ParseInt(); var url = streamInfoDic.Get("url"); var sig = streamInfoDic.GetOrDefault("s"); var contentLength = streamInfoDic.Get("clen").ParseLong(); var bitrate = streamInfoDic.Get("bitrate").ParseLong(); #if RELEASE if (!MediaStreamInfo.IsKnown(itag)) { continue; } #endif // Decipher signature if needed if (sig.IsNotBlank()) { var playerSource = await GetPlayerSourceAsync(context.SourceUrl).ConfigureAwait(false); sig = playerSource.Decipher(sig); url = UrlHelper.SetUrlQueryParameter(url, "signature", sig); } // Set rate bypass url = UrlHelper.SetUrlQueryParameter(url, "ratebypass", "yes"); // Check if audio var isAudio = streamInfoDic.Get("type").Contains("audio/"); // If audio stream if (isAudio) { var streamInfo = new AudioStreamInfo(itag, url, contentLength, bitrate); audioStreamInfos.Add(streamInfo); } // If video stream else { // Parse additional data var size = streamInfoDic.Get("size"); var width = size.SubstringUntil("x").ParseInt(); var height = size.SubstringAfter("x").ParseInt(); var resolution = new VideoResolution(width, height); var framerate = streamInfoDic.Get("fps").ParseInt(); var streamInfo = new VideoStreamInfo(itag, url, contentLength, bitrate, resolution, framerate); videoStreamInfos.Add(streamInfo); } } }
public YoutubeModel(Video metadata, MediaStreamInfo streamInfo, string path) { Id = metadata.Id; Title = metadata.Title; Author = metadata.Author; Duration = metadata.Duration; UploadDate = metadata.UploadDate; Extension = streamInfo.Container.GetFileExtension(); Path = path; }
public static VideoEncoding GetVideoEncoding(MediaStreamInfo stream) { VideoStreamInfo VInfo = stream as VideoStreamInfo; MuxedStreamInfo MInfo = stream as MuxedStreamInfo; if (VInfo == null && MInfo == null) { return(VideoEncoding.H264); } return(VInfo?.VideoEncoding ?? MInfo.VideoEncoding); }
private async Task ResolveMuxedStreamInfosAsync(PlayerContext context, string encodedData, ICollection <MuxedStreamInfo> streamInfos) { foreach (var streamEncoded in encodedData.Split(",")) { var streamInfoDic = UrlHelper.GetDictionaryFromUrlQuery(streamEncoded); var itag = streamInfoDic.Get("itag").ParseInt(); var url = streamInfoDic.Get("url"); var sig = streamInfoDic.GetOrDefault("s"); #if RELEASE if (!MediaStreamInfo.IsKnown(itag)) { continue; } #endif // Decipher signature if needed if (sig.IsNotBlank()) { var playerSource = await GetPlayerSourceAsync(context.SourceUrl).ConfigureAwait(false); sig = playerSource.Decipher(sig); url = UrlHelper.SetUrlQueryParameter(url, "signature", sig); } // Probe stream and get content length long contentLength; using (var request = new HttpRequestMessage(HttpMethod.Head, url)) using (var response = await _httpService.PerformRequestAsync(request).ConfigureAwait(false)) { // Some muxed streams can be gone if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.Gone) { continue; } // Ensure success response.EnsureSuccessStatusCode(); // Extract content length contentLength = response.Content.Headers.ContentLength ?? throw new ParseException("Could not extract content length"); } // Set rate bypass url = UrlHelper.SetUrlQueryParameter(url, "ratebypass", "yes"); var streamInfo = new MuxedStreamInfo(itag, url, contentLength); streamInfos.Add(streamInfo); } }
private YoutubeModel CreateModel(Video video, MediaStreamInfo info, string path) { try { return(new YoutubeModel(video, info, path)); } catch { throw new YoutubeHandlerException(video, info, "Model could not be instantiated."); } }
/// <summary> /// Gets the actual media stream represented by given metadata /// </summary> public async Task <MediaStream> GetMediaStreamAsync(MediaStreamInfo mediaStreamInfo) { if (mediaStreamInfo == null) { throw new ArgumentNullException(nameof(mediaStreamInfo)); } // Get var stream = await _httpService.GetStreamAsync(mediaStreamInfo.Url).ConfigureAwait(false); return(new MediaStream(mediaStreamInfo, stream)); }
private static async Task <string> DownloadVideo(MediaStreamInfo streamInfo, StorageItem video, ILogger log, CancellationToken cancellationToken) { log.LogInformation("Downloading..."); var cleanTitle = CleanTitle(video.Title); var streamFileExt = streamInfo.Container.GetFileExtension(); var streamFilePath = Path.Combine(ConversionConfiguration.TempDirectoryPath, cleanTitle.Replace(".mp3", "." + streamFileExt)); using (var streamFile = new FileStream(streamFilePath, FileMode.Create)) { await YoutubeClient.DownloadMediaStreamAsync(streamInfo, streamFile, null, cancellationToken); } return(streamFilePath); }
protected void DownloadVideo(string filename, YoutubeClient client, MediaStreamInfo streamInfo, string directoryToSaveVideo) { Directory.CreateDirectory(directoryToSaveVideo); var fileName = filename.CleanFileName(); var filePath = Path.Combine(directoryToSaveVideo, fileName); using (var progressBar = customProgressBarService.CreateProgressBar()) { client.DownloadMediaStreamAsync(streamInfo, filePath, progressBar) .GetAwaiter() .GetResult(); } }
public static double GetVideoFrameRate(MediaStreamInfo stream) { VideoStreamInfo VInfo = stream as VideoStreamInfo; if (VInfo != null) { return(VInfo.Framerate); } else { return(0); } }
/// <inheritdoc /> public void DownloadMediaStreamAsync(MediaStreamInfo info, Stream output, //IProgress<double> progress = null, CancellationToken cancellationToken = default(CancellationToken)) { info.GuardNotNull(nameof(info)); output.GuardNotNull(nameof(output)); // Determine if stream is rate-limited var isRateLimited = !Regex.IsMatch(info.Url, @"ratebypass[=/]yes"); // Download rate-limited streams in segments if (isRateLimited) { // Determine segment count //const long segmentSize = 9_898_989; // this number was carefully devised through research const long segmentSize = 9898989; // this number was carefully devised through research var segmentCount = (int)Math.Ceiling(1.0 * info.Size / segmentSize); // Keep track of bytes copied for progress reporting var totalBytesCopied = 0L; for (var i = 0; i < segmentCount; i++) { // Determine segment range var from = i * segmentSize; var to = (i + 1) * segmentSize - 1; // Download segment using (var input = _httpClient.GetStreamAsync(info.Url, from, to)) { int bytesCopied; do { // Copy bytesCopied = input.CopyChunkToAsync(output, cancellationToken); // Report progress totalBytesCopied += bytesCopied; //progress?.Report(1.0 * totalBytesCopied / info.Size); } while (bytesCopied > 0); } } } // Download non-limited streams directly else { using (var input = GetMediaStreamAsync(info)) input.CopyToAsync(output, cancellationToken); } }
/// <inheritdoc /> public Task <MediaStream> GetMediaStreamAsync(MediaStreamInfo info) { // Determine if stream is rate-limited var isRateLimited = !Regex.IsMatch(info.Url, "ratebypass[=/]yes"); // Determine segment size var segmentSize = isRateLimited ? 9_898_989 // this number was carefully devised through research : long.MaxValue; // don't use segmentation for non-rate-limited streams // Get segmented stream var stream = _httpClient.CreateSegmentedStream(info.Url, info.Size, segmentSize); // This method must return a task for backwards-compatibility reasons return(Task.FromResult(new MediaStream(info, stream))); }
/// <inheritdoc /> public async Task <MediaStream> GetMediaStreamAsync(MediaStreamInfo info) { info.GuardNotNull(nameof(info)); // Maximum segment stream size const long segmentSize = 9_898_989; // this number was carefully devised through research // Determine if stream is rate-limited var isRateLimited = !Regex.IsMatch(info.Url, @"ratebypass[=/]yes"); // Determine if the stream is longer than one segment var isMultiSegment = info.Size > segmentSize; // If rate-limited and long enough - split into segments and wrap into one stream if (isRateLimited && isMultiSegment) { // Determine segment count var segmentCount = (int)Math.Ceiling(1.0 * info.Size / segmentSize); // Create resolvers for multi stream var resolvers = new List <Func <Task <Stream> > >(); for (var i = 0; i < segmentCount; i++) { // Determine segment range var from = i * segmentSize; var to = (i + 1) * segmentSize - 1; // Create resolver for this segment var resolver = new Func <Task <Stream> >(() => _httpClient.GetStreamAsync(info.Url, from, to)); resolvers.Add(resolver); } // Create multi stream from segment resolvers var stream = new AsyncMultiStream(resolvers); return(new MediaStream(info, stream)); } // If not rate-limited or not long enough - get the stream in one segment else { // Get the whole stream as one segment var stream = await _httpClient.GetStreamAsync(info.Url, 0, info.Size).ConfigureAwait(false); return(new MediaStream(info, stream)); } }
public async Task <string> DownloadVideoOptionsTask(string url) { //try //{ var client = new YoutubeClient(); var id = YoutubeClient.ParseVideoId(url); var video = await client.GetVideoAsync(id); var author = video.Author; var converter = new YoutubeConverter(client, "C:\\ffmpeg-4.2.2\\bin\\ffmpeg.exe"); var mediaStreamInfoSet = await client.GetVideoMediaStreamInfosAsync(id); // Select video stream var videoStreamInfo = mediaStreamInfoSet.Video.FirstOrDefault(s => s.VideoQualityLabel == "240p"); // Select audio stream var audioStreamInfo = mediaStreamInfoSet.Audio.First(s => s.Bitrate == 128); // Combine them into a collection var mediaStreamInfos = new MediaStreamInfo[] { audioStreamInfo, videoStreamInfo }; // Download and process them into one file await converter.DownloadAndProcessMediaStreamsAsync(mediaStreamInfos, $"C:\\Temp\\{author}.wav", "wav"); var path = $"C:\\Temp\\{author}.wav"; Console.WriteLine("[DownloadVideoTask] - Done Download Video"); return(path); //} //catch (Exception e) //{ // Console.WriteLine($"[DownloadVideoTask] - Error {e}"); // return null; //} }
private async void Button_Click(object sender, RoutedEventArgs e) { string link = linkBox.Text; var id = YoutubeClient.ParseVideoId(link); client = new YoutubeClient(); video = await client.GetVideoAsync(id); streamInfoSet = await client.GetVideoMediaStreamInfosAsync(video.Id); streamInfo = streamInfoSet.Audio.WithHighestBitrate(); ext = streamInfo.Container.GetFileExtension(); MediaStreamInfo m = audioStreamInfo = streamInfoSet.Audio .OrderByDescending(s => s.Container == Container.WebM) .ThenByDescending(s => s.Bitrate) .First(); var pic = new BitmapImage(new Uri(video.Thumbnails.HighResUrl)); thumbnail.Source = pic; //pic.CreateOptions = BitmapCreateOptions.None; //WriteableBitmap wb = new WriteableBitmap(pic); //ImageConverter converter = new ImageConverter(); //byte[] b = (byte[])converter.ConvertTo(m, typeof(byte[])); //MemoryStream ms = new MemoryStream(b); var webClient = new WebClient(); byte[] imageBytes = webClient.DownloadData(video.Thumbnails.HighResUrl); picture = new Picture(imageBytes); titleInfo.Text = video.Title; }
void VideoStartup(Model model) { player = new HostedPlayer(); var res = model.encoderResolution; videoBuff = new VideoBuffer(res.width, res.height); player.SetVideoBuffer(videoBuff); var account = AccountManager.Instance.CurrentAccount; UserNameToken utoken = null; if (!account.IsAnonymous) { utoken = new UserNameToken(account.Name, account.Password); } if (model.metadataReceiver != null) { player.SetMetadataReciever(model.metadataReceiver); } MediaStreamInfo.Transport transp; switch (model.streamSetup.transport.protocol) { case TransportProtocol.http: transp = MediaStreamInfo.Transport.Http; break; case TransportProtocol.rtsp: transp = MediaStreamInfo.Transport.Tcp; break; default: transp = MediaStreamInfo.Transport.Udp; break; } MediaStreamInfo mstrInfo = new MediaStreamInfo(model.mediaUri.uri, transp, utoken); disposables.Add(player.Play(mstrInfo, this)); InitPlayback(videoBuff); }
private async Task <string> DownloadVideoStreamAsync(string url, MediaStreamInfo streamInfo) { string videoId = ParseVideoId(url); try { var extension = streamInfo.Container.GetFileExtension(); var filename = String.Format("{0}.{1}", videoId, extension); var path = _config.DownloadDirectory + filename; CreateDownloadDirectoryIfNotExists(); await _client.DownloadMediaStreamAsync(streamInfo, path); return(path); } catch { throw new YoutubeHandlerException(url, "Media stream could not be downloaded."); } }
public static async void DownloadVideo(MediaStreamInfo mediaStreamInfos, string name, string toast = "", bool isNotification = false, string body = "") { // YoutubeConverter converter = new YoutubeConverter(); YoutubeClient client = new YoutubeClient(); // Download and process them into one file /* * string basePath = App.GetDownloadPath("", "/YouTube"); * string path = App.GetDownloadPath(name, "/YouTube").Replace(basePath, ""); * if (basePath.EndsWith("\\")) { * basePath = basePath.Substring(0, basePath.Length - 1); * } * print("BasePath: " + basePath); * print("ExtraPath " + path);*/ string rootPath = App.GetDownloadPath("", "/YouTube"); if (rootPath.EndsWith("\\")) { rootPath = rootPath.Substring(0, rootPath.Length - 1); } if (!File.Exists(rootPath)) { Directory.CreateDirectory(rootPath); } await client.DownloadMediaStreamAsync(mediaStreamInfos, App.GetDownloadPath(name, "/YouTube") + ".mp4"); if (toast != "") { if (isNotification) { App.ShowNotification(toast, body); } else { App.ShowToast(toast); } } // await converter.DownloadAndProcessMediaStreamsAsync(mediaStreamInfos, basePath + "/" + path + ".mp4",".mp4"); }
private string GetStreamDescription(MediaStreamInfo stream) { if (stream is VideoStreamInfo) { VideoStreamInfo VStream = stream as VideoStreamInfo; return(string.Format("{0} {1}p ({2}mb)", VStream.VideoEncoding, DownloadManager.GetVideoHeight(VStream), VStream.Size / 1024 / 1024)); } else if (stream is AudioStreamInfo) { AudioStreamInfo AStream = stream as AudioStreamInfo; return(string.Format("{0} {1}kbps ({2}mb)", AStream.AudioEncoding, AStream.Bitrate / 1024, AStream.Size / 1024 / 1024)); } else if (stream is MuxedStreamInfo) { MuxedStreamInfo MStream = stream as MuxedStreamInfo; return(string.Format("{0} {1}p ({2}mb) (with audio)", MStream.VideoEncoding, DownloadManager.GetVideoHeight(MStream), MStream.Size / 1024 / 1024)); } else { return(""); } }
static async Task Main(string[] args) { var client = new YoutubeClient(); var converter = new YoutubeConverter(client); // re-using the same client instance for efficiency, not required // Get media stream info set var mediaStreamInfoSet = await client.GetVideoMediaStreamInfosAsync("NIJHqNWMtAw"); // Select audio stream var audioStreamInfo = mediaStreamInfoSet.Audio.WithHighestBitrate(); // Select video stream var videoStreamInfo = mediaStreamInfoSet.Video.FirstOrDefault(s => s.VideoQualityLabel.Contains("360")); // Combine them into a collection var mediaStreamInfos = new MediaStreamInfo[] { audioStreamInfo, videoStreamInfo }; // Download and process them into one file await converter.DownloadAndProcessMediaStreamsAsync(mediaStreamInfos, @"video.mp4", "mp4", new MyProgress()); Console.WriteLine("Done"); }
public async Task<MediaItem> GetItemInfo(string itemId) { MediaItem item = new MediaItem(); string userId = await GetUserID(); ServerListItem server = settings.GetServer(); if (server == null) { throw new Exception("Server not set"); } Uri url = new Uri("http://" + server + "/mediabrowser/Users/" + userId + "/Items/" + itemId + "?format=json"); HttpClient httpClient = new HttpClient(); string authorization = await GetAuthorizationHeader(); httpClient.DefaultRequestHeaders.Add("Authorization", authorization); string authToken = await Authenticate(); httpClient.DefaultRequestHeaders.Add("X-MediaBrowser-Token", authToken); HttpResponseMessage itemResponce = await httpClient.GetAsync(url); itemResponce.EnsureSuccessStatusCode(); string itemResponceText = await itemResponce.Content.ReadAsStringAsync(); JObject itemInfo = JObject.Parse(itemResponceText); if (itemInfo["RunTimeTicks"] != null) { long runTimeSeconds = (long)itemInfo["RunTimeTicks"]; runTimeSeconds = (runTimeSeconds / 1000) / 10000; item.Duration = runTimeSeconds; } else { item.Duration = 0; } item.Id = (itemInfo["Id"] != null) ? (string)itemInfo["Id"] : ""; item.Name = (itemInfo["Name"] != null) ? (string)itemInfo["Name"] : ""; item.Year = (itemInfo["ProductionYear"] != null) ? (int)itemInfo["ProductionYear"] : 0; item.Series = (itemInfo["SeriesName"] != null) ? (string)itemInfo["SeriesName"] : ""; item.Type = (itemInfo["Type"] != null) ? (string)itemInfo["Type"] : ""; item.Season = (itemInfo["ParentIndexNumber"] != null) ? (int)itemInfo["ParentIndexNumber"] : 0; item.EpisodeIndex = (itemInfo["IndexNumber"] != null) ? (int)itemInfo["IndexNumber"] : 0; item.SeriesId = (itemInfo["SeriesId"] != null) ? (string)itemInfo["SeriesId"] : ""; // extract media streams JArray streams = (JArray)itemInfo["MediaStreams"]; item.mediaStreams = new List<MediaStreamInfo>(); foreach (JObject stream in streams) { MediaStreamInfo mInfo = new MediaStreamInfo(); mInfo.Index = (int)stream["Index"]; mInfo.Type = (string)stream["Type"]; mInfo.Language = (string)stream["Language"]; mInfo.Codec = (string)stream["Codec"]; mInfo.IsTextSubtitleStream = (bool)stream["IsTextSubtitleStream"]; item.mediaStreams.Add(mInfo); } return item; }