/// <summary>
        /// 获取历史动态
        /// </summary>
        /// <param name="offset">偏移值,初次不需要,每次请求会返回下一次请求的偏移值</param>
        /// <returns>Item1:下次偏移值;Item2:动态列表</returns>
        public async Task <Tuple <string, List <Topic> > > GetHistoryDynamicAsync(string offset)
        {
            var param = new Dictionary <string, string>();

            param.Add("qn", "32");
            param.Add("uid", BiliTool.mid);
            param.Add("offset_dynamic_id", offset);
            param.Add("rsp_type", "2");
            param.Add("type_list", "268435455");
            string url  = BiliTool.UrlContact(Api.DYNAMIC_HISTORY, param, true);
            var    data = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(data))
            {
                try
                {
                    var    jobj       = JObject.Parse(data);
                    string nextOffset = jobj["next_offset"].ToString();
                    var    topics     = JsonConvert.DeserializeObject <List <Topic> >(jobj["cards"].ToString());
                    topics.RemoveAll(p => p == null || p.card == null || p.card.Length < 10 || p.desc.status != 1);
                    return(new Tuple <string, List <Topic> >(nextOffset, topics));
                }
                catch (Exception)
                {
                }
            }
            return(null);
        }
Exemplo n.º 2
0
        /// <summary>
        /// 获取番剧播放信息
        /// </summary>
        /// <param name="aid">番剧类型标识</param>
        /// <param name="cid">视频分Pid</param>
        /// <param name="qn">分辨率ID</param>
        /// <returns></returns>
        public async Task <VideoPlayBase> GetBangumiPlayAsync(int type, int cid, int qn = 64)
        {
            var param = new Dictionary <string, string>();

            param.Add("module", "bangumi");
            param.Add("season_type", type.ToString());
            param.Add("cid", cid.ToString());
            param.Add("qn", qn.ToString());
            param.Add("fnver", "0");
            param.Add("otype", "json");
            param.Add("fnval", "16");
            string url  = BiliTool.UrlContact(Api.ANIME_PLAY, param, true, true);
            var    data = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(data))
            {
                var jobj = JObject.Parse(data);
                if (jobj.ContainsKey("dash"))
                {
                    return(JsonConvert.DeserializeObject <VideoPlayDash>(data));
                }
                else if (jobj.ContainsKey("durl"))
                {
                    return(JsonConvert.DeserializeObject <VideoPlayFlv>(data));
                }
            }
            return(null);
        }
Exemplo n.º 3
0
        /// <summary>
        /// 获取频道下的视频信息
        /// </summary>
        /// <param name="channelId">频道ID</param>
        /// <param name="sort">排序方式,可选值(hot,view,new)</param>
        /// <param name="offset">偏移值,初次不需要,每次请求会返回下一次请求的偏移值</param>
        /// <returns>Item1:下次偏移值;Item2:榜一视频(如果有);Item3:视频列表</returns>
        public async Task <Tuple <string, VideoBase, List <VideoChannel> > > GetChannelVideosAsync(int channelId, string sort = "hot", string offset = "")
        {
            var param = new Dictionary <string, string>();

            param.Add("channel_id", channelId.ToString());
            param.Add("sort", sort);
            if (!string.IsNullOrEmpty(offset))
            {
                param.Add("offset", offset);
            }
            string url     = BiliTool.UrlContact(Api.CHANNEL_VIDEO, param, true);
            string content = await BiliTool.GetTextFromWebAsync(url, true);

            if (!string.IsNullOrEmpty(content))
            {
                var jobj = JObject.Parse(content);
                if (jobj["code"].ToString() == "0")
                {
                    var       items      = jobj["data"]["items"];
                    string    nextOffset = jobj.SelectToken("data.offset").ToString();
                    VideoBase rankFirst  = null;
                    if (items.First()["goto"].ToString() == "channel_detail_rank")
                    {
                        rankFirst = JsonConvert.DeserializeObject <VideoBase>(items.First().SelectToken("items[0]").ToString());
                    }
                    var videoList = JsonConvert.DeserializeObject <List <VideoChannel> >(items.ToString());
                    videoList.RemoveAll(p => p.@goto != "av");
                    return(new Tuple <string, VideoBase, List <VideoChannel> >(nextOffset, rankFirst, videoList));
                }
            }
            return(null);
        }
        /// <summary>
        /// 获取用户空间历史动态
        /// </summary>
        /// <param name="uid">要查看的用户ID</param>
        /// <param name="page">页码</param>
        /// <param name="offset_id">偏移值,初次不需要,每次请求会返回下一次请求的偏移值</param>
        /// <returns>Item1:下次偏移值;Item2:动态列表</returns>
        public async Task <Tuple <string, List <Topic> > > GetUserSpaceDynamicAsync(int uid, int page = 1, string offset_id = "0")
        {
            var param = new Dictionary <string, string>();

            param.Add("host_uid", uid.ToString());
            param.Add("qn", "32");
            if (!string.IsNullOrEmpty(BiliTool.mid))
            {
                param.Add("visitor_uid", BiliTool.mid);
            }
            param.Add("offset_dynamic_id", offset_id);
            param.Add("page", page.ToString());
            string url  = BiliTool.UrlContact(Api.DYNAMIC_USER_HISTORY, param, true);
            var    data = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(data))
            {
                try
                {
                    var    jobj       = JObject.Parse(data);
                    string nextOffset = jobj["next_offset"].ToString();
                    var    topics     = JsonConvert.DeserializeObject <List <Topic> >(jobj["cards"].ToString());
                    topics.RemoveAll(p => p == null || p.card == null || p.card.Length < 10 || p.desc.status != 1);
                    return(new Tuple <string, List <Topic> >(nextOffset, topics));
                }
                catch (Exception)
                {
                }
            }
            return(null);
        }
Exemplo n.º 5
0
        /// <summary>
        /// 获取我收藏的播单(最多20个)
        /// </summary>
        /// <returns>Item1: 我创建的;Item2: 我收藏的</returns>
        public async Task <Tuple <List <FavoriteItem>, List <FavoriteItem> > > GetMyMainlyFavoritesAsync()
        {
            var param = new Dictionary <string, string>();

            param.Add("up_mid", _userId);
            string url      = BiliTool.UrlContact(Api.ACCOUNT_MEDIALIST, param, true);
            string response = await BiliTool.GetTextFromWebAsync(url);

            try
            {
                var  jarr      = JArray.Parse(response);
                bool hasMy     = jarr[0]["mediaListResponse"] != null;
                bool hasOther  = jarr[1]["mediaListResponse"] != null;
                var  myList    = new List <FavoriteItem>();
                var  otherList = new List <FavoriteItem>();
                if (hasMy)
                {
                    myList = JsonConvert.DeserializeObject <List <FavoriteItem> >(jarr[0].SelectToken("mediaListResponse.list").ToString());
                }
                if (hasOther)
                {
                    otherList = JsonConvert.DeserializeObject <List <FavoriteItem> >(jarr[1].SelectToken("mediaListResponse.list").ToString());
                }
                return(new Tuple <List <FavoriteItem>, List <FavoriteItem> >(myList, otherList));
            }
            catch (Exception)
            {
                return(null);
            }
        }
        /// <summary>
        /// 不喜欢某视频
        /// </summary>
        /// <param name="arg">参数</param>
        /// <param name="reason_id">原因ID</param>
        /// <param name="go">类型</param>
        /// <param name="isFeedback">标识是反馈还是不感兴趣</param>
        /// <returns></returns>
        public async Task <bool> DislikeRecommendVideoAsync(Args arg, int reason_id, string go, bool isFeedback = false)
        {
            var param = new Dictionary <string, string>();

            param.Add("id", arg.aid.ToString());
            param.Add("rid", arg.rid.ToString());
            if (isFeedback)
            {
                param.Add("feedback_id", reason_id.ToString());
            }
            else
            {
                param.Add("reason_id", reason_id.ToString());
            }
            param.Add("goto", go);
            param.Add("mid", arg.up_id.ToString());
            param.Add("tag_id", arg.tid.ToString());
            var url      = BiliTool.UrlContact(Api.VIDEO_RECOMMEND_DISLIKE, param, true);
            var response = await BiliTool.GetTextFromWebAsync(url, true);

            if (!string.IsNullOrEmpty(response))
            {
                var jobj = JObject.Parse(response);
                return(jobj["code"].ToString() == "0");
            }
            return(false);
        }
Exemplo n.º 7
0
        /// <summary>
        /// 获取动漫索引筛查结果
        /// </summary>
        /// <param name="page">页码</param>
        /// <param name="type">分区类型</param>
        /// <param name="conditions">限制条件</param>
        /// <returns></returns>
        public async Task <Tuple <bool, List <AnimeIndexResult> > > GetBangumiIndexResultsAsync(int page, int type, List <KeyValueModel> conditions)
        {
            var param = new Dictionary <string, string>();

            foreach (var item in conditions)
            {
                param.Add(item.Key, item.Value);
            }
            param.Add("type", "0");
            param.Add("page", page.ToString());
            param.Add("season_type", type.ToString());
            param.Add("pagesize", "21");
            string url      = BiliTool.UrlContact(Api.ANIME_INDEX_RESULT, param, true);
            var    response = await BiliTool.GetTextFromWebAsync(url);

            try
            {
                if (!string.IsNullOrEmpty(response))
                {
                    var  jobj    = JObject.Parse(response);
                    bool hasNext = jobj["has_next"].ToString() == "1";
                    var  data    = JsonConvert.DeserializeObject <List <AnimeIndexResult> >(jobj["list"].ToString());
                    return(new Tuple <bool, List <AnimeIndexResult> >(hasNext, data));
                }
            }
            catch (Exception)
            {
            }

            return(null);
        }
Exemplo n.º 8
0
 /// <summary>
 /// Cookie转化处理
 /// </summary>
 /// <returns></returns>
 public async Task SSO()
 {
     try
     {
         var url = BiliTool.UrlContact(Api.PASSPORT_SSO, hasAccessKey: true);
         await BiliTool.GetTextFromWebAsync(url, true);
     }
     catch (Exception)
     {
     }
 }
Exemplo n.º 9
0
        /// <summary>
        /// 获取关注者的未读消息数
        /// </summary>
        /// <returns></returns>
        public async Task <int> GetFollowerUnreadCountAsync()
        {
            string url      = BiliTool.UrlContact(Api.APP_FOLLOWER_UNREAD, null, true);
            string response = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(response))
            {
                var jobj = JObject.Parse(response);
                return(Convert.ToInt32(jobj["count"].ToString()));
            }
            return(-1);
        }
Exemplo n.º 10
0
        /// <summary>
        /// 不喜欢某番剧
        /// </summary>
        /// <param name="arg">参数</param>
        /// <returns></returns>
        public async Task <bool> DislikeRecommendVideoAsync(string bangumiId)
        {
            var param = new Dictionary <string, string>();

            param.Add("id", bangumiId);
            param.Add("goto", "bangumi");
            param.Add("reason_id", "1");
            var url      = BiliTool.UrlContact(Api.VIDEO_RECOMMEND_DISLIKE, param, true);
            var response = await BiliTool.GetTextFromWebAsync(url, true);

            if (!string.IsNullOrEmpty(response))
            {
                var jobj = JObject.Parse(response);
                return(jobj["code"].ToString() == "0");
            }
            return(false);
        }
        /// <summary>
        /// 获取字幕文件索引
        /// </summary>
        /// <param name="aid">视频ID</param>
        /// <param name="cid">分PID</param>
        /// <returns></returns>
        public async Task <List <SubtitleIndexItem> > GetVideoSubtitleIndexAsync(int aid, int cid)
        {
            var param = new Dictionary <string, string>();

            param.Add("id", $"cid:{cid}");
            param.Add("aid", aid.ToString());
            string url    = BiliTool.UrlContact(Api.VIDEO_SUBTITLE, param, true);
            string result = await BiliTool.GetTextFromWebAsync(url, true, needReferer : true);

            if (!string.IsNullOrEmpty(result) && result.Contains("subtitle"))
            {
                var json  = Regex.Match(result, @"<subtitle>(.*?)</subtitle>").Groups[1].Value;
                var index = JsonConvert.DeserializeObject <VideoSubtitleIndex>(json);
                return(index.subtitles);
            }
            return(null);
        }
        /// <summary>
        /// 加载默认的分区内容
        /// </summary>
        /// <param name="rid">分区ID</param>
        /// <param name="ctime">偏移值</param>
        /// <returns></returns>
        public async Task <Tuple <List <RegionBanner>, int, List <RegionVideo> > > GetRegionSquareAsync(int rid, int ctime = 0)
        {
            var param = new Dictionary <string, string>();

            param.Add("rid", rid.ToString());
            param.Add("pull", "0");
            string api = "";

            if (ctime == 0)
            {
                api = Api.REGION_DYNAMIC_INIT;
            }
            else
            {
                api = Api.REGION_DYNAMIC_REFRESH;
                param.Add("ctime", ctime.ToString());
            }
            string url     = BiliTool.UrlContact(api, param, true);
            string content = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(content))
            {
                var jobj = JObject.Parse(content);
                var list = new List <RegionVideo>();
                List <RegionBanner> banner = new List <RegionBanner>();
                if (jobj.ContainsKey("banner"))
                {
                    var ban = JsonConvert.DeserializeObject <List <RegionBanner> >(jobj["banner"]["top"].ToString());
                    ban.ForEach(p => banner.Add(p));
                }
                if (jobj.ContainsKey("recommend"))
                {
                    var rec = JsonConvert.DeserializeObject <List <RegionVideo> >(jobj["recommend"].ToString());
                    rec.ForEach(p => list.Add(p));
                }
                if (jobj.ContainsKey("new"))
                {
                    var news = JsonConvert.DeserializeObject <List <RegionVideo> >(jobj["new"].ToString());
                    news.ForEach(p => list.Add(p));
                }
                var result = new Tuple <List <RegionBanner>, int, List <RegionVideo> >(banner, Convert.ToInt32(jobj["cbottom"]), list);
                return(result);
            }
            return(null);
        }
Exemplo n.º 13
0
        /// <summary>
        /// 检查用户是否投币
        /// </summary>
        /// <param name="epid">标识ID</param>
        /// <returns></returns>
        public async Task <bool> CheckUserCoinAsync(int epid)
        {
            var param = new Dictionary <string, string>();

            param.Add("ep_id", epid.ToString());
            string url = BiliTool.UrlContact(Api.ANIME_CHECK_COIN, param, true);

            try
            {
                var num = await BiliTool.GetTextFromWebAsync(url, false, "result.number");

                return(Convert.ToInt32(num) > 0);
            }
            catch (Exception)
            {
                return(false);
            }
        }
        /// <summary>
        /// 检查视频状态(是否投币,点赞,收藏等)
        /// </summary>
        /// <param name="aid">视频ID</param>
        /// <param name="type">检查类型</param>
        /// <returns></returns>
        public async Task <bool> CheckVideoStatusAsync(int aid, string type = "like")
        {
            var param = new Dictionary <string, string>();

            param.Add("aid", aid.ToString());
            string url = "";

            switch (type)
            {
            case "like":
                url = Api.VIDEO_IS_LIKE;
                break;

            case "coin":
                url = Api.VIDEO_IS_COIN;
                break;

            case "favorite":
                url = Api.VIDEO_IS_FAVORITE;
                break;
            }
            url = BiliTool.UrlContact(url, param, true);
            var content = await BiliTool.GetTextFromWebAsync(url);

            if (type == "like")
            {
                return(content == "1");
            }
            else
            {
                var jobj = JObject.Parse(content);
                if (type == "coin")
                {
                    return(jobj["multiply"].ToString() == "1");
                }
                else if (type == "favorite")
                {
                    return(Convert.ToBoolean(jobj["favoured"]));
                }
            }
            return(false);
        }
Exemplo n.º 15
0
        /// <summary>
        /// 检查令牌状态
        /// </summary>
        /// <returns></returns>
        public async Task <bool> CheckTokenStatusAsync()
        {
            try
            {
                var param = new Dictionary <string, string>();
                param.Add("access_token", _accessToken);
                var url     = BiliTool.UrlContact(Api.PASSPORT_CHECK_TOKEN, param);
                var content = await BiliTool.GetTextFromWebAsync(url, true);

                var obj = JObject.Parse(content);
                if (Convert.ToInt32(obj["code"]) == 0)
                {
                    return(true);
                }
            }
            catch (Exception)
            {
            }
            return(false);
        }
Exemplo n.º 16
0
        /// <summary>
        /// 获取频道页综合信息
        /// </summary>
        /// <returns></returns>
        public async Task <ChannelSquare> GetSquareAsync()
        {
            var param = new Dictionary <string, string>();

            _squareChannelOffset = _squareChannelOffset > 100 ? 15 : _squareChannelOffset + 15;
            param.Add("offset_rcmd", _squareChannelOffset.ToString());
            param.Add("pn", "0");
            param.Add("qn", "32");
            param.Add("spmid", "traffic.channel-square.0.0");
            string url     = BiliTool.UrlContact(Api.CHANNEL_SQUARE, param, true);
            string content = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(content))
            {
                try
                {
                    var    jarr       = JArray.Parse(content);
                    string subString  = jarr.Where(p => p["model_type"].ToString() == "subscribe").First().SelectToken("items").ToString();
                    var    subscribes = JsonConvert.DeserializeObject <List <ChannelSlim> >(subString);
                    subscribes.RemoveAll(p => p.id == 0);
                    var square = new ChannelSquare()
                    {
                        Subscribes = subscribes
                    };
                    if (!string.IsNullOrEmpty(BiliTool._accessToken))
                    {
                        var scanToken = jarr.Where(p => p["model_type"].ToString() == "scaned").FirstOrDefault();
                        if (scanToken != null)
                        {
                            var scaneds = JsonConvert.DeserializeObject <List <ChannelView> >(scanToken.SelectToken("items").ToString());
                            square.Scaneds = scaneds;
                        }
                    }
                    return(square);
                }
                catch (Exception)
                {
                }
            }
            return(null);
        }
Exemplo n.º 17
0
        private async void BackupWebView_NavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
        {
            if (args.Uri == null)
            {
                return;
            }
            if (args.Uri.AbsoluteUri == "https://passport.bilibili.com/ajax/miniLogin/redirect")
            {
                var results = await BiliTool.GetTextFromWebAsync("https://passport.bilibili.com/login/app/third?appkey=27eb53fc9058f8c3&api=http%3A%2F%2Flink.acg.tv%2Fforum.php&sign=67ec798004373253d60114caaad89a8c", true);

                var obj = JObject.Parse(results);
                if (Convert.ToInt32(obj["code"].ToString()) == 0)
                {
                    BackupWebView.Navigate(new Uri(obj["data"]["confirm_uri"].ToString()));
                }
                else
                {
                    new TipPopup("登陆失败,请重试").ShowError();
                }
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// 获取评论列表
        /// </summary>
        /// <param name="oid">源ID</param>
        /// <param name="next">下一页偏移值</param>
        /// <param name="mode">排序方式:3-按热度,2-按时间</param>
        /// <returns>Item1:下一次偏移值,Item2:评论总数,Item3:评论列表,Item4: 是否到了结尾,Item5: 置顶回复</returns>
        public async Task <Tuple <int, int, List <Reply>, bool, Reply> > GetReplyAsync(string oid, int next, int mode, string type = "1")
        {
            var param = new Dictionary <string, string>();

            param.Add("oid", oid);
            param.Add("next", next.ToString());
            param.Add("prev", "0");
            param.Add("type", type);
            param.Add("mode", mode.ToString());
            param.Add("ps", "30");
            param.Add("plat", "3");
            var    url      = BiliTool.UrlContact(Api.REPLY_LIST, param, true);
            string response = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(response))
            {
                try
                {
                    var   jobj  = JObject.Parse(response);
                    int   ne    = Convert.ToInt32(jobj["cursor"]["next"].ToString());
                    int   all   = Convert.ToInt32(jobj["cursor"]["all_count"].ToString());
                    bool  isEnd = Convert.ToBoolean(jobj["cursor"]["is_end"].ToString());
                    Reply top   = null;
                    if (jobj["top"]["upper"].Type != JTokenType.Null)
                    {
                        top = JsonConvert.DeserializeObject <Reply>(jobj["top"]["upper"].ToString());
                    }
                    var replies = JsonConvert.DeserializeObject <List <Reply> >(jobj["replies"].ToString());
                    return(new Tuple <int, int, List <Reply>, bool, Reply>(ne, all, replies, isEnd, top));
                }
                catch (Exception)
                {
                    return(null);
                }
            }
            else
            {
                return(null);
            }
        }
Exemplo n.º 19
0
        /// <summary>
        /// 获取Emoji表情列表
        /// </summary>
        /// <returns></returns>
        public async Task <List <EmojiContainer> > GetTotalEmojiAsync()
        {
            string response = await BiliTool.GetTextFromWebAsync(Api.APP_EMOJI);

            var list = new List <EmojiContainer>();

            if (!string.IsNullOrEmpty(response))
            {
                var jobj = JObject.Parse(response);
                if (jobj.ContainsKey("vip"))
                {
                    var vips = JsonConvert.DeserializeObject <List <EmojiContainer> >(jobj["vip"].ToString());
                    list = list.Concat(vips).ToList();
                }
                if (jobj.ContainsKey("free"))
                {
                    var frees = JsonConvert.DeserializeObject <List <EmojiContainer> >(jobj["free"].ToString());
                    list = list.Concat(frees).ToList();
                }
            }
            return(list);
        }
Exemplo n.º 20
0
        /// <summary>
        /// 测试请求,验证网络是否可访问
        /// </summary>
        /// <returns></returns>
        public async Task <bool> ValidateRequestAsync()
        {
            string url      = Api.OTHER_ZONE;
            string response = await BiliTool.GetTextFromWebAsync(url, true);

            try
            {
                if (!string.IsNullOrEmpty(response))
                {
                    var jobj = JObject.Parse(response);
                    if (jobj["code"].ToString() == "0")
                    {
                        return(true);
                    }
                }
            }
            catch (Exception ex)
            {
                return(false);
            }
            return(false);
        }
Exemplo n.º 21
0
        /// <summary>
        /// 获取我正在追的影视剧
        /// </summary>
        /// <returns></returns>
        public async Task <Tuple <int, List <FavoriteAnime> > > GetMyFavoriteCinemaAsync(int page = 1)
        {
            var param = new Dictionary <string, string>();

            param.Add("ps", "20");
            param.Add("pn", page.ToString());
            param.Add("status", "2");
            string url     = BiliTool.UrlContact(Api.ACCOUNT_FAVOROTE_CINEMA, param, true);
            var    respons = await BiliTool.GetTextFromWebAsync(url, false, "result");

            if (!string.IsNullOrEmpty(respons))
            {
                var jobj = JObject.Parse(respons);
                var list = JsonConvert.DeserializeObject <List <FavoriteAnime> >(jobj["follow_list"]?.ToString() ?? "[]");
                if (list == null)
                {
                    list = new List <FavoriteAnime>();
                }
                var total = Convert.ToInt32(jobj["total"].ToString());
                return(new Tuple <int, List <FavoriteAnime> >(total, list));
            }
            return(null);
        }
        /// <summary>
        /// 获取话题动态
        /// </summary>
        /// <param name="topicId">话题ID</param>
        /// <param name="topicName">话题名</param>
        /// <param name="offset">偏移值,初次不需要,每次请求会返回下一次请求的偏移值</param>
        /// <returns>Item1:下次偏移值;Item2:视频列表</returns>
        public async Task <Tuple <string, List <Topic> > > GetTopicAsync(int topicId, string topicName, string offset = "")
        {
            var param = new Dictionary <string, string>();

            param.Add("topic_id", topicId.ToString());
            param.Add("topic_name", Uri.EscapeDataString(topicName));
            //param.Add("video_meta", "qn:32,fnval:16,fnver:0,fourk:1");
            if (!string.IsNullOrEmpty(offset))
            {
                param.Add("offset", offset);
            }
            string url  = BiliTool.UrlContact(Api.TOPIC_COMPLEX, param, true);
            var    data = await BiliTool.GetTextFromWebAsync(url);

            if (!string.IsNullOrEmpty(data))
            {
                var    jobj       = JObject.Parse(data);
                string nextOffset = jobj["offset"].ToString();
                var    topics     = JsonConvert.DeserializeObject <List <Topic> >(jobj["cards"].ToString());
                topics.RemoveAll(p => p == null || p.card == null || p.card.Length < 10 || p.desc.status != 1);
                return(new Tuple <string, List <Topic> >(nextOffset, topics));
            }
            return(null);
        }