1 ' Tween - Client of Twitter
2 ' Copyright (c) 2007-2010 kiri_feather (@kiri_feather) <kiri_feather@gmail.com>
3 ' (c) 2008-2010 Moz (@syo68k) <http://iddy.jp/profile/moz/>
4 ' (c) 2008-2010 takeshik (@takeshik) <http://www.takeshik.org/>
7 ' This file is part of Tween.
9 ' This program is free software; you can redistribute it and/or modify it
10 ' under the terms of the GNU General Public License as published by the Free
11 ' Software Foundation; either version 3 of the License, or (at your option)
14 ' This program is distributed in the hope that it will be useful, but
15 ' WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 ' or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 ' You should have received a copy of the GNU General Public License along
20 ' with this program. If not, see <http://www.gnu.org/licenses/>, or write to
21 ' the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
22 ' Boston, MA 02110-1301, USA.
27 Imports System.Threading
29 Imports System.Text.RegularExpressions
30 Imports System.Globalization
31 Imports System.Diagnostics
35 Delegate Sub GetIconImageDelegate(ByVal post As PostClass)
36 'Delegate Function GetTimelineDelegate(ByVal page As Integer, _
37 ' ByVal read As Boolean, _
38 ' ByRef endPage As Integer, _
39 ' ByVal gType As WORKERTYPE, _
40 ' ByRef getDM As Boolean) As String
41 'Delegate Function GetDirectMessageDelegate(ByVal page As Integer, _
42 ' ByVal read As Boolean, _
43 ' ByVal endPage As Integer, _
44 ' ByVal gType As WORKERTYPE) As String
45 Private ReadOnly LockObj As New Object
46 'Private GetTmSemaphore As New Threading.Semaphore(8, 8)
48 'Private follower As New List(Of String)
49 Private followerId As New List(Of Long)
50 'Private tmpFollower As New List(Of String)
52 Private _followersCount As Integer = 0
53 Private _friendsCount As Integer = 0
54 Private _statusesCount As Integer = 0
55 Private _location As String = ""
56 Private _bio As String = ""
57 'Private _useSsl As Boolean = True
58 Private _protocol As String = "https://"
59 Private _bitlyId As String = ""
60 Private _bitlyKey As String = ""
63 Private _uid As String
64 'Private _pwd As String
65 'Private _proxyType As ProxyType
66 'Private _proxyAddress As String
67 'Private _proxyPort As Integer
68 'Private _proxyUser As String
69 'Private _proxyPassword As String
71 'Private _nextThreshold As Integer
72 'Private _nextPages As Integer
74 Private _iconSz As Integer
75 Private _getIcon As Boolean
76 Private _lIcon As ImageList
77 Private _dIcon As Dictionary(Of String, Image)
79 Private _tinyUrlResolve As Boolean
80 Private _restrictFavCheck As Boolean
81 'Private _useAPI As Boolean
83 Private _hubServer As String
84 'Private _defaultTimeOut As Integer ' MySocketクラスへ渡すタイムアウト待ち時間(秒単位 ミリ秒への換算はMySocketクラス側で行う)
85 Private _countApi As Integer
86 Private _countApiReply As Integer
87 'Private _usePostMethod As Boolean
88 'Private _ApiMethod As MySocket.REQ_TYPE
89 Private _readOwnPost As Boolean
90 Private _hashList As New List(Of String)
93 'Private _authKey As String 'StatusUpdate、発言削除で使用
94 'Private _authKeyDM As String 'DM送信、DM削除で使用
95 Private _infoTwitter As String = ""
96 'Private _dmCount As Integer
97 'Private _getDm As Boolean
98 Private _remainCountApi As Integer = -1
100 Private _ShortUrlService() As String = { _
101 "http://tinyurl.com/", _
103 "http://snipurl.com/", _
104 "http://snurl.com/", _
106 "http://qurlyq.com/", _
107 "http://dwarfurl.com/", _
108 "http://icanhaz.com/", _
110 "http://urlenco.de/", _
112 "http://piurl.com/", _
113 "http://linkbee.com/", _
114 "http://traceurl.com/", _
115 "http://twurl.nl/", _
117 "http://rubyurl.com/", _
118 "http://budurl.com/", _
120 "http://twitthis.com/", _
122 "http://tumblr.com/", _
123 "http://www.qurl.com/", _
124 "http://digg.com/", _
126 "http://ustre.am/", _
128 "http://airme.us/", _
129 "http://qurl.com/", _
130 "http://bctiny.com/", _
134 "http://bkite.com/", _
135 "http://youtu.be/", _
140 Private Const _apiHost As String = "api."
141 Private Const _baseUrlStr As String = "twitter.com"
142 'Private Const _loginPath As String = "/sessions"
143 'Private Const _homePath As String = "/home"
144 'Private Const _replyPath As String = "/replies"
145 'Private Const _DMPathRcv As String = "/inbox"
146 'Private Const _DMPathSnt As String = "/sent"
147 Private Const _DMDestroyPath As String = "/1/direct_messages/destroy/"
148 Private Const _StDestroyPath As String = "/1/statuses/destroy/"
149 Private Const _postRetweetPath As String = "/1/statuses/retweet/"
150 Private Const _uidHeader As String = "session[username_or_email]="
151 Private Const _pwdHeader As String = "session[password]="
152 Private Const _pageQry As String = "?page="
153 Private Const _cursorQry As String = "?cursor="
154 Private Const _statusHeader As String = "status="
155 Private Const _statusUpdatePathAPI As String = "/1/statuses/update.xml"
156 'Private Const _linkToOld As String = "class=""section_links"" rel=""prev"""
157 Private Const _postFavAddPath As String = "/1/favorites/create/"
158 Private Const _postFavRemovePath As String = "/1/favorites/destroy/"
159 'Private Const _authKeyHeader As String = "authenticity_token="
160 'Private Const _parseLink1 As String = "<a href="""
161 'Private Const _parseLink2 As String = """>"
162 'Private Const _parseLink3 As String = "</a>"
163 Private Const _GetFollowers As String = "/1/statuses/followers.xml"
164 Private Const _ShowStatus As String = "/1/statuses/show/"
165 Private Const _rateLimitStatus As String = "/1/account/rate_limit_status.xml"
166 Private Const FOLLOWER_PATH As String = "/1/followers/ids.xml"
167 Private Const RECEIVE_PATH As String = "/1/direct_messages.xml"
168 Private Const SENT_PATH As String = "/1/direct_messages/sent.xml"
169 Private Const COUNT_QUERY As String = "count="
170 Private Const FAV_PATH As String = "/1/favorites.xml"
171 Private Const PATH_FRIENDSHIP As String = "/1/friendships/show.xml?source_screen_name="
172 Private Const QUERY_TARGET As String = "&target_screen_name="
173 Private Const FRIEND_PATH As String = "/1/statuses/home_timeline.xml"
174 Private Const REPLY_PATH As String = "/1/statuses/mentions.xml"
175 Private Const PATH_FOLLOW As String = "/1/friendships/create.xml?screen_name="
176 Private Const PATH_REMOVE As String = "/1/friendships/destroy.xml?screen_name="
181 '''OAuthのアクセストークン取得先URI
183 Private Const AccessTokenUrl As String = "http://twitter.com/oauth/access_token"
186 '''OAuthのリクエストトークン取得先URI
188 Private Const RequestTokenUrl As String = "http://twitter.com/oauth/request_token"
191 '''OAuthのユーザー認証用ページURI
194 '''クエリ「oauth_token=リクエストトークン」を付加して、このURIをブラウザで開く。ユーザーが承認操作を行うとPINコードが表示される。
196 Private Const AuthorizeUrl As String = "http://twitter.com/oauth/authorize"
199 'Private Const wedataUrl As String = "http://wedata.net/databases/Tween/items.json"
201 Private op As New Outputz
202 'max_idで古い発言を取得するために保持(lists分は個別タブで管理)
203 Private minHomeTimeline As Long = Long.MaxValue
204 Private minMentions As Long = Long.MaxValue
205 Private minDirectmessage As Long = Long.MaxValue
206 Private minDirectmessageSent As Long = Long.MaxValue
207 Private minFavorites As Long = Long.MaxValue
209 Private twCon As New HttpTwitter
211 Public Function Authenticate(ByVal username As String, ByVal password As String) As Boolean
212 Dim rslt As Boolean = twCon.AuthUserAndPass(username, password)
214 _uid = twCon.AuthenticatedUsername.ToLower
219 Public Sub ClearAuthInfo()
220 twCon.ClearAuthInfo()
223 Public Sub Initialize(ByVal token As String, ByVal tokenSecret As String, ByVal username As String)
225 twCon.Initialize(token, tokenSecret, username)
226 _uid = username.ToLower
229 Public Sub Initialize(ByVal username As String, ByVal password As String)
231 twCon.Initialize(username, password)
232 _uid = username.ToLower
235 'Private Function SignIn() As String
236 ' If _endingFlag Then Return ""
239 ' Dim account As String = ""
240 ' Static skipCount As Integer = 0
243 ' If _signed Then Return ""
244 ' If Twitter.AccountState <> ACCOUNT_STATE.Valid AndAlso skipCount < 10 Then
246 ' Return "SignIn -> Check Username/Password in setting."
253 ' MySocket.ResetCookie()
255 ' Dim resStatus As String = ""
256 ' Dim resMsg As String = ""
258 ' '設定によらずログイン処理はhttps固定
259 ' resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + "/login", resStatus, MySocket.REQ_TYPE.ReqGET), String)
260 ' If resMsg.Length = 0 Then
261 ' 'Twitter.AccountState = ACCOUNT_STATE.Invalid
262 ' Return "SignIn -> " + resStatus
264 ' Dim authToken As String = ""
265 ' Dim rg As New Regex("authenticity_token"" type=""hidden"" value=""(?<auth>[a-z0-9]+)""")
266 ' Dim m As Match = rg.Match(resMsg)
268 ' authToken = m.Result("${auth}")
270 ' Return "SignIn -> Can't get token."
273 ' account = _authKeyHeader + authToken + "&" + _uidHeader + _uid + "&" + _pwdHeader + HttpUtility.UrlEncode(_pwd) + "&" + "remember_me=1"
276 ' resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + _loginPath, resStatus, MySocket.REQ_TYPE.ReqPOST, account), String)
277 ' If resStatus.StartsWith("OK") Then
278 ' 'OK (username/passwordが合致しない)
279 ' Dim msg As String = resStatus
280 ' If resMsg.Contains("Wrong Username/Email and password combination.") Then
281 ' msg = "Wrong Username or password."
283 ' '未知の応答(May be required Chapta)
284 ' msg = "Wrong Username or password. Try from web."
286 ' Twitter.AccountState = ACCOUNT_STATE.Invalid
287 ' Return "SignIn Failed -> " + msg
288 ' ElseIf resMsg.Contains("https://twitter.com/account/locked") Then '302 FOUND
289 ' Dim msg As String = "You account is Locked Out."
290 ' Twitter.AccountState = ACCOUNT_STATE.Invalid
291 ' Return "SignIn Failed -> " + msg
292 ' ElseIf resMsg.Contains("https://twitter.com:443/") Then '302 FOUND
294 ' ElseIf resMsg.Contains("https://twitter.com/") OrElse _
295 ' resMsg.Contains("http://twitter.com/") Then '302 FOUND
297 ' ElseIf resStatus.StartsWith("Err:") Then
299 ' Return "SignIn Failed"
301 ' '応答がOK でありサインインできていない場合の未知の応答
302 ' 'TraceOut(True, "SignIn Failed." + vbCrLf + "resStatus:" + resStatus + vbCrLf + "resMsg:" + vbCrLf + resMsg)
303 ' Twitter.AccountState = ACCOUNT_STATE.Invalid
304 ' Return "SignIn Failed -> " + "Unknown problems."
306 ' Twitter.AccountState = ACCOUNT_STATE.Valid
312 'Public Function GetTimeline(ByVal page As Integer, _
313 ' ByVal read As Boolean, _
314 ' ByRef endPage As Integer, _
315 ' ByVal gType As WORKERTYPE, _
316 ' ByRef getDM As Boolean) As String
318 ' If endPage = 0 Then
320 ' Dim epage As Integer = page
321 ' GetTmSemaphore.WaitOne()
322 ' Dim trslt As String = ""
323 ' trslt = GetTimelineThread(page, read, epage, gType, getDM)
324 ' If trslt.Length > 0 Then Return trslt
326 ' If epage < page OrElse gType = WORKERTYPE.Reply Then Return ""
329 ' '起動時モード or 通常モードの読み込み継続 -> 複数ページ同時取得
330 ' Dim num As Integer = endPage - page
331 ' Dim ar(num) As IAsyncResult
332 ' Dim dlgt(num) As GetTimelineDelegate
334 ' For idx As Integer = 0 To num
335 ' dlgt(idx) = New GetTimelineDelegate(AddressOf GetTimelineThread)
336 ' GetTmSemaphore.WaitOne()
337 ' ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, getDM, Nothing, Nothing)
339 ' Dim rslt As String = ""
340 ' For idx As Integer = 0 To num
341 ' Dim epage As Integer = 0
342 ' Dim dm As Boolean = False
343 ' Dim trslt As String = ""
345 ' trslt = dlgt(idx).EndInvoke(epage, dm, ar(idx))
346 ' Catch ex As Exception
347 ' '最後までendinvoke回す(ゾンビ化回避)
348 ' ex.Data("IsTerminatePermission") = False
350 ' rslt = "GetTimelineErr"
352 ' If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
353 ' If dm Then getDM = True
358 ' Private Function GetTimelineThread(ByVal page As Integer, _
359 ' ByVal read As Boolean, _
360 ' ByRef endPage As Integer, _
361 ' ByVal gType As WORKERTYPE, _
362 ' ByRef getDM As Boolean) As String
364 ' If _endingFlag Then Return ""
366 ' Dim retMsg As String = ""
367 ' Dim resStatus As String = ""
369 ' Static redirectToTimeline As String = ""
370 ' Static redirectToReply As String = ""
372 ' If _signed = False Then
374 ' If retMsg.Length > 0 Then
379 ' If _endingFlag Then Return ""
382 ' Dim pageQuery As String
387 ' pageQuery = _pageQry + page.ToString
390 ' If gType = WORKERTYPE.Timeline Then
391 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _homePath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
393 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _replyPath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
396 ' If retMsg.Length = 0 Then
401 ' ' tr 要素の class 属性を消去
402 ' retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
405 ' ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
406 ' ' If idx = -1 Then Exit Do
407 ' ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
408 ' ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
409 ' ' Catch ex As Exception
411 ' ' TraceOut("TM-Remove: " + retMsg)
412 ' ' Return "GetTimeline -> Err: Can't parse data."
416 ' If _endingFlag Then Return ""
419 ' Dim strSepTmp As String
420 ' If gType = WORKERTYPE.Timeline Then
421 ' strSepTmp = _splitPostRecent
423 ' strSepTmp = _splitPost
426 ' Dim pos1 As Integer
427 ' Dim pos2 As Integer
429 ' pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
433 ' Return "GetTimeline -> Err: tweets count is 0."
436 ' Dim strSep() As String = {strSepTmp}
437 ' Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
438 ' Dim intCnt As Integer = 0
439 ' Dim listCnt As Integer = 0
441 ' listCnt = TabInformations.GetInstance.ItemCount
443 ' Dim dlgt(20) As GetIconImageDelegate
444 ' Dim ar(20) As IAsyncResult
445 ' Dim arIdx As Integer = -1
449 ' For Each strPost As String In posts
453 ' If page = 1 And gType = WORKERTYPE.Timeline Then
455 ' 'pos1 = strPost.IndexOf(_getSiv, 0)
457 ' ' pos2 = strPost.IndexOf(_getSivTo, pos1 + _getSiv.Length)
458 ' ' If pos2 > -1 Then
459 ' ' _authSiv = strPost.Substring(pos1 + _getSiv.Length, pos2 - pos1 - _getSiv.Length)
463 ' ' Return "GetTimeline -> Err: Can't get Siv."
468 ' ' Return "GetTimeline -> Err: Can't get Siv."
472 ' If GetAuthKey(retMsg) < 0 Then
474 ' Return "GetTimeline -> Err: Can't get auth token."
478 ' pos1 = retMsg.IndexOf(_getInfoTwitter, StringComparison.Ordinal)
480 ' pos2 = retMsg.IndexOf(_getInfoTwitterTo, pos1, StringComparison.Ordinal)
482 ' _infoTwitter = retMsg.Substring(pos1 + _getInfoTwitter.Length, pos2 - pos1 - _getInfoTwitter.Length)
492 ' Dim post As New PostClass
494 ' pos1 = strPost.IndexOf("</ol>")
496 ' strPost = strPost.Substring(0, pos1)
502 ' pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
503 ' post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
504 ' Catch ex As Exception
506 ' TraceOut("TM-ID:" + strPost)
507 ' Return "GetTimeline -> Err: Can't get ID."
511 ' pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
512 ' pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
513 ' post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
514 ' Catch ex As Exception
516 ' TraceOut("TM-Name:" + strPost)
517 ' Return "GetTimeline -> Err: Can't get Name."
521 ' If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
522 ' post.Nickname = post.Name
525 ' pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
526 ' pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
527 ' post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
528 ' Catch ex As Exception
530 ' TraceOut("TM-Nick:" + strPost)
531 ' Return "GetTimeline -> Err: Can't get Nick."
537 ' If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
540 ' Dim orgData As String = ""
542 ' If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
544 ' pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
545 ' pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
546 ' orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
547 ' Catch ex As Exception
549 ' TraceOut("TM-VBody:" + strPost)
550 ' Return "GetTimeline -> Err: Can't get Valentine body."
557 ' pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
558 ' pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
559 ' post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
560 ' Catch ex As Exception
562 ' TraceOut("TM-Img:" + strPost)
563 ' Return "GetTimeline -> Err: Can't get ImagePath."
567 ' If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
568 ' post.IsProtect = True
572 ' If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
573 ' rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
574 ' m = rg.Match(strPost)
576 ' post.RetweetedBy = m.Result("${name}")
578 ' post.RetweetedBy = ""
580 ' rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
581 ' m = rg.Match(strPost)
583 ' post.RetweetedId = Long.Parse(m.Result("${id}"))
585 ' post.RetweetedId = 0
590 ' pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
594 ' If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
596 ' orgData += " <3 you! Do you <3 "
597 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
598 ' pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
599 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
601 ' pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
604 ' orgData += " <3 's "
605 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
607 ' pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
608 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
612 ' pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
613 ' orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
616 ' Catch ex As Exception
618 ' TraceOut("TM-VBody2:" + strPost)
619 ' Return "GetTimeline -> Err: Can't get Valentine body2."
624 ' pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
625 ' orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
626 ' Catch ex As Exception
628 ' TraceOut("TM-Body:" + strPost)
629 ' Return "GetTimeline -> Err: Can't get body."
633 ' ' orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
636 ' orgData = orgData.Replace("<3", "♡")
640 ' orgData = PreProcessUrl(orgData)
642 ' '短縮URL解決処理(orgData書き換え)
643 ' orgData = ShortUrlResolve(orgData)
646 ' post.OriginalData = AdjustHtml(orgData)
648 ' '単純テキストの取り出し(リンクタグ除去)
650 ' post.Data = GetPlainText(orgData)
651 ' Catch ex As Exception
653 ' TraceOut("TM-Link:" + strPost)
654 ' Return "GetTimeline -> Err: Can't parse links."
658 ' Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
659 ' If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
664 ' pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
666 ' pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
667 ' post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
671 ' Catch ex As Exception
673 ' TraceOut("TM-Date:" + strPost)
674 ' Return "GetTimeline -> Err: Can't get date."
677 ' '取得できなくなったため暫定対応(2/26)
683 ' 'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
684 ' rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
685 ' m = rg.Match(strPost)
687 ' post.Source = m.Result("${name}")
689 ' post.Source = "Web"
692 ' ' pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
693 ' ' If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
694 ' ' If pos1 > -1 Then
695 ' ' pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
696 ' ' pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
697 ' ' post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
699 ' ' post.Source = "Web"
701 ' 'Catch ex As Exception
703 ' ' TraceOut("TM-Src:" + strPost)
704 ' ' Return "GetTimeline -> Err: Can't get src."
707 ' 'Get Reply(in_reply_to_user/id)
708 ' 'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
709 ' rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
710 ' m = rg.Match(strPost)
712 ' post.InReplyToUser = m.Result("${name}")
713 ' post.InReplyToId = Long.Parse(m.Result("${id}"))
714 ' post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
718 ' rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
719 ' m = rg.Match(orgData)
721 ' post.ReplyToList.Add(m.Groups(1).Value.ToLower())
724 ' If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
726 ' If gType = WORKERTYPE.Reply Then post.IsReply = True
729 ' If strPost.IndexOf("class=""fav-action fav""") > -1 Then
734 ' 'pos1 = strPost.IndexOf(_parseStar, pos2, StringComparison.Ordinal)
737 ' ' pos2 = strPost.IndexOf(_parseStarTo, pos1 + _parseStar.Length, StringComparison.Ordinal)
738 ' ' If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = _parseStarEmpty Then
739 ' ' post.IsFav = False
741 ' ' post.IsFav = True
743 ' ' Catch ex As Exception
745 ' ' TraceOut("TM-Fav:" + strPost)
746 ' ' Return "GetTimeline -> Err: Can't get fav status."
749 ' ' post.IsFav = False
752 ' If _endingFlag Then Return ""
754 ' post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
756 ' If follower.Count > 1 Then
757 ' post.IsOwl = Not follower.Contains(post.Name.ToLower())
763 ' If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
766 ' dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
767 ' ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
772 ' If intCnt = posts.Length AndAlso gType = WORKERTYPE.Timeline AndAlso page = 1 Then
773 ' pos1 = strPost.IndexOf(_parseDMcountFrom, pos2, StringComparison.Ordinal)
776 ' pos2 = strPost.IndexOf(_parseDMcountTo, pos1 + _parseDMcountFrom.Length, StringComparison.Ordinal)
777 ' Dim dmCnt As Integer = Integer.Parse(strPost.Substring(pos1 + _parseDMcountFrom.Length, pos2 - pos1 - _parseDMcountFrom.Length))
778 ' If dmCnt > _dmCount Then
782 ' Catch ex As Exception
783 ' Return "GetTimeline -> Err: Can't get DM count."
790 ' For i As Integer = 0 To arIdx
792 ' dlgt(i).EndInvoke(ar(i))
793 ' Catch ex As Exception
794 ' '最後までendinvoke回す(ゾンビ化回避)
795 ' ex.Data("IsTerminatePermission") = False
801 ' If page = 1 AndAlso (TabInformations.GetInstance.ItemCount - listCnt) >= _nextThreshold Then
802 ' '新着が閾値の件数以上なら、次のページも念のため読み込み
803 ' endPage = _nextPages + 1
809 ' GetTmSemaphore.Release()
813 ' Public Function GetDirectMessage(ByVal page As Integer, _
814 ' ByVal read As Boolean, _
815 ' ByVal endPage As Integer, _
816 ' ByVal gType As WORKERTYPE) As String
818 ' If endPage = 0 Then
823 ' Dim num As Integer = endPage - page
824 ' Dim ar(num) As IAsyncResult
825 ' Dim dlgt(num) As GetDirectMessageDelegate
827 ' For idx As Integer = 0 To num
828 ' gType = WORKERTYPE.DirectMessegeRcv
829 ' dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
830 ' GetTmSemaphore.WaitOne()
831 ' ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
833 ' Dim rslt As String = ""
834 ' For idx As Integer = 0 To num
835 ' Dim trslt As String = ""
837 ' trslt = dlgt(idx).EndInvoke(ar(idx))
838 ' Catch ex As Exception
839 ' '最後までendinvoke回す(ゾンビ化回避)
840 ' ex.Data("IsTerminatePermission") = False
842 ' rslt = "GetDirectMessageErr"
844 ' If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
846 ' For idx As Integer = 0 To num
847 ' gType = WORKERTYPE.DirectMessegeSnt
848 ' dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
849 ' GetTmSemaphore.WaitOne()
850 ' ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
852 ' For idx As Integer = 0 To num
853 ' Dim trslt As String = ""
855 ' trslt = dlgt(idx).EndInvoke(ar(idx))
856 ' Catch ex As Exception
857 ' '最後までendinvoke回す(ゾンビ化回避)
858 ' ex.Data("IsTerminatePermission") = False
860 ' rslt = "GetDirectMessageErr"
862 ' If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
867 ' Private Function GetDirectMessageThread(ByVal page As Integer, _
868 ' ByVal read As Boolean, _
869 ' ByVal endPage As Integer, _
870 ' ByVal gType As WORKERTYPE) As String
872 ' If _endingFlag Then Return ""
874 ' Dim retMsg As String = ""
875 ' Dim resStatus As String = ""
877 ' Static redirectToDmRcv As String = ""
878 ' Static redirectToDmSnd As String = ""
882 ' If _signed = False Then
884 ' If retMsg.Length > 0 Then
889 ' If _endingFlag Then Return ""
892 ' Dim pageQuery As String = _pageQry + page.ToString
893 ' If gType = WORKERTYPE.DirectMessegeRcv Then
894 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathRcv + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
896 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathSnt + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
899 ' If retMsg.Length = 0 Then
904 ' ' tr 要素の class 属性を消去
905 ' retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
908 ' ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
909 ' ' If idx = -1 Then Exit Do
910 ' ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
911 ' ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
912 ' ' Catch ex As Exception
914 ' ' TraceOut("DM-Remove: " + retMsg)
915 ' ' Return "GetDm -> Err: Can't parse data."
919 ' If _endingFlag Then Return ""
922 ' 'If GetAuthKeyDM(retMsg) < 0 Then
924 ' ' Return "GetDirectMessage -> Err: Busy(1)"
927 ' Dim pos1 As Integer
928 ' Dim pos2 As Integer
931 ' pos1 = retMsg.IndexOf(_splitDM, StringComparison.Ordinal)
933 ' '0件(メッセージなし。エラーの場合もありうるが判別できないので正常として戻す)
937 ' Dim strSep() As String = {_splitDM}
938 ' Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
939 ' Dim intCnt As Integer = 0 'カウンタ
940 ' 'Dim listCnt As Integer = 0
942 ' ' listCnt = TabInformations.GetInstance.ItemCount
944 ' Dim dlgt(20) As GetIconImageDelegate
945 ' Dim ar(20) As IAsyncResult
946 ' Dim arIdx As Integer = -1
948 ' For Each strPost As String In posts
951 ' If intCnt > 1 Then '1件目はヘッダなので無視
952 ' 'Dim lItem As New MyListItem
953 ' Dim post As New PostClass()
955 ' pos1 = strPost.IndexOf("</ol>")
957 ' strPost = strPost.Substring(0, pos1)
963 ' pos2 = strPost.IndexOf("""", 0, StringComparison.Ordinal)
964 ' post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
965 ' Catch ex As Exception
967 ' TraceOut("DM-ID:" + strPost)
968 ' Return "GetDirectMessage -> Err: Can't get ID"
973 ' pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
974 ' pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
975 ' post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
976 ' Catch ex As Exception
978 ' TraceOut("DM-Name:" + strPost)
979 ' Return "GetDirectMessage -> Err: Can't get Name"
984 ' pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
985 ' pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
986 ' post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
987 ' Catch ex As Exception
989 ' TraceOut("DM-Nick:" + strPost)
990 ' Return "GetDirectMessage -> Err: Can't get Nick."
994 ' If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
999 ' pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
1000 ' pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
1001 ' post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
1002 ' Catch ex As Exception
1004 ' TraceOut("DM-Img:" + strPost)
1005 ' Return "GetDirectMessage -> Err: Can't get ImagePath"
1010 ' pos1 = strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal)
1011 ' If pos1 > -1 Then post.IsProtect = True
1012 ' Catch ex As Exception
1014 ' TraceOut("DM-Protect:" + strPost)
1015 ' Return "GetDirectMessage -> Err: Can't get Protect"
1018 ' Dim orgData As String = ""
1022 ' pos1 = strPost.IndexOf(_parseDM1, pos2, StringComparison.Ordinal)
1024 ' pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
1025 ' orgData = strPost.Substring(pos1 + _parseDM1.Length, pos2 - pos1 - _parseDM1.Length).Trim()
1027 ' pos1 = strPost.IndexOf(_parseDM11, pos2, StringComparison.Ordinal)
1028 ' pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
1029 ' orgData = strPost.Substring(pos1 + _parseDM11.Length, pos2 - pos1 - _parseDM11.Length).Trim()
1031 ' 'orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1032 ' orgData = orgData.Replace("<3", "♡")
1033 ' Catch ex As Exception
1035 ' TraceOut("DM-Body:" + strPost)
1036 ' Return "GetDirectMessage -> Err: Can't get body"
1039 ' 'URL前処理(IDNデコードなど)
1040 ' orgData = PreProcessUrl(orgData)
1042 ' '短縮URL解決処理(orgData書き換え)
1043 ' orgData = ShortUrlResolve(orgData)
1046 ' post.OriginalData = AdjustHtml(orgData)
1048 ' '単純テキストの取り出し(リンクタグ除去)
1050 ' post.Data = GetPlainText(orgData)
1051 ' Catch ex As Exception
1053 ' TraceOut("DM-Link:" + strPost)
1054 ' Return "GetDirectMessage -> Err: Can't parse links"
1060 ' pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1062 ' pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1063 ' post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
1065 ' post.PDate = Now()
1067 ' Catch ex As Exception
1069 ' TraceOut("DM-Date:" + strPost)
1070 ' Return "GetDirectMessage -> Err: Can't get date."
1073 ' '取得できなくなったため暫定対応(2/26)
1074 ' post.PDate = Now()
1078 ' 'pos1 = strPost.IndexOf(_parseStar, pos2)
1079 ' 'pos2 = strPost.IndexOf("""", pos1 + _parseStar.Length)
1080 ' 'If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = "empty" Then
1081 ' ' lItem.Fav = False
1083 ' ' lItem.Fav = True
1085 ' post.IsFav = False
1088 ' If _endingFlag Then Return ""
1091 ' If gType = WORKERTYPE.DirectMessegeRcv Then
1092 ' post.IsOwl = False
1097 ' post.IsRead = read
1102 ' dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1103 ' ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1107 ' For i As Integer = 0 To arIdx
1109 ' dlgt(i).EndInvoke(ar(i))
1110 ' Catch ex As Exception
1111 ' ex.Data("IsTerminatePermission") = False
1119 ' GetTmSemaphore.Release()
1123 ' Public Function GetFavorites(ByVal page As Integer, _
1124 ' ByVal read As Boolean, _
1125 ' ByRef endPage As Integer, _
1126 ' ByVal gType As WORKERTYPE, _
1127 ' ByRef getDM As Boolean) As String
1129 ' GetTmSemaphore.WaitOne()
1131 ' If _endingFlag Then Return ""
1133 ' Dim retMsg As String = ""
1134 ' Dim resStatus As String = ""
1136 ' Static redirectToFav As String = ""
1137 ' Const FAV_PATH As String = "/favorites"
1139 ' If _signed = False Then
1141 ' If retMsg.Length > 0 Then
1146 ' If _endingFlag Then Return ""
1149 ' Dim pageQuery As String
1154 ' pageQuery = _pageQry + page.ToString
1157 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + FAV_PATH + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
1159 ' If retMsg.Length = 0 Then
1164 ' ' tr 要素の class 属性を消去
1165 ' retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
1168 ' ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
1169 ' ' If idx = -1 Then Exit Do
1170 ' ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
1171 ' ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
1172 ' ' Catch ex As Exception
1174 ' ' TraceOut("GetFav-Remove: " + retMsg)
1175 ' ' Return "GetFav -> Err: Can't parse data."
1179 ' If _endingFlag Then Return ""
1182 ' Dim strSepTmp As String
1183 ' strSepTmp = _splitPostRecent
1185 ' Dim pos1 As Integer
1186 ' Dim pos2 As Integer
1188 ' pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
1192 ' Return "GetTimeline -> Err: tweets count is 0."
1195 ' Dim strSep() As String = {strSepTmp}
1196 ' Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
1197 ' Dim intCnt As Integer = 0
1198 ' 'Dim listCnt As Integer = 0
1200 ' ' listCnt = TabInformations.GetInstance.ItemCount
1202 ' Dim dlgt(20) As GetIconImageDelegate
1203 ' Dim ar(20) As IAsyncResult
1204 ' Dim arIdx As Integer = -1
1208 ' For Each strPost As String In posts
1211 ' If intCnt = 1 Then
1215 ' Dim post As New PostClass
1217 ' pos1 = strPost.IndexOf("</ol>")
1219 ' strPost = strPost.Substring(0, pos1)
1225 ' pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
1226 ' post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
1227 ' Catch ex As Exception
1229 ' TraceOut("TM-ID:" + strPost)
1230 ' Return "GetTimeline -> Err: Can't get ID."
1234 ' pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
1235 ' pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
1236 ' post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
1237 ' Catch ex As Exception
1239 ' TraceOut("TM-Name:" + strPost)
1240 ' Return "GetTimeline -> Err: Can't get Name."
1244 ' If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
1245 ' post.Nickname = post.Name
1248 ' pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
1249 ' pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
1250 ' post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
1251 ' Catch ex As Exception
1253 ' TraceOut("TM-Nick:" + strPost)
1254 ' Return "GetTimeline -> Err: Can't get Nick."
1260 ' ' If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
1263 ' Dim orgData As String = ""
1265 ' If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
1267 ' pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
1268 ' pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
1269 ' orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
1270 ' Catch ex As Exception
1272 ' TraceOut("TM-VBody:" + strPost)
1273 ' Return "GetTimeline -> Err: Can't get Valentine body."
1280 ' pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
1281 ' pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
1282 ' post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
1283 ' Catch ex As Exception
1285 ' TraceOut("TM-Img:" + strPost)
1286 ' Return "GetTimeline -> Err: Can't get ImagePath."
1290 ' If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
1291 ' post.IsProtect = True
1295 ' If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
1296 ' rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
1297 ' m = rg.Match(strPost)
1299 ' post.RetweetedBy = m.Result("${name}")
1301 ' post.RetweetedBy = ""
1303 ' rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
1304 ' m = rg.Match(strPost)
1306 ' post.RetweetedId = Long.Parse(m.Result("${id}"))
1308 ' post.RetweetedId = 0
1313 ' pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
1317 ' If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
1319 ' orgData += " <3 you! Do you <3 "
1320 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1321 ' pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
1322 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1324 ' pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
1327 ' orgData += " <3 's "
1328 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1330 ' pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
1331 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1335 ' pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
1336 ' orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
1339 ' Catch ex As Exception
1341 ' TraceOut("TM-VBody2:" + strPost)
1342 ' Return "GetTimeline -> Err: Can't get Valentine body2."
1347 ' pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
1348 ' orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
1349 ' Catch ex As Exception
1351 ' TraceOut("TM-Body:" + strPost)
1352 ' Return "GetTimeline -> Err: Can't get body."
1356 ' ' orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1359 ' orgData = orgData.Replace("<3", "♡")
1362 ' 'URL前処理(IDNデコードなど)
1363 ' orgData = PreProcessUrl(orgData)
1365 ' '短縮URL解決処理(orgData書き換え)
1366 ' orgData = ShortUrlResolve(orgData)
1369 ' post.OriginalData = AdjustHtml(orgData)
1371 ' '単純テキストの取り出し(リンクタグ除去)
1373 ' post.Data = GetPlainText(orgData)
1374 ' Catch ex As Exception
1376 ' TraceOut("TM-Link:" + strPost)
1377 ' Return "GetTimeline -> Err: Can't parse links."
1380 ' ' Imageタグ除去(ハロウィン)
1381 ' Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
1382 ' If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
1387 ' pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1389 ' pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1390 ' post.PDate = DateTime.ParseExact(strPost.Substring(pos1 + _parseDate.Length, pos2 - pos1 - _parseDate.Length), "ddd MMM dd HH':'mm':'ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, Globalization.DateTimeStyles.None)
1392 ' post.PDate = Now()
1394 ' Catch ex As Exception
1396 ' TraceOut("TM-Date:" + strPost)
1397 ' Return "GetTimeline -> Err: Can't get date."
1400 ' '取得できなくなったため暫定対応(2/26)
1401 ' post.PDate = Now()
1406 ' 'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
1407 ' rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
1408 ' m = rg.Match(strPost)
1410 ' post.Source = m.Result("${name}")
1412 ' post.Source = "Web"
1415 ' ' pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
1416 ' ' If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
1417 ' ' If pos1 > -1 Then
1418 ' ' pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
1419 ' ' pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
1420 ' ' post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
1422 ' ' post.Source = "Web"
1424 ' 'Catch ex As Exception
1426 ' ' TraceOut("TM-Src:" + strPost)
1427 ' ' Return "GetTimeline -> Err: Can't get src."
1430 ' 'Get Reply(in_reply_to_user/id)
1431 ' 'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
1432 ' rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
1433 ' m = rg.Match(strPost)
1435 ' post.InReplyToUser = m.Result("${name}")
1436 ' post.InReplyToId = Long.Parse(m.Result("${id}"))
1437 ' post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1441 ' rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
1442 ' m = rg.Match(orgData)
1444 ' post.ReplyToList.Add(m.Groups(1).Value.ToLower())
1447 ' If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
1452 ' If _endingFlag Then Return ""
1454 ' post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1456 ' If follower.Count > 1 Then
1457 ' post.IsOwl = Not follower.Contains(post.Name.ToLower())
1459 ' post.IsOwl = False
1462 ' post.IsRead = read
1465 ' dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1466 ' ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1472 ' For i As Integer = 0 To arIdx
1474 ' dlgt(i).EndInvoke(ar(i))
1475 ' Catch ex As Exception
1476 ' '最後までendinvoke回す(ゾンビ化回避)
1477 ' ex.Data("IsTerminatePermission") = False
1484 ' GetTmSemaphore.Release()
1488 Private Function PreProcessUrl(ByVal orgData As String) As String
1489 Dim posl1 As Integer
1490 Dim posl2 As Integer = 0
1491 Dim IDNConveter As IdnMapping = New IdnMapping()
1492 Dim href As String = "<a href="""
1495 If orgData.IndexOf(href, posl2, StringComparison.Ordinal) > -1 Then
1496 Dim urlStr As String = ""
1498 posl1 = orgData.IndexOf(href, posl2, StringComparison.Ordinal)
1499 posl1 += href.Length
1500 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1501 urlStr = orgData.Substring(posl1, posl2 - posl1)
1503 If Not urlStr.StartsWith("http://") AndAlso Not urlStr.StartsWith("https://") AndAlso Not urlStr.StartsWith("ftp://") Then
1507 Dim replacedUrl As String = IDNDecode(urlStr)
1508 If replacedUrl Is Nothing Then Continue Do
1509 If replacedUrl = urlStr Then Continue Do
1511 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + replacedUrl)
1520 ' Private Function doShortUrlResolve(ByRef orgData As String) As Boolean
1521 ' Dim replaced As Boolean = False
1522 ' For Each _svc As String In _ShortUrlService
1523 ' Dim svc As String = _svc
1524 ' Dim posl1 As Integer
1525 ' Dim posl2 As Integer = 0
1528 ' If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1529 ' Dim urlStr As String = ""
1531 ' posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1532 ' posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1533 ' posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1534 ' urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1535 ' Dim Response As String = ""
1536 ' Dim retUrlStr As String = ""
1537 ' Dim tmpurlStr As String = urlStr
1538 ' Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1539 ' Dim tmpSchemeAndDomain As String = ""
1540 ' For i As Integer = 0 To 4 'とりあえず5回試す
1541 ' retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo), String))
1542 ' If retUrlStr.Length > 0 Then
1543 ' ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1544 ' ' 取得試行回数オーバーの場合は取得結果を転送先とする
1545 ' Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1546 ' If scd.Success AndAlso scd.Value <> svc Then
1549 ' tmpurlStr = retUrlStr
1553 ' If tmpurlStr <> urlStr Then
1554 ' '少なくとも一度以上転送されている (前回の結果を転送先とする)
1555 ' retUrlStr = tmpurlStr
1563 ' If retUrlStr.Length > 0 Then
1564 ' If Not retUrlStr.StartsWith("http") Then
1565 ' If retUrlStr.StartsWith("/") Then
1566 ' retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1567 ' ElseIf retUrlStr.StartsWith("data:") Then
1570 ' retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1573 ' retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1575 ' orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1576 ' posl2 = 0 '置換した場合は頭から再探索(複数同時置換での例外対応)
1579 ' Catch ex As Exception
1581 ' 'Return "GetTimeline -> Err: Can't get tinyurl."
1592 ' Private Sub doShortUrlResolve(ByRef orgData As String)
1593 ' 'Dim replaced As Boolean = False
1594 ' 'Dim svc As String
1595 ' 'Dim posl1 As Integer
1596 ' 'Dim posl2 As Integer = 0
1597 ' Static urlCache As New Specialized.StringDictionary()
1598 ' If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1600 ' Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1601 ' Dim m As MatchCollection = rx.Matches(orgData)
1602 ' Dim urlList As New List(Of String)
1603 ' For Each orgUrlMatch As Match In m
1604 ' Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1605 ' Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1606 ' If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1607 ' Not urlList.Contains(orgUrl + orgUrlPath) Then
1608 ' urlList.Add(orgUrl + orgUrlPath)
1611 ' For Each orgUrl As String In urlList
1612 ' If urlCache.ContainsKey(orgUrl) Then
1614 ' orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1615 ' Catch ex As Exception
1620 ' 'urlとして生成できない場合があるらしい
1621 ' 'Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1622 ' Dim retUrlStr As String = ""
1623 ' Dim tmpurlStr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1624 ' Dim httpVar As New HttpVarious
1625 ' retUrlStr = urlEncodeMultibyteChar(httpVar.GetRedirectTo(tmpurlStr))
1626 ' If retUrlStr.StartsWith("http") Then
1627 ' retUrlStr = retUrlStr.Replace("""", "%22") 'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1628 ' orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1629 ' urlCache.Add(orgUrl, retUrlStr)
1631 ' Catch ex As Exception
1637 ' 'For Each ma As Match In m
1638 ' ' svc = ma.Result("${svc}")
1639 ' ' posl1 = ma.Index
1640 ' ' If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1641 ' ' Dim urlStr As String = ""
1643 ' ' posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1644 ' ' posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1645 ' ' posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1646 ' ' urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1647 ' ' Dim Response As String = ""
1648 ' ' Dim retUrlStr As String = ""
1649 ' ' Dim tmpurlStr As String = urlStr
1650 ' ' Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1651 ' ' Dim tmpSchemeAndDomain As String = ""
1652 ' ' For i As Integer = 0 To 4 'とりあえず5回試す
1653 ' ' retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo, timeOut:=2000), String))
1654 ' ' If retUrlStr.Length > 0 Then
1655 ' ' ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1656 ' ' ' 取得試行回数オーバーの場合は取得結果を転送先とする
1657 ' ' Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1658 ' ' If scd.Success AndAlso scd.Value <> svc Then
1659 ' ' svc = scd.Value()
1661 ' ' tmpurlStr = retUrlStr
1664 ' ' ' 転送先URLが返されなかった
1665 ' ' If tmpurlStr <> urlStr Then
1666 ' ' '少なくとも一度以上転送されている (前回の結果を転送先とする)
1667 ' ' retUrlStr = tmpurlStr
1675 ' ' If retUrlStr.Length > 0 Then
1676 ' ' If Not retUrlStr.StartsWith("http") Then
1677 ' ' If retUrlStr.StartsWith("/") Then
1678 ' ' retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1679 ' ' ElseIf retUrlStr.StartsWith("data:") Then
1682 ' ' retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1685 ' ' retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1687 ' ' orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1688 ' ' posl2 = 0 '置換した場合は頭から再探索(複数同時置換での例外対応)
1691 ' ' Catch ex As Exception
1692 ' ' '_signed = False
1693 ' ' 'Return "GetTimeline -> Err: Can't get tinyurl."
1703 Private Function ShortUrlResolve(ByVal orgData As String) As String
1704 If _tinyUrlResolve Then
1705 Static urlCache As New Specialized.StringDictionary()
1706 If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1708 'Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1709 Dim m As MatchCollection = Regex.Matches(orgData, "<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1710 Dim urlList As New List(Of String)
1711 For Each orgUrlMatch As Match In m
1712 Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1713 Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1714 If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1715 Not urlList.Contains(orgUrl + orgUrlPath) Then
1716 urlList.Add(orgUrl + orgUrlPath)
1719 For Each orgUrl As String In urlList
1720 If urlCache.ContainsKey(orgUrl) Then
1722 orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1723 Catch ex As Exception
1728 'urlとして生成できない場合があるらしい
1729 'Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1730 Dim retUrlStr As String = ""
1731 Dim tmpurlStr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1732 Dim httpVar As New HttpVarious
1733 retUrlStr = urlEncodeMultibyteChar(httpVar.GetRedirectTo(tmpurlStr))
1734 If retUrlStr.StartsWith("http") Then
1735 retUrlStr = retUrlStr.Replace("""", "%22") 'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1736 orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1737 urlCache.Add(orgUrl, retUrlStr)
1739 Catch ex As Exception
1748 Private Function GetPlainText(ByVal orgData As String) As String
1749 Return HttpUtility.HtmlDecode(Regex.Replace(orgData, "(?<tagStart><a [^>]+>)(?<text>[^<]+)(?<tagEnd></a>)", "${text}"))
1751 ''単純テキストの取り出し(リンクタグ除去)
1752 'If orgData.IndexOf(_parseLink1, StringComparison.Ordinal) = -1 Then
1753 ' retStr = HttpUtility.HtmlDecode(orgData)
1755 ' Dim posl1 As Integer
1756 ' Dim posl2 As Integer
1757 ' Dim posl3 As Integer = 0
1763 ' posl1 = orgData.IndexOf(_parseLink1, posl3, StringComparison.Ordinal)
1764 ' If posl1 = -1 Then Exit Do
1766 ' If (posl3 + _parseLink3.Length <> posl1) Or posl3 = 0 Then
1767 ' If posl3 <> 0 Then
1768 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length, posl1 - posl3 - _parseLink3.Length))
1770 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(0, posl1))
1773 ' posl2 = orgData.IndexOf(_parseLink2, posl1, StringComparison.Ordinal)
1774 ' posl3 = orgData.IndexOf(_parseLink3, posl2, StringComparison.Ordinal)
1775 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl2 + _parseLink2.Length, posl3 - posl2 - _parseLink2.Length))
1777 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length))
1783 ' htmlの簡易サニタイズ(詳細表示に不要なタグの除去)
1785 Private Function SanitizeHtml(ByVal orgdata As String) As String
1786 Dim retdata As String = orgdata
1788 ' <script ~ </script>
1789 'Dim rx As Regex = New Regex( _
1790 ' "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
1791 ' "</(script|object|applet|image|frameset|fieldset|legend|style)>", RegexOptions.IgnoreCase)
1792 retdata = Regex.Replace(retdata, "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
1793 "</(script|object|applet|image|frameset|fieldset|legend|style)>", "", RegexOptions.IgnoreCase)
1796 'rx = New Regex("<(frame|link|iframe|img)>", RegexOptions.IgnoreCase)
1797 retdata = Regex.Replace(retdata, "<(frame|link|iframe|img)>", "", RegexOptions.IgnoreCase)
1802 Private Function AdjustHtml(ByVal orgData As String) As String
1803 Dim retStr As String = orgData
1804 'Dim hash As New Regex("<a [^>]+>[#|#](?<1>[a-zA-Z0-9_]+)</a>")
1805 Dim m As Match = Regex.Match(retStr, "<a [^>]+>[#|#](?<1>[a-zA-Z0-9_]+)</a>")
1808 _hashList.Add("#" + m.Groups(1).Value)
1812 retStr = Regex.Replace(retStr, "<a [^>]*href=""/", "<a href=""" + _protocol + "twitter.com/")
1813 retStr = retStr.Replace("<a href=", "<a target=""_self"" href=")
1814 retStr = retStr.Replace(vbLf, "<br>")
1816 '半角スペースを置換(Thanks @anis774)
1817 Dim ret As Boolean = False
1819 ret = EscapeSpace(retStr)
1821 'Dim isTag As Boolean = False
1822 'For i As Integer = 0 To retStr.Length - 1
1823 ' If retStr(i) = "<"c Then
1826 ' If retStr(i) = ">"c Then
1830 ' If (Not isTag) AndAlso (retStr(i) = " "c) Then
1831 ' retStr = retStr.Remove(i, 1)
1832 ' retStr = retStr.Insert(i, " ")
1836 Return SanitizeHtml(retStr)
1839 Private Function EscapeSpace(ByRef html As String) As Boolean
1840 '半角スペースを置換(Thanks @anis774)
1841 Dim isTag As Boolean = False
1842 For i As Integer = 0 To html.Length - 1
1843 If html(i) = "<"c Then
1846 If html(i) = ">"c Then
1850 If (Not isTag) AndAlso (html(i) = " "c) Then
1851 html = html.Remove(i, 1)
1852 html = html.Insert(i, " ")
1859 Private Sub GetIconImage(ByVal post As PostClass)
1864 If Not _getIcon Then
1865 post.ImageIndex = -1
1866 TabInformations.GetInstance.AddPost(post)
1871 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1874 If post.ImageIndex > -1 Then
1875 TabInformations.GetInstance.AddPost(post)
1879 Dim httpVar As New HttpVarious
1880 img = httpVar.GetImage(post.ImageUrl)
1881 If img Is Nothing Then
1882 post.ImageIndex = -1
1883 TabInformations.GetInstance.AddPost(post)
1887 If _endingFlag Then Exit Sub
1889 bmp2 = New Bitmap(_iconSz, _iconSz)
1890 Using g As Graphics = Graphics.FromImage(bmp2)
1891 g.InterpolationMode = Drawing2D.InterpolationMode.High
1892 g.DrawImage(img, 0, 0, _iconSz, _iconSz)
1897 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1898 If post.ImageIndex = -1 Then
1900 If img.RawFormat.Guid = Imaging.ImageFormat.Gif.Guid Then
1901 Dim fd As New System.Drawing.Imaging.FrameDimension(img.FrameDimensionsList(0))
1902 Dim fd_count As Integer = img.GetFrameCount(fd)
1903 If fd_count > 1 Then
1905 For i As Integer = 0 To fd_count - 1
1906 img.SelectActiveFrame(fd, i)
1908 _dIcon.Add(post.ImageUrl, img) '詳細表示用ディクショナリに追加
1909 Catch ex As Exception
1910 Dim bmp As New Bitmap(48, 48)
1911 Using g As Graphics = Graphics.FromImage(bmp)
1912 g.InterpolationMode = Drawing2D.InterpolationMode.High
1913 g.DrawImage(img, 0, 0, 48, 48)
1915 _dIcon.Add(post.ImageUrl, bmp) '詳細表示用ディクショナリに追加
1919 _dIcon.Add(post.ImageUrl, img) '詳細表示用ディクショナリに追加
1921 _lIcon.Images.Add(post.ImageUrl, bmp2)
1922 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1924 _dIcon.Add(post.ImageUrl, img)
1925 _lIcon.Images.Add(post.ImageUrl, bmp2)
1926 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1928 Catch ex As InvalidOperationException
1929 'タイミングにより追加できない場合がある?(キー重複ではない)
1930 post.ImageIndex = -1
1934 TabInformations.GetInstance.AddPost(post)
1935 Catch ex As ArgumentException
1944 'Private Function GetAuthKey(ByVal resMsg As String) As Integer
1945 ' Dim pos1 As Integer
1946 ' Dim pos2 As Integer
1948 ' pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1953 ' pos2 = resMsg.IndexOf(_getAuthKeyTo, pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1955 ' _authKey = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1963 'Private Function GetAuthKeyDM(ByVal resMsg As String) As Integer
1964 ' Dim pos1 As Integer
1965 ' Dim pos2 As Integer
1967 ' pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1972 ' pos2 = resMsg.IndexOf("""", pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1973 ' _authKeyDM = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1978 Private Structure PostInfo
1979 Public CreatedAt As String
1981 Public Text As String
1982 Public UserId As String
1983 Public Sub New(ByVal Created As String, ByVal IdStr As String, ByVal txt As String, ByVal uid As String)
1989 Public Shadows Function Equals(ByVal dst As PostInfo) As Boolean
1990 If Me.CreatedAt = dst.CreatedAt AndAlso Me.Id = dst.Id AndAlso Me.Text = dst.Text AndAlso Me.UserId = dst.UserId Then
1998 Private Function IsPostRestricted(ByRef resMsg As String) As Boolean
1999 Static _prev As New PostInfo("", "", "", "")
2000 Dim _current As New PostInfo("", "", "", "")
2003 Dim xd As XmlDocument = New XmlDocument()
2006 _current.CreatedAt = xd.SelectSingleNode("/status/created_at/text()").Value
2007 _current.Id = xd.SelectSingleNode("/status/id/text()").Value
2008 _current.Text = xd.SelectSingleNode("/status/text/text()").Value
2009 _current.UserId = xd.SelectSingleNode("/status/user/id/text()").Value
2011 If _current.Equals(_prev) Then
2014 _prev.CreatedAt = _current.CreatedAt
2015 _prev.Id = _current.Id
2016 _prev.Text = _current.Text
2017 _prev.UserId = _current.UserId
2018 Catch ex As XmlException
2025 Public Function PostStatus(ByVal postStr As String, ByVal reply_to As Long) As String
2027 If _endingFlag Then Return ""
2029 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2031 postStr = postStr.Trim()
2033 Dim res As HttpStatusCode
2034 Dim content As String = ""
2036 res = twCon.UpdateStatus(postStr, reply_to, content)
2037 Catch ex As Exception
2038 Return "Err:" + ex.Message
2042 Case HttpStatusCode.OK
2043 Dim xd As XmlDocument = New XmlDocument()
2046 Dim xNode As XmlNode = Nothing
2047 xNode = xd.SelectSingleNode("/status/user/followers_count/text()")
2048 If xNode IsNot Nothing Then _followersCount = Integer.Parse(xNode.Value)
2049 xNode = xd.SelectSingleNode("/status/user/friends_count/text()")
2050 If xNode IsNot Nothing Then _friendsCount = Integer.Parse(xNode.Value)
2051 xNode = xd.SelectSingleNode("/status/user/statuses_count/text()")
2052 If xNode IsNot Nothing Then _statusesCount = Integer.Parse(xNode.Value)
2053 xNode = xd.SelectSingleNode("/status/user/location/text()")
2054 If xNode IsNot Nothing Then _location = xNode.Value
2055 xNode = xd.SelectSingleNode("/status/user/description/text()")
2056 If xNode IsNot Nothing Then _bio = xNode.Value
2057 Catch ex As Exception
2061 If Not postStr.StartsWith("D ", StringComparison.OrdinalIgnoreCase) AndAlso _
2062 Not postStr.StartsWith("DM ", StringComparison.OrdinalIgnoreCase) AndAlso _
2063 IsPostRestricted(content) Then
2064 Return "OK:Delaying?"
2066 If op.Post(postStr.Length) Then
2069 Return "Outputz:Failed"
2071 Case HttpStatusCode.Forbidden
2072 Dim xd As XmlDocument = New XmlDocument
2075 Dim xNode As XmlNode = Nothing
2076 xNode = xd.SelectSingleNode("/hash/error")
2077 Return "OK:" + xNode.InnerText
2078 Catch ex As Exception
2080 Return "Err:Update Limits?"
2081 Case HttpStatusCode.Unauthorized
2082 Twitter.AccountState = ACCOUNT_STATE.Invalid
2083 Return "Check your Username/Password."
2085 Return "Err:" + res.ToString
2089 Public Function RemoveStatus(ByVal id As Long) As String
2090 If _endingFlag Then Return ""
2092 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2094 Dim res As HttpStatusCode
2097 res = twCon.DestroyStatus(id)
2098 Catch ex As Exception
2099 Return "Err:" + ex.Message
2103 Case HttpStatusCode.OK
2105 Case HttpStatusCode.Unauthorized
2106 Twitter.AccountState = ACCOUNT_STATE.Invalid
2107 Return "Check your Username/Password."
2108 Case HttpStatusCode.NotFound
2111 Return "Err:" + res.ToString
2116 Public Function PostRetweet(ByVal id As Long, ByVal read As Boolean) As String
2117 If _endingFlag Then Return ""
2118 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2121 Dim target As Long = id
2122 If TabInformations.GetInstance.Item(id).RetweetedId > 0 Then
2123 target = TabInformations.GetInstance.Item(id).RetweetedId '再RTの場合は元発言をRT
2126 Dim res As HttpStatusCode
2127 Dim content As String = ""
2129 res = twCon.RetweetStatus(target, content)
2130 Catch ex As Exception
2131 Return "Err:" + ex.Message
2135 Case HttpStatusCode.Unauthorized
2136 Twitter.AccountState = ACCOUNT_STATE.Invalid
2137 Return "Check your Username/Password."
2138 Case Is <> HttpStatusCode.OK
2139 Return "Err:" + res.ToString()
2142 Dim dlgt As GetIconImageDelegate 'countQueryに合わせる
2143 Dim ar As IAsyncResult 'countQueryに合わせる
2144 Dim xdoc As New XmlDocument
2146 xdoc.LoadXml(content)
2147 Catch ex As Exception
2149 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
2150 Return "Invalid XML!"
2154 Dim xentryNode As XmlNode = xdoc.DocumentElement.SelectSingleNode("/status")
2155 If xentryNode Is Nothing Then Return "Invalid XML!"
2156 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
2157 Dim post As New PostClass
2159 post.Id = Long.Parse(xentry.Item("id").InnerText)
2162 If TabInformations.GetInstance.ContainsKey(post.Id) Then Return ""
2165 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
2166 If xRnode Is Nothing Then Return "Invalid XML!"
2168 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
2169 post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
2171 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
2173 post.Data = xRentry.Item("text").InnerText
2174 'Source取得(htmlの場合は、中身を取り出し)
2175 post.Source = xRentry.Item("source").InnerText
2177 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
2178 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
2179 post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
2182 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
2183 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
2184 post.Name = xRUentry.Item("screen_name").InnerText
2185 post.Nickname = xRUentry.Item("name").InnerText
2186 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
2187 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
2188 'post.IsMe = post.Name.ToLower.Equals(_uid)
2192 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
2193 post.RetweetedBy = xUentry.Item("screen_name").InnerText
2196 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
2197 post.Data = HttpUtility.HtmlDecode(post.Data)
2198 post.Data = post.Data.Replace("<3", "♡")
2200 If post.Source.StartsWith("<") Then
2201 'Dim rgS As New Regex(">(?<source>.+)<")
2202 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
2204 post.Source = mS.Result("${source}")
2209 post.IsReply = post.ReplyToList.Contains(_uid)
2214 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
2216 If post.IsMe AndAlso _readOwnPost Then post.IsRead = True
2219 Catch ex As Exception
2221 'MessageBox.Show("不正なXMLです。(TL-Parse)")
2222 Return "Invalid XML!"
2225 '非同期アイコン取得&StatusDictionaryに追加
2226 dlgt = New GetIconImageDelegate(AddressOf GetIconImage)
2227 ar = dlgt.BeginInvoke(post, Nothing, Nothing)
2232 Catch ex As Exception
2233 '最後までendinvoke回す(ゾンビ化回避)
2234 ex.Data("IsTerminatePermission") = False
2241 Public Function RemoveDirectMessage(ByVal id As Long) As String
2242 If _endingFlag Then Return ""
2244 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2246 Dim res As HttpStatusCode
2249 res = twCon.DestroyDirectMessage(id)
2250 Catch ex As Exception
2251 Return "Err:" + ex.Message
2255 Case HttpStatusCode.OK
2257 Case HttpStatusCode.Unauthorized
2258 Twitter.AccountState = ACCOUNT_STATE.Invalid
2259 Return "Check your Username/Password."
2260 Case HttpStatusCode.NotFound
2263 Return "Err:" + res.ToString
2267 Public Function PostFollowCommand(ByVal screenName As String) As String
2269 If _endingFlag Then Return ""
2271 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2273 Dim res As HttpStatusCode
2276 res = twCon.CreateFriendships(screenName)
2277 Catch ex As Exception
2278 Return "Err:" + ex.Message
2282 Case HttpStatusCode.OK
2284 Case HttpStatusCode.Unauthorized
2285 Twitter.AccountState = ACCOUNT_STATE.Invalid
2286 Return "Check your Username/Password."
2287 Case HttpStatusCode.Forbidden
2288 Return "Err:Update Limits?"
2290 Return "Err:" + res.ToString
2294 Public Function PostRemoveCommand(ByVal screenName As String) As String
2296 If _endingFlag Then Return ""
2298 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2300 Dim res As HttpStatusCode
2303 res = twCon.DestroyFriendships(screenName)
2304 Catch ex As Exception
2305 Return "Err:" + ex.Message
2309 Case HttpStatusCode.OK
2311 Case HttpStatusCode.Unauthorized
2312 Twitter.AccountState = ACCOUNT_STATE.Invalid
2313 Return "Check your Username/Password."
2315 Return "Err:" + res.ToString
2319 Public Function GetFriendshipInfo(ByVal screenName As String, ByRef isFollowing As Boolean, ByRef isFollowed As Boolean) As String
2321 If _endingFlag Then Return ""
2323 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2325 Dim res As HttpStatusCode
2326 Dim content As String = ""
2328 res = twCon.ShowFriendships(_uid, screenName, content)
2329 Catch ex As Exception
2330 Return "Err:" + ex.Message
2334 Case HttpStatusCode.OK
2335 Dim xdoc As New XmlDocument
2336 Dim result As String = ""
2338 xdoc.LoadXml(content)
2339 isFollowing = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/following").InnerText)
2340 isFollowed = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/followed_by").InnerText)
2341 Catch ex As Exception
2342 result = "Err:Invalid XML."
2345 Case HttpStatusCode.BadRequest
2346 Return "Err:API Limits?"
2347 Case HttpStatusCode.Unauthorized
2348 Twitter.AccountState = ACCOUNT_STATE.Invalid
2349 Return "Check your Username/Password."
2351 Return "Err:" + res.ToString
2355 Public Function PostFavAdd(ByVal id As Long) As String
2356 If _endingFlag Then Return ""
2358 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2360 Dim res As HttpStatusCode
2363 res = twCon.CreateFavorites(id)
2364 Catch ex As Exception
2365 Return "Err:" + ex.Message
2369 Case HttpStatusCode.OK
2370 If Not _restrictFavCheck Then Return ""
2371 Case HttpStatusCode.Unauthorized
2372 Twitter.AccountState = ACCOUNT_STATE.Invalid
2373 Return "Check your Username/Password."
2374 Case HttpStatusCode.Forbidden
2375 Return "Err:Update Limits?"
2377 Return "Err:" + res.ToString
2380 'http://twitter.com/statuses/show/id.xml APIを発行して本文を取得
2382 Dim content As String = ""
2384 res = twCon.ShowStatuses(id, content)
2385 Catch ex As Exception
2386 Return "Err:" + ex.Message
2390 Case HttpStatusCode.OK
2392 Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(content))
2394 While rd.EOF = False
2395 If rd.IsStartElement("favorited") Then
2396 If rd.ReadElementContentAsBoolean() = True Then
2397 Return "" '正常にふぁぼれている
2399 Return "NG(Restricted?)" '正常応答なのにふぁぼれてないので制限っぽい
2406 Return "Err:Invalid XML!"
2408 Catch ex As XmlException
2411 Case HttpStatusCode.Unauthorized
2412 Twitter.AccountState = ACCOUNT_STATE.Invalid
2413 Return "Check your Username/Password."
2414 Case HttpStatusCode.BadRequest
2415 Return "Err:API Limits?"
2417 Return "Err:" + res.ToString
2422 Public Function PostFavRemove(ByVal id As Long) As String
2423 If _endingFlag Then Return ""
2425 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2427 Dim res As HttpStatusCode
2430 res = twCon.DestroyFavorites(id)
2431 Catch ex As Exception
2432 Return "Err:" + ex.Message
2436 Case HttpStatusCode.OK
2438 Case HttpStatusCode.Unauthorized
2439 Twitter.AccountState = ACCOUNT_STATE.Invalid
2440 Return "Check your Username/Password."
2441 Case HttpStatusCode.Forbidden
2442 Return "Err:Update Limits?"
2444 Return "Err:" + res.ToString
2448 '#Region "follower取得"
2449 ' 'Delegate Function GetFollowersDelegate(ByVal Query As Integer) As String
2450 ' 'Private semaphore As Threading.Semaphore = Nothing
2451 ' 'Private threadNum As Integer = 0
2452 ' Private _threadErr As Boolean = False
2454 ' Private Function GetFollowersMethod() As String
2455 ' Dim resStatus As String = ""
2456 ' Dim resMsg As String = ""
2457 ' Dim lineCount As Integer = 0
2458 ' Dim page As Long = -1
2461 ' If _endingFlag Then Exit Do
2462 ' resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _apiHost + _hubServer + _GetFollowers + _cursorQry + page.ToString, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2463 ' If resStatus.StartsWith("OK") = False Then
2464 ' Debug.WriteLine(page.ToString)
2469 ' Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(resMsg))
2472 ' While rd.EOF = False
2473 ' If rd.IsStartElement("screen_name") Then
2474 ' Dim tmp As String = rd.ReadElementString("screen_name").ToLower()
2476 ' If Not tmpFollower.Contains(tmp) Then
2477 ' tmpFollower.Add(tmp)
2481 ' ElseIf rd.IsStartElement("next_cursor") Then
2482 ' page = Long.Parse(rd.ReadElementString("next_cursor"))
2483 ' If page = 0 Then Exit Do
2490 ' Catch ex As Exception
2492 ' TraceOut("NG(XmlException)")
2493 ' Return "NG(XmlException)"
2495 ' Loop While lineCount > 0
2500 'Private Sub GetFollowersCallback(ByVal ar As IAsyncResult)
2501 ' Dim dlgt As GetFollowersDelegate = DirectCast(ar.AsyncState, GetFollowersDelegate)
2504 ' Dim ret As String = dlgt.EndInvoke(ar)
2505 ' If Not ret.Equals("") AndAlso Not _threadErr Then
2509 ' Catch ex As Exception
2511 ' ex.Data("IsTerminatePermission") = False
2514 ' GetTmSemaphore.Release() ' セマフォから出る
2515 ' Interlocked.Decrement(threadNum) ' スレッド数カウンタを-1
2520 '' キャッシュの検証と読み込み -1を渡した場合は読み込みのみ行う(APIエラーでFollowersCountが取得できなかったとき)
2521 'Private Function ValidateCache() As Integer
2525 ' Dim setting As SettingFollower = SettingFollower.Load()
2526 ' follower = setting.Follower
2527 ' If follower.Count = 0 OrElse Not follower(0).Equals(_uid.ToLower()) Then
2528 ' ' 別IDの場合はキャッシュ破棄して読み直し
2531 ' Catch ex As XmlException
2534 ' Catch ex As InvalidOperationException
2539 ' 'If _FollowersCount = -1 Then Return tmpFollower.Count
2540 ' Return follower.Count
2542 ' 'If (_FollowersCount + 1) = tmpFollower.Count Then
2543 ' ' '変動がないので読み込みの必要なし
2545 ' 'ElseIf (_FollowersCount + 1) < tmpFollower.Count Then
2546 ' ' '減っている場合はどこが抜けているのかわからないので全部破棄して読み直し
2547 ' ' tmpFollower.Clear()
2548 ' ' tmpFollower.Add(_uid.ToLower())
2549 ' ' Return _FollowersCount
2554 ' 'Return _FollowersCount - tmpFollower.Count
2558 'Private Sub UpdateCache()
2559 ' Dim setting As New SettingFollower(follower)
2563 ' Public Function GetFollowers(ByVal CacheInvalidate As Boolean) As String
2565 ' Dim sw As New System.Diagnostics.Stopwatch
2569 ' If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2571 ' 'Dim resStatus As String = ""
2572 ' 'Dim resMsg As String = ""
2573 ' 'Dim i As Integer = 0
2574 ' 'Dim DelegateInstance As GetFollowersDelegate = New GetFollowersDelegate(AddressOf GetFollowersMethod)
2575 ' 'Dim threadMax As Integer = 4 ' 最大スレッド数
2576 ' 'Dim followersCount As Integer = 0
2578 ' 'Interlocked.Exchange(threadNum, 0) ' スレッド数カウンタ初期化
2579 ' _threadErr = False
2581 ' tmpFollower.Clear()
2582 ' 'follower.Add(_uid.ToLower())
2583 ' tmpFollower.Add(_uid.ToLower())
2585 ' 'resMsg = DirectCast(CreateSocket.GetWebResponse("https://twitter.com/users/show/" + _uid + ".xml", resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2586 ' 'If resMsg = "" Then
2587 ' ' If resStatus.StartsWith("Err: BadRequest") Then
2588 ' ' Return "Maybe, the requests reached API limit."
2589 ' ' ElseIf resStatus.StartsWith("Err: Unauthorized") Then
2590 ' ' Twitter.AccountState = ACCOUNT_STATE.Invalid
2591 ' ' Return "Check your Username/Password."
2593 ' ' Return resStatus
2597 ' 'Dim xd As XmlDocument = New XmlDocument()
2599 ' ' xd.LoadXml(resMsg)
2600 ' ' followersCount = Integer.Parse(xd.SelectSingleNode("/user/followers_count/text()").Value)
2601 ' 'Catch ex As Exception
2602 ' ' 'If CacheInvalidate OrElse ValidateCache(-1) < 0 Then
2603 ' ' If ValidateCache(-1) < 0 Then
2604 ' ' ' FollowersカウントがAPIで取得できず、なおかつキャッシュから読めなかった
2605 ' ' SyncLock LockObj
2606 ' ' follower.Clear()
2607 ' ' follower.Add(_uid.ToLower())
2609 ' ' Return "Can't get followers_count and invalid cache."
2611 ' ' 'キャッシュを読み出せたのでキャッシュを使う
2612 ' ' SyncLock LockObj
2613 ' ' follower = tmpFollower
2619 ' 'Dim tmp As Integer
2621 ' ''If CacheInvalidate Then
2622 ' 'tmp = followersCount
2624 ' ''tmp = ValidateCache(followersCount)
2629 ' ' i = (tmp + 100) \ 100 ' Followersカウント取得しページ単位に切り上げる。1ページ余分に読む
2631 ' ' ' ' キャッシュの件数に変化がなかった
2634 ' ' ' Console.WriteLine(sw.ElapsedMilliseconds)
2636 ' ' ' SyncLock LockObj
2637 ' ' ' follower = tmpFollower
2640 ' ' Return "" 'ユーザー情報のフォロワー数が0
2644 ' ''semaphore = New System.Threading.Semaphore(threadMax, threadMax) 'スレッド最大数
2646 ' 'For cnt As Integer = 0 To i
2647 ' ' If _endingFlag Then Exit For
2648 ' ' 'semaphore.WaitOne() 'セマフォ取得 threadMax以上ならここでブロックされる
2649 ' ' GetTmSemaphore.WaitOne()
2650 ' ' 'Interlocked.Increment(threadNum) 'スレッド数カウンタを+1
2651 ' ' 'DelegateInstance.BeginInvoke(cnt + 1, New System.AsyncCallback(AddressOf GetFollowersCallback), DelegateInstance)
2652 ' ' Dim ret As String = GetFollowersMethod(cnt + 1)
2653 ' ' 'Interlocked.Decrement(threadNum) 'スレッド数カウンタを-1
2654 ' ' GetTmSemaphore.Release()
2655 ' ' If _threadErr Then Exit For
2658 ' '''全てのスレッドの終了を待つ(スレッド数カウンタが0になるまで待機)
2660 ' '' Thread.Sleep(50)
2661 ' ''Loop Until Interlocked.Add(threadNum, 0) = 0
2663 ' ''semaphore.Close()
2665 ' Dim ret As String = GetFollowersMethod()
2666 ' If _endingFlag Then Return ""
2668 ' If _threadErr Then
2669 ' If ValidateCache() > 0 Then
2671 ' For Each name As String In tmpFollower
2672 ' If Not follower.Contains(name) Then follower.Add(name)
2675 ' If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2676 ' ret = "Can't get followers. Use cache."
2678 ' ' エラーが発生しているならFollowersリストクリア
2681 ' follower.Add(_uid.ToLower())
2683 ' ret = "Can't get followers."
2687 ' follower = tmpFollower
2692 ' If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2696 ' 'Console.WriteLine(sw.ElapsedMilliseconds)
2699 ' TabInformations.GetInstance.RefreshOwl(follower)
2705 'Public Sub RefreshOwl()
2706 ' TabInformations.GetInstance.RefreshOwl(follower)
2709 'Public Sub RefreshOwlApi()
2710 ' TabInformations.GetInstance.RefreshOwl(followerId)
2713 Public ReadOnly Property Username() As String
2715 Return twCon.AuthenticatedUsername
2719 Public ReadOnly Property Password() As String
2721 Return twCon.Password
2725 Private Shared _accountState As ACCOUNT_STATE = ACCOUNT_STATE.Valid
2726 Public Shared Property AccountState() As ACCOUNT_STATE
2728 Return _accountState
2730 Set(ByVal value As ACCOUNT_STATE)
2731 _accountState = value
2735 'Public Property NextThreshold() As Integer
2737 ' Return _nextThreshold
2739 ' Set(ByVal value As Integer)
2740 ' _nextThreshold = value
2744 'Public Property NextPages() As Integer
2748 ' Set(ByVal value As Integer)
2749 ' _nextPages = value
2753 Public ReadOnly Property InfoTwitter() As String
2759 'Public Property UseAPI() As Boolean
2763 ' Set(ByVal value As Boolean)
2768 ' Public Sub GetWedata()
2769 ' Dim resStatus As String = ""
2770 ' Dim resMsg As String = ""
2772 ' resMsg = DirectCast(CreateSocket.GetWebResponse(wedataUrl, resStatus, timeOut:=10 * 1000), String) 'タイムアウト時間を10秒に設定
2773 ' If resMsg.Length = 0 Then Exit Sub
2775 ' Dim rs As New System.IO.StringReader(resMsg)
2777 ' Dim mode As Integer = 0 '0:search name 1:search data 2:read data
2778 ' Dim name As String = ""
2782 ' While rs.Peek() > -1
2787 ' If ln.StartsWith(" ""name"": ") Then
2788 ' name = ln.Substring(13, ln.Length - 2 - 13)
2792 ' If ln = " ""data"": {" Then
2796 ' If ln = " }," Then
2799 ' If ln.EndsWith(",") Then ln = ln.Substring(0, ln.Length - 1)
2801 ' Case "SplitPostReply"
2802 ' If ln.StartsWith(" ""tagfrom"": """) Then
2803 ' _splitPost = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2805 ' Case "SplitPostRecent"
2806 ' If ln.StartsWith(" ""tagfrom"": """) Then
2807 ' _splitPostRecent = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2810 ' If ln.StartsWith(" ""tagto"": """) Then
2811 ' _statusIdTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2814 ' If ln.StartsWith(" ""tagfrom"": """) Then
2815 ' _isProtect = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2818 ' If ln.StartsWith(" ""tagfrom"": """) Then
2819 ' _isReplyEng = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2821 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2822 ' _isReplyJpn = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2824 ' If ln.StartsWith(" ""tagto"": """) Then
2825 ' _isReplyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2828 ' ' If ln.StartsWith(" ""tagfrom"": """) Then
2829 ' ' _parseStar = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2831 ' ' If ln.StartsWith(" ""tagfrom2"": """) Then
2832 ' ' _parseStarEmpty = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2834 ' ' If ln.StartsWith(" ""tagto"": """) Then
2835 ' ' _parseStarTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2838 ' If ln.StartsWith(" ""tagfrom"": """) Then
2839 ' _followerList = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2841 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2842 ' _followerMbr1 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2844 ' If ln.StartsWith(" ""tagfrom3"": """) Then
2845 ' _followerMbr2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2847 ' If ln.StartsWith(" ""tagto"": """) Then
2848 ' _followerMbr3 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2851 ' If ln.StartsWith(" ""tagfrom"": """) Then
2852 ' _splitDM = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2855 ' If ln.StartsWith(" ""tagfrom"": """) Then
2856 ' _parseDM1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2858 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2859 ' _parseDM11 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2861 ' If ln.StartsWith(" ""tagto"": """) Then
2862 ' _parseDM2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2865 ' If ln.StartsWith(" ""tagfrom"": """) Then
2866 ' _parseDate = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2868 ' If ln.StartsWith(" ""tagto"": """) Then
2869 ' _parseDateTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2872 ' If ln.StartsWith(" ""tagfrom"": """) Then
2873 ' _parseMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2875 ' If ln.StartsWith(" ""tagto"": """) Then
2876 ' _parseMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2878 ' Case "GetImagePath"
2879 ' If ln.StartsWith(" ""tagfrom"": """) Then
2880 ' _parseImg = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2882 ' If ln.StartsWith(" ""tagto"": """) Then
2883 ' _parseImgTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2886 ' If ln.StartsWith(" ""tagfrom"": """) Then
2887 ' _parseNick = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2889 ' If ln.StartsWith(" ""tagto"": """) Then
2890 ' _parseNickTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2893 ' If ln.StartsWith(" ""tagfrom"": """) Then
2894 ' _parseName = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2896 ' If ln.StartsWith(" ""tagto"": """) Then
2897 ' _parseNameTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2900 ' ' If ln.StartsWith(" ""tagfrom"": """) Then
2901 ' ' _getSiv = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2903 ' ' If ln.StartsWith(" ""tagto"": """) Then
2904 ' ' _getSivTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2907 ' If ln.StartsWith(" ""tagfrom"": """) Then
2908 ' _getAuthKey = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2910 ' If ln.StartsWith(" ""tagto"": """) Then
2911 ' _getAuthKeyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2913 ' Case "InfoTwitter"
2914 ' If ln.StartsWith(" ""tagfrom"": """) Then
2915 ' _getInfoTwitter = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2917 ' If ln.StartsWith(" ""tagto"": """) Then
2918 ' _getInfoTwitterTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2920 ' Case "GetProtectMsg"
2921 ' If ln.StartsWith(" ""tagfrom"": """) Then
2922 ' _parseProtectMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2924 ' If ln.StartsWith(" ""tagto"": """) Then
2925 ' _parseProtectMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2928 ' If ln.StartsWith(" ""tagfrom"": """) Then
2929 ' _parseDMcountFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2931 ' If ln.StartsWith(" ""tagto"": """) Then
2932 ' _parseDMcountTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2935 ' If ln.StartsWith(" ""tagfrom"": """) Then
2936 ' _parseSourceFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2938 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2939 ' _parseSource2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2941 ' If ln.StartsWith(" ""tagto"": """) Then
2942 ' _parseSource2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2944 ' Case "RemoveClass"
2945 ' If ln.StartsWith(" ""tagfrom"": """) Then
2946 ' _removeClass = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2956 ' GenerateAnalyzeKey()
2960 Public WriteOnly Property GetIcon() As Boolean
2961 Set(ByVal value As Boolean)
2966 Public WriteOnly Property TinyUrlResolve() As Boolean
2967 Set(ByVal value As Boolean)
2968 _tinyUrlResolve = value
2972 'Public WriteOnly Property SelectedProxyType() As ProxyType
2973 ' Set(ByVal value As ProxyType)
2974 ' _proxyType = value
2978 'Public WriteOnly Property ProxyAddress() As String
2979 ' Set(ByVal value As String)
2980 ' _proxyAddress = value
2984 'Public WriteOnly Property ProxyPort() As Integer
2985 ' Set(ByVal value As Integer)
2986 ' _proxyPort = value
2990 'Public WriteOnly Property ProxyUser() As String
2991 ' Set(ByVal value As String)
2992 ' _proxyUser = value
2996 'Public WriteOnly Property ProxyPassword() As String
2997 ' Set(ByVal value As String)
2998 ' _proxyPassword = value
3002 Public WriteOnly Property RestrictFavCheck() As Boolean
3003 Set(ByVal value As Boolean)
3004 _restrictFavCheck = value
3008 Public WriteOnly Property IconSize() As Integer
3009 Set(ByVal value As Integer)
3014 Public Function MakeShortUrl(ByVal ConverterType As UrlConverter, ByVal SrcUrl As String) As String
3015 Dim src As String = urlEncodeMultibyteChar(SrcUrl)
3016 Dim param As New Dictionary(Of String, String)
3017 Dim content As String = ""
3019 For Each svc As String In _ShortUrlService
3020 If SrcUrl.StartsWith(svc) Then
3021 Return "Can't convert"
3026 If SrcUrl.StartsWith("http://nico.ms/") Then Return "Can't convert"
3028 SrcUrl = HttpUtility.UrlEncode(SrcUrl)
3030 Select Case ConverterType
3031 Case UrlConverter.TinyUrl 'tinyurl
3032 If SrcUrl.StartsWith("http") Then
3033 If "http://tinyurl.com/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3034 ' 明らかに長くなると推測できる場合は圧縮しない
3038 If Not (New HttpVarious).PostData("http://tinyurl.com/api-create.php?url=" + SrcUrl, Nothing, content) Then
3039 Return "Can't convert"
3042 If Not content.StartsWith("http://tinyurl.com/") Then
3043 Return "Can't convert"
3045 Case UrlConverter.Isgd
3046 If SrcUrl.StartsWith("http") Then
3047 If "http://is.gd/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3048 ' 明らかに長くなると推測できる場合は圧縮しない
3052 If Not (New HttpVarious).PostData("http://is.gd/api.php?longurl=" + SrcUrl, Nothing, content) Then
3053 Return "Can't convert"
3056 If Not content.StartsWith("http://is.gd/") Then
3057 Return "Can't convert"
3059 Case UrlConverter.Twurl
3060 If SrcUrl.StartsWith("http") Then
3061 If "http://twurl.nl/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3062 ' 明らかに長くなると推測できる場合は圧縮しない
3066 param.Add("link[url]", SrcUrl)
3067 If Not (New HttpVarious).PostData("http://tweetburner.com/links", param, content) Then
3068 Return "Can't convert"
3071 If Not content.StartsWith("http://twurl.nl/") Then
3072 Return "Can't convert"
3074 Case UrlConverter.Unu
3075 If SrcUrl.StartsWith("http") Then
3076 If "http://u.nu/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3077 ' 明らかに長くなると推測できる場合は圧縮しない
3081 If Not (New HttpVarious).PostData("http://u.nu/unu-api-simple?url=" + SrcUrl, Nothing, content) Then
3082 Return "Can't convert"
3085 If Not content.StartsWith("http://u.nu") Then
3086 Return "Can't convert"
3088 Case UrlConverter.Bitly, UrlConverter.Jmp
3089 Dim BitlyLogin As String = "tweenapi"
3090 Dim BitlyApiKey As String = "R_c5ee0e30bdfff88723c4457cc331886b"
3091 If _bitlyId <> "" Then
3092 BitlyLogin = _bitlyId
3093 BitlyApiKey = _bitlyKey
3095 Const BitlyApiVersion As String = "2.0.1"
3096 If SrcUrl.StartsWith("http") Then
3097 If "http://bit.ly/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3098 ' 明らかに長くなると推測できる場合は圧縮しない
3102 Dim req As String = ""
3103 If ConverterType = UrlConverter.Bitly Then
3104 req = "http://api.bit.ly/shorten?version="
3106 req = "http://api.j.mp/shorten?version="
3108 req += BitlyApiVersion + _
3109 "&login=" + BitlyLogin + _
3110 "&apiKey=" + BitlyApiKey + _
3111 "&longUrl=" + SrcUrl
3112 If BitlyLogin <> "tweenapi" Then req += "&history=1"
3113 If Not (New HttpVarious).PostData(req, Nothing, content) Then
3114 Return "Can't convert"
3116 'Dim rx As Regex = New Regex("""shortUrl"": ""(?<ShortUrl>.*?)""")
3117 If Regex.Match(content, """shortUrl"": ""(?<ShortUrl>.*?)""").Success Then
3118 content = Regex.Match(content, """shortUrl"": ""(?<ShortUrl>.*?)""").Groups("ShortUrl").Value
3122 If Not content.StartsWith("http://bit.ly") AndAlso Not content.StartsWith("http://j.mp") Then
3123 Return "Can't convert"
3127 Dim ch As Char() = {ControlChars.Cr, ControlChars.Lf}
3128 content = content.TrimEnd(ch)
3129 If src.Length < content.Length Then content = src ' 圧縮の結果逆に長くなった場合は圧縮前のURLを返す
3133 'Public Function MakeShortNicoms(ByVal SrcUrl As String) As String
3134 ' Dim content As String = ""
3136 ' If Not (New HttpVarious).GetData("http://nico.ms/q/" + SrcUrl, Nothing, content) Then
3137 ' Return "Can't convert"
3140 ' If content.StartsWith("http") Then
3143 ' Return "Can't convert"
3149 Public Function GetVersionInfo() As String
3150 Dim content As String = ""
3151 If Not (New HttpVarious).GetData("http://tween.sourceforge.jp/version2.txt?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), Nothing, content) Then
3152 Throw New Exception("GetVersionInfo Failed")
3157 Public Function GetTweenBinary(ByVal strVer As String) As String
3159 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/Tween" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3160 Path.Combine(Application.StartupPath(), "TweenNew.exe")) Then
3161 Return "Err:Download failed"
3163 If Directory.Exists(Path.Combine(Application.StartupPath(), "en")) = False Then
3164 Directory.CreateDirectory(Path.Combine(Application.StartupPath(), "en"))
3166 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenRes" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3167 Path.Combine(Application.StartupPath(), "en\Tween.resourcesNew.dll")) Then
3168 Return "Err:Download failed"
3170 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenUp.gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3171 Path.Combine(Application.StartupPath(), "TweenUp.exe")) Then
3172 Return "Err:Download failed"
3174 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenDll" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3175 Path.Combine(Application.StartupPath(), "TweenNew.XmlSerializers.dll")) Then
3176 Return "Err:Download failed"
3179 Catch ex As Exception
3180 Return "Err:Download failed"
3185 Public WriteOnly Property ListIcon() As ImageList
3186 Set(ByVal value As ImageList)
3191 Public WriteOnly Property DetailIcon() As Dictionary(Of String, Image)
3192 Set(ByVal value As Dictionary(Of String, Image))
3197 'Public Property DefaultTimeOut() As Integer
3199 ' Return _defaultTimeOut
3201 ' Set(ByVal value As Integer)
3202 ' _defaultTimeOut = value
3206 Public WriteOnly Property CountApi() As Integer
3208 Set(ByVal value As Integer)
3213 Public WriteOnly Property CountApiReply() As Integer
3215 Set(ByVal value As Integer)
3216 _countApiReply = value
3220 ' Public WriteOnly Property UsePostMethod() As Boolean
3221 ' Set(ByVal value As Boolean)
3222 ' _usePostMethod = False
3224 ' 'POSTメソッドが弾かれるためGETに固定(2009/4/9)
3226 ' _ApiMethod = MySocket.REQ_TYPE.ReqPOSTAPI
3228 ' _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
3231 ' _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
3236 Public Property ReadOwnPost() As Boolean
3240 Set(ByVal value As Boolean)
3241 _readOwnPost = value
3245 Public ReadOnly Property FollowersCount() As Integer
3247 Return _followersCount
3251 Public ReadOnly Property FriendsCount() As Integer
3253 Return _friendsCount
3257 Public ReadOnly Property StatusesCount() As Integer
3259 Return _statusesCount
3263 Public ReadOnly Property Location() As String
3269 Public ReadOnly Property Bio() As String
3275 Public WriteOnly Property UseSsl() As Boolean
3276 Set(ByVal value As Boolean)
3277 HttpTwitter.UseSsl = value
3279 _protocol = "https://"
3281 _protocol = "http://"
3286 Public WriteOnly Property BitlyId() As String
3287 Set(ByVal value As String)
3292 Public WriteOnly Property BitlyKey() As String
3293 Set(ByVal value As String)
3298 Public Function GetTimelineApi(ByVal read As Boolean, _
3299 ByVal gType As WORKERTYPE, _
3300 ByVal more As Boolean) As String
3302 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3304 If _endingFlag Then Return ""
3306 Dim countQuery As Integer
3307 Dim res As HttpStatusCode
3308 Dim content As String = ""
3310 If gType = WORKERTYPE.Timeline Then
3312 res = twCon.HomeTimeline(_countApi, minHomeTimeline, 0, content)
3314 res = twCon.HomeTimeline(_countApi, 0, 0, content)
3316 countQuery = _countApi
3319 res = twCon.Mentions(_countApiReply, minMentions, 0, content)
3321 res = twCon.Mentions(_countApiReply, 0, 0, content)
3323 countQuery = _countApiReply
3325 Catch ex As Exception
3326 Return "Err:" + ex.Message
3329 Case HttpStatusCode.OK
3330 Case HttpStatusCode.Unauthorized
3331 Twitter.AccountState = ACCOUNT_STATE.Invalid
3332 Return "Check your Username/Password."
3333 Case HttpStatusCode.BadRequest
3334 Return "Err:API Limits?"
3336 Return "Err:" + res.ToString()
3339 Dim arIdx As Integer = -1
3340 Dim dlgt(countQuery) As GetIconImageDelegate 'countQueryに合わせる
3341 Dim ar(countQuery) As IAsyncResult 'countQueryに合わせる
3342 Dim xdoc As New XmlDocument
3344 xdoc.LoadXml(content)
3345 Catch ex As Exception
3347 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3348 Return "Invalid XML!"
3351 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3352 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3353 Dim post As New PostClass
3355 post.Id = Long.Parse(xentry.Item("id").InnerText)
3356 If gType = WORKERTYPE.Timeline Then
3357 If minHomeTimeline > post.Id Then minHomeTimeline = post.Id
3359 If minMentions > post.Id Then minMentions = post.Id
3363 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3366 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3367 If xRnode IsNot Nothing Then
3368 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3369 post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3371 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3373 post.Data = xRentry.Item("text").InnerText
3374 'Source取得(htmlの場合は、中身を取り出し)
3375 post.Source = xRentry.Item("source").InnerText
3377 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3378 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3379 'post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
3380 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3383 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3384 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3385 post.Name = xRUentry.Item("screen_name").InnerText
3386 post.Nickname = xRUentry.Item("name").InnerText
3387 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3388 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3389 post.IsMe = post.Name.ToLower.Equals(_uid)
3392 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3393 post.RetweetedBy = xUentry.Item("screen_name").InnerText
3395 post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3397 post.Data = xentry.Item("text").InnerText
3398 'Source取得(htmlの場合は、中身を取り出し)
3399 post.Source = xentry.Item("source").InnerText
3400 Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3401 post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3402 'in_reply_to_user_idを使うか?
3403 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3406 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3407 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3408 post.Name = xUentry.Item("screen_name").InnerText
3409 post.Nickname = xUentry.Item("name").InnerText
3410 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3411 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3412 post.IsMe = post.Name.ToLower.Equals(_uid)
3415 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3416 post.Data = HttpUtility.HtmlDecode(post.Data)
3417 post.Data = post.Data.Replace("<3", "♡")
3419 If post.Source.StartsWith("<") Then
3420 'Dim rgS As New Regex(">(?<source>.+)<")
3421 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
3423 post.Source = mS.Result("${source}")
3428 If gType = WORKERTYPE.Timeline Then
3429 post.IsReply = post.ReplyToList.Contains(_uid)
3437 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3439 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3442 Catch ex As Exception
3444 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3448 '非同期アイコン取得&StatusDictionaryに追加
3450 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3451 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3455 For i As Integer = 0 To arIdx
3457 dlgt(i).EndInvoke(ar(i))
3458 Catch ex As Exception
3459 '最後までendinvoke回す(ゾンビ化回避)
3460 ex.Data("IsTerminatePermission") = False
3465 'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3470 Public Function GetSearch(ByVal read As Boolean, _
3471 ByVal tab As TabClass, _
3472 ByVal more As Boolean) As String
3474 If _endingFlag Then Return ""
3476 Dim res As HttpStatusCode
3477 Dim content As String = ""
3478 Dim page As Integer = 0
3479 If more Then page = tab.SearchPage
3481 res = twCon.Search(tab.SearchWords, tab.SearchLang, 40, page, content)
3482 Catch ex As Exception
3483 Return "Err:" + ex.Message
3486 Case HttpStatusCode.BadRequest
3487 Return "Invalid query"
3488 Case HttpStatusCode.NotFound
3489 Return "Invalid query"
3490 Case HttpStatusCode.PaymentRequired 'API Documentには420と書いてあるが、該当コードがないので402にしてある
3491 Return "Search API Limit?"
3492 Case HttpStatusCode.OK
3494 Return "Err:" + res.ToString
3497 If Not TabInformations.GetInstance.ContainsTab(tab) Then Return ""
3499 Dim arIdx As Integer = -1
3500 Dim dlgt(40) As GetIconImageDelegate 'countQueryに合わせる
3501 Dim ar(40) As IAsyncResult 'countQueryに合わせる
3502 Dim xdoc As New XmlDocument
3504 xdoc.LoadXml(content)
3505 Catch ex As Exception
3507 Return "Invalid ATOM!"
3509 Dim nsmgr As New XmlNamespaceManager(xdoc.NameTable)
3510 nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom")
3511 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr)
3512 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3513 Dim post As New PostClass
3515 post.Id = Long.Parse(xentry.Item("id").InnerText.Split(":"c)(2))
3516 If TabInformations.GetInstance.ContainsKey(post.Id, tab.TabName) Then Continue For
3517 post.PDate = DateTime.Parse(xentry.Item("published").InnerText)
3519 post.Data = xentry.Item("title").InnerText
3520 'Source取得(htmlの場合は、中身を取り出し)
3521 post.Source = xentry.Item("twitter:source").InnerText
3522 post.InReplyToId = 0
3523 post.InReplyToUser = ""
3527 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./search:author", nsmgr), XmlElement)
3529 post.Name = xUentry.Item("name").InnerText.Split(" "c)(0).Trim
3530 post.Nickname = xUentry.Item("name").InnerText.Substring(post.Name.Length).Trim
3531 If post.Nickname.Length > 2 Then
3532 post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2)
3534 post.Nickname = post.Name
3536 post.ImageUrl = CType(xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr), XmlElement).GetAttribute("href")
3537 post.IsProtect = False
3538 post.IsMe = post.Name.ToLower.Equals(_uid)
3541 post.OriginalData = CreateHtmlAnchor(HttpUtility.HtmlEncode(post.Data), post.ReplyToList)
3542 post.Data = HttpUtility.HtmlDecode(post.Data)
3544 If post.Source.StartsWith("<") Then
3545 'Dim rgS As New Regex(">(?<source>.+)<")
3546 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
3548 post.Source = mS.Result("${source}")
3553 post.IsReply = post.ReplyToList.Contains(_uid)
3556 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3558 post.SearchTabName = tab.TabName
3559 Catch ex As Exception
3564 '非同期アイコン取得&StatusDictionaryに追加
3566 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3567 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3571 '' 遡るための情報max_idやnext_pageの情報を保持する
3574 For i As Integer = 0 To arIdx
3576 dlgt(i).EndInvoke(ar(i))
3577 Catch ex As Exception
3578 '最後までendinvoke回す(ゾンビ化回避)
3579 ex.Data("IsTerminatePermission") = False
3587 Public Function GetDirectMessageApi(ByVal read As Boolean, _
3588 ByVal gType As WORKERTYPE, _
3589 ByVal more As Boolean) As String
3590 If _endingFlag Then Return ""
3592 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3594 Dim res As HttpStatusCode
3595 Dim content As String = ""
3598 If gType = WORKERTYPE.DirectMessegeRcv Then
3600 res = twCon.DirectMessages(20, minDirectmessage, 0, content)
3602 res = twCon.DirectMessages(20, 0, 0, content)
3606 res = twCon.DirectMessagesSent(20, minDirectmessageSent, 0, content)
3608 res = twCon.DirectMessagesSent(20, 0, 0, content)
3611 Catch ex As Exception
3612 Return "Err:" + ex.Message
3616 Case HttpStatusCode.OK
3617 Case HttpStatusCode.Unauthorized
3618 Twitter.AccountState = ACCOUNT_STATE.Invalid
3619 Return "Check your Username/Password."
3620 Case HttpStatusCode.BadRequest
3621 Return "Err:API Limits?"
3623 Return "Err:" + res.ToString()
3626 Dim arIdx As Integer = -1
3627 Dim dlgt(20) As GetIconImageDelegate 'countQueryに合わせる
3628 Dim ar(20) As IAsyncResult 'countQueryに合わせる
3629 Dim xdoc As New XmlDocument
3631 xdoc.LoadXml(content)
3632 Catch ex As Exception
3634 'MessageBox.Show("不正なXMLです。(DM-LoadXml)")
3635 Return "Invalid XML!"
3638 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./direct_message")
3639 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3640 Dim post As New PostClass
3642 post.Id = Long.Parse(xentry.Item("id").InnerText)
3643 If gType = WORKERTYPE.DirectMessegeRcv Then
3644 If minDirectmessage > post.Id Then minDirectmessage = post.Id
3646 If minDirectmessageSent > post.Id Then minDirectmessageSent = post.Id
3650 If TabInformations.GetInstance.GetTabByType(TabUsageType.DirectMessage).Contains(post.Id) Then Continue For
3654 post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3656 post.Data = xentry.Item("text").InnerText
3658 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3659 post.Data = HttpUtility.HtmlDecode(post.Data)
3660 post.Data = post.Data.Replace("<3", "♡")
3663 If gType = WORKERTYPE.DirectMessegeRcv Then
3670 Dim xUentry As XmlElement
3671 If gType = WORKERTYPE.DirectMessegeRcv Then
3672 xUentry = CType(xentry.SelectSingleNode("./sender"), XmlElement)
3675 xUentry = CType(xentry.SelectSingleNode("./recipient"), XmlElement)
3678 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3679 post.Name = xUentry.Item("screen_name").InnerText
3680 post.Nickname = xUentry.Item("name").InnerText
3681 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3682 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3683 Catch ex As Exception
3685 'MessageBox.Show("不正なXMLです。(DM-Parse)")
3690 post.IsReply = False
3693 '非同期アイコン取得&StatusDictionaryに追加
3695 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3696 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3700 For i As Integer = 0 To arIdx
3702 dlgt(i).EndInvoke(ar(i))
3703 Catch ex As Exception
3704 '最後までendinvoke回す(ゾンビ化回避)
3705 ex.Data("IsTerminatePermission") = False
3710 '_remainCountApi = sck.RemainCountApi
3711 'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3716 Public Function GetFavoritesApi(ByVal read As Boolean, _
3717 ByVal gType As WORKERTYPE) As String
3719 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3721 If _endingFlag Then Return ""
3723 Dim res As HttpStatusCode
3724 Dim content As String = ""
3726 res = twCon.Favorites(_countApi, content)
3727 Catch ex As Exception
3728 Return "Err:" + ex.Message
3732 Case HttpStatusCode.OK
3733 Case HttpStatusCode.Unauthorized
3734 Twitter.AccountState = ACCOUNT_STATE.Invalid
3735 Return "Check your Username/Password."
3736 Case HttpStatusCode.BadRequest
3737 Return "Err:API Limits?"
3739 Return "Err:" + res.ToString()
3742 Dim arIdx As Integer = -1
3743 Dim dlgt(_countApi) As GetIconImageDelegate 'countQueryに合わせる
3744 Dim ar(_countApi) As IAsyncResult 'countQueryに合わせる
3745 Dim xdoc As New XmlDocument
3747 xdoc.LoadXml(content)
3748 Catch ex As Exception
3750 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3751 Return "Invalid XML!"
3754 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3755 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3756 Dim post As New PostClass
3758 post.Id = Long.Parse(xentry.Item("id").InnerText)
3759 If minFavorites > post.Id Then minFavorites = post.Id
3762 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3765 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3766 If xRnode IsNot Nothing Then
3767 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3768 post.PDate = DateTime.ParseExact(xRentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3770 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3772 post.Data = xRentry.Item("text").InnerText
3773 'Source取得(htmlの場合は、中身を取り出し)
3774 post.Source = xRentry.Item("source").InnerText
3776 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3777 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3778 'in_reply_to_user_idを使うか?
3779 post.IsFav = Boolean.Parse(xRentry.Item("favorited").InnerText)
3782 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3783 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3784 post.Name = xRUentry.Item("screen_name").InnerText
3785 post.Nickname = xRUentry.Item("name").InnerText
3786 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3787 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3788 post.IsMe = post.Name.ToLower.Equals(_uid)
3791 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3792 post.RetweetedBy = xUentry.Item("screen_name").InnerText
3794 post.PDate = DateTime.ParseExact(xentry.Item("created_at").InnerText, "ddd MMM dd HH:mm:ss zzzz yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None)
3796 post.Data = xentry.Item("text").InnerText
3797 'Source取得(htmlの場合は、中身を取り出し)
3798 post.Source = xentry.Item("source").InnerText
3799 Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3800 post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3801 'in_reply_to_user_idを使うか?
3802 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3805 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3806 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3807 post.Name = xUentry.Item("screen_name").InnerText
3808 post.Nickname = xUentry.Item("name").InnerText
3809 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3810 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3811 post.IsMe = post.Name.ToLower.Equals(_uid)
3814 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3815 post.Data = HttpUtility.HtmlDecode(post.Data)
3816 post.Data = post.Data.Replace("<3", "♡")
3818 If post.Source.StartsWith("<") Then
3819 'Dim rgS As New Regex(">(?<source>.+)<")
3820 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
3822 post.Source = mS.Result("${source}")
3827 post.IsReply = post.ReplyToList.Contains(_uid)
3832 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3836 Catch ex As Exception
3838 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3842 '非同期アイコン取得&StatusDictionaryに追加
3844 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3845 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3849 For i As Integer = 0 To arIdx
3851 dlgt(i).EndInvoke(ar(i))
3852 Catch ex As Exception
3853 '最後までendinvoke回す(ゾンビ化回避)
3854 ex.Data("IsTerminatePermission") = False
3859 '_remainCountApi = sck.RemainCountApi
3860 'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3865 Public Function GetFollowersApi() As String
3866 If _endingFlag Then Return ""
3867 Dim cursor As Long = -1
3868 Dim tmpFollower As New List(Of Long)(followerId)
3872 Dim ret As String = FollowerApi(cursor)
3875 followerId.AddRange(tmpFollower)
3878 Loop While cursor > 0
3880 TabInformations.GetInstance.RefreshOwl(followerId)
3885 Private Function FollowerApi(ByRef cursor As Long) As String
3886 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3888 Dim res As HttpStatusCode
3889 Dim content As String = ""
3891 res = twCon.FollowerIds(cursor, content)
3892 Catch ex As Exception
3893 Return "Err:" + ex.Message
3897 Case HttpStatusCode.OK
3898 Case HttpStatusCode.Unauthorized
3899 Twitter.AccountState = ACCOUNT_STATE.Invalid
3900 Return "Check your Username/Password."
3901 Case HttpStatusCode.BadRequest
3902 Return "Err:API Limits?"
3904 Return "Err:" + res.ToString()
3907 Dim xdoc As New XmlDocument
3909 xdoc.LoadXml(content)
3910 Catch ex As Exception
3912 Return "Invalid XML!"
3916 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/id_list/ids/id")
3917 followerId.Add(Long.Parse(xentryNode.InnerText))
3919 cursor = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/id_list/next_cursor").InnerText)
3920 Catch ex As Exception
3922 Return "Invalid XML!"
3929 Public Function GetListsApi() As String
3930 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3932 Dim res As HttpStatusCode
3933 Dim content As String = ""
3934 Dim cursor As Long = -1
3936 Dim lists As New List(Of ListElement)
3939 res = twCon.GetLists(Me.Username, cursor, content)
3940 Catch ex As Exception
3941 Return "Err:" + ex.Message
3945 Case HttpStatusCode.OK
3946 Case HttpStatusCode.Unauthorized
3947 Twitter.AccountState = ACCOUNT_STATE.Invalid
3948 Return "Check your Username/Password."
3949 Case HttpStatusCode.BadRequest
3950 Return "Err:API Limits?"
3952 Return "Err:" + res.ToString()
3955 Dim xdoc As New XmlDocument
3957 xdoc.LoadXml(content)
3958 Catch ex As Exception
3960 Return "Invalid XML!"
3964 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/lists_list/lists/list")
3965 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3966 Dim lst As New ListElement
3967 lst.Description = xentry.Item("description").InnerText
3968 lst.Id = Long.Parse(xentry.Item("id").InnerText)
3969 lst.IsPublic = (xentry.Item("mode").InnerText = "public")
3970 lst.MemberCount = Integer.Parse(xentry.Item("member_count").InnerText)
3971 lst.Name = xentry.Item("name").InnerText
3972 lst.SubscriberCount = Integer.Parse(xentry.Item("subscriber_count").InnerText)
3973 lst.Slug = xentry.Item("slug").InnerText
3974 Dim xUserEntry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3975 lst.Nickname = xUserEntry.Item("name").InnerText
3976 lst.Username = xUserEntry.Item("screen_name").InnerText
3977 lst.UserId = Long.Parse(xUserEntry.Item("id").InnerText)
3980 cursor = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/lists_list/next_cursor").InnerText)
3981 Catch ex As Exception
3983 Return "Invalid XML!"
3985 Loop While cursor <> 0
3991 res = twCon.GetListsSubscriptions(Me.Username, cursor, content)
3992 Catch ex As Exception
3993 Return "Err:" + ex.Message
3997 Case HttpStatusCode.OK
3998 Case HttpStatusCode.Unauthorized
3999 Twitter.AccountState = ACCOUNT_STATE.Invalid
4000 Return "Check your Username/Password."
4001 Case HttpStatusCode.BadRequest
4002 Return "Err:API Limits?"
4004 Return "Err:" + res.ToString()
4007 Dim xdoc As New XmlDocument
4009 xdoc.LoadXml(content)
4010 Catch ex As Exception
4012 Return "Invalid XML!"
4016 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/lists_list/lists/list")
4017 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
4018 Dim lst As New ListElement
4019 lst.Description = xentry.Item("description").InnerText
4020 lst.Id = Long.Parse(xentry.Item("id").InnerText)
4021 lst.IsPublic = (xentry.Item("mode").InnerText = "public")
4022 lst.MemberCount = Integer.Parse(xentry.Item("member_count").InnerText)
4023 lst.Name = xentry.Item("name").InnerText
4024 lst.SubscriberCount = Integer.Parse(xentry.Item("subscriber_count").InnerText)
4025 lst.Slug = xentry.Item("slug").InnerText
4026 Dim xUserEntry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
4027 lst.Nickname = xUserEntry.Item("name").InnerText
4028 lst.Username = xUserEntry.Item("screen_name").InnerText
4029 lst.UserId = Long.Parse(xUserEntry.Item("id").InnerText)
4032 cursor = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/lists_list/next_cursor").InnerText)
4033 Catch ex As Exception
4035 Return "Invalid XML!"
4037 Loop While cursor <> 0
4043 Private Function CreateHtmlAnchor(ByVal Text As String, ByVal AtList As List(Of String)) As String
4044 'Dim retStr As String = HttpUtility.HtmlEncode(Text) '要検証(デコードされて取得されるので再エンコード)
4045 'Dim retStr As String = HttpUtility.HtmlDecode(Text)
4046 Dim retStr As String = ""
4048 'Dim rgUrl As Regex = New Regex("(?<![0-9A-Za-z=])(?:https?|shttp|ftps?)://(?:(?:[-_.!~*'()a-zA-Z0-9;:&=+$,]|%[0-9A-Fa-f" + _
4049 ' "][0-9A-Fa-f])*@)?(?:(?:[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.)" + _
4050 ' "*[a-zA-Z](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.?|[0-9]+\.[0-9]+\.[0-9]+\." + _
4051 ' "[0-9]+)(?::[0-9]*)?(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f]" + _
4052 ' "[0-9A-Fa-f])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-" + _
4053 ' "Fa-f])*)*(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f" + _
4054 ' "])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)*)" + _
4055 ' "*)?(?:\?(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])" + _
4056 ' "*)?(?:#(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)?")
4057 Const rgUrl As String = "(?<before>(?:[^\/""':!=]|^|\:))" + _
4058 "(?<url>(?<protocol>https?://|www\.)" + _
4059 "(?<domain>(?:[\.-]|[^\p{P}])+\.[a-z]{2,}(?::[0-9]+)?)" + _
4060 "(?<path>/[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9)=#/]?)?" + _
4061 "(?<query>\?[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9_&=#])?)"
4063 retStr = Regex.Replace(Text, rgUrl, New MatchEvaluator(AddressOf AutoLinkUrl), RegexOptions.IgnoreCase)
4066 'Dim rg As New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,24}[a-zA-Z0-9_])")
4067 'Dim rg As New Regex("(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,79}[a-zA-Z0-9_])", RegexOptions.Compiled)
4068 'Dim m As Match = Regex.Match(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,79}[a-zA-Z0-9_])")
4070 retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,79}[a-zA-Z0-9_])", "$1@<a href=""/$2"">$2</a>")
4072 'rg = New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20})")
4073 'rg = New Regex("(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})", RegexOptions.Compiled)
4074 Dim m As Match = Regex.Match(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})")
4076 AtList.Add(m.Result("$2").ToLower)
4080 retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})", "$1@<a href=""/$2"">$2</a>")
4083 'Dim rgh As New Regex("(^|[ .!,\-:;<>?])#([^] !""#$%&'()*+,.:;<=>?@\-[\^`{|}~\r\n]+)")
4084 'Dim rgh As New Regex("(^|[^a-zA-Z0-9_/&])[##]([a-zA-Z0-9_]+)", RegexOptions.Compiled)
4085 Dim mhs As MatchCollection = Regex.Matches(retStr, "(^|[^a-zA-Z0-9_/&])[##]([a-zA-Z0-9_]+)")
4086 For Each mt As Match In mhs
4087 If Not IsNumeric(mt.Result("$2")) Then
4088 'retStr = retStr.Replace(mt.Result("$1") + mt.Result("$2"), "<a href=""" + _protocol + "twitter.com/search?q=%23" + mt.Result("$2") + """>#" + mt.Result("$2") + "</a>")
4090 _hashList.Add("#" + mt.Result("$2"))
4094 retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_/&])[##]([a-zA-Z0-9_]+)", New MatchEvaluator(AddressOf AutoLinkHashtag))
4096 retStr = AdjustHtml(ShortUrlResolve(PreProcessUrl(retStr))) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
4100 Private Function AutoLinkUrl(ByVal m As Match) As String
4101 Dim sb As New StringBuilder(m.Result("${before}<a href="""))
4102 If m.Result("${protocol}").StartsWith("w", StringComparison.OrdinalIgnoreCase) Then
4103 sb.Append("http://")
4105 sb.Append(m.Result("${url}"">")).Append(m.Result("${url}")).Append("</a>")
4109 Private Function AutoLinkHashtag(ByVal m As Match) As String
4110 If IsNumeric(m.Result("$2")) Then Return m.Result("$1#$2")
4111 Dim sb As New StringBuilder(m.Result("$1<a href="""))
4112 Return sb.Append(_protocol).Append("twitter.com/search?q=%23").Append(m.Result("$2"">#$2</a>")).ToString
4115 Public ReadOnly Property RemainCountApi() As Integer
4117 Return twCon.RemainCountApi
4121 Public Function GetInfoApi(ByRef info As ApiInfo) As Boolean
4122 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return True
4124 If _endingFlag Then Return True
4126 'info.MaxCount = twCon.UpperCountApi
4127 'info.RemainCount = twCon.RemainCountApi
4128 'info.ResetTime = twCon.ResetTimeApi
4130 Dim res As HttpStatusCode
4131 Dim content As String = ""
4133 res = twCon.RateLimitStatus(content)
4134 Catch ex As Exception
4138 If res <> HttpStatusCode.OK Then Return False
4140 Dim xdoc As New XmlDocument
4142 xdoc.LoadXml(content)
4143 info.MaxCount = Integer.Parse(xdoc.SelectSingleNode("/hash/hourly-limit").InnerText)
4144 info.RemainCount = Integer.Parse(xdoc.SelectSingleNode("/hash/remaining-hits").InnerText)
4145 info.ResetTime = DateTime.Parse(xdoc.SelectSingleNode("/hash/reset-time").InnerText)
4146 'info.ResetTimeInSeconds = Integer.Parse(xdoc.SelectSingleNode("/hash/reset-time-in-seconds").InnerText)
4148 Catch ex As Exception
4153 Public Function GetHashList() As String()
4154 Dim hashArray As String()
4156 hashArray = _hashList.ToArray
4162 '#Region "デバッグモード解析キー自動生成"
4164 ' Public Sub GenerateAnalyzeKey()
4165 ' '解析キー情報部分のソースをwedataから作成する
4166 ' '生成したソースはプロジェクトのディレクトリにコピーする
4167 ' Dim sw As New System.IO.StreamWriter(".\AnalyzeKey.vb", _
4169 ' System.Text.Encoding.UTF8)
4171 ' sw.WriteLine("Public Module AnalyzeKey")
4172 ' sw.WriteLine("' このファイルはデバッグビルドのTweenにより自動作成されました 作成日時 " + DateAndTime.Now.ToString())
4175 ' sw.WriteLine(" Public _splitPost As String = " + Chr(34) + _splitPost.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4176 ' sw.WriteLine(" Public _splitPostRecent As String = " + Chr(34) + _splitPostRecent.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4177 ' sw.WriteLine(" Public _statusIdTo As String = " + Chr(34) + _statusIdTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4178 ' sw.WriteLine(" Public _splitDM As String = " + Chr(34) + _splitDM.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4179 ' sw.WriteLine(" Public _parseName As String = " + Chr(34) + _parseName.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4180 ' sw.WriteLine(" Public _parseNameTo As String = " + Chr(34) + _parseNameTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4181 ' sw.WriteLine(" Public _parseNick As String = " + Chr(34) + _parseNick.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4182 ' sw.WriteLine(" Public _parseNickTo As String = " + Chr(34) + _parseNickTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4183 ' sw.WriteLine(" Public _parseImg As String = " + Chr(34) + _parseImg.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4184 ' sw.WriteLine(" Public _parseImgTo As String = " + Chr(34) + _parseImgTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4185 ' sw.WriteLine(" Public _parseMsg1 As String = " + Chr(34) + _parseMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4186 ' sw.WriteLine(" Public _parseMsg2 As String = " + Chr(34) + _parseMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4187 ' sw.WriteLine(" Public _parseDM1 As String = " + Chr(34) + _parseDM1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4188 ' sw.WriteLine(" Public _parseDM11 As String = " + Chr(34) + _parseDM11.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4189 ' sw.WriteLine(" Public _parseDM2 As String = " + Chr(34) + _parseDM2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4190 ' sw.WriteLine(" Public _parseDate As String = " + Chr(34) + _parseDate.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4191 ' sw.WriteLine(" Public _parseDateTo As String = " + Chr(34) + _parseDateTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4192 ' sw.WriteLine(" Public _getAuthKey As String = " + Chr(34) + _getAuthKey.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4193 ' sw.WriteLine(" Public _getAuthKeyTo As String = " + Chr(34) + _getAuthKeyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4194 ' 'sw.WriteLine(" Public _parseStar As String = " + Chr(34) + _parseStar.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4195 ' 'sw.WriteLine(" Public _parseStarTo As String = " + Chr(34) + _parseStarTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4196 ' 'sw.WriteLine(" Public _parseStarEmpty As String = " + Chr(34) + _parseStarEmpty.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4197 ' sw.WriteLine(" Public _followerList As String = " + Chr(34) + _followerList.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4198 ' sw.WriteLine(" Public _followerMbr1 As String = " + Chr(34) + _followerMbr1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4199 ' sw.WriteLine(" Public _followerMbr2 As String = " + Chr(34) + _followerMbr2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4200 ' sw.WriteLine(" Public _followerMbr3 As String = " + Chr(34) + _followerMbr3.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4201 ' sw.WriteLine(" Public _getInfoTwitter As String = " + Chr(34) + _getInfoTwitter.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4202 ' sw.WriteLine(" Public _getInfoTwitterTo As String = " + Chr(34) + _getInfoTwitterTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4203 ' sw.WriteLine(" Public _isProtect As String = " + Chr(34) + _isProtect.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4204 ' sw.WriteLine(" Public _isReplyEng As String = " + Chr(34) + _isReplyEng.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4205 ' sw.WriteLine(" Public _isReplyJpn As String = " + Chr(34) + _isReplyJpn.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4206 ' sw.WriteLine(" Public _isReplyTo As String = " + Chr(34) + _isReplyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4207 ' sw.WriteLine(" Public _parseProtectMsg1 As String = " + Chr(34) + _parseProtectMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4208 ' sw.WriteLine(" Public _parseProtectMsg2 As String = " + Chr(34) + _parseProtectMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4209 ' sw.WriteLine(" Public _parseDMcountFrom As String = " + Chr(34) + _parseDMcountFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4210 ' sw.WriteLine(" Public _parseDMcountTo As String = " + Chr(34) + _parseDMcountTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4211 ' sw.WriteLine(" Public _parseSourceFrom As String = " + Chr(34) + _parseSourceFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4212 ' sw.WriteLine(" Public _parseSource2 As String = " + Chr(34) + _parseSource2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4213 ' sw.WriteLine(" Public _parseSourceTo As String = " + Chr(34) + _parseSourceTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4214 ' sw.WriteLine(" Public _removeClass As String = " + Chr(34) + _removeClass.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4215 ' sw.WriteLine("End Module")
4218 ' 'MessageBox.Show("解析キー情報定義ファイル AnalyzeKey.vbを生成しました")
4224 Public ReadOnly Property AccessToken() As String
4226 Return twCon.AccessToken
4230 Public ReadOnly Property AccessTokenSecret() As String
4232 Return twCon.AccessTokenSecret