예제 #1
0
        protected override void Run()
        {
            base.Run();
            string ret = "";

            try
            {
                ret = HttpGet($"https://api.live.bilibili.com/room/v1/Room/get_info?room_id={TargetRoom}&from=room");
                //ret = HttpGet("https://api.live.bilibili.com/live/getInfo?roomid=" + TargetRoom);
                JObject obj = JObject.Parse(ret);
                if (obj["code"].Value <int>() == -400)
                {
                    Console.WriteLine("无效的房间号ID:" + TargetRoom);
                    return;
                }
                bool   status = obj["data"]["live_status"].Value <int>() == 1;
                string title  = obj["data"]["title"].Value <string>();
                //string nickname = obj["data"]["ANCHOR_NICK_NAME"].Value<string>();
                //Console.WriteLine(String.Format("Bilibili LiveRoom{0},Status:{1}", title, status ? "ON" : "OFF"));
                if (status != prevStatus)
                {
                    if (status == true)
                    {
                        DiffDetected?.Invoke(
                            "http://live.bilibili.com/" + TargetRoom,
                            "开启了直播间" + title + "!",
                            "直播间标题是:" + title,
                            "Bilibili.Live." + TargetRoom);
                    }
                    else
                    {
                        DiffDetected?.Invoke(
                            "http://live.bilibili.com/" + TargetRoom,
                            "关闭了直播间" + title + "!",
                            "直播间标题是:" + title,
                            "Bilibili.Live." + TargetRoom);
                    }
                    prevStatus = status;
                }
            }
            catch (Exception)
            {
                /*
                 * File.AppendAllText("LiveError.log",
                 *  "\n" + e + "\n" + "收到包内容:\n" + ret);
                 */
            }
        }
예제 #2
0
        private void GetDreamList(int targetUser, NianData data)
        {
            int page = 1;

            if (data.Dreams == null)
            {
                data.Dreams = new List <DreamInfo>();
            }
            for (page = 1;
                 page <= Math.Ceiling(
                     int.Parse(data.ListItems["dream"]) / 20.0f);
                 page++)
            {
                var result = api.GetUserDreams(targetUser.ToString(), page);
                foreach (var dreamStatus in (JArray)result["dreams"])
                {
                    var dreamInfo = (JObject)dreamStatus;
                    var id        = dreamInfo["id"].Value <string>();
                    var title     = dreamInfo["title"].Value <string>();
                    var di        = data.Dreams.FirstOrDefault(
                        info => info.Status["id"] == id);
                    if (di == null)
                    {
                        di = new DreamInfo();
                        data.Dreams.Add(di);
                        DiffDetected?.Invoke(
                            "http://nian.so/#!/dream/" + id,
                            uName + "新增了梦想" + title,
                            uName + "新增了梦想" + title,
                            "Nian." + targetUser + ".Dream." + id + ".Info");
                        di.Status = new Dictionary <string, string>();
                        di.Steps  = new List <StepInfo>();
                    }
                    foreach (var val in dreamInfo)
                    {
                        di.Status[val.Key] = val.Value.Value <string>();
                    }
                }
            }
            foreach (var dataDream in data.Dreams)
            {
                GetDreamExtendInfo(dataDream, data, currentPeroid % privatePeroid != 0);
            }
        }
예제 #3
0
        /// <summary>
        /// 对应数据项的增量抓取函数表
        /// </summary>

        private void GetDreamExtendInfo(Dream dream, NianContext context, bool Incremantal = true)
        {
            int lastupdated = 0;

            {
                string tmp;
                dream.Status.TryGetValue("lastupdated", out tmp);
                lastupdated = int.Parse(tmp ?? "0");
            }
            context.Entry(dream).Collection(d => d.Steps).Load();
            int maxPage = 1;
            //Origin Target
            int  unresolvedDiff = 0;
            bool isAllResolved  = false;
            int  pos            = dream.Steps.FindLastIndex(info => info.IsRemoved == false);

            bool        isFoundHead   = false;//是否找到最近出现的元素
            List <Step> pendingInsert = new List <Step>();
            int         page;

            for (page = 1; page <= maxPage; page++)
            {
                if (dream.Status.ContainsKey("private"))
                {
                    if (dream.Status["private"] == "2")
                    {
                        continue;                                 //被删除的记本
                    }
                    if (dream.Status["private"] == "1" && currentPeroid % privatePeroid != 0)
                    {
                        return;
                    }
                    //私密记本一天只能拉取1次
                }
                var result = api.GetDreamUpdate(dream.Status["id"], page);
                //Get Extend Dream Info

                var id = dream.Status["id"]; var title = dream.Status["title"];
                if (page == 1)
                {
                    var dreamInfo = (JObject)result["dream"];
                    foreach (var values in dreamInfo)
                    {
                        string valItem = "";
                        if (values.Value is JArray)
                        {
                            continue;
                        }
                        string targetValue = values.Value.Value <string>();
                        if (dream.Status.ContainsKey(values.Key))
                        {
                            valItem = dream.Status[values.Key];
                        }
                        if (values.Key == "step")
                        {
                            unresolvedDiff =
                                int.Parse(targetValue) - int.Parse("0" + valItem);
                        }
                        if (valItem != targetValue)
                        {
                            DiffDetected?.Invoke(
                                "http://nian.so/#!/dream/" + id,
                                uName + "修改了梦想" + title + "的信息",
                                "属性" + values.Key + "从" + valItem + "变为" + targetValue,
                                "Nian." + TargetUID + ".Dream." + id + ".Info." + values.Key);
                            dream.Status[values.Key] = targetValue;
                        }
                    }
                    maxPage = (int)Math.Ceiling(int.Parse(dream.Status["step"]) / 20.0f);
                }
                if (unresolvedDiff == 0 && Incremantal)//需要翻到下一页才能完全保证,因为有同时删除和增加的情况
                {
                    if (isAllResolved)
                    {
                        break;
                    }
                    else
                    {
                        isAllResolved = true;
                    }
                }
                else
                {
                    isAllResolved = false;
                }
                var stepsArray = (JArray)result["steps"];
                foreach (var stepInfo in stepsArray)
                {
                    Step si;
                    int  unresolvedComment = 0;
                    var  currentId         = stepInfo["sid"].Value <int>();
                    int  index             = dream.Steps.FindIndex(item => item.StepId == currentId);
                    Step refsi             = dream.Steps.ElementAtOrDefault(index);
                    if (index == -1)
                    {
                        if (isFoundHead)
                        {
                            throw new Exception("莫名的顺序,怀疑不对");
                        }
                        si = new Step
                        {
                            Comments = new List <Comment>()
                        };
                        pendingInsert.Add(si);
                        foreach (var val in (JObject)stepInfo)
                        {
                            if (val.Key == "images")
                            {
                                foreach (var imgPath in (JArray)val.Value)
                                {
                                    si.Images.Add(imgPath["path"].Value <string>());
                                }
                            }
                            else
                            {
                                si.Status[val.Key] = val.Value.Value <string>();
                            }
                        }
                        DiffDetected?.Invoke(
                            "http://nian.so/m/step/" + currentId,
                            uName + "在记本" + title + "发布了一条足迹",
                            "足迹内容:" + si.Status["content"],
                            "Nian." + TargetUID + ".Dream." + id + ".Step." + currentId);
                        unresolvedComment = ((JObject)stepInfo)["comments"].Value <int>();
                        unresolvedDiff--;
                        si.Status["lastupdated"] = DateTime.Now.ToUnixTime().ToString();
                        lastupdated = (int)DateTime.Now.ToUnixTime();
                    }
                    else
                    {
                        isFoundHead = true;
                        if (refsi.IsRemoved == true)
                        {
                            refsi.IsRemoved = false; //修复之前因为转为private被误标记为已删除的内容
                            pos             = index;
                        }
                        if (pos - index < 0)
                        {
                            throw new Exception("???WTF???");
                        }
                        for (int j = index + 1; j <= pos; j++)
                        {
                            if (!dream.Steps[j].IsRemoved)
                            {
                                dream.Steps[j].IsRemoved = true;
                                unresolvedDiff++;
                                DiffDetected?.Invoke(
                                    "http://nian.so/m/dream/" + dream.DreamId,
                                    uName + "删除了一条在" + title + "的足迹",
                                    "足迹内容:" + dream.Steps[j].Status["content"],
                                    "Nian." + TargetUID + ".Dream." + id + ".Step." + dream.Steps[j].StepId);
                                dream.Steps[j].Status["lastupdated"] = DateTime.Now.ToUnixTime().ToString();
                                lastupdated = (int)DateTime.Now.ToUnixTime();
                            }
                        }
                        pos = index - 1;
                        unresolvedComment =
                            int.Parse(refsi.Status["comments"]) -
                            ((JObject)stepInfo)["comments"].Value <int>();
                        refsi.Status["comments"] = ((JObject)stepInfo)["comments"].Value <string>();
                        si = refsi;
                    }

                    //需要检测的只有comment
                    if (unresolvedComment != 0)
                    {
                        ResolveComment(si, context, unresolvedComment);
                        si.Status["lastupdated"] = DateTime.Now.ToUnixTime().ToString();
                        lastupdated = (int)DateTime.Now.ToUnixTime();
                    }
                }
                dream.Status["lastupdated"] = lastupdated.ToString();
            }
            page -= 1;                                         //for跳出的那一轮需要减去
            if ((page == maxPage || maxPage == 0) && pos >= 0) //最后一页时如果pos不等于0,说明有step被删除了
            {
                for (int j = pos; j >= 0; j--)
                {
                    if (!dream.Steps[j].IsRemoved)
                    {
                        dream.Steps[j].IsRemoved = true;
                        unresolvedDiff++;
                        DiffDetected?.Invoke(
                            "http://nian.so/m/dream/" + dream.Status["id"],
                            uName + "删除了一条在" + dream.Status["title"] + "的足迹",
                            "足迹内容:" + dream.Steps[j].Status["content"],
                            "Nian." + TargetUID + ".Dream." + dream.Status["id"] + ".Step." + dream.Steps[j].Status["sid"]);
                    }
                }
            }
            if (unresolvedDiff != 0)
            {
                Console.WriteLine("Still Have UnresolvedDiff!!!!" + " Offset:" + unresolvedDiff);
            }
            for (int j = pendingInsert.Count - 1; j >= 0; j--)
            {
                dream.Steps.Add(pendingInsert[j]);
            }
        }
예제 #4
0
        protected override void Run()
        {
            if (IsFirstRun && _isDeferedLogin)
            {
                waitToken.WaitHandle.WaitOne(1000);
                Login();
            }
            if (IsFirstRun && !IsTest)
            {
                waitToken.WaitHandle.WaitOne(new Random().Next(0, 100000));
            }

            var value = DiffDetected;

            if (_isFirstRun)
            {
                DiffDetected = null;
            }
            using (var transaction = context.Database.BeginTransaction())
            {
                foreach (var uid in TargetUID.Split(',').Select(str => int.Parse(str)))
                {
                    try
                    {
                        var data = context.UserInfo.SingleOrDefault(r => r.UserId == uid);
                        if (data == null)
                        {
                            data        = new User();
                            data.UserId = uid;
                            context.UserInfo.Add(data);
                        }

                        currentTime = DateTime.Now;
                        //Status Data Compare
                        var userData = api.GetUserData(TargetUID.ToString());
                        var result   = userData["user"] as JObject;
                        uName = result["name"].Value <string>();
                        foreach (var obj in result)
                        {
                            var val = obj.Value as JValue;
                            if (val != null)
                            {
                                var targetValue = obj.Value.Value <string>();
                                var sourceValue = "";
                                if (data.Status.ContainsKey(obj.Key))
                                {
                                    sourceValue = data.Status[obj.Key];
                                }
                                if (sourceValue != targetValue)
                                {
                                    data.Status[obj.Key] = targetValue;
                                    DiffDetected?.Invoke(
                                        "http://nian.so/#!/user/" + TargetUID,
                                        uName + "修改了" + obj.Key,
                                        uName + "修改了" + obj.Key + ",从" + sourceValue + "变为" + targetValue,
                                        "Nian." + TargetUID + ".UserInfo." + obj.Key);
                                }
                            }
                        }

                        Console.WriteLine("wwww" + data);
                        GetDreamList(uid, context);

                        currentPeroid++;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        Console.WriteLine("Module" + Alias + " Throw an Exception");
                    }
                }
            }

            context.SaveChanges();

            if (_isFirstRun)
            {
                _isFirstRun  = false;
                DiffDetected = value;
            }
            Console.WriteLine(Alias + ":Data Fetched");
        }
예제 #5
0
        private void ResolveComment(Step step, NianContext context, int unresolvedComments)
        {
            //不想写增量了!
            //不过不用增量的方法怎么检测删除比较好呢?
            //还是写增量逻辑吧Q Q
            context.Entry(step).Collection(b => b.Comments);
            bool           isFoundHead   = false;
            List <Comment> pendingInsert = new List <Comment>();
            bool           isAllResolved = false;
            int            pos           = step.Comments.FindLastIndex(info => info.IsRemoved == false);
            int            maxPage       = (int)Math.Ceiling(int.Parse(step.Status["comments"]) / 15.0f);
            string         sid           = step.StepId.ToString();

            for (int page = 1; page <= maxPage; page++)
            {
                var result       = api.GetComments(step.StepId.ToString(), page);
                var commentArray = (JArray)result["comments"];
                foreach (var comment in commentArray)
                {
                    var cid   = comment["id"].Value <int>();
                    int index = step.Comments.FindIndex(item => item.CommentId == cid);
                    if (index == -1)
                    {
                        if (isFoundHead)
                        {
                            throw new Exception("这里顺序不对吧");
                        }
                        //CreateNew
                        Comment cmt = new Comment
                        {
                        };
                        pendingInsert.Add(cmt);
                        foreach (var val in (JObject)comment)
                        {
                            cmt.Status[val.Key] = val.Value.Value <string>();
                        }
                        DiffDetected?.Invoke(
                            "http://nian.so/m/step/" + step.Status["sid"],
                            uName + "的足迹下出现了一条新评论!",
                            "足迹:" + step.Status["content"] + " 评论:" + cmt.Status["content"] + " - By " + cmt.Status["user"],
                            "Nian." + TargetUID + ".Dream." + step.Status["dream"] + ".Step." + sid + ".Comments");
                        unresolvedComments--;
                    }
                    else
                    {
                        isFoundHead = true;
                        if (pos - index < 0)
                        {
                            throw new Exception("??????WTF");
                        }
                        for (int j = index + 1; j <= pos; j++)
                        {
                            if (!step.Comments[j].IsRemoved)
                            {
                                step.Comments[j].IsRemoved = true;
                                unresolvedComments++;
                                DiffDetected?.Invoke(
                                    "http://nian.so/m/step/" + step.Status["sid"],
                                    uName + "的足迹下有一条评论被删除了!",
                                    "足迹:" + step.Status["content"] + " 评论:" + step.Comments[j].Status["content"] + " - By " + step.Comments[j].Status["user"],
                                    "Nian." + TargetUID + ".Dream." + step.Status["dream"] + ".Step." + sid + ".Comments");
                            }
                        }
                        pos = index - 1;
                    }
                }
                if (unresolvedComments == 0)
                {
                    if (isAllResolved)
                    {
                        break;
                    }
                    else
                    {
                        isAllResolved = true;
                    }
                }
                else
                {
                    isAllResolved = false;
                }
            }
            for (int j = pendingInsert.Count - 1; j >= 0; j--)
            {
                step.Comments.Add(pendingInsert[j]);
            }
        }
예제 #6
0
        protected override void Run()
        {
            base.Run();
            if (IsFirstRun)
            {
                this.waitToken.WaitHandle.WaitOne(new Random().Next(0, 2000000));
            }
            List <string> historyFeeds = new List <string>();
            var           result       = _conn.Query <FeedGUID>("SELECT GUID FROM FeedData ORDER BY PubTime DESC LIMIT 50");

            foreach (var val in result)
            {
                historyFeeds.Add(val.GUID);
            }
            SyndicationFeed feed;

            try
            {
                feed = GetFeed(URL, CustomTimeFormat);
            }
            catch (Exception e)
            {
                //Network Error
                Console.WriteLine(e);
                Console.WriteLine("Unable to Get Feed:" + URL);
                return;
            }
            string title = feed.Title.Text;

            _conn.RunInTransaction(() =>
            {
                foreach (var synItem in feed.Items.Reverse())
                {
                    if (historyFeeds.IndexOf(synItem.Id) != -1)
                    {
                        continue;
                    }
                    try
                    {
                        _conn.Insert(new RSSData
                        {
                            Description = synItem.Summary.Text,
                            GUID        = synItem.Id,
                            Title       = synItem.Title.Text,
                            PubTime     = synItem.PublishDate.DateTime.ToUniversalTime()
                        });
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"Failed to Insert data:\n{synItem.Id}\n{synItem.Title.Text}\n{synItem.Summary.Text}\n{synItem.PublishDate}");
                        Console.WriteLine("Error info:" + e);
                        //continue;
                        break;
                        //此处违反约束的原因是重复的Id,所以不应该更新数据
                        //因为其实数据约束也就这一个嘛
                    }
                    DiffDetected?.Invoke(synItem.Id, title + " - " + synItem.Title.Text, synItem.Summary.Text, Alias + ".Updated");
                }
            });

            /*
             * using (SQLiteTransaction trans = _conn.BeginTransaction())
             * {
             *  foreach (var synItem in feed.Items.Reverse())
             *  {
             *      if (historyFeeds.IndexOf(synItem.Id) != -1) continue;
             *      try
             *      {
             *          _conn.ExecCommand(
             *              "INSERT INTO FeedData(GUID,Title,Desc, PubTime) VALUES(@GUID,@Title,@Desc,@PubTime)",
             *              new Dictionary<string, object>
             *              {
             *                  {"@GUID", synItem.Id},
             *                  {"@Title", synItem.Title.Text},
             *                  {"@Desc", synItem.Summary.Text},
             *                  {"@PubTime", synItem.PublishDate.DateTime.ToUnixTime()}
             *              });
             *      }
             *      catch (Exception e)
             *      {
             *          //Another change will modify even if some commands fail.
             *          Console.WriteLine(e);
             *      }
             *      DiffDetected?.Invoke(synItem.Id,synItem.Title.Text,synItem.Summary.Text,Alias + ".Updated");
             *  }
             *  trans.Commit();
             * }
             */
        }
예제 #7
0
        protected override void Run()
        {
            if (IsFirstRun && _isDeferedLogin)
            {
                waitToken.WaitHandle.WaitOne(1000);
                Login();
            }
            if (IsFirstRun && !IsTest)
            {
                waitToken.WaitHandle.WaitOne(new Random().Next(0, 100000));
            }
            var col   = db.GetCollection <NianData>();
            var value = DiffDetected;

            if (_isFirstRun)
            {
                DiffDetected = null;
            }
            var trans = db.BeginTrans();

            try {
                currentTime = DateTime.Now;
                //Status Data Compare
                var userData = api.GetUserData(TargetUID.ToString());
                var result   = userData["user"] as JObject;
                uName = result["name"].Value <string>();
                foreach (var obj in result)
                {
                    var val = obj.Value as JValue;
                    if (val != null)
                    {
                        var targetValue = obj.Value.Value <string>();
                        var sourceValue = "";
                        if (data.ListItems.ContainsKey(obj.Key))
                        {
                            sourceValue = data.ListItems[obj.Key];
                        }
                        if (sourceValue != targetValue)
                        {
                            data.ListItems[obj.Key] = targetValue;
                            DiffDetected?.Invoke(
                                "http://nian.so/#!/user/" + TargetUID,
                                uName + "修改了" + obj.Key,
                                uName + "修改了" + obj.Key + ",从" + sourceValue + "变为" + targetValue,
                                "Nian." + TargetUID + ".UserInfo." + obj.Key);
                        }
                    }
                }
                Console.WriteLine("wwww" + data);
                GetDreamList(TargetUID, data);
                col.Update(data);

                currentPeroid++;
            }
            catch (Exception e) {
                Console.WriteLine(e);
                Console.WriteLine("Module" + Alias + " Throw an Exception");
            }
            finally {
                trans.Commit();
            }
            if (_isFirstRun)
            {
                _isFirstRun  = false;
                DiffDetected = value;
            }
            Console.WriteLine(Alias + ":Data Fetched");
        }
예제 #8
0
        public void OnDataUpdated(JObject newData)
        {
            var tmpData = DiffDetected;

            if (firstRun)
            {
                DiffDetected = null;
            }
            var trans = database.BeginTrans();
            var col   = database.GetCollection <NetEaseData>();
            var uName = newData["status"]["name"].Value <string>();
            var uid   = newData["status"]["uid"].Value <string>();

            foreach (var prop in (JObject)newData["status"])
            {
                string sourceValue;
                data.ListItems.TryGetValue(prop.Key, out sourceValue);
                var targetValue = prop.Value.Value <string>();
                if (sourceValue == null)
                {
                    sourceValue = "";
                }
                if (targetValue == null)
                {
                    targetValue = "";
                }
                if (sourceValue != targetValue)
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#/user/home?id=" + uid,
                        uName + "修改了" + prop.Key,
                        uName + "修改了" + prop.Key + ",从" + sourceValue + "变为" + targetValue,
                        "UserInfo." + prop.Key);
                    data.ListItems[prop.Key] = targetValue;
                }
            }
            {
                int  pos         = -1;
                bool isHeadFound = false;
                DataHelper.IncrementalLoop(ref pos, ref isHeadFound,
                                           (JArray)newData["shares"].AsJEnumerable(),
                                           data.Events,
                                           shareInfo => EventData.FromJson((JObject)shareInfo), (a, b) => a.RelatedLink == b.RelatedLink, modifiedData =>
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#" + modifiedData.RelatedLink,
                        uName + "删除了歌曲分享:" + modifiedData.SongName,
                        string.Format("{0} - {1}\n{2}", modifiedData.SongName, modifiedData.SongArtist,
                                      modifiedData.Comment),
                        "UserInfo." + uid + ".Event");
                }, modifiedData =>
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#" + modifiedData.RelatedLink,
                        uName + "分享了一首好听的歌曲:" + modifiedData.SongName,
                        string.Format("{0} - {1}\n{2}", modifiedData.SongName, modifiedData.SongArtist,
                                      modifiedData.Comment),
                        "UserInfo." + uid + ".Event");
                });
            }
            {
                int  pos         = -1;
                bool isFoundHead = false;
                DataHelper.IncrementalLoop(ref pos, ref isFoundHead,
                                           (JArray)newData["follows"].AsJEnumerable(),
                                           data.Follows,
                                           follow => new RemovableString()
                {
                    Value = follow.Value <string>()
                },
                                           (a, b) => !a.IsRemoved && !b.IsRemoved && a.Value.Equals(b.Value),
                                           info =>
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#/user/follows?id=" + uid,
                        uName + "取消关注了一位小姐姐:" + info.Value,
                        uName + "取消关注了一位小姐姐:" + info.Value,
                        "UserInfo." + uid + ".Fans"
                        );
                },
                                           info =>
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#/user/follows?id=" + uid,
                        uName + "关注了一位小姐姐:" + info.Value,
                        uName + "关注了一位小姐姐:" + info.Value,
                        "UserInfo." + uid + ".Follow"
                        );
                }

                                           );
            }
            {
                int  pos         = -1;
                bool isFoundHead = false;
                DataHelper.IncrementalLoop(ref pos, ref isFoundHead,
                                           (JArray)newData["fans"].AsJEnumerable(),
                                           data.Fans,
                                           follow => new RemovableString()
                {
                    Value = follow.Value <string>()
                },
                                           (a, b) => !a.IsRemoved && !b.IsRemoved && a.Value.Equals(b.Value),
                                           info =>
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#/user/fans?id=" + uid,
                        uName + "的粉丝减少了一位:" + info.Value,
                        uName + "的粉丝减少了一位:" + info.Value,
                        "UserInfo." + uid + ".Fans"
                        );
                },
                                           info =>
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#/user/fans?id=" + uid,
                        uName + "增加了一名新粉丝:" + info.Value,
                        uName + "增加了一名新粉丝:" + info.Value,
                        "UserInfo." + uid + ".Follow"
                        );
                }
                                           );
            }
            if (newData["freqWeekly"] != null && ((JArray)newData["freqWeekly"]).Count != 0)
            {
                string srcStr = string.Concat(((JArray)newData["freqWeekly"]).AsJEnumerable()
                                              .Select(info => info["songName"].Value <string>() + " - " + info["songArtist"].Value <string>() + "\n"));
                var diffBuilder = new InlineDiffBuilder(new Differ());
                var diff        = diffBuilder.BuildDiffModel(data.WeeklyFreq ?? "", srcStr);
                int ranking     = 1;
                //0-----4------12------20
                // Flag  OldRank NewRank
                Dictionary <string, int> changedSongs = new Dictionary <string, int>();
                foreach (var result in diff.Lines)
                {
                    int val = 0;
                    changedSongs.TryGetValue(result.Text, out val);
                    switch (result.Type)
                    {
                    case ChangeType.Inserted:
                        changedSongs[result.Text] = val | 1 | (ranking << 12);
                        ranking++;
                        break;

                    case ChangeType.Deleted:
                        changedSongs[result.Text] = val | 2 | (ranking << 4);
                        break;

                    default:
                        ranking++;
                        break;
                    }
                }
                StringBuilder changes = new StringBuilder("");
                foreach (var changedSong in changedSongs)
                {
                    if ((changedSong.Value & 3) == 1)
                    {
                        //Add
                        changes.AppendLine(string.Format(
                                               "{0} 排名: {1} -> {2}",
                                               changedSong.Key,
                                               "新入榜",
                                               ((changedSong.Value & 0xFF000) >> 12).ToString()));
                    }
                    else if ((changedSong.Value & 3) == 2)
                    {
                        //Remove Only
                        changes.AppendLine(string.Format(
                                               "{0} 排名: {1} -> {2}",
                                               changedSong.Key,
                                               ((changedSong.Value & 0xFF0) >> 4).ToString(),
                                               "排名外"));
                    }
                    else
                    {
                        //Insert And Remove/
                        changes.AppendLine(string.Format(
                                               "{0} 排名: {1} -> {2}",
                                               changedSong.Key,
                                               ((changedSong.Value & 0xFF0) >> 4).ToString(),
                                               ((changedSong.Value & 0xFF000) >> 12).ToString()));
                    }
                }
                if (changedSongs.Count > 0)
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#/user/home?id=" + uid,
                        uName + "的歌曲周榜产生了变化",
                        changes.ToString(),
                        "UserInfo." + uid + ".WeekRanking");
                }
                data.WeeklyFreq = srcStr;
            }
            if (newData["freqAll"] != null && ((JArray)newData["freqAll"]).Count != 0)
            {
                string srcStr = string.Concat(((JArray)newData["freqAll"]).AsJEnumerable()
                                              .Select(info => info["songName"].Value <string>() + " - " + info["songArtist"].Value <string>() + "\n"));
                var diffBuilder = new InlineDiffBuilder(new Differ());
                var diff        = diffBuilder.BuildDiffModel(data.WeeklyFreq ?? "", srcStr);
                int ranking     = 1;
                //0-----4------12------20
                // Flag  OldRank NewRank
                Dictionary <string, int> changedSongs = new Dictionary <string, int>();
                foreach (var result in diff.Lines)
                {
                    int val = 0;
                    changedSongs.TryGetValue(result.Text, out val);
                    switch (result.Type)
                    {
                    case ChangeType.Inserted:
                        changedSongs[result.Text] = val | 1 | (ranking << 12);
                        ranking++;
                        break;

                    case ChangeType.Deleted:
                        changedSongs[result.Text] = val | 2 | (ranking << 4);
                        break;

                    default:
                        ranking++;
                        break;
                    }
                }
                StringBuilder changes = new StringBuilder("");
                foreach (var changedSong in changedSongs)
                {
                    if ((changedSong.Value & 3) == 1)
                    {
                        //Add
                        changes.AppendLine(string.Format(
                                               "{0} 排名: {1} -> {2}",
                                               changedSong.Key,
                                               "新入榜",
                                               ((changedSong.Value & 0xFF000) >> 12).ToString()));
                    }
                    else if ((changedSong.Value & 3) == 2)
                    {
                        //Remove Only
                        changes.AppendLine(string.Format(
                                               "{0} 排名: {1} -> {2}",
                                               changedSong.Key,
                                               ((changedSong.Value & 0xFF0) >> 4).ToString(),
                                               "排名外"));
                    }
                    else
                    {
                        //Insert And Remove/
                        changes.AppendLine(string.Format(
                                               "{0} 排名: {1} -> {2}",
                                               changedSong.Key,
                                               ((changedSong.Value & 0xFF0) >> 4).ToString(),
                                               ((changedSong.Value & 0xFF000) >> 12).ToString()));
                    }
                }
                if (changedSongs.Count > 0)
                {
                    DiffDetected?.Invoke(
                        "http://music.163.com/#/user/home?id=" + uid,
                        uName + "的歌曲榜产生了变化",
                        changes.ToString(),
                        "UserInfo." + uid + ".WeekRanking");
                }
                data.AllFreq = srcStr;
            }
            {
                var playListRoot = (JArray)newData["playLists"];
                foreach (var playList in playListRoot)
                {
                    var id           = playList["id"].Value <string>();
                    var playListName = playList["playList"].Value <string>();
                    var currentList  = data.PlayLists.FirstOrDefault(lst => lst.ListItems["id"] == id);
                    if (currentList == null)
                    {
                        currentList = new PlayList
                        {
                            MusicList = new List <SongInfo>(),
                            ListItems = new Dictionary <string, string>()
                        };
                        data.PlayLists.Add(currentList);
                    }
                    foreach (var prop in (JObject)playList)
                    {
                        if (prop.Key == "musicList")
                        {
                            continue;
                        }
                        string sourceValue;
                        currentList.ListItems.TryGetValue(prop.Key, out sourceValue);
                        var targetValue = prop.Value.Value <string>();
                        if (string.IsNullOrWhiteSpace(sourceValue))
                        {
                            sourceValue = "";
                        }
                        if (string.IsNullOrWhiteSpace(targetValue))
                        {
                            targetValue = "";
                        }
                        sourceValue = sourceValue.Trim("\n \t".ToCharArray());
                        targetValue = targetValue.Trim("\n \t".ToCharArray());
                        if (!sourceValue.Equals(targetValue))
                        {
                            DiffDetected?.Invoke(
                                "http://music.163.com/#/user/home?id=" + uid,
                                uName + "修改了播放列表" + playListName + "的属性" + prop.Key,
                                uName + "修改了" + prop.Key + ",从" + sourceValue + "变为" + targetValue,
                                "UserInfo." + uid + "." + id + "." + prop.Key);
                            currentList.ListItems[prop.Key] = targetValue;
                        }
                    }
                    int  pos         = -1;
                    bool IsFoundHead = false;
                    DataHelper.IncrementalLoop(ref pos, ref IsFoundHead, (JArray)playList["musicList"], currentList.MusicList,
                                               src => new SongInfo()
                    {
                        Value = src["songName"].Value <string>(), SongId = src["id"].Value <int>()
                    },
                                               (a, b) => !a.IsRemoved && !b.IsRemoved && a.SongId == b.SongId,
                                               music =>
                    {
                        DiffDetected?.Invoke(
                            "http://music.163.com/#/playlist?id=" + id,
                            uName + "的播放列表" + playListName + "移除了曲目" + music.Value,
                            uName + "的播放列表" + playListName + "移除了曲目" + music.Value,
                            "UserInfo." + uid + "." + id + ".Music");
                    },
                                               music =>
                    {
                        DiffDetected?.Invoke(
                            "http://music.163.com/#/playlist?id=" + id,
                            uName + "的播放列表" + playListName + "增加了曲目" + music.Value,
                            uName + "的播放列表" + playListName + "增加了曲目" + music.Value,
                            "UserInfo." + uid + "." + id + ".Music");
                    }
                                               );
                }
            }
            col.Update(data);
            trans.Commit();
            if (firstRun)
            {
                DiffDetected = tmpData;
                firstRun     = false;
            }
        }