From 5bd22d86e4d082ddf81130c0d05fd249b9d5007b Mon Sep 17 00:00:00 2001 From: Kimura Youichi Date: Sun, 19 Jan 2020 08:11:54 +0900 Subject: [PATCH] =?utf8?q?pbs.twimg.com=20=E3=81=AE=E7=94=BB=E5=83=8FURL?= =?utf8?q?=E3=81=AE=E3=83=95=E3=82=A9=E3=83=BC=E3=83=9E=E3=83=83=E3=83=88?= =?utf8?q?=E5=A4=89=E6=9B=B4=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit https://developer.twitter.com/en/docs/tweets/data-dictionary/overview/entities-object#photo_format --- .../Thumbnail/Services/PbsTwimgComTest.cs | 126 +++++++++++++++++++++ OpenTween/Resources/ChangeLog.txt | 1 + OpenTween/Thumbnail/Services/PbsTwimgCom.cs | 50 +++++--- 3 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 OpenTween.Tests/Thumbnail/Services/PbsTwimgComTest.cs diff --git a/OpenTween.Tests/Thumbnail/Services/PbsTwimgComTest.cs b/OpenTween.Tests/Thumbnail/Services/PbsTwimgComTest.cs new file mode 100644 index 00000000..2c70e8e5 --- /dev/null +++ b/OpenTween.Tests/Thumbnail/Services/PbsTwimgComTest.cs @@ -0,0 +1,126 @@ +// OpenTween - Client of Twitter +// Copyright (c) 2020 kim_upsilon (@kim_upsilon) +// All rights reserved. +// +// This file is part of OpenTween. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program. If not, see , or write to +// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, +// Boston, MA 02110-1301, USA. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Threading.Tasks; +using OpenTween.Models; +using Xunit; + +namespace OpenTween.Thumbnail.Services +{ + public class PbsTwimgComTest + { + [Fact] + public void ModernUrlPattern_Test() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr?format=jpg&name=large"; + var matches = PbsTwimgCom.ModernUrlPattern.Match(mediaUrl); + + Assert.True(matches.Success); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr", matches.Groups["base_url"].Value); + Assert.Equal("jpg", matches.Groups["format"].Value); + } + + [Fact] + public void ModernUrlPattern_UnorderedTest() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr?name=large&format=jpg"; + var matches = PbsTwimgCom.ModernUrlPattern.Match(mediaUrl); + + Assert.True(matches.Success); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr", matches.Groups["base_url"].Value); + Assert.Equal("jpg", matches.Groups["format"].Value); + } + + [Fact] + public void ModernUrlPattern_LegacyUrlTest() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr.jpg:large"; + var matches = PbsTwimgCom.ModernUrlPattern.Match(mediaUrl); + + Assert.False(matches.Success); + } + + [Fact] + public void LegacyUrlPattern_Test() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr.jpg"; + var matches = PbsTwimgCom.LegacyUrlPattern.Match(mediaUrl); + + Assert.True(matches.Success); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr", matches.Groups["base_url"].Value); + Assert.Equal("jpg", matches.Groups["format"].Value); + } + + [Fact] + public void LegacyUrlPattern_SizeNameTest() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr.jpg:large"; + var matches = PbsTwimgCom.LegacyUrlPattern.Match(mediaUrl); + + Assert.True(matches.Success); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr", matches.Groups["base_url"].Value); + Assert.Equal("jpg", matches.Groups["format"].Value); + } + + [Fact] + public void LegacyUrlPattern_ModernUrlTest() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr?format=jpg&name=large"; + var matches = PbsTwimgCom.LegacyUrlPattern.Match(mediaUrl); + + Assert.False(matches.Success); + } + + [Fact] + public async Task GetThumbnailInfoAsync_ModernUrlTest() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr?format=jpg&name=large"; + + var service = new PbsTwimgCom(); + var thumb = await service.GetThumbnailInfoAsync(mediaUrl, new PostClass(), CancellationToken.None) + .ConfigureAwait(false); + + Assert.NotNull(thumb); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr?format=jpg&name=large", thumb!.ThumbnailImageUrl); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr?format=jpg&name=orig", thumb!.FullSizeImageUrl); + } + + [Fact] + public async Task GetThumbnailInfoAsync_LegacyUrlTest() + { + var mediaUrl = "https://pbs.twimg.com/media/DYlFv51VwAUdqWr.jpg"; + + var service = new PbsTwimgCom(); + var thumb = await service.GetThumbnailInfoAsync(mediaUrl, new PostClass(), CancellationToken.None) + .ConfigureAwait(false); + + Assert.NotNull(thumb); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr?format=jpg&name=large", thumb!.ThumbnailImageUrl); + Assert.Equal("https://pbs.twimg.com/media/DYlFv51VwAUdqWr?format=jpg&name=orig", thumb!.FullSizeImageUrl); + } + } +} diff --git a/OpenTween/Resources/ChangeLog.txt b/OpenTween/Resources/ChangeLog.txt index a8e1e4c4..0865de17 100644 --- a/OpenTween/Resources/ChangeLog.txt +++ b/OpenTween/Resources/ChangeLog.txt @@ -1,6 +1,7 @@ 更新履歴 ==== Ver 2.4.4-dev(2019/xx/xx) + * CHG: pic.twitter.com の画像URLのフォーマット変更に対応 ==== Ver 2.4.3(2019/12/06) * FIX: 関連発言表示のタブを読み込み中に閉じるとエラーが発生する不具合を修正 diff --git a/OpenTween/Thumbnail/Services/PbsTwimgCom.cs b/OpenTween/Thumbnail/Services/PbsTwimgCom.cs index 8e65b07c..b05440e0 100644 --- a/OpenTween/Thumbnail/Services/PbsTwimgCom.cs +++ b/OpenTween/Thumbnail/Services/PbsTwimgCom.cs @@ -32,28 +32,52 @@ using OpenTween.Models; namespace OpenTween.Thumbnail.Services { - class PbsTwimgCom : SimpleThumbnailService + class PbsTwimgCom : IThumbnailService { - public static readonly string UrlPattern = @"^(https?://pbs\.twimg\.com/[^:]+)(?:\:.+)?$"; + public static readonly Regex ModernUrlPattern = + new Regex(@"^(?https?://pbs\.twimg\.com/[^:.]+)\?([^&]+?&)?format=(?[A-Za-z]+)"); - public PbsTwimgCom() - : base(UrlPattern, "${1}", "${1}:orig") - { - } + public static readonly Regex LegacyUrlPattern = + new Regex(@"^(?https?://pbs\.twimg\.com/[^.]+)\.(?[A-Za-z]+)(?:\:.+)?$"); + + public override Task GetThumbnailInfoAsync(string url, PostClass post, CancellationToken token) + => Task.FromResult(this.GetThumbnailInfo(url, post, token)); - public override async Task GetThumbnailInfoAsync(string url, PostClass post, CancellationToken token) + private ThumbnailInfo? GetThumbnailInfo(string url, PostClass post, CancellationToken token) { - var thumb = await base.GetThumbnailInfoAsync(url, post, token) - .ConfigureAwait(false); + string baseUrl; + string format; - if (thumb == null) + // 現状の Twitter API から返る media_url_https は LegacyUrlPettern の形式になっているが、 + // どちらの形式でも動くようにする + if (ModernUrlPattern.Match(url) is { Success: true } matchesModern) + { + baseUrl = matchesModern.Groups["base_url"].Value; + format = matchesModern.Groups["format"].Value; + } + else if (LegacyUrlPattern.Match(url) is { Success: true } matchesLegacy) + { + baseUrl = matchesLegacy.Groups["base_url"].Value; + format = matchesLegacy.Groups["format"].Value; + } + else + { return null; + } + + var mediaOrig = $"{baseUrl}?format={format}&name=orig"; + var mediaLarge = $"{baseUrl}?format={format}&name=large"; var media = post.Media.FirstOrDefault(x => x.Url == url); - if (media != null) + var altText = media?.AltText; + + var thumb = new ThumbnailInfo { - thumb.TooltipText = media.AltText; - } + MediaPageUrl = mediaOrig, + ThumbnailImageUrl = mediaLarge, + TooltipText = altText, + FullSizeImageUrl = mediaOrig, + }; return thumb; } -- 2.11.0