Exemple #1
0
        public void UnreadCount_Test()
        {
            var tab = new TabClass { TabType = MyCommon.TabUsageType.UserTimeline };

            tab.UnreadManage = true;

            // 未読なし
            Assert.Equal(0, tab.UnreadCount);

            tab.AddPostToInnerStorage(new PostClass
            {
                StatusId = 100L,
                IsRead = false, // 未読
            });
            tab.AddSubmit();

            Assert.Equal(1, tab.UnreadCount);

            tab.AddPostToInnerStorage(new PostClass
            {
                StatusId = 50L,
                IsRead = true, // 既読
            });
            tab.AddSubmit();

            Assert.Equal(1, tab.UnreadCount);
        }
Exemple #2
0
        public void OldestUnreadId_DisabledTest()
        {
            var tab = new TabClass { TabType = MyCommon.TabUsageType.UserTimeline };

            // 未読表示無効
            tab.UnreadManage = false;

            tab.AddPostToInnerStorage(new PostClass
            {
                StatusId = 100L,
                IsRead = false, // 未読
            });
            tab.AddSubmit();

            Assert.Equal(-1L, tab.OldestUnreadId);
        }
Exemple #3
0
        public void NextUnreadId_SortByIdAscTest()
        {
            var tab = new TabClass { TabType = MyCommon.TabUsageType.UserTimeline };

            tab.UnreadManage = true;

            // ID の昇順でソート
            tab.SetSortMode(ComparerMode.Id, SortOrder.Ascending);

            // 画面には上から 100 → 200 → 300 の順に並ぶ
            tab.AddPostToInnerStorage(new PostClass { StatusId = 100L, IsRead = false });
            tab.AddPostToInnerStorage(new PostClass { StatusId = 200L, IsRead = false });
            tab.AddPostToInnerStorage(new PostClass { StatusId = 300L, IsRead = false });
            tab.AddSubmit();

            // 昇順/降順に関わらず、ID の小さい順に未読の ID を返す
            Assert.Equal(100L, tab.NextUnreadId);
        }
Exemple #4
0
        public void RemoveFilter_Test()
        {
            var tab = new TabClass();

            var filter = new PostFilterRule();
            tab.FilterArray = new[] { filter };
            tab.FilterModified = false;

            tab.RemoveFilter(filter);

            Assert.Empty(tab.FilterArray);
            Assert.True(tab.FilterModified);
        }
Exemple #5
0
        public void OnFilterModified_Test()
        {
            var tab = new TabClass();

            var filter = new PostFilterRule();
            tab.FilterArray = new[] { filter };
            tab.FilterModified = false;

            // TabClass に紐付いているフィルタを変更
            filter.FilterSource = "OpenTween";

            Assert.True(tab.FilterModified);
        }
Exemple #6
0
        private string CreatePostsFromPhoenixSearch(string content, MyCommon.WORKERTYPE gType, TabClass tab, bool read, int count, ref long minimumId, ref string nextPageQuery)
        {
            TwitterDataModel.SearchResult items;
            try
            {
                items = MyCommon.CreateDataFromJson<TwitterDataModel.SearchResult>(content);
            }
            catch(SerializationException ex)
            {
                MyCommon.TraceOut(ex.Message + Environment.NewLine + content);
                return "Json Parse Error(DataContractJsonSerializer)";
            }
            catch(Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid Json!";
            }

            nextPageQuery = items.NextPage;

            foreach (var status in items.Statuses)
            {
                PostClass post = null;
                post = CreatePostsFromStatusData(status);
                if (post == null) continue;

                if (minimumId > post.StatusId) minimumId = post.StatusId;
                //二重取得回避
                lock (LockObj)
                {
                    if (tab == null)
                    {
                        if (TabInformations.GetInstance().ContainsKey(post.StatusId)) continue;
                    }
                    else
                    {
                        if (TabInformations.GetInstance().ContainsKey(post.StatusId, tab.TabName)) continue;
                    }
                }

                post.IsRead = read;
                if (post.IsMe && !read && _readOwnPost) post.IsRead = true;

                if (tab != null) post.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(post);
            }

            return string.IsNullOrEmpty(items.ErrMsg) ? string.Empty : "Err:" + items.ErrMsg;
        }
Exemple #7
0
        private async Task FavRemoveAsync(IReadOnlyList<long> statusIds, TabClass tab)
        {
            await this.workerSemaphore.WaitAsync();

            try
            {
                var progress = new Progress<string>(x => this.StatusLabel.Text = x);

                await this.FavRemoveAsyncInternal(progress, this.workerCts.Token, statusIds, tab);
            }
            catch (WebApiException ex)
            {
                this._myStatusError = true;
                this.StatusLabel.Text = ex.Message;
            }
            finally
            {
                this.workerSemaphore.Release();
            }
        }
Exemple #8
0
        public string GetSearch(bool read,
                            TabClass tab,
                            bool more)
        {
            if (MyCommon._endingFlag) return string.Empty;

            HttpStatusCode res;
            var content = string.Empty;
            var page = 0;
            var sinceId = 0;
            var count = 100;
            if (AppendSettingDialog.Instance.UseAdditionalCount &&
                AppendSettingDialog.Instance.SearchCountApi != 0)
            {
                count = AppendSettingDialog.Instance.SearchCountApi;
            }
            else
            {
                count = AppendSettingDialog.Instance.CountApi;
            }
            if (more)
            {
                page = tab.GetSearchPage(count);
            }
            else
            {
                sinceId = (int)tab.SinceId;
            }

            try
            {
                // TODO:一時的に40>100件に 件数変更UI作成の必要あり
                res = twCon.Search(tab.SearchWords, tab.SearchLang, count, page, sinceId, ref content);
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }
            switch (res)
            {
                case HttpStatusCode.BadRequest:
                    return "Invalid query";
                case HttpStatusCode.NotFound:
                    return "Invalid query";
                case HttpStatusCode.PaymentRequired: //API Documentには420と書いてあるが、該当コードがないので402にしてある
                    return "Search API Limit?";
                case HttpStatusCode.OK:
                    break;
                default:
                    return "Err:" + res.ToString() + "(" + MethodBase.GetCurrentMethod().Name + ")";
            }

            if (!TabInformations.GetInstance().ContainsTab(tab)) return string.Empty;
            content = Regex.Replace(content, @"[\x00-\x1f-[\x0a\x0d]]+", " ");
            var xdoc = new XmlDocument();
            try
            {
                xdoc.LoadXml(content);
            }
            catch(Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid ATOM!";
            }
            var nsmgr = new XmlNamespaceManager(xdoc.NameTable);
            nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom");
            nsmgr.AddNamespace("twitter", "http://api.twitter.com/");
            nsmgr.AddNamespace("georss", "http://www.georss.org/georss");
            foreach (var xentryNode in xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr))
            {
                var xentry = (XmlElement)xentryNode;
                var post = new PostClass();
                try
                {
                    post.StatusId = long.Parse(xentry["id"].InnerText.Split(':')[2]);
                    if (TabInformations.GetInstance().ContainsKey(post.StatusId, tab.TabName)) continue;
                    post.CreatedAt = DateTime.Parse(xentry["published"].InnerText);
                    //本文
                    post.TextFromApi = xentry["title"].InnerText;
                    //Source取得(htmlの場合は、中身を取り出し)
                    post.Source = xentry["twitter:source"].InnerText;
                    post.InReplyToStatusId = 0;
                    post.InReplyToUser = string.Empty;
                    post.InReplyToUserId = 0;
                    post.IsFav = false;

                    // Geoが勝手に付加されるバグがいっこうに修正されないので暫定的にGeo情報を無視する
                    if (xentry["twitter:geo"].HasChildNodes)
                    {
                        var pnt = ((XmlElement)xentry.SelectSingleNode("twitter:geo/georss:point", nsmgr)).InnerText.Split(' ');
                        post.PostGeo = new PostClass.StatusGeo {Lat = Double.Parse(pnt[0]), Lng = Double.Parse(pnt[1])};
                    }

                    //以下、ユーザー情報
                    var xUentry = (XmlElement)xentry.SelectSingleNode("./search:author", nsmgr);
                    post.UserId = 0;
                    post.ScreenName = xUentry["name"].InnerText.Split(' ')[0].Trim();
                    post.Nickname = xUentry["name"].InnerText.Substring(post.ScreenName.Length).Trim();
                    if (post.Nickname.Length > 2)
                    {
                        post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2);
                    }
                    else
                    {
                        post.Nickname = post.ScreenName;
                    }
                    post.ImageUrl = ((XmlElement)xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr)).GetAttribute("href");
                    post.IsProtect = false;
                    post.IsMe = post.ScreenName.ToLower().Equals(_uname);

                    //HTMLに整形
                    post.Text = CreateHtmlAnchor(HttpUtility.HtmlEncode(post.TextFromApi), post.ReplyToList, post.Media);
                    post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi);
                    //Source整形
                    CreateSource(ref post);

                    post.IsRead = read;
                    post.IsReply = post.ReplyToList.Contains(_uname);
                    post.IsExcludeReply = false;

                    post.IsOwl = false;
                    if (post.IsMe && !read && _readOwnPost) post.IsRead = true;
                    post.IsDm = false;
                    post.RelTabName = tab.TabName;
                    if (!more && post.StatusId > tab.SinceId) tab.SinceId = post.StatusId;
                }
                catch(Exception ex)
                {
                    MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                    continue;
                }

                //this._dIcon.Add(post.ImageUrl, null);
                TabInformations.GetInstance().AddPost(post);

            }

            // TODO
            // 遡るための情報max_idやnext_pageの情報を保持する

            #if UNDEFINED__
            var xNode = xdoc.DocumentElement.SelectSingleNode("/search:feed/twitter:warning", nsmgr);

            if (xNode != null)
            {
                return "Warn:" + xNode.InnerText + "(" + MethodBase.GetCurrentMethod().Name + ")";
            }
            #endif

            return string.Empty;
        }
Exemple #9
0
        public string GetUserTimelineApi(bool read,
                                         int count,
                                         string userName,
                                         TabClass tab,
                                         bool more)
        {
            if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid) return string.Empty;

            if (MyCommon._endingFlag) return string.Empty;

            HttpStatusCode res = HttpStatusCode.BadRequest;
            var content = string.Empty;

            if (count == 0) count = 20;
            try
            {
                if (string.IsNullOrEmpty(userName))
                {
                    var target = tab.User;
                    if (string.IsNullOrEmpty(target)) return string.Empty;
                    userName = target;
                    res = twCon.UserTimeline(0, target, count, 0, 0, ref content);
                }
                else
                {
                    if (more)
                    {
                        res = twCon.UserTimeline(0, userName, count, tab.OldestId, 0, ref content);
                    }
                    else
                    {
                        res = twCon.UserTimeline(0, userName, count, 0, 0, ref content);
                    }
                }
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }
            switch (res)
            {
                case HttpStatusCode.OK:
                    Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
                    break;
                case HttpStatusCode.Unauthorized:
                    Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
                    return "Err:@" + userName + "'s Tweets are protected.";
                case HttpStatusCode.BadRequest:
                    return "Err:API Limits?";
                default:
                    return "Err:" + res.ToString() + "(" + MethodBase.GetCurrentMethod().Name + ")";
            }

            List<TwitterDataModel.Status> items;
            try
            {
                items = MyCommon.CreateDataFromJson<List<TwitterDataModel.Status>>(content);
            }
            catch(SerializationException ex)
            {
                MyCommon.TraceOut(ex.Message + Environment.NewLine + content);
                return "Json Parse Error(DataContractJsonSerializer)";
            }
            catch(Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid Json!";
            }

            foreach (var status in items)
            {
                var item = CreatePostsFromStatusData(status);
                if (item == null) continue;
                if (item.StatusId < tab.OldestId) tab.OldestId = item.StatusId;
                item.IsRead = read;
                if (item.IsMe && !read && _readOwnPost) item.IsRead = true;
                if (tab != null) item.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(item);
            }

            return string.Empty;
        }
Exemple #10
0
        private async Task FavRemoveAsyncInternal(IProgress<string> p, CancellationToken ct, IReadOnlyList<long> statusIds, TabClass tab)
        {
            if (ct.IsCancellationRequested)
                return;

            if (!CheckAccountValid())
                throw new WebApiException("Auth error. Check your account");

            var successIds = new List<long>();

            await Task.Run(() =>
            {
                //スレッド処理はしない
                var allCount = 0;
                var failedCount = 0;
                foreach (var statusId in statusIds)
                {
                    allCount++;

                    var post = tab.Posts[statusId];

                    p.Report(Properties.Resources.GetTimelineWorker_RunWorkerCompletedText17 +
                        allCount + "/" + statusIds.Count +
                        Properties.Resources.GetTimelineWorker_RunWorkerCompletedText18 +
                        failedCount);

                    if (!post.IsFav)
                        continue;

                    var err = this.tw.PostFavRemove(post.RetweetedId ?? post.StatusId);

                    if (!string.IsNullOrEmpty(err))
                    {
                        failedCount++;
                        continue;
                    }

                    successIds.Add(statusId);
                    post.IsFav = false; // リスト再描画必要

                    if (this._statuses.ContainsKey(statusId))
                    {
                        this._statuses[statusId].IsFav = false;
                    }

                    // 検索,リスト,UserTimeline,Relatedの各タブに反映
                    foreach (var tb in this._statuses.GetTabsInnerStorageType())
                    {
                        if (tb.Contains(statusId))
                            tb.Posts[statusId].IsFav = false;
                    }
                }
            });

            if (ct.IsCancellationRequested)
                return;

            this.RemovePostFromFavTab(successIds.ToArray());

            this.RefreshTimeline(false);

            if (this._curList != null && this._curTab != null && this._curTab.Text == tab.TabName)
            {
                if (tab.TabType == MyCommon.TabUsageType.Favorites)
                {
                    // 色変えは不要
                }
                else
                {
                    using (ControlTransaction.Update(this._curList))
                    {
                        foreach (var statusId in successIds)
                        {
                            var idx = tab.IndexOf(statusId);
                            if (idx == -1)
                                continue;

                            var post = tab.Posts[statusId];
                            this.ChangeCacheStyleRead(post.IsRead, idx);
                        }
                    }

                    if (successIds.Contains(this._curPost.StatusId))
                        await this.DispSelectedPost(true); // 選択アイテム再表示
                }
            }
        }
Exemple #11
0
        public string GetUserTimelineApi(bool read,
                                         int count,
                                         string userName,
                                         TabClass tab,
                                         bool more)
        {
            if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid) return "";

            if (MyCommon._endingFlag) return "";

            IList<TwitterDataModel.Status> items;
            try
            {
                if (string.IsNullOrEmpty(userName))
                {
                    var target = tab.User;
                    if (string.IsNullOrEmpty(target)) return "";
                    userName = target;
                    items = GetUserTimelineStatusApi(target, count, 0);
                }
                else
                {
                    if (more)
                    {
                        items = GetUserTimelineStatusApi(userName, count, tab.OldestId);
                    }
                    else
                    {
                        items = GetUserTimelineStatusApi(userName, count, 0);
                    }
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }

            IList<PostClass> postList = StatusListToPostClassList(items);

            foreach (var item in postList)
            {
                if (item.StatusId < tab.OldestId) tab.OldestId = item.StatusId;
                item.IsRead = read;
                if (item.IsMe && !read && _readOwnPost) item.IsRead = true;
                if (tab != null) item.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(item);
            }

            return "";
        }
Exemple #12
0
        public string GetUserTimelineApi(bool read,
                                         int count,
                                         string userName,
                                         TabClass tab,
                                         bool more)
        {
            if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid) return "";

            if (MyCommon._endingFlag) return "";

            HttpStatusCode res;
            var content = "";

            if (count == 0) count = 20;
            try
            {
                if (string.IsNullOrEmpty(userName))
                {
                    var target = tab.User;
                    if (string.IsNullOrEmpty(target)) return "";
                    userName = target;
                    res = twCon.UserTimeline(null, target, count, null, null, ref content);
                }
                else
                {
                    if (more)
                    {
                        res = twCon.UserTimeline(null, userName, count, tab.OldestId, null, ref content);
                    }
                    else
                    {
                        res = twCon.UserTimeline(null, userName, count, null, null, ref content);
                    }
                }
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }

            if (res == HttpStatusCode.Unauthorized)
                return "Err:@" + userName + "'s Tweets are protected.";

            var err = this.CheckStatusCode(res, content);
            if (err != null) return err;

            return CreatePostsFromJson(content, MyCommon.WORKERTYPE.UserTimeline, tab, read, ref tab.OldestId);
        }
Exemple #13
0
        private string CreatePostsFromSearchJson(string content, TabClass tab, bool read, int count, ref long minimumId, bool more)
        {
            TwitterSearchResult items;
            try
            {
                items = TwitterSearchResult.ParseJson(content);
            }
            catch (SerializationException ex)
            {
                MyCommon.TraceOut(ex.Message + Environment.NewLine + content);
                return "Json Parse Error(DataContractJsonSerializer)";
            }
            catch (Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid Json!";
            }
            foreach (var result in items.Statuses)
            {
                PostClass post = null;
                post = CreatePostsFromStatusData(result);

                if (post == null)
                {
                    // Search API は相変わらずぶっ壊れたデータを返すことがあるため、必要なデータが欠如しているものは取得し直す
                    var ret = this.GetStatusApi(read, result.Id, ref post);
                    if (!string.IsNullOrEmpty(ret)) continue;
                }

                if (minimumId > post.StatusId) minimumId = post.StatusId;
                if (!more && post.StatusId > tab.SinceId) tab.SinceId = post.StatusId;
                //二重取得回避
                lock (LockObj)
                {
                    if (tab == null)
                    {
                        if (TabInformations.GetInstance().ContainsKey(post.StatusId)) continue;
                    }
                    else
                    {
                        if (tab.Contains(post.StatusId)) continue;
                    }
                }

                post.IsRead = read;
                if ((post.IsMe && !read) && this._readOwnPost) post.IsRead = true;

                if (tab != null) post.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(post);
            }

            return "";
        }
Exemple #14
0
        private string CreatePostsFromSearchJson(string content, TabClass tab, bool read, int count, ref long minimumId, bool more)
        {
            TwitterDataModel.SearchResult items;
            try
            {
                items = MyCommon.CreateDataFromJson<TwitterDataModel.SearchResult>(content);
            }
            catch (SerializationException ex)
            {
                MyCommon.TraceOut(ex.Message + Environment.NewLine + content);
                return "Json Parse Error(DataContractJsonSerializer)";
            }
            catch (Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid Json!";
            }
            foreach (var result in items.Results)
            {
                PostClass post = null;
                post = CreatePostsFromSearchResultData(result);
                if (post == null) continue;

                if (minimumId > post.StatusId) minimumId = post.StatusId;
                if (!more && post.StatusId > tab.SinceId) tab.SinceId = post.StatusId;
                //二重取得回避
                lock (LockObj)
                {
                    if (tab == null)
                    {
                        if (TabInformations.GetInstance().ContainsKey(post.StatusId)) continue;
                    }
                    else
                    {
                        if (TabInformations.GetInstance().ContainsKey(post.StatusId, tab.TabName)) continue;
                    }
                }

                post.IsRead = read;
                if ((post.IsMe && !read) && this._readOwnPost) post.IsRead = true;

                if (tab != null) post.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(post);
            }

            return "";
        }
Exemple #15
0
 public bool ContainsTab(TabClass ts)
 {
     return _tabs.ContainsValue(ts);
 }
Exemple #16
0
 public bool AddTab(string TabName, MyCommon.TabUsageType TabType, ListElement List)
 {
     if (_tabs.ContainsKey(TabName)) return false;
     var tb = new TabClass(TabName, TabType, List);
     _tabs.Add(TabName, tb);
     tb.SortMode = this.SortMode;
     tb.SortOrder = this.SortOrder;
     return true;
 }
Exemple #17
0
        public void OnFilterModified_DetachedTest()
        {
            var tab = new TabClass();

            var filter = new PostFilterRule();
            tab.FilterArray = new[] { filter };

            tab.RemoveFilter(filter);
            tab.FilterModified = false;

            // TabClass から既に削除されたフィルタを変更
            filter.FilterSource = "OpenTween";

            Assert.False(tab.FilterModified);
        }
Exemple #18
0
        public string GetPhoenixSearch(bool read,
                                TabClass tab,
                                bool more)
        {
            if (MyCommon._endingFlag) return string.Empty;

            HttpStatusCode res;
            var content = string.Empty;
            var page = 0;
            var sinceId = 0;
            var count = 100;
            var querystr = string.Empty;
            if (AppendSettingDialog.Instance.UseAdditionalCount &&
                AppendSettingDialog.Instance.SearchCountApi != 0)
            {
                count = AppendSettingDialog.Instance.SearchCountApi;
            }
            if (more)
            {
                page = tab.GetSearchPage(count);
                if (!string.IsNullOrEmpty(tab.NextPageQuery))
                {
                    querystr = tab.NextPageQuery;
                }
            }
            else
            {
                sinceId = (int)tab.SinceId;
            }

            try
            {
                if (string.IsNullOrEmpty(querystr))
                {
                    res = twCon.PhoenixSearch(tab.SearchWords, tab.SearchLang, count, page, sinceId, ref content);
                }
                else
                {
                    res = twCon.PhoenixSearch(querystr, ref content);
                }
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }
            switch (res)
            {
                case HttpStatusCode.BadRequest:
                    return "Invalid query";
                case HttpStatusCode.NotFound:
                    return "Invalid query";
                case HttpStatusCode.PaymentRequired: //API Documentには420と書いてあるが、該当コードがないので402にしてある
                    return "Search API Limit?";
                case HttpStatusCode.OK:
                    break;
                default:
                    return "Err:" + res.ToString() + "(" + MethodBase.GetCurrentMethod().Name + ")";
            }

            if (!TabInformations.GetInstance().ContainsTab(tab)) return string.Empty;

            //// TODO
            //// 遡るための情報max_idやnext_pageの情報を保持する

            string nextPageQuery = tab.NextPageQuery;
            var ret = CreatePostsFromPhoenixSearch(content, MyCommon.WORKERTYPE.PublicSearch, tab, read, count, ref tab.OldestId, ref nextPageQuery);
            tab.NextPageQuery = nextPageQuery;
            return ret;
        }
Exemple #19
0
        public string GetListStatus(bool read,
                                TabClass tab,
                                bool more,
                                bool startup)
        {
            if (MyCommon._endingFlag) return "";

            HttpStatusCode res;
            var content = "";
            int count;
            if (SettingCommon.Instance.UseAdditionalCount)
            {
                count = SettingCommon.Instance.ListCountApi;
                if (count == 0)
                {
                    if (more && SettingCommon.Instance.MoreCountApi != 0)
                    {
                        count = SettingCommon.Instance.MoreCountApi;
                    }
                    else if (startup && SettingCommon.Instance.FirstCountApi != 0)
                    {
                        count = SettingCommon.Instance.FirstCountApi;
                    }
                    else
                    {
                        count = SettingCommon.Instance.CountApi;
                    }
                }
            }
            else
            {
                count = SettingCommon.Instance.CountApi;
            }
            try
            {
                if (more)
                {
                    res = twCon.GetListsStatuses(tab.ListInfo.UserId, tab.ListInfo.Id, count, tab.OldestId, null, SettingCommon.Instance.IsListsIncludeRts, ref content);
                }
                else
                {
                    res = twCon.GetListsStatuses(tab.ListInfo.UserId, tab.ListInfo.Id, count, null, null, SettingCommon.Instance.IsListsIncludeRts, ref content);
                }
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }

            var err = this.CheckStatusCode(res, content);
            if (err != null) return err;

            return CreatePostsFromJson(content, MyCommon.WORKERTYPE.List, tab, read, ref tab.OldestId);
        }
Exemple #20
0
        public string GetUserTimelineApi(bool read,
                                         int count,
                                         string userName,
                                         TabClass tab,
                                         bool more)
        {
            if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid) return "";

            if (MyCommon._endingFlag) return "";

            HttpStatusCode res;
            var content = "";

            if (count == 0) count = 20;
            try
            {
                if (string.IsNullOrEmpty(userName))
                {
                    var target = tab.User;
                    if (string.IsNullOrEmpty(target)) return "";
                    userName = target;
                    res = twCon.UserTimeline(null, target, count, null, null, ref content);
                }
                else
                {
                    if (more)
                    {
                        res = twCon.UserTimeline(null, userName, count, tab.OldestId, null, ref content);
                    }
                    else
                    {
                        res = twCon.UserTimeline(null, userName, count, null, null, ref content);
                    }
                }
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }

            if (res == HttpStatusCode.Unauthorized)
                return "Err:@" + userName + "'s Tweets are protected.";

            var err = this.CheckStatusCode(res, content);
            if (err != null) return err;

            TwitterStatus[] items;
            try
            {
                items = TwitterStatus.ParseJsonArray(content);
            }
            catch(SerializationException ex)
            {
                MyCommon.TraceOut(ex.Message + Environment.NewLine + content);
                return "Json Parse Error(DataContractJsonSerializer)";
            }
            catch(Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid Json!";
            }

            foreach (var status in items)
            {
                var item = CreatePostsFromStatusData(status);
                if (item == null) continue;
                if (item.StatusId < tab.OldestId) tab.OldestId = item.StatusId;
                item.IsRead = read;
                if (item.IsMe && !read && _readOwnPost) item.IsRead = true;
                if (tab != null) item.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(item);
            }

            return "";
        }
Exemple #21
0
        public string GetListStatus(bool read,
                                TabClass tab,
                                bool more,
                                bool startup)
        {
            if (MyCommon._endingFlag) return string.Empty;

            HttpStatusCode res;
            var content = string.Empty;
            int count;
            if (AppendSettingDialog.Instance.UseAdditionalCount)
            {
                count = AppendSettingDialog.Instance.ListCountApi;
                if (count == 0)
                {
                    if (more && AppendSettingDialog.Instance.MoreCountApi != 0)
                    {
                        count = AppendSettingDialog.Instance.MoreCountApi;
                    }
                    else if (startup && AppendSettingDialog.Instance.FirstCountApi != 0)
                    {
                        count = AppendSettingDialog.Instance.FirstCountApi;
                    }
                    else
                    {
                        count = AppendSettingDialog.Instance.CountApi;
                    }
                }
            }
            else
            {
                count = AppendSettingDialog.Instance.CountApi;
            }
            try
            {
                if (more)
                {
                    res = twCon.GetListsStatuses(tab.ListInfo.UserId, tab.ListInfo.Id, count, tab.OldestId, 0, AppendSettingDialog.Instance.IsListStatusesIncludeRts, ref content);
                }
                else
                {
                    res = twCon.GetListsStatuses(tab.ListInfo.UserId, tab.ListInfo.Id, count, 0, 0, AppendSettingDialog.Instance.IsListStatusesIncludeRts, ref content);
                }
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }
            switch (res)
            {
                case HttpStatusCode.OK:
                    Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
                    break;
                case HttpStatusCode.Unauthorized:
                    Twitter.AccountState = MyCommon.ACCOUNT_STATE.Invalid;
                    return Properties.Resources.Unauthorized;
                case HttpStatusCode.BadRequest:
                    return "Err:API Limits?";
                default:
                    return "Err:" + res.ToString() + "(" + MethodBase.GetCurrentMethod().Name + ")";
            }

            return CreatePostsFromJson(content, MyCommon.WORKERTYPE.List, tab, read, count, ref tab.OldestId);
        }
Exemple #22
0
        public string GetRelatedResult(bool read, TabClass tab)
        {
            var rslt = "";
            var relPosts = new Dictionary<Int64, PostClass>();
            if (tab.RelationTargetPost.TextFromApi.Contains("@") && tab.RelationTargetPost.InReplyToStatusId == null)
            {
                //検索結果対応
                var p = TabInformations.GetInstance()[tab.RelationTargetPost.StatusId];
                if (p != null && p.InReplyToStatusId != null)
                {
                    tab.RelationTargetPost = p;
                }
                else
                {
                    rslt = this.GetStatusApi(read, tab.RelationTargetPost.StatusId, ref p);
                    if (!string.IsNullOrEmpty(rslt)) return rslt;
                    tab.RelationTargetPost = p;
                }
            }
            relPosts.Add(tab.RelationTargetPost.StatusId, tab.RelationTargetPost.Clone());

            // in_reply_to_status_id を使用してリプライチェインを辿る
            var nextPost = FindTopOfReplyChain(relPosts, tab.RelationTargetPost.StatusId);
            var loopCount = 1;
            while (nextPost.InReplyToStatusId != null && loopCount++ <= 20)
            {
                var inReplyToId = nextPost.InReplyToStatusId.Value;

                var inReplyToPost = TabInformations.GetInstance()[inReplyToId];
                if (inReplyToPost != null)
                {
                    inReplyToPost = inReplyToPost.Clone();
                }
                else
                {
                    var errorText = this.GetStatusApi(read, inReplyToId, ref inReplyToPost);
                    if (!string.IsNullOrEmpty(errorText))
                    {
                        rslt = errorText;
                        break;
                    }
                }

                relPosts.Add(inReplyToPost.StatusId, inReplyToPost);

                nextPost = FindTopOfReplyChain(relPosts, nextPost.StatusId);
            }

            //MRTとかに対応のためツイート内にあるツイートを指すURLを取り込む
            var text = tab.RelationTargetPost.Text;
            var ma = Twitter.StatusUrlRegex.Matches(text).Cast<Match>()
                .Concat(Twitter.ThirdPartyStatusUrlRegex.Matches(text).Cast<Match>());
            foreach (var _match in ma)
            {
                Int64 _statusId;
                if (Int64.TryParse(_match.Groups["StatusId"].Value, out _statusId))
                {
                    if (relPosts.ContainsKey(_statusId))
                        continue;

                    PostClass p = null;
                    var _post = TabInformations.GetInstance()[_statusId];
                    if (_post == null)
                    {
                        this.GetStatusApi(read, _statusId, ref p);
                    }
                    else
                    {
                        p = _post.Clone();
                    }

                    if (p != null)
                        relPosts.Add(p.StatusId, p);
                }
            }

            relPosts.Values.ToList().ForEach(p =>
            {
                if (p.IsMe && !read && this._readOwnPost)
                    p.IsRead = true;
                else
                    p.IsRead = read;

                p.RelTabName = tab.TabName;
                TabInformations.GetInstance().AddPost(p);
            });

            return rslt;
        }
Exemple #23
0
        public string GetRelatedResult(bool read, TabClass tab)
        {
            var rslt = string.Empty;
            var relPosts = new List<PostClass>();
            if (tab.RelationTargetPost.TextFromApi.Contains("@") && tab.RelationTargetPost.InReplyToStatusId == 0)
            {
                //検索結果対応
                var p = TabInformations.GetInstance()[tab.RelationTargetPost.StatusId];
                if (p != null && p.InReplyToStatusId > 0)
                {
                    tab.RelationTargetPost = p;
                }
                else
                {
                    rslt = this.GetStatusApi(read, tab.RelationTargetPost.StatusId, ref p);
                    if (!string.IsNullOrEmpty(rslt)) return rslt;
                    tab.RelationTargetPost = p;
                }
            }
            relPosts.Add(tab.RelationTargetPost.Copy());
            var tmpPost = relPosts[0];
            do
            {
                rslt = this.GetRelatedResultsApi(read, tmpPost, tab, relPosts);
                if (!string.IsNullOrEmpty(rslt)) break;
                tmpPost = CheckReplyToPost(relPosts);
            } while (tmpPost != null);

            relPosts.ForEach(p => TabInformations.GetInstance().AddPost(p));
            return rslt;
        }
Exemple #24
0
        public string GetSearch(bool read,
                            TabClass tab,
                            bool more)
        {
            if (MyCommon._endingFlag) return "";

            HttpStatusCode res;
            var content = "";
            long? maxId = null;
            long? sinceId = null;
            var count = 100;
            if (SettingCommon.Instance.UseAdditionalCount &&
                SettingCommon.Instance.SearchCountApi != 0)
            {
                count = SettingCommon.Instance.SearchCountApi;
            }
            else
            {
                count = SettingCommon.Instance.CountApi;
            }
            if (more)
            {
                maxId = tab.OldestId - 1;
            }
            else
            {
                sinceId = tab.SinceId;
            }

            try
            {
                // TODO:一時的に40>100件に 件数変更UI作成の必要あり
                res = twCon.Search(tab.SearchWords, tab.SearchLang, count, maxId, sinceId, ref content);
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }
            switch (res)
            {
                case HttpStatusCode.BadRequest:
                    return "Invalid query";
                case HttpStatusCode.NotFound:
                    return "Invalid query";
                case HttpStatusCode.PaymentRequired: //API Documentには420と書いてあるが、該当コードがないので402にしてある
                    return "Search API Limit?";
                case HttpStatusCode.OK:
                    break;
                default:
                    return "Err:" + res.ToString() + "(" + MethodBase.GetCurrentMethod().Name + ")";
            }

            if (!TabInformations.GetInstance().ContainsTab(tab)) return "";

            return this.CreatePostsFromSearchJson(content, tab, read, count, ref tab.OldestId, more);
        }
Exemple #25
0
        public string GetStatusApi(bool read,
                                   Int64 id,
                                   TabClass tab)
        {
            PostClass post = null;
            var r = this.GetStatusApi(read, id, ref post);

            if (string.IsNullOrEmpty(r))
            {
                if (tab != null) post.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(post);
            }

            return r;
        }
Exemple #26
0
        public void OldestUnreadIndex_DisabledTest()
        {
            var tab = new TabClass { TabType = MyCommon.TabUsageType.UserTimeline };

            // 未読表示無効
            tab.UnreadManage = false;

            tab.AddPostToInnerStorage(new PostClass
            {
                StatusId = 100L,
                IsRead = false, // 未読
            });
            tab.AddSubmit();

            tab.SortMode = ComparerMode.Id;
            tab.SortOrder = SortOrder.Ascending;
            tab.Sort();

            Assert.Equal(-1, tab.OldestUnreadIndex);
        }
Exemple #27
0
        private string CreatePostsFromJson(string content, MyCommon.WORKERTYPE gType, TabClass tab, bool read, int count, ref long minimumId)
        {
            List<TwitterDataModel.Status> items;
            try
            {
                items = MyCommon.CreateDataFromJson<List<TwitterDataModel.Status>>(content);
            }
            catch(SerializationException ex)
            {
                MyCommon.TraceOut(ex.Message + Environment.NewLine + content);
                return "Json Parse Error(DataContractJsonSerializer)";;
            }
            catch(Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid Json!";
            }

            foreach (var status in items)
            {
                PostClass post = null;
                post = CreatePostsFromStatusData(status);
                if (post == null) continue;

                if (minimumId > post.StatusId) minimumId = post.StatusId;
                //二重取得回避
                lock (LockObj)
                {
                    if (tab == null)
                    {
                        if (TabInformations.GetInstance().ContainsKey(post.StatusId)) continue;
                    }
                    else
                    {
                        if (TabInformations.GetInstance().ContainsKey(post.StatusId, tab.TabName)) continue;
                    }
                }

                //RT禁止ユーザーによるもの
                if (post.RetweetedId > 0 && this.noRTId.Contains(post.RetweetedByUserId)) continue;

                post.IsRead = read;
                if (post.IsMe && !read && _readOwnPost) post.IsRead = true;

                if (tab != null) post.RelTabName = tab.TabName;
                //非同期アイコン取得&StatusDictionaryに追加
                TabInformations.GetInstance().AddPost(post);
            }

            return string.Empty;
        }
Exemple #28
0
        public void SetReadState_MarkAsUnreadTest()
        {
            var tab = new TabClass { TabType = MyCommon.TabUsageType.UserTimeline };

            tab.UnreadManage = true;

            tab.AddPostToInnerStorage(new PostClass
            {
                StatusId = 100L,
                IsRead = true, // 既読
            });
            tab.AddSubmit();

            Assert.Equal(0, tab.UnreadCount);

            tab.SetReadState(100L, false); // 未読にする

            Assert.Equal(1, tab.UnreadCount);
        }
Exemple #29
0
        private string GetRelatedResultsApi(bool read,
                                             PostClass post,
                                             TabClass tab,
                                             List<PostClass> relatedPosts)
        {
            if (Twitter.AccountState != MyCommon.ACCOUNT_STATE.Valid) return string.Empty;

            if (MyCommon._endingFlag) return string.Empty;

            HttpStatusCode res = HttpStatusCode.BadRequest;
            var content = string.Empty;
            try
            {
                if (post.RetweetedId > 0)
                {
                    res = twCon.GetRelatedResults(post.RetweetedId, ref content);
                }
                else
                {
                    res = twCon.GetRelatedResults(post.StatusId, ref content);
                }
            }
            catch(Exception ex)
            {
                return "Err:" + ex.Message;
            }
            switch (res)
            {
                case HttpStatusCode.OK:
                    Twitter.AccountState = MyCommon.ACCOUNT_STATE.Valid;
                    break;
                case HttpStatusCode.Unauthorized:
                    Twitter.AccountState = MyCommon.ACCOUNT_STATE.Invalid;
                    return Properties.Resources.Unauthorized;
                case HttpStatusCode.BadRequest:
                    return "Err:API Limits?";
                default:
                    return "Err:" + res.ToString() + "(" + MethodBase.GetCurrentMethod().Name + ")";
            }

            List<TwitterDataModel.RelatedResult> items;
            try
            {
                items = MyCommon.CreateDataFromJson<List<TwitterDataModel.RelatedResult>>(content);
            }
            catch(SerializationException ex)
            {
                MyCommon.TraceOut(ex.Message + Environment.NewLine + content);
                return "Json Parse Error(DataContractJsonSerializer)";
            }
            catch(Exception ex)
            {
                MyCommon.TraceOut(ex, MethodBase.GetCurrentMethod().Name + " " + content);
                return "Invalid Json!";
            }

            var targetItem = post;
            if (targetItem == null)
            {
                return string.Empty;
            }
            else
            {
                targetItem = targetItem.Copy();
            }
            targetItem.RelTabName = tab.TabName;
            TabInformations.GetInstance().AddPost(targetItem);

            PostClass replyToItem = null;
            var replyToUserName = targetItem.InReplyToUser;
            if (targetItem.InReplyToStatusId > 0 && TabInformations.GetInstance()[targetItem.InReplyToStatusId] != null)
            {
                replyToItem = TabInformations.GetInstance()[targetItem.InReplyToStatusId].Copy();
                replyToItem.IsRead = read;
                if (replyToItem.IsMe && !read && _readOwnPost) replyToItem.IsRead = true;
                replyToItem.RelTabName = tab.TabName;
            }

            var replyAdded = false;
            foreach (var relatedData in items)
            {
                foreach (var result in relatedData.Results)
                {
                    var item = CreatePostsFromStatusData(result.Status);
                    if (item == null) continue;
                    if (targetItem.InReplyToStatusId == item.StatusId)
                    {
                        replyToItem = null;
                        replyAdded = true;
                    }
                    item.IsRead = read;
                    if (item.IsMe && !read && _readOwnPost) item.IsRead = true;
                    if (tab != null) item.RelTabName = tab.TabName;
                    //非同期アイコン取得&StatusDictionaryに追加
                    relatedPosts.Add(item);
                }
            }
            if (replyToItem != null)
            {
                relatedPosts.Add(replyToItem);
            }
            else if (targetItem.InReplyToStatusId > 0 && !replyAdded)
            {
                PostClass p = null;
                var rslt = string.Empty;
                rslt = GetStatusApi(read, targetItem.InReplyToStatusId, ref p);
                if (string.IsNullOrEmpty(rslt))
                {
                    p.IsRead = read;
                    p.RelTabName = tab.TabName;
                    relatedPosts.Add(p);
                }
                return rslt;
            }

            //発言者・返信先ユーザーの直近10発言取得
            //var rslt = this.GetUserTimelineApi(read, 10, string.Empty, tab);
            //if (!string.IsNullOrEmpty(rslt)) return rslt;
            //if (!string.IsNullOrEmpty(replyToUserName))
            //    rslt = this.GetUserTimelineApi(read, 10, replyToUserName, tab);
            //}
            //return rslt;

            //MRTとかに対応のためツイート内にあるツイートを指すURLを取り込む
            var ma = Regex.Matches(tab.RelationTargetPost.Text, "title=\"https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/(?<StatusId>[0-9]+))\"");
            foreach (Match _match in ma)
            {
                Int64 _statusId;
                if (Int64.TryParse(_match.Groups["StatusId"].Value, out _statusId))
                {
                    PostClass p = null;
                    var _post = TabInformations.GetInstance()[_statusId];
                    if (_post == null)
                    {
                        var result = this.GetStatusApi(read, _statusId, ref p);
                    }
                    else
                    {
                        p = _post.Copy();
                    }
                    if (p != null)
                    {
                        p.IsRead = read;
                        p.RelTabName = tab.TabName;
                        relatedPosts.Add(p);
                    }
                }
            }
            return string.Empty;
        }
Exemple #30
0
        public void AddFilter_Test()
        {
            var tab = new TabClass();

            var filter = new PostFilterRule();
            tab.AddFilter(filter);

            Assert.Equal(new[] { filter }, tab.FilterArray);
            Assert.True(tab.FilterModified);
        }