Ejemplo n.º 1
0
        /// <summary>
        /// Read the YouTube player configuration (args and assets) from the JSON data embedded into the HTML page.
        /// It serves as the primary source of obtaining the stream manifest data.
        /// </summary>
        internal static YTPlayerConfig getYTPlayerConfig(string watchHTML)
        {
            string configRaw = Helpers.DoRegex(extractYTPlayerConfig, watchHTML, 1);

            if (string.IsNullOrEmpty(configRaw))
            {
                CSTube.Log("ERROR: Video is unavailable!");
                return(new YTPlayerConfig());
            }

            // Get config as JSON structure
            JObject obj         = Helpers.TryParseJObject(configRaw);
            JToken  argsToken   = obj.GetValue("args");
            JToken  assetsToken = obj.GetValue("assets");

            // Create config and read it from JSON
            YTPlayerConfig config = new YTPlayerConfig();

            config.args   = ObscuredContainer.FromJSONRecursive(argsToken, 10);
            config.assets = ObscuredContainer.FromJSONRecursive(assetsToken, 10);

            if (config.args == null || config.assets == null)
            {
                CSTube.Log("ERROR: Player Config JSON is invalid!");
            }
            return(config);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Get the URL to the base JavaScript.
 /// </summary>
 internal static string getJSURL(YTPlayerConfig config)
 {
     return("https://youtube.com" + config.assets.GetValue <string>("js"));
 }
Ejemplo n.º 3
0
        /// <summary>
        /// Fetches the information about this video (including available streams and captions).
        /// Conains two synchronous HTTP fetches and several descrambling and signing algorithms.
        /// </summary>
        public async Task FetchInformation()
        {
            CSTube.Log("Fetching information of video " + videoID);

            // Page HTML
            watchHTML = await Helpers.ReadHTML(watchURL);

            if (string.IsNullOrEmpty(watchHTML))
            {
                return;
            }

            // PlayerConfig JSON
            playerConfig = Extract.getYTPlayerConfig(watchHTML);

            if (playerConfig.args == null || playerConfig.assets == null)
            {
                return;
            }

            // JavaScript Source
            string jsURL = Extract.getJSURL(playerConfig);

            jsSRC = await Helpers.ReadHTML(jsURL);

            // VideoInfo Raw Data
            //string videoInfoURL = Extract.getVideoInfoURL(videoID, watchURL, watchHTML);
            //videoInfoRAW = Helpers.ReadHTML(videoInfoURL);

            CSTube.Log("Finished downloading information! Continuing to parse!");

            // Parse Raw video info data
            //System.Collections.Specialized.NameValueCollection p = HttpUtility.ParseQueryString(videoInfoRAW);
            //videoInfo = ObscuredContainer.FromDictionary(p.AllKeys.ToDictionary(k => k, k => (object)p[k]));


            // Get all stream formats this video has (progressive and adaptive)
            List <string> streamMaps = new List <string>();

            streamMaps.Add("url_encoded_fmt_stream_map");
            if (playerConfig.args.ContainsKey("adaptive_fmts"))
            {
                streamMaps.Add("adaptive_fmts");
            }
            foreach (string streamFormat in streamMaps)
            {
                // Descramble stream data in player args
                ObscuredContainer streamBundle = Mixins.ApplyDescrambler(playerConfig.args, streamFormat);

                // If required, apply signature to the stream URLs
                Mixins.ApplySignature(streamBundle, jsSRC);

                // Write stream data into Stream objects
                foreach (object streamData in streamBundle.Values)
                {
                    formatStreams.Add(new Stream((ObscuredContainer)streamData));
                }
            }


            // Try to read out captionTracks if existant
            ObscuredContainer captionTrackBundle =
                Helpers.TryGetAttribute <ObscuredContainer>(playerConfig.args,
                                                            "player_response/captions/playerCaptionsTracklistRenderer/captionTracks");

            if (captionTrackBundle != null)
            {             // Write caption tracks into Caption objects
                foreach (object captionTrack in captionTrackBundle.Values)
                {
                    captionTracks.Add(new Caption((ObscuredContainer)captionTrack));
                }
            }

            videoDataAvailable = true;

            // Log success!
            CSTube.Log(string.Format(
                           "Finished parsing video data! Found {0} video streams and {1} caption tracks for video '{2}'!",
                           formatStreams.Count, captionTracks.Count, title
                           ));
            CSTube.Log(string.Format("Video Streams: \n \t " +
                                     string.Join(" \n \t ", formatStreams.Select(s => s.ToString()))
                                     ));
            if (captionTracks.Count > 0)
            {
                CSTube.Log(string.Format("Caption Tracks: \n \t " +
                                         string.Join(" \n \t ", captionTracks.Select(s => s.ToString()))
                                         ));
            }
        }