Exemple #1
0
        private async Task SetRecentStatusAsync(TwitterStatus status, CancellationToken cancellationToken)
        {
            if (status != null)
            {
                var entities = status.MergedEntities;

                foreach (var entity in entities.Urls)
                {
                    entity.ExpandedUrl = await ShortUrl.Instance.ExpandUrlAsync(entity.ExpandedUrl);
                }

                var html = TweetFormatter.AutoLinkHtml(status.FullText, entities);
                html = this.mainForm.createDetailHtml(html +
                                                      " Posted at " + MyCommon.DateTimeParse(status.CreatedAt) +
                                                      " via " + status.Source);

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                this.RecentPostBrowser.DocumentText = html;
            }
            else
            {
                this.RecentPostBrowser.DocumentText = Properties.Resources.ShowUserInfo2;
            }
        }
        private async Task SetDescriptionAsync(string?descriptionText, TwitterEntities?entities, CancellationToken cancellationToken)
        {
            if (descriptionText != null)
            {
                var urlEntities = entities?.Urls ?? Array.Empty <TwitterEntityUrl>();

                foreach (var entity in urlEntities)
                {
                    entity.ExpandedUrl = await ShortUrl.Instance.ExpandUrlAsync(entity.ExpandedUrl);
                }

                // user.entities には urls 以外のエンティティが含まれていないため、テキストをもとに生成する
                var mergedEntities = urlEntities.AsEnumerable <TwitterEntity>()
                                     .Concat(TweetExtractor.ExtractHashtagEntities(descriptionText))
                                     .Concat(TweetExtractor.ExtractMentionEntities(descriptionText))
                                     .Concat(TweetExtractor.ExtractEmojiEntities(descriptionText));

                var html = TweetFormatter.AutoLinkHtml(descriptionText, mergedEntities);
                html = this.mainForm.createDetailHtml(html);

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                this.DescriptionBrowser.DocumentText = html;
            }
            else
            {
                this.DescriptionBrowser.DocumentText = "";
            }
        }
Exemple #3
0
        public void CreateRetweetUnofficial_WithFormatterTest()
        {
            // TweetFormatterでHTMLに整形 → CreateRetweetUnofficialで復元 までの動作が正しく行えているか

            var text     = "#てすと @TwitterAPI \n http://t.co/KYi7vMZzRt";
            var entities = new TwitterEntity[]
            {
                new TwitterEntityHashtag
                {
                    Indices = new[] { 0, 4 },
                    Text    = "てすと",
                },
                new TwitterEntityMention
                {
                    Indices    = new[] { 5, 16 },
                    Id         = 6253282L,
                    Name       = "Twitter API",
                    ScreenName = "twitterapi",
                },
                new TwitterEntityUrl
                {
                    Indices     = new[] { 19, 41 },
                    DisplayUrl  = "twitter.com",
                    ExpandedUrl = "http://twitter.com/",
                    Url         = "http://t.co/KYi7vMZzRt",
                },
            };

            var html = TweetFormatter.AutoLinkHtml(text, entities);

            var expected = "#てすと @TwitterAPI " + Environment.NewLine + " http://twitter.com/";

            Assert.Equal(expected, TweenMain.CreateRetweetUnofficial(html, true));
        }
Exemple #4
0
        private async Task SetDescriptionAsync(string descriptionText, TwitterEntities entities, CancellationToken cancellationToken)
        {
            if (descriptionText != null)
            {
                foreach (var entity in entities.Urls)
                {
                    entity.ExpandedUrl = await ShortUrl.Instance.ExpandUrlAsync(entity.ExpandedUrl);
                }

                // user.entities には urls 以外のエンティティが含まれていないため、テキストをもとに生成する
                entities.Hashtags     = TweetExtractor.ExtractHashtagEntities(descriptionText).ToArray();
                entities.UserMentions = TweetExtractor.ExtractMentionEntities(descriptionText).ToArray();

                var html = TweetFormatter.AutoLinkHtml(descriptionText, entities);
                html = this.mainForm.createDetailHtml(html);

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                this.DescriptionBrowser.DocumentText = html;
            }
            else
            {
                this.DescriptionBrowser.DocumentText = "";
            }
        }
        private async Task SetRecentStatusAsync(TwitterStatus?status, CancellationToken cancellationToken)
        {
            if (status != null)
            {
                var entities    = status.MergedEntities;
                var urlEntities = entities.Urls ?? Array.Empty <TwitterEntityUrl>();

                foreach (var entity in urlEntities)
                {
                    entity.ExpandedUrl = await ShortUrl.Instance.ExpandUrlAsync(entity.ExpandedUrl);
                }

                var mergedEntities = entities.Concat(TweetExtractor.ExtractEmojiEntities(status.FullText));

                var html = TweetFormatter.AutoLinkHtml(status.FullText, mergedEntities);
                html = this.mainForm.createDetailHtml(html +
                                                      " Posted at " + MyCommon.DateTimeParse(status.CreatedAt).ToLocalTimeString() +
                                                      " via " + status.Source);

                if (cancellationToken.IsCancellationRequested)
                {
                    return;
                }

                this.RecentPostBrowser.DocumentText = html;
            }
            else
            {
                this.RecentPostBrowser.DocumentText = Properties.Resources.ShowUserInfo2;
            }
        }
        public void AutoLinkHtml_EntityNullTest3()
        {
            var text = "てすとてすとー";
            IEnumerable <TwitterEntity>?entities = null;

            var expected = "てすとてすとー";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_BreakLineTest()
        {
            var             text     = "てすと\nてすと\nてすと";
            TwitterEntities?entities = null;

            var expected = "てすと<br>てすと<br>てすと";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_WhitespaceTest()
        {
            // 連続する半角スペースを表示するため 1 文字おきに &nbsp; に変換する
            var text = "a a  a   a    a";

            var expected = "a a &nbsp;a &nbsp; a &nbsp; &nbsp;a";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities: null));
        }
        public void AutoLinkHtml_EntityNullTest2()
        {
            var text     = "てすとてすとー";
            var entities = new TwitterEntities
            {
                Urls         = null,
                Hashtags     = null,
                UserMentions = null,
                Media        = null,
            };

            var expected = "てすとてすとー";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void FormatHashtagEntity_Test()
        {
            var text     = "#OpenTween";
            var entities = new[]
            {
                new TwitterEntityHashtag
                {
                    Indices = new[] { 0, 10 },
                    Text    = "OpenTween",
                },
            };

            var expected = "<a class=\"hashtag\" href=\"https://twitter.com/search?q=%23OpenTween\">#OpenTween</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_OverlappedEntitiesTest()
        {
            // extended_entities で追加される、区間が重複したエンティティを考慮
            // 参照: https://dev.twitter.com/docs/api/multiple-media-extended-entities

            var text     = "\"I hope you'll keep...building bonds of friendship that will enrich your lives &amp; enrich our world\" \u2014FLOTUS in China, http://t.co/fxmuQN9JL9";
            var entities = new[]
            {
                new TwitterEntityMedia
                {
                    DisplayUrl    = "pic.twitter.com/fxmuQN9JL9",
                    ExpandedUrl   = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
                    Indices       = new[] { 121, 143 },
                    MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EH6yIQAEYvxu.jpg",
                    Url           = "http://t.co/fxmuQN9JL9",
                },
                new TwitterEntityMedia
                {
                    DisplayUrl    = "pic.twitter.com/fxmuQN9JL9",
                    ExpandedUrl   = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
                    Indices       = new[] { 121, 143 },
                    MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EHxAIIAE8dtg.jpg",
                    Url           = "http://t.co/fxmuQN9JL9",
                },
                new TwitterEntityMedia
                {
                    DisplayUrl    = "pic.twitter.com/fxmuQN9JL9",
                    ExpandedUrl   = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
                    Indices       = new[] { 121, 143 },
                    MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EH3pIYAE4LQn.jpg",
                    Url           = "http://t.co/fxmuQN9JL9",
                },
                new TwitterEntityMedia
                {
                    DisplayUrl    = "pic.twitter.com/fxmuQN9JL9",
                    ExpandedUrl   = "http://twitter.com/FLOTUS/status/449660889793581056/photo/1",
                    Indices       = new[] { 121, 143 },
                    MediaUrlHttps = "https://pbs.twimg.com/media/Bj2EL3DIEAAzGAX.jpg",
                    Url           = "http://t.co/fxmuQN9JL9",
                },
            };

            var expected = "&quot;I hope you&#39;ll keep...building bonds of friendship that will enrich your lives &amp; enrich our world&quot; \u2014FLOTUS in China, " +
                           "<a href=\"http://t.co/fxmuQN9JL9\" title=\"http://twitter.com/FLOTUS/status/449660889793581056/photo/1\">pic.twitter.com/fxmuQN9JL9</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_EscapeUrlTest()
        {
            // 日本語ハッシュタグのリンク先URLを適切にエスケープする
            var text     = "#ぜんぶ雪のせいだ";
            var entities = new[]
            {
                new TwitterEntityHashtag
                {
                    Indices = new[] { 0, 9 },
                    Text    = "ぜんぶ雪のせいだ",
                },
            };

            var expected = "<a class=\"hashtag\" href=\"https://twitter.com/search?q=%23%E3%81%9C%E3%82%93%E3%81%B6%E9%9B%AA%E3%81%AE%E3%81%9B%E3%81%84%E3%81%A0\">#ぜんぶ雪のせいだ</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void FormatEmojiEntity_Test()
        {
            var text     = "🍣";
            var entities = new[]
            {
                new TwitterEntityEmoji
                {
                    Indices = new[] { 0, 1 },
                    Text    = "🍣",
                    Url     = "https://twemoji.maxcdn.com/2/72x72/1f363.png",
                },
            };

            var expected = "<img class=\"emoji\" src=\"https://twemoji.maxcdn.com/2/72x72/1f363.png\" alt=\"🍣\" />";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void FormatUrlEntity_Test()
        {
            var text     = "http://t.co/6IwepKCM0P";
            var entities = new[]
            {
                new TwitterEntityUrl
                {
                    Indices     = new[] { 0, 22 },
                    DisplayUrl  = "example.com",
                    ExpandedUrl = "http://example.com/",
                    Url         = "http://t.co/6IwepKCM0P",
                },
            };

            var expected = "<a href=\"http://t.co/6IwepKCM0P\" title=\"http://example.com/\">example.com</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void FormatEmojiEntity_EmptyUrlTest()
        {
            // 余分な U+FE0F があった場合に Url が空の絵文字エンティティが渡される
            var text     = "\uFE0F";
            var entities = new[]
            {
                new TwitterEntityEmoji
                {
                    Indices = new[] { 0, 1 },
                    Text    = "",
                    Url     = "",
                },
            };

            var expected = "";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_CombiningCharacterSequenceTest()
        {
            // 結合文字列 é ( e + \u0301 ) を含むツイート
            // 参照: https://dev.twitter.com/issues/251
            var text     = "Cafe\u0301 #test";
            var entities = new[]
            {
                new TwitterEntityHashtag
                {
                    Indices = new[] { 6, 11 },
                    Text    = "test",
                },
            };

            var expected = "Cafe\u0301 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23test\">#test</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_CompositeCharacterTest()
        {
            // 合成文字 é ( \u00e9 ) を含むツイート
            // 参照: https://dev.twitter.com/issues/251
            var text     = "Caf\u00e9 #test";
            var entities = new[]
            {
                new TwitterEntityHashtag
                {
                    Indices = new[] { 5, 10 },
                    Text    = "test",
                },
            };

            var expected = "Caf\u00e9 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23test\">#test</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void FormatMentionEntity_Test()
        {
            var text     = "@TwitterAPI";
            var entities = new[]
            {
                new TwitterEntityMention
                {
                    Indices    = new[] { 0, 11 },
                    Id         = 6253282L,
                    Name       = "Twitter API",
                    ScreenName = "twitterapi",
                },
            };

            var expected = "<a class=\"mention\" href=\"https://twitter.com/twitterapi\">@TwitterAPI</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void FormatUrlEntity_TwitterComTest()
        {
            var text     = "https://t.co/0Ko1I27m0a";
            var entities = new[]
            {
                new TwitterEntityUrl
                {
                    Indices     = new[] { 0, 23 },
                    DisplayUrl  = "twitter.com/twitterapi",
                    ExpandedUrl = "https://twitter.com/twitterapi",
                    Url         = "https://t.co/0Ko1I27m0a",
                },
            };

            // twitter.com 宛のリンクは t.co を経由せずにリンクする
            var expected = "<a href=\"https://twitter.com/twitterapi\" title=\"https://twitter.com/twitterapi\">twitter.com/twitterapi</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_EscapeTest()
        {
            // Twitter APIの中途半端なエスケープの対象とならない「"」や「'」に対するエスケープ処理を施す
            var text     = "\"\'@twitterapi\'\"";
            var entities = new[]
            {
                new TwitterEntityMention
                {
                    Indices    = new[] { 2, 13 },
                    Id         = 6253282L,
                    Name       = "Twitter API",
                    ScreenName = "twitterapi",
                },
            };

            var expected = "&quot;&#39;<a class=\"mention\" href=\"https://twitter.com/twitterapi\">@twitterapi</a>&#39;&quot;";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_EscapeTest2()
        {
            // 「<」や「>」についてはエスケープされた状態でAPIからテキストが返されるため、二重エスケープとならないように考慮する
            var text     = "&lt;b&gt; @twitterapi &lt;/b&gt;";
            var entities = new[]
            {
                new TwitterEntityMention
                {
                    Indices    = new[] { 10, 21 },
                    Id         = 6253282L,
                    Name       = "Twitter API",
                    ScreenName = "twitterapi",
                },
            };

            var expected = "&lt;b&gt; <a class=\"mention\" href=\"https://twitter.com/twitterapi\">@twitterapi</a> &lt;/b&gt;";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_EscapeTest3()
        {
            // 万が一「<」や「>」がエスケープされていない状態のテキストを受け取っても適切にエスケープが施されるようにする
            var text     = "<b> @twitterapi </b>";
            var entities = new[]
            {
                new TwitterEntityMention
                {
                    Indices    = new[] { 4, 15 },
                    Id         = 6253282L,
                    Name       = "Twitter API",
                    ScreenName = "twitterapi",
                },
            };

            var expected = "&lt;b&gt; <a class=\"mention\" href=\"https://twitter.com/twitterapi\">@twitterapi</a> &lt;/b&gt;";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_SurrogatePairTest()
        {
            // UTF-16 で 4 バイトで表される文字を含むツイート
            // 参照: https://sourceforge.jp/ticket/browse.php?group_id=6526&tid=33079
            var text     = "🐬🐬 @irucame 🐬🐬";
            var entities = new[]
            {
                new TwitterEntityMention
                {
                    Indices    = new[] { 3, 11 },
                    Id         = 89942943L,
                    ScreenName = "irucame",
                },
            };

            var expected = "🐬🐬 <a class=\"mention\" href=\"https://twitter.com/irucame\">@irucame</a> 🐬🐬";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void FormatMediaEntity_AltTextTest()
        {
            var text     = "http://t.co/h5dCr4ftN4";
            var entities = new[]
            {
                new TwitterEntityMedia
                {
                    Indices = new[] { 0, 22 },
                    Sizes   = new TwitterMediaSizes
                    {
                        Large = new TwitterMediaSizes.Size {
                            Resize = "fit", Height = 329, Width = 1024
                        },
                        Medium = new TwitterMediaSizes.Size {
                            Resize = "fit", Height = 204, Width = 600
                        },
                        Small = new TwitterMediaSizes.Size {
                            Resize = "fit", Height = 116, Width = 340
                        },
                        Thumb = new TwitterMediaSizes.Size {
                            Resize = "crop", Height = 150, Width = 150
                        },
                    },
                    Type          = "photo",
                    Id            = 426404550379986940L,
                    MediaUrl      = "http://pbs.twimg.com/media/BerkrewCYAAV4Kf.png",
                    MediaUrlHttps = "https://pbs.twimg.com/media/BerkrewCYAAV4Kf.png",
                    Url           = "http://t.co/h5dCr4ftN4",
                    DisplayUrl    = "pic.twitter.com/h5dCr4ftN4",
                    ExpandedUrl   = "http://twitter.com/kim_upsilon/status/426404550371598337/photo/1",
                    AltText       = "ATOKの推測変換候補のスクリーンショット",
                },
            };

            var expected = "<a href=\"http://t.co/h5dCr4ftN4\" title=\"ATOKの推測変換候補のスクリーンショット\">pic.twitter.com/h5dCr4ftN4</a>";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }
        public void AutoLinkHtml_SurrogatePairTest2()
        {
            // 現時点では存在しないものの、ハッシュタグなどエンティティ内にサロゲートペアが含まれる場合も考慮する
            var text     = "🐬🐬 #🐬🐬 🐬🐬 #🐬🐬 🐬🐬";
            var entities = new[]
            {
                new TwitterEntityHashtag
                {
                    Indices = new[] { 3, 6 },
                    Text    = "🐬🐬",
                },
                new TwitterEntityHashtag
                {
                    Indices = new[] { 10, 13 },
                    Text    = "🐬🐬",
                },
            };

            var expected = "🐬🐬 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23%F0%9F%90%AC%F0%9F%90%AC\">#🐬🐬</a> " +
                           "🐬🐬 <a class=\"hashtag\" href=\"https://twitter.com/search?q=%23%F0%9F%90%AC%F0%9F%90%AC\">#🐬🐬</a> 🐬🐬";

            Assert.Equal(expected, TweetFormatter.AutoLinkHtml(text, entities));
        }