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); */ } }
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); } }
/// <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]); } }
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"); }
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]); } }
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(); * } */ }
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"); }
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; } }