Example #1
0
        /// <summary>
        /// Apply the decrypted signature to the stream manifest.
        /// </summary>
        public static void ApplySignature(ObscuredContainer streamContainer, string js)
        {
            int numSignaturesFound = 0;

            foreach (KeyValuePair <string, object> s in streamContainer)
            {             // Iterate over each stream and sign the URLs
                ObscuredContainer stream = (ObscuredContainer)s.Value;
                string            URL    = stream.GetValue <string>("url");
                if (URL.Contains("signature="))
                {                 // Sometimes, signature is provided directly by YT, so we can skip the whole signature descrambling
                    numSignaturesFound++;
                    continue;
                }

                // Get, decode and save signature
                string cipheredSignature = stream.GetValue <string>("s");
                string signature         = Cipher.DecodeSignature(js, cipheredSignature);
                stream["url"] = URL + "&signature=" + signature;

                /*YouTube.Log(string.Format (
                 *      "Descrambled Signature for ITag={0} \n \t s={1} \n \t signature={2}",
                 *      stream.GetValue<string>("itag"),
                 *      cipheredSignature,
                 *      signature));*/
            }

            if (numSignaturesFound > 0)
            {
                CSTube.Log(string.Format("{0} out of {1} URLs already contained a signature!", numSignaturesFound, streamContainer.Count));
            }
        }
Example #2
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);
        }
Example #3
0
        /// <summary>
        /// Extracts the raw transform plan as a list of havascript functions from the specified code.
        /// </summary>
        private static string[] getTransformPlan(string js)
        {
            string name    = Regex.Escape(getInitialFunctionName(js));
            string pattern = name + @"=function\([a-z]\)\{[a-z]=[a-z]\.split\(""""\);(.*?);return [a-z].join\(""""\)\};";

            string[] plan = Helpers.DoRegex(pattern, js, 1).Split(';');
            CSTube.Log("Transform Plan " + name + ":" + string.Join(" || ", plan));
            return(plan);
        }
Example #4
0
        /// <summary>
        /// Creates a new Youtube video inspector and automatically fetches video information asynchronously.
        /// </summary>
        public static async Task <Video> Fetch(string url, bool log = true)
        {
            CSTube.SetLogState(log);
            Video video = new Video(url);
            await video.FetchInformation();

            CSTube.SetLogState(true);
            return(video);
        }
Example #5
0
        /// <summary>
        /// Extracts the transform object from the specified funcVar in the specified javascript code.
        /// Returns a list of function definitions inside the object.
        /// Format: {ID}:{FunctionDef}
        /// </summary>
        private static string[] getTransformObject(string js, string funcVar)
        {
            string pattern = "var " + Regex.Escape(funcVar) + @"=\{(.*?)\};";

            string[] obj = Helpers.DoRegex(pattern, js, 1, RegexOptions.Singleline)
                           .Replace("\n", " ")
                           .Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries)
                           .Select(s => s.Trim())
                           .ToArray();
            CSTube.Log("Transform Object " + funcVar + ": " + string.Join(" || ", obj));
            return(obj);
        }
Example #6
0
        /// <summary>
        /// Write the media stream to the specified path.
        /// </summary>
        public void Download(string path)
        {
            CSTube.Log(string.Format("Downloading File to {0}", path));

            Directory.CreateDirectory(Path.GetDirectoryName(path));

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(URL);

            using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
            {
                CSTube.Log(string.Format("Total file size in bytes: {0}", response.Headers["content-length"]));
                using (System.IO.Stream input = response.GetResponseStream())
                    using (System.IO.Stream output = File.OpenWrite(path))
                        input.CopyToAsync(output).Wait();
            }
        }
Example #7
0
        /// <summary>
        /// Reads all HTML from the specified URL synchronously.
        /// </summary>
        public static async Task <string> ReadHTML(string URL)
        {
            string     result;
            WebRequest req = WebRequest.Create(URL);

            req.Method = "GET";
            try
            {
                using (StreamReader reader = new StreamReader(req.GetResponse().GetResponseStream()))
                    result = await reader.ReadToEndAsync();
            }
            catch (WebException e)
            {
                CSTube.Log("ERROR: Request Timeout, check your internet connection!");
                return(null);
            }
            return(result);
        }
Example #8
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()))
                                         ));
            }
        }