示例#1
0
        private static R <PlayResource, LocalStr> ParseLiveData(AudioResource resource, JsonPlayerResponse parsed)
        {
            var webListResponse = WebWrapper.GetResponse(new Uri(parsed.streamingData.hlsManifestUrl), response =>
            {
                return(AudioTags.M3uReader.TryGetData(response.GetResponseStream()).OkOr(null));
            });

            if (webListResponse.Ok)
            {
                const string AacHe = "mp4a.40.5";
                const string AacLc = "mp4a.40.2";

                var webList    = webListResponse.Value;
                var streamPref = from item in webList
                                 let codecs = item.StreamMeta != null?StreamCodecMatch.Match(item.StreamMeta).Groups[1].Value : ""
                                              let codecPref = codecs.Contains(AacLc) ? 0
                                                                                                                                                                         : codecs.Contains(AacHe) ? 1
                                                                                                                                                                         : 2
                                                              let bitrate = item.StreamMeta != null?int.Parse(StreamBitrateMatch.Match(item.StreamMeta).Groups[1].Value) : int.MaxValue
                                                                            orderby codecPref, bitrate ascending
                select item;

                var streamSelect = streamPref.FirstOrDefault();
                if (streamSelect != null)
                {
                    if (resource.ResourceTitle == null)
                    {
                        resource = resource.WithTitle(StringNormalize.Normalize(parsed.videoDetails.title));
                    }
                    return(new PlayResource(streamSelect.TrackUrl, resource));
                }
            }
            return(new LocalStr(strings.error_media_no_stream_extracted));
        }
示例#2
0
        private R <PlayResource, LocalStr> ResolveResourceInternal(AudioResource resource)
        {
            if (!WebWrapper.DownloadString(out string resulthtml, new Uri($"https://www.youtube.com/get_video_info?video_id={resource.ResourceId}")))
            {
                return(new LocalStr(strings.error_net_no_connection));
            }

            var videoTypes = new List <VideoData>();
            var dataParse  = ParseQueryString(resulthtml);

            if (dataParse.TryGetValue("player_response", out var playerData))
            {
                var parsed = JsonConvert.DeserializeObject <JsonPlayerResponse>(playerData[0]);
                Log.Debug("Extracted data: {@playerData}", parsed);

                if (parsed?.videoDetails != null)
                {
                    if (resource.ResourceTitle == null)
                    {
                        resource = resource.WithTitle(StringNormalize.Normalize(parsed.videoDetails.title));
                    }

                    bool isLive = parsed.videoDetails.isLive ?? false;
                    if (isLive && parsed.streamingData?.hlsManifestUrl != null)
                    {
                        return(ParseLiveData(resource, parsed));
                    }
                    else if (isLive)
                    {
                        Log.Warn("Live stream without hls stream data");
                    }

                    ParsePlayerData(parsed, videoTypes);
                }
            }

            if (dataParse.TryGetValue("url_encoded_fmt_stream_map", out var videoDataUnsplit))
            {
                ParseEncodedFmt(videoDataUnsplit, videoTypes);
            }

            if (dataParse.TryGetValue("adaptive_fmts", out videoDataUnsplit))
            {
                ParseAdaptiveFmt(videoDataUnsplit, videoTypes);
            }

            // Validation Process

            if (videoTypes.Count <= 0)
            {
                return(new LocalStr(strings.error_media_no_stream_extracted));
            }

            int codec = SelectStream(videoTypes);

            if (codec < 0)
            {
                return(new LocalStr(strings.error_media_no_stream_extracted));
            }

            var result = ValidateMedia(videoTypes[codec]);

            if (!result.Ok)
            {
                return(result.Error);
            }

            if (resource.ResourceTitle == null)
            {
                resource = resource.WithTitle($"<YT - no title : {resource.ResourceId}>");
            }

            return(new PlayResource(videoTypes[codec].Link, resource));
        }
示例#3
0
        private static R <PlayResource, LocalStr> YoutubeDlWrapped(AudioResource resource)
        {
            R <JsonYtdlDump, LocalStr> GetResourceInfo(string id)
            {
                var result = YoutubeDlHelper.GetSingleVideo(id);

                if (!result.Ok)
                {
                    return(result.Error);
                }

                return(result.Value);
            }

            Log.Debug("Falling back to youtube-dl!");

            // Get first try information
            var resourceInfo = GetResourceInfo(resource.ResourceId);

            if (!resourceInfo.Ok)
            {
                return(resourceInfo.Error);
            }
            var response = resourceInfo.Value;

            var formats = YoutubeDlHelper.SortBest(response.formats);

            if (formats.Count == 0)
            {
                return(new LocalStr(strings.error_ytdl_empty_response));
            }
            string url = formats[0]?.url;

            Log.Trace("Found the following audio codec possibilities:");
            foreach (var f in formats)
            {
                if (f.acodec != "none")
                {
                    Log.Trace("Result: abr={0} acodec={1} vcodec={2} url={3}", f.abr, f.acodec, f.vcodec, f.url);
                }
            }
            Log.Trace("Using version with {0}kbit/s", formats[0]?.abr);

            // Resource is broken
            if (string.IsNullOrEmpty(url))
            {
                return(new LocalStr(strings.error_ytdl_empty_response));
            }

            // Check if URL actually works. If not, return an error.
            var resp = new HttpClient().GetAsync(url, HttpCompletionOption.ResponseHeadersRead).Result;

            if (!resp.IsSuccessStatusCode)
            {
                Log.Info("Download URL generated by youtube-dl responds with non-200 status code: " + resp.StatusCode);
                return(new LocalStr("Youtube-URL for song is broken."));
            }

            if (resource.ResourceTitle == null)
            {
                resource = resource.WithTitle(StringNormalize.Normalize(response.title) ?? $"Youtube-{resource.ResourceId}");
            }


            Log.Debug("youtube-dl succeeded!");
            return(new PlayResource(url, resource));
        }