public override int DiscoverSubCategories(Category parentCategory)
        {
            parentCategory.SubCategories = new List<Category>();

            #region Help

            if (parentCategory.IsHelpState())
                throw new OnlineVideosException("Forum: http://tinyurl.com/ov-netflix");

            #endregion

            #region Profiles
            if (parentCategory.IsProfilesState())
            {
                foreach (JToken profile in profiles)
                {
                    Category profileCat = new Category() { Name = profile["profileName"].Value<string>(), HasSubCategories = true, Thumb = profile["avatar"]["images"]["100"].Value<string>(), ParentCategory = parentCategory };
                    profileCat.SetState(NetflixUtils.ProfileState);
                    profileCat.SetProfile(profile);
                    parentCategory.SubCategories.Add(profileCat);
                }
            }

            else if (parentCategory.IsProfileState())
            {
                Settings.Categories.Clear();
                Settings.DynamicCategoriesDiscovered = false;
                currentProfile = parentCategory.GetProfile();
                parentCategory.ParentCategory.Name = ProfileCategoryName;
                MyGetWebData(string.Format(switchProfileUrl, apiRoot, ProfileToken));
                if (rememberStartupUserProfile)
                {
                    List<OnlineVideos.Reflection.FieldPropertyDescriptorByRef> props = GetUserConfigurationProperties();
                    OnlineVideos.Reflection.FieldPropertyDescriptorByRef prop = props.First(p => p.DisplayName == "Startup user profile");
                    this.SetConfigValueFromString(prop, ProfileName);
                    startupUserProfile = ProfileName;
                }
                throw new OnlineVideosException(CangedToProfile);

            }
            #endregion

            #region Home Categories
            

            else if (parentCategory.IsHomeCategoriesState())
            {
                string data = MyGetWebData((parentCategory as RssLink).Url);
                List<Category> cats = GetHomeCategories(data, parentCategory);
                parentCategory.SubCategories = cats;
            }

            #endregion

            #region Kids
            else if (parentCategory.IsKidsState())
            {
                string data = MyGetWebData((parentCategory as RssLink).Url);
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(data);
                RssLink characters = new RssLink() { Name = "Characters", HasSubCategories = true, SubCategories = new List<Category>(), ParentCategory = parentCategory };
                //Well use regex in this case...
                Regex rgx = new Regex(@"title=\\\""(?<name>[^\\]*)\\\"".href=\\\""(?<url>[^\\]*)(?:[^<]*)<img.src=\\""(?<thumb>[^\\]*)");
                foreach (Match m in rgx.Matches(data))
                {
                    RssLink character = new RssLink()
                    {
                        Name = m.Groups["name"].Value,
                        Url = m.Groups["url"].Value,
                        Thumb = m.Groups["thumb"].Value,
                        ParentCategory = characters,
                        HasSubCategories = true
                    };
                    character.SetState(NetflixUtils.SinglePageCategoriesState);
                    characters.SubCategories.Add(character);
                }
                characters.SubCategoriesDiscovered = characters.SubCategories.Count > 0;
                parentCategory.SubCategories.Add(characters);

                foreach (HtmlNode a in doc.DocumentNode.SelectNodes("//a[contains(@href, 'netflix.com/KidsAltGenre')]"))
                {
                    string url = a.GetAttributeValue("href", "");
                    if (!parentCategory.SubCategories.Any(c => (c as RssLink).Url == url))
                    {
                        RssLink category = new RssLink()
                        {
                            Name = a.InnerText.Trim(),
                            Url = a.GetAttributeValue("href", ""),
                            HasSubCategories = true,
                            ParentCategory = parentCategory
                        };
                        category.SetState(NetflixUtils.SinglePageCategoriesState);
                        parentCategory.SubCategories.Add(category);
                    }
                }

            }
            #endregion

            #region SinglePageCategories
            else if (parentCategory.IsSinglePageCategoriesState())
            {
                foreach (NetflixData d in GetSinglePageNetflixData(parentCategory, enableAddRemoveMylist))
                {
                    RssLink cat = new RssLink()
                    {
                        Name = d.Title,
                        Url = d.Id,
                        Thumb = d.Cover,
                        ParentCategory = parentCategory,
                        HasSubCategories = !(parentCategory.ParentCategory != null && parentCategory.ParentCategory.Name == "Characters"),
                        Description = d.Description
                    };
                    cat.SetState(NetflixUtils.TitleState);
                    if (!string.IsNullOrEmpty(d.TrackId))
                        cat.SetTrackId(d.TrackId);
                    parentCategory.SubCategories.Add(cat);
                }
            }
            #endregion

            #region MultiplePageCategories
            else if (parentCategory.IsMultiplePageCategoriesState()) //This is browse categories
            {
                string url = (parentCategory as RssLink).Url;
                string data = MyGetWebData(url);
                SetShaktiApiAndBuildId(data);
                Uri uri = new Uri(url);
                string agid = HttpUtility.ParseQueryString(uri.Query).Get("agid");
                if (!string.IsNullOrEmpty(ShaktiApi) && !string.IsNullOrEmpty(BuildId) && !string.IsNullOrEmpty(agid))
                {
                    data = MyGetWebData(string.Format(genreUrl, ShaktiApi, BuildId, agid, 0, 50, BrowseSort));
                    JObject json = (JObject)JsonConvert.DeserializeObject(data);
                    foreach (JObject item in json["catalogItems"])
                    {
                        RssLink category = new RssLink()
                        {
                            Name = (string)item["title"],
                            Url = ((int)item["titleId"]).ToString(),
                            Thumb = (string)item["boxart"],
                            ParentCategory = parentCategory,
                            HasSubCategories = true,
                            Description = enableDesc && enableDescInListing ? GetTitleDescription(((int)item["titleId"]).ToString(), ((int)item["trackId"]).ToString()) : ""
                        };
                        category.SetState(NetflixUtils.TitleState);
                        if (enableDesc || enableAddRemoveMylist)
                            category.SetTrackId(((int)item["trackId"]).ToString());
                        parentCategory.SubCategories.Add(category);
                    }
                    if (parentCategory.SubCategories.Count >= 50)
                    {
                        NextPageCategory next = new NextPageCategory() { Url = string.Format(genreUrl, ShaktiApi, BuildId, agid, "START_INDEX", "STOP_INDEX", BrowseSort), ParentCategory = parentCategory };
                        next.SetState(NetflixUtils.TitleState);
                        next.SetStartIndex("51");
                        parentCategory.SubCategories.Add(next);
                    }
                }
            }
            #endregion

            #region Title
            else if (parentCategory.IsTitleState())
            {
                string data = MyGetWebData(movieUrl + (parentCategory as RssLink).Url);
                Regex rgx = new Regex(@"nf\.constants\.page\.contextData =(.*); }\(netflix\)\);");
                Match m = rgx.Match(data);
                if (m.Success)
                {
                    string jsonData = m.Groups[1].Value;
                    JObject json = (JObject)JsonConvert.DeserializeObject(jsonData);

                    #region Series
                    if ((bool)json["displayPage"]["data"]["isShow"])
                    {

                        #region Multiple seasons
                        if (data.Contains("class=\"seasonItem"))
                        {
                            HtmlDocument doc = new HtmlDocument();
                            doc.LoadHtml(data);
                            foreach (HtmlNode li in doc.DocumentNode.SelectNodes("//li[starts-with(@class, 'seasonItem')]"))
                            {
                                HtmlNode a = li.SelectSingleNode("a");
                                RssLink season = new RssLink()
                                {
                                    Name = "Season " + a.InnerText,
                                    Url = string.Format(seasonDetailsUrl, (parentCategory as RssLink).Url, a.GetAttributeValue("data-vid", "")),
                                    HasSubCategories = true,
                                    ParentCategory = parentCategory,
                                    Thumb = parentCategory.Thumb
                                };
                                season.SetState(NetflixUtils.EpisodesState);
                                parentCategory.SubCategories.Add(season);
                            }
                        }
                        #endregion

                        #region Single season
                        else if (data.Contains("data-episodeid=\""))
                        {
                            HtmlDocument doc = new HtmlDocument();
                            doc.LoadHtml(data);
                            HtmlNode docNode = doc.DocumentNode;
                            HtmlNode seasonNode = docNode.SelectSingleNode("//span[@class = 'selectorTxt']");
                            string season = seasonNode == null ? "1x" : (seasonNode.InnerText + "x");
                            HtmlNode episodes = docNode.SelectSingleNode("//ul[@class = 'episodeList']");
                            foreach (HtmlNode episode in episodes.SelectNodes("li"))
                            {
                                string seqNum = episode.SelectSingleNode("span[@class = 'seqNum']").InnerText;
                                HtmlNode pDesc = enableDesc ? episode.SelectSingleNode(".//p[@class = 'synopsis']") : null;
                                parentCategory.SubCategories.Add(new RssLink()
                                {
                                    Name = season + (seqNum.Count() < 2 ? ("0" + seqNum) : seqNum) + " " + episode.SelectSingleNode("span[@class = 'episodeTitle']").InnerText,
                                    Url = episode.GetAttributeValue("data-episodeid", ""),
                                    ParentCategory = parentCategory,
                                    Thumb = parentCategory.Thumb,
                                    Description = pDesc != null ? pDesc.InnerText : "",
                                    HasSubCategories = false
                                });
                            }
                        }
                        #endregion

                        #region Netflix title
                        else
                        {
                            data = MyGetWebData(string.Format(netflixOrgEpisodes, apiRoot, (parentCategory as RssLink).Url, latestAuthUrl));
                            rgx = new Regex(@"({""title"":[^$]*)");
                            m = rgx.Match(data);
                            if (m.Success)
                            {
                                data = m.Groups[1].Value;

                                json = (JObject)JsonConvert.DeserializeObject(data);
                                foreach (JArray seasonArray in json["episodes"])
                                {
                                    foreach (JToken episode in seasonArray.Where(e => e["availableForED"] == null || e["availableForED"].Value<bool>()))
                                    {
                                        int e = (int)episode["episode"];
                                        int s = (int)episode["season"];
                                        RssLink cat = new RssLink()
                                        {
                                            Name = s + "x" + (e < 10 ? ("0" + e) : e.ToString()) + " " + (string)episode["title"],
                                            ParentCategory = parentCategory,
                                            Thumb = parentCategory.Thumb,
                                            HasSubCategories = false,
                                            Url = episode["episodeId"].ToString()
                                        };
                                        JToken stills = episode["stills"];
                                        if (stills != null && stills.Count() > 0)
                                        {
                                            cat.Thumb = stills.Last()["url"].Value<string>();
                                        }
                                        if (enableDesc)
                                        {
                                            cat.Description = episode["synopsis"].Value<string>();
                                        }
                                        parentCategory.SubCategories.Add(cat);
                                    }
                                }
                                parentCategory.SubCategories.Sort((c1, c2) => c1.Name.CompareTo(c2.Name));
                            }
                        #endregion
                        }
                    }
                    #endregion

                    #region Movies
                    else
                    {
                        parentCategory.SubCategories.Add(new RssLink() { Description = GetTitleDescription((parentCategory as RssLink).Url, parentCategory.GetTrackId()), Name = parentCategory.Name, Url = (parentCategory as RssLink).Url, Thumb = parentCategory.Thumb, ParentCategory = parentCategory, HasSubCategories = false });
                    }
                    #endregion
                }
            }


            #endregion

            #region Episodes
            else
            {
                string jsonData = MyGetWebData((parentCategory as RssLink).Url);
                JObject json = (JObject)JsonConvert.DeserializeObject(jsonData);
                string data = (string)json["html"];
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(data);
                HtmlNode docNode = doc.DocumentNode;
                HtmlNode episodes = docNode.SelectSingleNode("//ul[@class = 'episodeList']");
                foreach (HtmlNode episode in episodes.SelectNodes("li"))
                {
                    string seqNum = episode.SelectSingleNode("span[@class = 'seqNum']").InnerText;
                    HtmlNode pDesc = enableDesc ? episode.SelectSingleNode(".//p[@class = 'synopsis']") : null;
                    parentCategory.SubCategories.Add(new RssLink()
                    {
                        Name = parentCategory.Name.Replace("Season", "") + "x" + (seqNum.Count() < 2 ? ("0" + seqNum) : seqNum) + " " + episode.SelectSingleNode("span[@class = 'episodeTitle']").InnerText,
                        Url = episode.GetAttributeValue("data-episodeid", ""),
                        ParentCategory = parentCategory,
                        Thumb = parentCategory.Thumb,
                        Description = pDesc != null ? pDesc.InnerText : "",
                        HasSubCategories = false
                    });
                }
            }
            #endregion

            parentCategory.SubCategoriesDiscovered = parentCategory.RememberDiscoveredItems() && parentCategory.SubCategories.Count > 0;
            return parentCategory.SubCategories.Count;
        }
 public override List<ContextMenuEntry> GetContextMenuEntries(Category selectedCategory, VideoInfo selectedItem)
 {
     List<ContextMenuEntry> result = new List<ContextMenuEntry>();
     if (enableAddRemoveMylist && selectedItem == null && selectedCategory.IsTitleState())
     {
         try
         {
             if (!string.IsNullOrEmpty(selectedCategory.GetTrackId()))
             {
                 string data = MyGetWebData(string.Format(bobUrl, ShaktiApi, BuildId, (selectedCategory as RssLink).Url, selectedCategory.GetTrackId(), latestAuthUrl));
                 JObject json = (JObject)JsonConvert.DeserializeObject(data);
                 if (json["isMovie"].Value<bool>() || json["isShow"].Value<bool>())
                 {
                     bool inPlayList = json["inPlayList"].Value<bool>();
                     ContextMenuEntry entry = new ContextMenuEntry() { DisplayText = (inPlayList ? "Remove from " : "Add to ") + "My List" };
                     result.Add(entry);
                 }
             }
         }
         catch { }
     }
     if (enableAddRemoveMylist && selectedItem != null && selectedItem.Other is SerializableDictionary<string,string>)
     {
         try
         {
             SerializableDictionary<string, string> other = selectedItem.Other as SerializableDictionary<string, string>;
             if (other.ContainsKey("TrackId") && other.ContainsKey("VideoId"))
             {
                 string data = MyGetWebData(string.Format(bobUrl, ShaktiApi, BuildId, other["VideoId"], other["TrackId"], latestAuthUrl));
                 JObject json = (JObject)JsonConvert.DeserializeObject(data);
                 if (json["isMovie"].Value<bool>() || json["isShow"].Value<bool>())
                 {
                     bool inPlayList = json["inPlayList"].Value<bool>();
                     ContextMenuEntry entry = new ContextMenuEntry() { DisplayText = (inPlayList ? "Remove from " : "Add to ") + "My List" };
                     result.Add(entry);
                 }
             }
         }
         catch { }
     }
     return result;
 }
        public override ContextMenuExecutionResult ExecuteContextMenuEntry(Category selectedCategory, VideoInfo selectedItem, ContextMenuEntry choice)
        {
            if (choice.DisplayText == "Add to My List")
            {
                ContextMenuExecutionResult result = new ContextMenuExecutionResult();
                //private string addRemoveMyListUrl = @"{0}/{1}/playlistop";
                //private string addRemoveMyListPostData = @"{""operation"":""{0}"",""videoId"":{1},""trackId"":{2},""authURL"":""{3}""}";

                string videoId;
                string trackId;
                string title;
                if (selectedItem == null)
                {
                    videoId = (selectedCategory as RssLink).Url;
                    trackId = selectedCategory.GetTrackId();
                    title = selectedCategory.Name;
                }
                else
                {
                    SerializableDictionary<string, string> other = selectedItem.Other as SerializableDictionary<string, string>;
                    videoId = other["VideoId"];
                    trackId = other["TrackId"];
                    title = selectedItem.Title;
                }
                GetWebData(string.Format(addRemoveMyListUrl, ShaktiApi, BuildId),
                    string.Format(addRemoveMyListPostData, addMyListOperation, videoId, trackId, latestAuthUrl),
                    cc, userAgent: UserAgent);
                result.RefreshCurrentItems = true;
                result.ExecutionResultMessage = title + " added to My List";
                return result;
            }
            if (choice.DisplayText == "Remove from My List")
            {
                string videoId;
                string trackId;
                string title;
                if (selectedItem == null)
                {
                    videoId = (selectedCategory as RssLink).Url;
                    trackId = selectedCategory.GetTrackId();
                    title = selectedCategory.Name;
                }
                else
                {
                    SerializableDictionary<string, string> other = selectedItem.Other as SerializableDictionary<string, string>;
                    videoId = other["VideoId"];
                    trackId = other["TrackId"];
                    title = selectedItem.Title;
                }
                ContextMenuExecutionResult result = new ContextMenuExecutionResult();
                GetWebData(string.Format(addRemoveMyListUrl, ShaktiApi, BuildId),
                    string.Format(addRemoveMyListPostData, removeMyListOperation, videoId, trackId, latestAuthUrl),
                    cc, userAgent: UserAgent);
                result.RefreshCurrentItems = true;
                result.ExecutionResultMessage = title + " removed from My List";
                return result;
            }
            return base.ExecuteContextMenuEntry(selectedCategory, selectedItem, choice);
        }