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/", _
141 Private Const _apiHost As String = "api."
142 Private Const _baseUrlStr As String = "twitter.com"
143 'Private Const _loginPath As String = "/sessions"
144 'Private Const _homePath As String = "/home"
145 'Private Const _replyPath As String = "/replies"
146 'Private Const _DMPathRcv As String = "/inbox"
147 'Private Const _DMPathSnt As String = "/sent"
148 Private Const _DMDestroyPath As String = "/1/direct_messages/destroy/"
149 Private Const _StDestroyPath As String = "/1/statuses/destroy/"
150 Private Const _postRetweetPath As String = "/1/statuses/retweet/"
151 Private Const _uidHeader As String = "session[username_or_email]="
152 Private Const _pwdHeader As String = "session[password]="
153 Private Const _pageQry As String = "?page="
154 Private Const _cursorQry As String = "?cursor="
155 Private Const _statusHeader As String = "status="
156 Private Const _statusUpdatePathAPI As String = "/1/statuses/update.xml"
157 'Private Const _linkToOld As String = "class=""section_links"" rel=""prev"""
158 Private Const _postFavAddPath As String = "/1/favorites/create/"
159 Private Const _postFavRemovePath As String = "/1/favorites/destroy/"
160 'Private Const _authKeyHeader As String = "authenticity_token="
161 'Private Const _parseLink1 As String = "<a href="""
162 'Private Const _parseLink2 As String = """>"
163 'Private Const _parseLink3 As String = "</a>"
164 Private Const _GetFollowers As String = "/1/statuses/followers.xml"
165 Private Const _ShowStatus As String = "/1/statuses/show/"
166 Private Const _rateLimitStatus As String = "/1/account/rate_limit_status.xml"
167 Private Const FOLLOWER_PATH As String = "/1/followers/ids.xml"
168 Private Const RECEIVE_PATH As String = "/1/direct_messages.xml"
169 Private Const SENT_PATH As String = "/1/direct_messages/sent.xml"
170 Private Const COUNT_QUERY As String = "count="
171 Private Const FAV_PATH As String = "/1/favorites.xml"
172 Private Const PATH_FRIENDSHIP As String = "/1/friendships/show.xml?source_screen_name="
173 Private Const QUERY_TARGET As String = "&target_screen_name="
174 Private Const FRIEND_PATH As String = "/1/statuses/home_timeline.xml"
175 Private Const REPLY_PATH As String = "/1/statuses/mentions.xml"
176 Private Const PATH_FOLLOW As String = "/1/friendships/create.xml?screen_name="
177 Private Const PATH_REMOVE As String = "/1/friendships/destroy.xml?screen_name="
182 '''OAuthのアクセストークン取得先URI
184 Private Const AccessTokenUrl As String = "http://twitter.com/oauth/access_token"
187 '''OAuthのリクエストトークン取得先URI
189 Private Const RequestTokenUrl As String = "http://twitter.com/oauth/request_token"
192 '''OAuthのユーザー認証用ページURI
195 '''クエリ「oauth_token=リクエストトークン」を付加して、このURIをブラウザで開く。ユーザーが承認操作を行うとPINコードが表示される。
197 Private Const AuthorizeUrl As String = "http://twitter.com/oauth/authorize"
200 'Private Const wedataUrl As String = "http://wedata.net/databases/Tween/items.json"
202 Private op As New Outputz
203 'max_idで古い発言を取得するために保持(lists分は個別タブで管理)
204 Private minHomeTimeline As Long = Long.MaxValue
205 Private minMentions As Long = Long.MaxValue
206 Private minDirectmessage As Long = Long.MaxValue
207 Private minDirectmessageSent As Long = Long.MaxValue
208 Private minFavorites As Long = Long.MaxValue
210 Private twCon As New HttpTwitter
212 Public Function Authenticate(ByVal username As String, ByVal password As String) As Boolean
214 Dim rslt As Boolean = twCon.AuthUserAndPass(username, password)
216 _uid = twCon.AuthenticatedUsername.ToLower
219 Catch ex As Exception
224 Public Sub ClearAuthInfo()
225 twCon.ClearAuthInfo()
228 Public Sub Initialize(ByVal token As String, ByVal tokenSecret As String, ByVal username As String)
230 twCon.Initialize(token, tokenSecret, username)
231 _uid = username.ToLower
234 Public Sub Initialize(ByVal username As String, ByVal password As String)
236 twCon.Initialize(username, password)
237 _uid = username.ToLower
240 'Private Function SignIn() As String
241 ' If _endingFlag Then Return ""
244 ' Dim account As String = ""
245 ' Static skipCount As Integer = 0
248 ' If _signed Then Return ""
249 ' If Twitter.AccountState <> ACCOUNT_STATE.Valid AndAlso skipCount < 10 Then
251 ' Return "SignIn -> Check Username/Password in setting."
258 ' MySocket.ResetCookie()
260 ' Dim resStatus As String = ""
261 ' Dim resMsg As String = ""
263 ' '設定によらずログイン処理はhttps固定
264 ' resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + "/login", resStatus, MySocket.REQ_TYPE.ReqGET), String)
265 ' If resMsg.Length = 0 Then
266 ' 'Twitter.AccountState = ACCOUNT_STATE.Invalid
267 ' Return "SignIn -> " + resStatus
269 ' Dim authToken As String = ""
270 ' Dim rg As New Regex("authenticity_token"" type=""hidden"" value=""(?<auth>[a-z0-9]+)""")
271 ' Dim m As Match = rg.Match(resMsg)
273 ' authToken = m.Result("${auth}")
275 ' Return "SignIn -> Can't get token."
278 ' account = _authKeyHeader + authToken + "&" + _uidHeader + _uid + "&" + _pwdHeader + HttpUtility.UrlEncode(_pwd) + "&" + "remember_me=1"
281 ' resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + _loginPath, resStatus, MySocket.REQ_TYPE.ReqPOST, account), String)
282 ' If resStatus.StartsWith("OK") Then
283 ' 'OK (username/passwordが合致しない)
284 ' Dim msg As String = resStatus
285 ' If resMsg.Contains("Wrong Username/Email and password combination.") Then
286 ' msg = "Wrong Username or password."
288 ' '未知の応答(May be required Chapta)
289 ' msg = "Wrong Username or password. Try from web."
291 ' Twitter.AccountState = ACCOUNT_STATE.Invalid
292 ' Return "SignIn Failed -> " + msg
293 ' ElseIf resMsg.Contains("https://twitter.com/account/locked") Then '302 FOUND
294 ' Dim msg As String = "You account is Locked Out."
295 ' Twitter.AccountState = ACCOUNT_STATE.Invalid
296 ' Return "SignIn Failed -> " + msg
297 ' ElseIf resMsg.Contains("https://twitter.com:443/") Then '302 FOUND
299 ' ElseIf resMsg.Contains("https://twitter.com/") OrElse _
300 ' resMsg.Contains("http://twitter.com/") Then '302 FOUND
302 ' ElseIf resStatus.StartsWith("Err:") Then
304 ' Return "SignIn Failed"
306 ' '応答がOK でありサインインできていない場合の未知の応答
307 ' 'TraceOut(True, "SignIn Failed." + vbCrLf + "resStatus:" + resStatus + vbCrLf + "resMsg:" + vbCrLf + resMsg)
308 ' Twitter.AccountState = ACCOUNT_STATE.Invalid
309 ' Return "SignIn Failed -> " + "Unknown problems."
311 ' Twitter.AccountState = ACCOUNT_STATE.Valid
317 'Public Function GetTimeline(ByVal page As Integer, _
318 ' ByVal read As Boolean, _
319 ' ByRef endPage As Integer, _
320 ' ByVal gType As WORKERTYPE, _
321 ' ByRef getDM As Boolean) As String
323 ' If endPage = 0 Then
325 ' Dim epage As Integer = page
326 ' GetTmSemaphore.WaitOne()
327 ' Dim trslt As String = ""
328 ' trslt = GetTimelineThread(page, read, epage, gType, getDM)
329 ' If trslt.Length > 0 Then Return trslt
331 ' If epage < page OrElse gType = WORKERTYPE.Reply Then Return ""
334 ' '起動時モード or 通常モードの読み込み継続 -> 複数ページ同時取得
335 ' Dim num As Integer = endPage - page
336 ' Dim ar(num) As IAsyncResult
337 ' Dim dlgt(num) As GetTimelineDelegate
339 ' For idx As Integer = 0 To num
340 ' dlgt(idx) = New GetTimelineDelegate(AddressOf GetTimelineThread)
341 ' GetTmSemaphore.WaitOne()
342 ' ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, getDM, Nothing, Nothing)
344 ' Dim rslt As String = ""
345 ' For idx As Integer = 0 To num
346 ' Dim epage As Integer = 0
347 ' Dim dm As Boolean = False
348 ' Dim trslt As String = ""
350 ' trslt = dlgt(idx).EndInvoke(epage, dm, ar(idx))
351 ' Catch ex As Exception
352 ' '最後までendinvoke回す(ゾンビ化回避)
353 ' ex.Data("IsTerminatePermission") = False
355 ' rslt = "GetTimelineErr"
357 ' If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
358 ' If dm Then getDM = True
363 ' Private Function GetTimelineThread(ByVal page As Integer, _
364 ' ByVal read As Boolean, _
365 ' ByRef endPage As Integer, _
366 ' ByVal gType As WORKERTYPE, _
367 ' ByRef getDM As Boolean) As String
369 ' If _endingFlag Then Return ""
371 ' Dim retMsg As String = ""
372 ' Dim resStatus As String = ""
374 ' Static redirectToTimeline As String = ""
375 ' Static redirectToReply As String = ""
377 ' If _signed = False Then
379 ' If retMsg.Length > 0 Then
384 ' If _endingFlag Then Return ""
387 ' Dim pageQuery As String
392 ' pageQuery = _pageQry + page.ToString
395 ' If gType = WORKERTYPE.Timeline Then
396 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _homePath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
398 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _replyPath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
401 ' If retMsg.Length = 0 Then
406 ' ' tr 要素の class 属性を消去
407 ' retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
410 ' ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
411 ' ' If idx = -1 Then Exit Do
412 ' ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
413 ' ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
414 ' ' Catch ex As Exception
416 ' ' TraceOut("TM-Remove: " + retMsg)
417 ' ' Return "GetTimeline -> Err: Can't parse data."
421 ' If _endingFlag Then Return ""
424 ' Dim strSepTmp As String
425 ' If gType = WORKERTYPE.Timeline Then
426 ' strSepTmp = _splitPostRecent
428 ' strSepTmp = _splitPost
431 ' Dim pos1 As Integer
432 ' Dim pos2 As Integer
434 ' pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
438 ' Return "GetTimeline -> Err: tweets count is 0."
441 ' Dim strSep() As String = {strSepTmp}
442 ' Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
443 ' Dim intCnt As Integer = 0
444 ' Dim listCnt As Integer = 0
446 ' listCnt = TabInformations.GetInstance.ItemCount
448 ' Dim dlgt(20) As GetIconImageDelegate
449 ' Dim ar(20) As IAsyncResult
450 ' Dim arIdx As Integer = -1
454 ' For Each strPost As String In posts
458 ' If page = 1 And gType = WORKERTYPE.Timeline Then
460 ' 'pos1 = strPost.IndexOf(_getSiv, 0)
462 ' ' pos2 = strPost.IndexOf(_getSivTo, pos1 + _getSiv.Length)
463 ' ' If pos2 > -1 Then
464 ' ' _authSiv = strPost.Substring(pos1 + _getSiv.Length, pos2 - pos1 - _getSiv.Length)
468 ' ' Return "GetTimeline -> Err: Can't get Siv."
473 ' ' Return "GetTimeline -> Err: Can't get Siv."
477 ' If GetAuthKey(retMsg) < 0 Then
479 ' Return "GetTimeline -> Err: Can't get auth token."
483 ' pos1 = retMsg.IndexOf(_getInfoTwitter, StringComparison.Ordinal)
485 ' pos2 = retMsg.IndexOf(_getInfoTwitterTo, pos1, StringComparison.Ordinal)
487 ' _infoTwitter = retMsg.Substring(pos1 + _getInfoTwitter.Length, pos2 - pos1 - _getInfoTwitter.Length)
497 ' Dim post As New PostClass
499 ' pos1 = strPost.IndexOf("</ol>")
501 ' strPost = strPost.Substring(0, pos1)
507 ' pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
508 ' post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
509 ' Catch ex As Exception
511 ' TraceOut("TM-ID:" + strPost)
512 ' Return "GetTimeline -> Err: Can't get ID."
516 ' pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
517 ' pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
518 ' post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
519 ' Catch ex As Exception
521 ' TraceOut("TM-Name:" + strPost)
522 ' Return "GetTimeline -> Err: Can't get Name."
526 ' If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
527 ' post.Nickname = post.Name
530 ' pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
531 ' pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
532 ' post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
533 ' Catch ex As Exception
535 ' TraceOut("TM-Nick:" + strPost)
536 ' Return "GetTimeline -> Err: Can't get Nick."
542 ' If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
545 ' Dim orgData As String = ""
547 ' If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
549 ' pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
550 ' pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
551 ' orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
552 ' Catch ex As Exception
554 ' TraceOut("TM-VBody:" + strPost)
555 ' Return "GetTimeline -> Err: Can't get Valentine body."
562 ' pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
563 ' pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
564 ' post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
565 ' Catch ex As Exception
567 ' TraceOut("TM-Img:" + strPost)
568 ' Return "GetTimeline -> Err: Can't get ImagePath."
572 ' If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
573 ' post.IsProtect = True
577 ' If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
578 ' rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
579 ' m = rg.Match(strPost)
581 ' post.RetweetedBy = m.Result("${name}")
583 ' post.RetweetedBy = ""
585 ' rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
586 ' m = rg.Match(strPost)
588 ' post.RetweetedId = Long.Parse(m.Result("${id}"))
590 ' post.RetweetedId = 0
595 ' pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
599 ' If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
601 ' orgData += " <3 you! Do you <3 "
602 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
603 ' pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
604 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
606 ' pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
609 ' orgData += " <3 's "
610 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
612 ' pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
613 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
617 ' pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
618 ' orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
621 ' Catch ex As Exception
623 ' TraceOut("TM-VBody2:" + strPost)
624 ' Return "GetTimeline -> Err: Can't get Valentine body2."
629 ' pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
630 ' orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
631 ' Catch ex As Exception
633 ' TraceOut("TM-Body:" + strPost)
634 ' Return "GetTimeline -> Err: Can't get body."
638 ' ' orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
641 ' orgData = orgData.Replace("<3", "♡")
645 ' orgData = PreProcessUrl(orgData)
647 ' '短縮URL解決処理(orgData書き換え)
648 ' orgData = ShortUrlResolve(orgData)
651 ' post.OriginalData = AdjustHtml(orgData)
653 ' '単純テキストの取り出し(リンクタグ除去)
655 ' post.Data = GetPlainText(orgData)
656 ' Catch ex As Exception
658 ' TraceOut("TM-Link:" + strPost)
659 ' Return "GetTimeline -> Err: Can't parse links."
663 ' Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
664 ' If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
669 ' pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
671 ' pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
672 ' 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)
676 ' Catch ex As Exception
678 ' TraceOut("TM-Date:" + strPost)
679 ' Return "GetTimeline -> Err: Can't get date."
682 ' '取得できなくなったため暫定対応(2/26)
688 ' 'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
689 ' rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
690 ' m = rg.Match(strPost)
692 ' post.Source = m.Result("${name}")
694 ' post.Source = "Web"
697 ' ' pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
698 ' ' If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
699 ' ' If pos1 > -1 Then
700 ' ' pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
701 ' ' pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
702 ' ' post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
704 ' ' post.Source = "Web"
706 ' 'Catch ex As Exception
708 ' ' TraceOut("TM-Src:" + strPost)
709 ' ' Return "GetTimeline -> Err: Can't get src."
712 ' 'Get Reply(in_reply_to_user/id)
713 ' 'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
714 ' rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
715 ' m = rg.Match(strPost)
717 ' post.InReplyToUser = m.Result("${name}")
718 ' post.InReplyToId = Long.Parse(m.Result("${id}"))
719 ' post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
723 ' rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
724 ' m = rg.Match(orgData)
726 ' post.ReplyToList.Add(m.Groups(1).Value.ToLower())
729 ' If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
731 ' If gType = WORKERTYPE.Reply Then post.IsReply = True
734 ' If strPost.IndexOf("class=""fav-action fav""") > -1 Then
739 ' 'pos1 = strPost.IndexOf(_parseStar, pos2, StringComparison.Ordinal)
742 ' ' pos2 = strPost.IndexOf(_parseStarTo, pos1 + _parseStar.Length, StringComparison.Ordinal)
743 ' ' If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = _parseStarEmpty Then
744 ' ' post.IsFav = False
746 ' ' post.IsFav = True
748 ' ' Catch ex As Exception
750 ' ' TraceOut("TM-Fav:" + strPost)
751 ' ' Return "GetTimeline -> Err: Can't get fav status."
754 ' ' post.IsFav = False
757 ' If _endingFlag Then Return ""
759 ' post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
761 ' If follower.Count > 1 Then
762 ' post.IsOwl = Not follower.Contains(post.Name.ToLower())
768 ' If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
771 ' dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
772 ' ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
777 ' If intCnt = posts.Length AndAlso gType = WORKERTYPE.Timeline AndAlso page = 1 Then
778 ' pos1 = strPost.IndexOf(_parseDMcountFrom, pos2, StringComparison.Ordinal)
781 ' pos2 = strPost.IndexOf(_parseDMcountTo, pos1 + _parseDMcountFrom.Length, StringComparison.Ordinal)
782 ' Dim dmCnt As Integer = Integer.Parse(strPost.Substring(pos1 + _parseDMcountFrom.Length, pos2 - pos1 - _parseDMcountFrom.Length))
783 ' If dmCnt > _dmCount Then
787 ' Catch ex As Exception
788 ' Return "GetTimeline -> Err: Can't get DM count."
795 ' For i As Integer = 0 To arIdx
797 ' dlgt(i).EndInvoke(ar(i))
798 ' Catch ex As Exception
799 ' '最後までendinvoke回す(ゾンビ化回避)
800 ' ex.Data("IsTerminatePermission") = False
806 ' If page = 1 AndAlso (TabInformations.GetInstance.ItemCount - listCnt) >= _nextThreshold Then
807 ' '新着が閾値の件数以上なら、次のページも念のため読み込み
808 ' endPage = _nextPages + 1
814 ' GetTmSemaphore.Release()
818 ' Public Function GetDirectMessage(ByVal page As Integer, _
819 ' ByVal read As Boolean, _
820 ' ByVal endPage As Integer, _
821 ' ByVal gType As WORKERTYPE) As String
823 ' If endPage = 0 Then
828 ' Dim num As Integer = endPage - page
829 ' Dim ar(num) As IAsyncResult
830 ' Dim dlgt(num) As GetDirectMessageDelegate
832 ' For idx As Integer = 0 To num
833 ' gType = WORKERTYPE.DirectMessegeRcv
834 ' dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
835 ' GetTmSemaphore.WaitOne()
836 ' ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
838 ' Dim rslt As String = ""
839 ' For idx As Integer = 0 To num
840 ' Dim trslt As String = ""
842 ' trslt = dlgt(idx).EndInvoke(ar(idx))
843 ' Catch ex As Exception
844 ' '最後までendinvoke回す(ゾンビ化回避)
845 ' ex.Data("IsTerminatePermission") = False
847 ' rslt = "GetDirectMessageErr"
849 ' If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
851 ' For idx As Integer = 0 To num
852 ' gType = WORKERTYPE.DirectMessegeSnt
853 ' dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
854 ' GetTmSemaphore.WaitOne()
855 ' ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
857 ' For idx As Integer = 0 To num
858 ' Dim trslt As String = ""
860 ' trslt = dlgt(idx).EndInvoke(ar(idx))
861 ' Catch ex As Exception
862 ' '最後までendinvoke回す(ゾンビ化回避)
863 ' ex.Data("IsTerminatePermission") = False
865 ' rslt = "GetDirectMessageErr"
867 ' If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
872 ' Private Function GetDirectMessageThread(ByVal page As Integer, _
873 ' ByVal read As Boolean, _
874 ' ByVal endPage As Integer, _
875 ' ByVal gType As WORKERTYPE) As String
877 ' If _endingFlag Then Return ""
879 ' Dim retMsg As String = ""
880 ' Dim resStatus As String = ""
882 ' Static redirectToDmRcv As String = ""
883 ' Static redirectToDmSnd As String = ""
887 ' If _signed = False Then
889 ' If retMsg.Length > 0 Then
894 ' If _endingFlag Then Return ""
897 ' Dim pageQuery As String = _pageQry + page.ToString
898 ' If gType = WORKERTYPE.DirectMessegeRcv Then
899 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathRcv + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
901 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathSnt + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
904 ' If retMsg.Length = 0 Then
909 ' ' tr 要素の class 属性を消去
910 ' retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
913 ' ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
914 ' ' If idx = -1 Then Exit Do
915 ' ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
916 ' ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
917 ' ' Catch ex As Exception
919 ' ' TraceOut("DM-Remove: " + retMsg)
920 ' ' Return "GetDm -> Err: Can't parse data."
924 ' If _endingFlag Then Return ""
927 ' 'If GetAuthKeyDM(retMsg) < 0 Then
929 ' ' Return "GetDirectMessage -> Err: Busy(1)"
932 ' Dim pos1 As Integer
933 ' Dim pos2 As Integer
936 ' pos1 = retMsg.IndexOf(_splitDM, StringComparison.Ordinal)
938 ' '0件(メッセージなし。エラーの場合もありうるが判別できないので正常として戻す)
942 ' Dim strSep() As String = {_splitDM}
943 ' Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
944 ' Dim intCnt As Integer = 0 'カウンタ
945 ' 'Dim listCnt As Integer = 0
947 ' ' listCnt = TabInformations.GetInstance.ItemCount
949 ' Dim dlgt(20) As GetIconImageDelegate
950 ' Dim ar(20) As IAsyncResult
951 ' Dim arIdx As Integer = -1
953 ' For Each strPost As String In posts
956 ' If intCnt > 1 Then '1件目はヘッダなので無視
957 ' 'Dim lItem As New MyListItem
958 ' Dim post As New PostClass()
960 ' pos1 = strPost.IndexOf("</ol>")
962 ' strPost = strPost.Substring(0, pos1)
968 ' pos2 = strPost.IndexOf("""", 0, StringComparison.Ordinal)
969 ' post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
970 ' Catch ex As Exception
972 ' TraceOut("DM-ID:" + strPost)
973 ' Return "GetDirectMessage -> Err: Can't get ID"
978 ' pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
979 ' pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
980 ' post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
981 ' Catch ex As Exception
983 ' TraceOut("DM-Name:" + strPost)
984 ' Return "GetDirectMessage -> Err: Can't get Name"
989 ' pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
990 ' pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
991 ' post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
992 ' Catch ex As Exception
994 ' TraceOut("DM-Nick:" + strPost)
995 ' Return "GetDirectMessage -> Err: Can't get Nick."
999 ' If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
1004 ' pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
1005 ' pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
1006 ' post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
1007 ' Catch ex As Exception
1009 ' TraceOut("DM-Img:" + strPost)
1010 ' Return "GetDirectMessage -> Err: Can't get ImagePath"
1015 ' pos1 = strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal)
1016 ' If pos1 > -1 Then post.IsProtect = True
1017 ' Catch ex As Exception
1019 ' TraceOut("DM-Protect:" + strPost)
1020 ' Return "GetDirectMessage -> Err: Can't get Protect"
1023 ' Dim orgData As String = ""
1027 ' pos1 = strPost.IndexOf(_parseDM1, pos2, StringComparison.Ordinal)
1029 ' pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
1030 ' orgData = strPost.Substring(pos1 + _parseDM1.Length, pos2 - pos1 - _parseDM1.Length).Trim()
1032 ' pos1 = strPost.IndexOf(_parseDM11, pos2, StringComparison.Ordinal)
1033 ' pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
1034 ' orgData = strPost.Substring(pos1 + _parseDM11.Length, pos2 - pos1 - _parseDM11.Length).Trim()
1036 ' 'orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1037 ' orgData = orgData.Replace("<3", "♡")
1038 ' Catch ex As Exception
1040 ' TraceOut("DM-Body:" + strPost)
1041 ' Return "GetDirectMessage -> Err: Can't get body"
1044 ' 'URL前処理(IDNデコードなど)
1045 ' orgData = PreProcessUrl(orgData)
1047 ' '短縮URL解決処理(orgData書き換え)
1048 ' orgData = ShortUrlResolve(orgData)
1051 ' post.OriginalData = AdjustHtml(orgData)
1053 ' '単純テキストの取り出し(リンクタグ除去)
1055 ' post.Data = GetPlainText(orgData)
1056 ' Catch ex As Exception
1058 ' TraceOut("DM-Link:" + strPost)
1059 ' Return "GetDirectMessage -> Err: Can't parse links"
1065 ' pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1067 ' pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1068 ' 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)
1070 ' post.PDate = Now()
1072 ' Catch ex As Exception
1074 ' TraceOut("DM-Date:" + strPost)
1075 ' Return "GetDirectMessage -> Err: Can't get date."
1078 ' '取得できなくなったため暫定対応(2/26)
1079 ' post.PDate = Now()
1083 ' 'pos1 = strPost.IndexOf(_parseStar, pos2)
1084 ' 'pos2 = strPost.IndexOf("""", pos1 + _parseStar.Length)
1085 ' 'If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = "empty" Then
1086 ' ' lItem.Fav = False
1088 ' ' lItem.Fav = True
1090 ' post.IsFav = False
1093 ' If _endingFlag Then Return ""
1096 ' If gType = WORKERTYPE.DirectMessegeRcv Then
1097 ' post.IsOwl = False
1102 ' post.IsRead = read
1107 ' dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1108 ' ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1112 ' For i As Integer = 0 To arIdx
1114 ' dlgt(i).EndInvoke(ar(i))
1115 ' Catch ex As Exception
1116 ' ex.Data("IsTerminatePermission") = False
1124 ' GetTmSemaphore.Release()
1128 ' Public Function GetFavorites(ByVal page As Integer, _
1129 ' ByVal read As Boolean, _
1130 ' ByRef endPage As Integer, _
1131 ' ByVal gType As WORKERTYPE, _
1132 ' ByRef getDM As Boolean) As String
1134 ' GetTmSemaphore.WaitOne()
1136 ' If _endingFlag Then Return ""
1138 ' Dim retMsg As String = ""
1139 ' Dim resStatus As String = ""
1141 ' Static redirectToFav As String = ""
1142 ' Const FAV_PATH As String = "/favorites"
1144 ' If _signed = False Then
1146 ' If retMsg.Length > 0 Then
1151 ' If _endingFlag Then Return ""
1154 ' Dim pageQuery As String
1159 ' pageQuery = _pageQry + page.ToString
1162 ' retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + FAV_PATH + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
1164 ' If retMsg.Length = 0 Then
1169 ' ' tr 要素の class 属性を消去
1170 ' retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+""\s+)", "${tagStart} ")
1173 ' ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
1174 ' ' If idx = -1 Then Exit Do
1175 ' ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
1176 ' ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
1177 ' ' Catch ex As Exception
1179 ' ' TraceOut("GetFav-Remove: " + retMsg)
1180 ' ' Return "GetFav -> Err: Can't parse data."
1184 ' If _endingFlag Then Return ""
1187 ' Dim strSepTmp As String
1188 ' strSepTmp = _splitPostRecent
1190 ' Dim pos1 As Integer
1191 ' Dim pos2 As Integer
1193 ' pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
1197 ' Return "GetTimeline -> Err: tweets count is 0."
1200 ' Dim strSep() As String = {strSepTmp}
1201 ' Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
1202 ' Dim intCnt As Integer = 0
1203 ' 'Dim listCnt As Integer = 0
1205 ' ' listCnt = TabInformations.GetInstance.ItemCount
1207 ' Dim dlgt(20) As GetIconImageDelegate
1208 ' Dim ar(20) As IAsyncResult
1209 ' Dim arIdx As Integer = -1
1213 ' For Each strPost As String In posts
1216 ' If intCnt = 1 Then
1220 ' Dim post As New PostClass
1222 ' pos1 = strPost.IndexOf("</ol>")
1224 ' strPost = strPost.Substring(0, pos1)
1230 ' pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
1231 ' post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
1232 ' Catch ex As Exception
1234 ' TraceOut("TM-ID:" + strPost)
1235 ' Return "GetTimeline -> Err: Can't get ID."
1239 ' pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
1240 ' pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
1241 ' post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
1242 ' Catch ex As Exception
1244 ' TraceOut("TM-Name:" + strPost)
1245 ' Return "GetTimeline -> Err: Can't get Name."
1249 ' If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
1250 ' post.Nickname = post.Name
1253 ' pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
1254 ' pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
1255 ' post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
1256 ' Catch ex As Exception
1258 ' TraceOut("TM-Nick:" + strPost)
1259 ' Return "GetTimeline -> Err: Can't get Nick."
1265 ' ' If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
1268 ' Dim orgData As String = ""
1270 ' If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
1272 ' pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
1273 ' pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
1274 ' orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
1275 ' Catch ex As Exception
1277 ' TraceOut("TM-VBody:" + strPost)
1278 ' Return "GetTimeline -> Err: Can't get Valentine body."
1285 ' pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
1286 ' pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
1287 ' post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
1288 ' Catch ex As Exception
1290 ' TraceOut("TM-Img:" + strPost)
1291 ' Return "GetTimeline -> Err: Can't get ImagePath."
1295 ' If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
1296 ' post.IsProtect = True
1300 ' If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
1301 ' rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
1302 ' m = rg.Match(strPost)
1304 ' post.RetweetedBy = m.Result("${name}")
1306 ' post.RetweetedBy = ""
1308 ' rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
1309 ' m = rg.Match(strPost)
1311 ' post.RetweetedId = Long.Parse(m.Result("${id}"))
1313 ' post.RetweetedId = 0
1318 ' pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
1322 ' If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
1324 ' orgData += " <3 you! Do you <3 "
1325 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1326 ' pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
1327 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1329 ' pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
1332 ' orgData += " <3 's "
1333 ' pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1335 ' pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
1336 ' orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1340 ' pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
1341 ' orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
1344 ' Catch ex As Exception
1346 ' TraceOut("TM-VBody2:" + strPost)
1347 ' Return "GetTimeline -> Err: Can't get Valentine body2."
1352 ' pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
1353 ' orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
1354 ' Catch ex As Exception
1356 ' TraceOut("TM-Body:" + strPost)
1357 ' Return "GetTimeline -> Err: Can't get body."
1361 ' ' orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1364 ' orgData = orgData.Replace("<3", "♡")
1367 ' 'URL前処理(IDNデコードなど)
1368 ' orgData = PreProcessUrl(orgData)
1370 ' '短縮URL解決処理(orgData書き換え)
1371 ' orgData = ShortUrlResolve(orgData)
1374 ' post.OriginalData = AdjustHtml(orgData)
1376 ' '単純テキストの取り出し(リンクタグ除去)
1378 ' post.Data = GetPlainText(orgData)
1379 ' Catch ex As Exception
1381 ' TraceOut("TM-Link:" + strPost)
1382 ' Return "GetTimeline -> Err: Can't parse links."
1385 ' ' Imageタグ除去(ハロウィン)
1386 ' Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
1387 ' If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
1392 ' pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1394 ' pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1395 ' 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)
1397 ' post.PDate = Now()
1399 ' Catch ex As Exception
1401 ' TraceOut("TM-Date:" + strPost)
1402 ' Return "GetTimeline -> Err: Can't get date."
1405 ' '取得できなくなったため暫定対応(2/26)
1406 ' post.PDate = Now()
1411 ' 'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
1412 ' rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
1413 ' m = rg.Match(strPost)
1415 ' post.Source = m.Result("${name}")
1417 ' post.Source = "Web"
1420 ' ' pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
1421 ' ' If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
1422 ' ' If pos1 > -1 Then
1423 ' ' pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
1424 ' ' pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
1425 ' ' post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
1427 ' ' post.Source = "Web"
1429 ' 'Catch ex As Exception
1431 ' ' TraceOut("TM-Src:" + strPost)
1432 ' ' Return "GetTimeline -> Err: Can't get src."
1435 ' 'Get Reply(in_reply_to_user/id)
1436 ' 'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
1437 ' rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
1438 ' m = rg.Match(strPost)
1440 ' post.InReplyToUser = m.Result("${name}")
1441 ' post.InReplyToId = Long.Parse(m.Result("${id}"))
1442 ' post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1446 ' rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
1447 ' m = rg.Match(orgData)
1449 ' post.ReplyToList.Add(m.Groups(1).Value.ToLower())
1452 ' If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
1457 ' If _endingFlag Then Return ""
1459 ' post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1461 ' If follower.Count > 1 Then
1462 ' post.IsOwl = Not follower.Contains(post.Name.ToLower())
1464 ' post.IsOwl = False
1467 ' post.IsRead = read
1470 ' dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1471 ' ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1477 ' For i As Integer = 0 To arIdx
1479 ' dlgt(i).EndInvoke(ar(i))
1480 ' Catch ex As Exception
1481 ' '最後までendinvoke回す(ゾンビ化回避)
1482 ' ex.Data("IsTerminatePermission") = False
1489 ' GetTmSemaphore.Release()
1493 Private Function PreProcessUrl(ByVal orgData As String) As String
1494 Dim posl1 As Integer
1495 Dim posl2 As Integer = 0
1496 Dim IDNConveter As IdnMapping = New IdnMapping()
1497 Dim href As String = "<a href="""
1500 If orgData.IndexOf(href, posl2, StringComparison.Ordinal) > -1 Then
1501 Dim urlStr As String = ""
1503 posl1 = orgData.IndexOf(href, posl2, StringComparison.Ordinal)
1504 posl1 += href.Length
1505 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1506 urlStr = orgData.Substring(posl1, posl2 - posl1)
1508 If Not urlStr.StartsWith("http://") AndAlso Not urlStr.StartsWith("https://") AndAlso Not urlStr.StartsWith("ftp://") Then
1512 Dim replacedUrl As String = IDNDecode(urlStr)
1513 If replacedUrl Is Nothing Then Continue Do
1514 If replacedUrl = urlStr Then Continue Do
1516 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + replacedUrl)
1525 ' Private Function doShortUrlResolve(ByRef orgData As String) As Boolean
1526 ' Dim replaced As Boolean = False
1527 ' For Each _svc As String In _ShortUrlService
1528 ' Dim svc As String = _svc
1529 ' Dim posl1 As Integer
1530 ' Dim posl2 As Integer = 0
1533 ' If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1534 ' Dim urlStr As String = ""
1536 ' posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1537 ' posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1538 ' posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1539 ' urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1540 ' Dim Response As String = ""
1541 ' Dim retUrlStr As String = ""
1542 ' Dim tmpurlStr As String = urlStr
1543 ' Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1544 ' Dim tmpSchemeAndDomain As String = ""
1545 ' For i As Integer = 0 To 4 'とりあえず5回試す
1546 ' retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo), String))
1547 ' If retUrlStr.Length > 0 Then
1548 ' ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1549 ' ' 取得試行回数オーバーの場合は取得結果を転送先とする
1550 ' Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1551 ' If scd.Success AndAlso scd.Value <> svc Then
1554 ' tmpurlStr = retUrlStr
1558 ' If tmpurlStr <> urlStr Then
1559 ' '少なくとも一度以上転送されている (前回の結果を転送先とする)
1560 ' retUrlStr = tmpurlStr
1568 ' If retUrlStr.Length > 0 Then
1569 ' If Not retUrlStr.StartsWith("http") Then
1570 ' If retUrlStr.StartsWith("/") Then
1571 ' retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1572 ' ElseIf retUrlStr.StartsWith("data:") Then
1575 ' retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1578 ' retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1580 ' orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1581 ' posl2 = 0 '置換した場合は頭から再探索(複数同時置換での例外対応)
1584 ' Catch ex As Exception
1586 ' 'Return "GetTimeline -> Err: Can't get tinyurl."
1597 ' Private Sub doShortUrlResolve(ByRef orgData As String)
1598 ' 'Dim replaced As Boolean = False
1599 ' 'Dim svc As String
1600 ' 'Dim posl1 As Integer
1601 ' 'Dim posl2 As Integer = 0
1602 ' Static urlCache As New Specialized.StringDictionary()
1603 ' If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1605 ' Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1606 ' Dim m As MatchCollection = rx.Matches(orgData)
1607 ' Dim urlList As New List(Of String)
1608 ' For Each orgUrlMatch As Match In m
1609 ' Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1610 ' Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1611 ' If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1612 ' Not urlList.Contains(orgUrl + orgUrlPath) Then
1613 ' urlList.Add(orgUrl + orgUrlPath)
1616 ' For Each orgUrl As String In urlList
1617 ' If urlCache.ContainsKey(orgUrl) Then
1619 ' orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1620 ' Catch ex As Exception
1625 ' 'urlとして生成できない場合があるらしい
1626 ' 'Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1627 ' Dim retUrlStr As String = ""
1628 ' Dim tmpurlStr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1629 ' Dim httpVar As New HttpVarious
1630 ' retUrlStr = urlEncodeMultibyteChar(httpVar.GetRedirectTo(tmpurlStr))
1631 ' If retUrlStr.StartsWith("http") Then
1632 ' retUrlStr = retUrlStr.Replace("""", "%22") 'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1633 ' orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1634 ' urlCache.Add(orgUrl, retUrlStr)
1636 ' Catch ex As Exception
1642 ' 'For Each ma As Match In m
1643 ' ' svc = ma.Result("${svc}")
1644 ' ' posl1 = ma.Index
1645 ' ' If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1646 ' ' Dim urlStr As String = ""
1648 ' ' posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1649 ' ' posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1650 ' ' posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1651 ' ' urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1652 ' ' Dim Response As String = ""
1653 ' ' Dim retUrlStr As String = ""
1654 ' ' Dim tmpurlStr As String = urlStr
1655 ' ' Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1656 ' ' Dim tmpSchemeAndDomain As String = ""
1657 ' ' For i As Integer = 0 To 4 'とりあえず5回試す
1658 ' ' retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo, timeOut:=2000), String))
1659 ' ' If retUrlStr.Length > 0 Then
1660 ' ' ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1661 ' ' ' 取得試行回数オーバーの場合は取得結果を転送先とする
1662 ' ' Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1663 ' ' If scd.Success AndAlso scd.Value <> svc Then
1664 ' ' svc = scd.Value()
1666 ' ' tmpurlStr = retUrlStr
1669 ' ' ' 転送先URLが返されなかった
1670 ' ' If tmpurlStr <> urlStr Then
1671 ' ' '少なくとも一度以上転送されている (前回の結果を転送先とする)
1672 ' ' retUrlStr = tmpurlStr
1680 ' ' If retUrlStr.Length > 0 Then
1681 ' ' If Not retUrlStr.StartsWith("http") Then
1682 ' ' If retUrlStr.StartsWith("/") Then
1683 ' ' retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1684 ' ' ElseIf retUrlStr.StartsWith("data:") Then
1687 ' ' retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1690 ' ' retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1692 ' ' orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1693 ' ' posl2 = 0 '置換した場合は頭から再探索(複数同時置換での例外対応)
1696 ' ' Catch ex As Exception
1697 ' ' '_signed = False
1698 ' ' 'Return "GetTimeline -> Err: Can't get tinyurl."
1708 Private Function ShortUrlResolve(ByVal orgData As String) As String
1709 If _tinyUrlResolve Then
1710 Static urlCache As New Specialized.StringDictionary()
1711 If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1713 'Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1714 Dim m As MatchCollection = Regex.Matches(orgData, "<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1715 Dim urlList As New List(Of String)
1716 For Each orgUrlMatch As Match In m
1717 Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1718 Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1719 If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1720 Not urlList.Contains(orgUrl + orgUrlPath) Then
1721 urlList.Add(orgUrl + orgUrlPath)
1724 For Each orgUrl As String In urlList
1725 If urlCache.ContainsKey(orgUrl) Then
1727 orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1728 Catch ex As Exception
1733 'urlとして生成できない場合があるらしい
1734 'Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1735 Dim retUrlStr As String = ""
1736 Dim tmpurlStr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1737 Dim httpVar As New HttpVarious
1738 retUrlStr = urlEncodeMultibyteChar(httpVar.GetRedirectTo(tmpurlStr))
1739 If retUrlStr.StartsWith("http") Then
1740 retUrlStr = retUrlStr.Replace("""", "%22") 'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1741 orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1742 urlCache.Add(orgUrl, retUrlStr)
1744 Catch ex As Exception
1753 Private Function GetPlainText(ByVal orgData As String) As String
1754 Return HttpUtility.HtmlDecode(Regex.Replace(orgData, "(?<tagStart><a [^>]+>)(?<text>[^<]+)(?<tagEnd></a>)", "${text}"))
1756 ''単純テキストの取り出し(リンクタグ除去)
1757 'If orgData.IndexOf(_parseLink1, StringComparison.Ordinal) = -1 Then
1758 ' retStr = HttpUtility.HtmlDecode(orgData)
1760 ' Dim posl1 As Integer
1761 ' Dim posl2 As Integer
1762 ' Dim posl3 As Integer = 0
1768 ' posl1 = orgData.IndexOf(_parseLink1, posl3, StringComparison.Ordinal)
1769 ' If posl1 = -1 Then Exit Do
1771 ' If (posl3 + _parseLink3.Length <> posl1) Or posl3 = 0 Then
1772 ' If posl3 <> 0 Then
1773 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length, posl1 - posl3 - _parseLink3.Length))
1775 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(0, posl1))
1778 ' posl2 = orgData.IndexOf(_parseLink2, posl1, StringComparison.Ordinal)
1779 ' posl3 = orgData.IndexOf(_parseLink3, posl2, StringComparison.Ordinal)
1780 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl2 + _parseLink2.Length, posl3 - posl2 - _parseLink2.Length))
1782 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length))
1788 ' htmlの簡易サニタイズ(詳細表示に不要なタグの除去)
1790 Private Function SanitizeHtml(ByVal orgdata As String) As String
1791 Dim retdata As String = orgdata
1793 ' <script ~ </script>
1794 'Dim rx As Regex = New Regex( _
1795 ' "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
1796 ' "</(script|object|applet|image|frameset|fieldset|legend|style)>", RegexOptions.IgnoreCase)
1797 retdata = Regex.Replace(retdata, "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
1798 "</(script|object|applet|image|frameset|fieldset|legend|style)>", "", RegexOptions.IgnoreCase)
1801 'rx = New Regex("<(frame|link|iframe|img)>", RegexOptions.IgnoreCase)
1802 retdata = Regex.Replace(retdata, "<(frame|link|iframe|img)>", "", RegexOptions.IgnoreCase)
1807 Private Function AdjustHtml(ByVal orgData As String) As String
1808 Dim retStr As String = orgData
1809 'Dim hash As New Regex("<a [^>]+>[#|#](?<1>[a-zA-Z0-9_]+)</a>")
1810 Dim m As Match = Regex.Match(retStr, "<a [^>]+>[#|#](?<1>[a-zA-Z0-9_]+)</a>")
1813 _hashList.Add("#" + m.Groups(1).Value)
1817 retStr = Regex.Replace(retStr, "<a [^>]*href=""/", "<a href=""" + _protocol + "twitter.com/")
1818 retStr = retStr.Replace("<a href=", "<a target=""_self"" href=")
1819 retStr = retStr.Replace(vbLf, "<br>")
1821 '半角スペースを置換(Thanks @anis774)
1822 Dim ret As Boolean = False
1824 ret = EscapeSpace(retStr)
1826 'Dim isTag As Boolean = False
1827 'For i As Integer = 0 To retStr.Length - 1
1828 ' If retStr(i) = "<"c Then
1831 ' If retStr(i) = ">"c Then
1835 ' If (Not isTag) AndAlso (retStr(i) = " "c) Then
1836 ' retStr = retStr.Remove(i, 1)
1837 ' retStr = retStr.Insert(i, " ")
1841 Return SanitizeHtml(retStr)
1844 Private Function EscapeSpace(ByRef html As String) As Boolean
1845 '半角スペースを置換(Thanks @anis774)
1846 Dim isTag As Boolean = False
1847 For i As Integer = 0 To html.Length - 1
1848 If html(i) = "<"c Then
1851 If html(i) = ">"c Then
1855 If (Not isTag) AndAlso (html(i) = " "c) Then
1856 html = html.Remove(i, 1)
1857 html = html.Insert(i, " ")
1864 Private Sub GetIconImage(ByVal post As PostClass)
1869 If Not _getIcon Then
1870 post.ImageIndex = -1
1871 TabInformations.GetInstance.AddPost(post)
1876 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1879 If post.ImageIndex > -1 Then
1880 TabInformations.GetInstance.AddPost(post)
1884 Dim httpVar As New HttpVarious
1885 img = httpVar.GetImage(post.ImageUrl)
1886 If img Is Nothing Then
1887 post.ImageIndex = -1
1888 TabInformations.GetInstance.AddPost(post)
1892 If _endingFlag Then Exit Sub
1894 bmp2 = New Bitmap(_iconSz, _iconSz)
1895 Using g As Graphics = Graphics.FromImage(bmp2)
1896 g.InterpolationMode = Drawing2D.InterpolationMode.High
1897 g.DrawImage(img, 0, 0, _iconSz, _iconSz)
1902 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1903 If post.ImageIndex = -1 Then
1905 If img.RawFormat.Guid = Imaging.ImageFormat.Gif.Guid Then
1906 Dim fd As New System.Drawing.Imaging.FrameDimension(img.FrameDimensionsList(0))
1907 Dim fd_count As Integer = img.GetFrameCount(fd)
1908 If fd_count > 1 Then
1910 For i As Integer = 0 To fd_count - 1
1911 img.SelectActiveFrame(fd, i)
1913 _dIcon.Add(post.ImageUrl, img) '詳細表示用ディクショナリに追加
1914 Catch ex As Exception
1915 Dim bmp As New Bitmap(48, 48)
1916 Using g As Graphics = Graphics.FromImage(bmp)
1917 g.InterpolationMode = Drawing2D.InterpolationMode.High
1918 g.DrawImage(img, 0, 0, 48, 48)
1920 _dIcon.Add(post.ImageUrl, bmp) '詳細表示用ディクショナリに追加
1924 _dIcon.Add(post.ImageUrl, img) '詳細表示用ディクショナリに追加
1926 _lIcon.Images.Add(post.ImageUrl, bmp2)
1927 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1929 _dIcon.Add(post.ImageUrl, img)
1930 _lIcon.Images.Add(post.ImageUrl, bmp2)
1931 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1933 Catch ex As InvalidOperationException
1934 'タイミングにより追加できない場合がある?(キー重複ではない)
1935 post.ImageIndex = -1
1939 TabInformations.GetInstance.AddPost(post)
1940 Catch ex As ArgumentException
1949 'Private Function GetAuthKey(ByVal resMsg As String) As Integer
1950 ' Dim pos1 As Integer
1951 ' Dim pos2 As Integer
1953 ' pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1958 ' pos2 = resMsg.IndexOf(_getAuthKeyTo, pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1960 ' _authKey = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1968 'Private Function GetAuthKeyDM(ByVal resMsg As String) As Integer
1969 ' Dim pos1 As Integer
1970 ' Dim pos2 As Integer
1972 ' pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1977 ' pos2 = resMsg.IndexOf("""", pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1978 ' _authKeyDM = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1983 Private Structure PostInfo
1984 Public CreatedAt As String
1986 Public Text As String
1987 Public UserId As String
1988 Public Sub New(ByVal Created As String, ByVal IdStr As String, ByVal txt As String, ByVal uid As String)
1994 Public Shadows Function Equals(ByVal dst As PostInfo) As Boolean
1995 If Me.CreatedAt = dst.CreatedAt AndAlso Me.Id = dst.Id AndAlso Me.Text = dst.Text AndAlso Me.UserId = dst.UserId Then
2003 Private Function IsPostRestricted(ByRef resMsg As String) As Boolean
2004 Static _prev As New PostInfo("", "", "", "")
2005 Dim _current As New PostInfo("", "", "", "")
2008 Dim xd As XmlDocument = New XmlDocument()
2011 _current.CreatedAt = xd.SelectSingleNode("/status/created_at/text()").Value
2012 _current.Id = xd.SelectSingleNode("/status/id/text()").Value
2013 _current.Text = xd.SelectSingleNode("/status/text/text()").Value
2014 _current.UserId = xd.SelectSingleNode("/status/user/id/text()").Value
2016 If _current.Equals(_prev) Then
2019 _prev.CreatedAt = _current.CreatedAt
2020 _prev.Id = _current.Id
2021 _prev.Text = _current.Text
2022 _prev.UserId = _current.UserId
2023 Catch ex As XmlException
2030 Public Function PostStatus(ByVal postStr As String, ByVal reply_to As Long) As String
2032 If _endingFlag Then Return ""
2034 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2036 postStr = postStr.Trim()
2038 Dim res As HttpStatusCode
2039 Dim content As String = ""
2041 res = twCon.UpdateStatus(postStr, reply_to, content)
2042 Catch ex As Exception
2043 Return "Err:" + ex.Message
2047 Case HttpStatusCode.OK
2048 Dim xd As XmlDocument = New XmlDocument()
2051 Dim xNode As XmlNode = Nothing
2052 xNode = xd.SelectSingleNode("/status/user/followers_count/text()")
2053 If xNode IsNot Nothing Then _followersCount = Integer.Parse(xNode.Value)
2054 xNode = xd.SelectSingleNode("/status/user/friends_count/text()")
2055 If xNode IsNot Nothing Then _friendsCount = Integer.Parse(xNode.Value)
2056 xNode = xd.SelectSingleNode("/status/user/statuses_count/text()")
2057 If xNode IsNot Nothing Then _statusesCount = Integer.Parse(xNode.Value)
2058 xNode = xd.SelectSingleNode("/status/user/location/text()")
2059 If xNode IsNot Nothing Then _location = xNode.Value
2060 xNode = xd.SelectSingleNode("/status/user/description/text()")
2061 If xNode IsNot Nothing Then _bio = xNode.Value
2062 Catch ex As Exception
2066 If Not postStr.StartsWith("D ", StringComparison.OrdinalIgnoreCase) AndAlso _
2067 Not postStr.StartsWith("DM ", StringComparison.OrdinalIgnoreCase) AndAlso _
2068 IsPostRestricted(content) Then
2069 Return "OK:Delaying?"
2071 If op.Post(postStr.Length) Then
2074 Return "Outputz:Failed"
2076 Case HttpStatusCode.Forbidden
2077 Dim xd As XmlDocument = New XmlDocument
2080 Dim xNode As XmlNode = Nothing
2081 xNode = xd.SelectSingleNode("/hash/error")
2082 Return "OK:" + xNode.InnerText
2083 Catch ex As Exception
2085 Return "Err:Update Limits?"
2086 Case HttpStatusCode.Unauthorized
2087 Twitter.AccountState = ACCOUNT_STATE.Invalid
2088 Return "Check your Username/Password."
2090 Return "Err:" + res.ToString
2094 Public Function RemoveStatus(ByVal id As Long) As String
2095 If _endingFlag Then Return ""
2097 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2099 Dim res As HttpStatusCode
2102 res = twCon.DestroyStatus(id)
2103 Catch ex As Exception
2104 Return "Err:" + ex.Message
2108 Case HttpStatusCode.OK
2110 Case HttpStatusCode.Unauthorized
2111 Twitter.AccountState = ACCOUNT_STATE.Invalid
2112 Return "Check your Username/Password."
2113 Case HttpStatusCode.NotFound
2116 Return "Err:" + res.ToString
2121 Public Function PostRetweet(ByVal id As Long, ByVal read As Boolean) As String
2122 If _endingFlag Then Return ""
2123 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2126 Dim target As Long = id
2127 If TabInformations.GetInstance.Item(id).RetweetedId > 0 Then
2128 target = TabInformations.GetInstance.Item(id).RetweetedId '再RTの場合は元発言をRT
2131 Dim res As HttpStatusCode
2132 Dim content As String = ""
2134 res = twCon.RetweetStatus(target, content)
2135 Catch ex As Exception
2136 Return "Err:" + ex.Message
2140 Case HttpStatusCode.Unauthorized
2141 Twitter.AccountState = ACCOUNT_STATE.Invalid
2142 Return "Check your Username/Password."
2143 Case Is <> HttpStatusCode.OK
2144 Return "Err:" + res.ToString()
2147 Dim dlgt As GetIconImageDelegate 'countQueryに合わせる
2148 Dim ar As IAsyncResult 'countQueryに合わせる
2149 Dim xdoc As New XmlDocument
2151 xdoc.LoadXml(content)
2152 Catch ex As Exception
2154 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
2155 Return "Invalid XML!"
2159 Dim xentryNode As XmlNode = xdoc.DocumentElement.SelectSingleNode("/status")
2160 If xentryNode Is Nothing Then Return "Invalid XML!"
2161 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
2162 Dim post As New PostClass
2164 post.Id = Long.Parse(xentry.Item("id").InnerText)
2167 If TabInformations.GetInstance.ContainsKey(post.Id) Then Return ""
2170 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
2171 If xRnode Is Nothing Then Return "Invalid XML!"
2173 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
2174 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)
2176 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
2178 post.Data = xRentry.Item("text").InnerText
2179 'Source取得(htmlの場合は、中身を取り出し)
2180 post.Source = xRentry.Item("source").InnerText
2182 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
2183 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
2184 post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
2187 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
2188 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
2189 post.Name = xRUentry.Item("screen_name").InnerText
2190 post.Nickname = xRUentry.Item("name").InnerText
2191 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
2192 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
2193 'post.IsMe = post.Name.ToLower.Equals(_uid)
2197 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
2198 post.RetweetedBy = xUentry.Item("screen_name").InnerText
2201 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
2202 post.Data = HttpUtility.HtmlDecode(post.Data)
2203 post.Data = post.Data.Replace("<3", "♡")
2205 If post.Source.StartsWith("<") Then
2206 'Dim rgS As New Regex(">(?<source>.+)<")
2207 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
2209 post.Source = mS.Result("${source}")
2214 post.IsReply = post.ReplyToList.Contains(_uid)
2219 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
2221 If post.IsMe AndAlso _readOwnPost Then post.IsRead = True
2224 Catch ex As Exception
2226 'MessageBox.Show("不正なXMLです。(TL-Parse)")
2227 Return "Invalid XML!"
2230 '非同期アイコン取得&StatusDictionaryに追加
2231 dlgt = New GetIconImageDelegate(AddressOf GetIconImage)
2232 ar = dlgt.BeginInvoke(post, Nothing, Nothing)
2237 Catch ex As Exception
2238 '最後までendinvoke回す(ゾンビ化回避)
2239 ex.Data("IsTerminatePermission") = False
2246 Public Function RemoveDirectMessage(ByVal id As Long) As String
2247 If _endingFlag Then Return ""
2249 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2251 Dim res As HttpStatusCode
2254 res = twCon.DestroyDirectMessage(id)
2255 Catch ex As Exception
2256 Return "Err:" + ex.Message
2260 Case HttpStatusCode.OK
2262 Case HttpStatusCode.Unauthorized
2263 Twitter.AccountState = ACCOUNT_STATE.Invalid
2264 Return "Check your Username/Password."
2265 Case HttpStatusCode.NotFound
2268 Return "Err:" + res.ToString
2272 Public Function PostFollowCommand(ByVal screenName As String) As String
2274 If _endingFlag Then Return ""
2276 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2278 Dim res As HttpStatusCode
2281 res = twCon.CreateFriendships(screenName)
2282 Catch ex As Exception
2283 Return "Err:" + ex.Message
2287 Case HttpStatusCode.OK
2289 Case HttpStatusCode.Unauthorized
2290 Twitter.AccountState = ACCOUNT_STATE.Invalid
2291 Return "Check your Username/Password."
2292 Case HttpStatusCode.Forbidden
2293 Return "Err:Update Limits?"
2295 Return "Err:" + res.ToString
2299 Public Function PostRemoveCommand(ByVal screenName As String) As String
2301 If _endingFlag Then Return ""
2303 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2305 Dim res As HttpStatusCode
2308 res = twCon.DestroyFriendships(screenName)
2309 Catch ex As Exception
2310 Return "Err:" + ex.Message
2314 Case HttpStatusCode.OK
2316 Case HttpStatusCode.Unauthorized
2317 Twitter.AccountState = ACCOUNT_STATE.Invalid
2318 Return "Check your Username/Password."
2320 Return "Err:" + res.ToString
2324 Public Function GetFriendshipInfo(ByVal screenName As String, ByRef isFollowing As Boolean, ByRef isFollowed As Boolean) As String
2326 If _endingFlag Then Return ""
2328 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2330 Dim res As HttpStatusCode
2331 Dim content As String = ""
2333 res = twCon.ShowFriendships(_uid, screenName, content)
2334 Catch ex As Exception
2335 Return "Err:" + ex.Message
2339 Case HttpStatusCode.OK
2340 Dim xdoc As New XmlDocument
2341 Dim result As String = ""
2343 xdoc.LoadXml(content)
2344 isFollowing = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/following").InnerText)
2345 isFollowed = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/followed_by").InnerText)
2346 Catch ex As Exception
2347 result = "Err:Invalid XML."
2350 Case HttpStatusCode.BadRequest
2351 Return "Err:API Limits?"
2352 Case HttpStatusCode.Unauthorized
2353 Twitter.AccountState = ACCOUNT_STATE.Invalid
2354 Return "Check your Username/Password."
2356 Return "Err:" + res.ToString
2360 Public Function PostFavAdd(ByVal id As Long) As String
2361 If _endingFlag Then Return ""
2363 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2365 Dim res As HttpStatusCode
2368 res = twCon.CreateFavorites(id)
2369 Catch ex As Exception
2370 Return "Err:" + ex.Message
2374 Case HttpStatusCode.OK
2375 If Not _restrictFavCheck Then Return ""
2376 Case HttpStatusCode.Unauthorized
2377 Twitter.AccountState = ACCOUNT_STATE.Invalid
2378 Return "Check your Username/Password."
2379 Case HttpStatusCode.Forbidden
2380 Return "Err:Update Limits?"
2382 Return "Err:" + res.ToString
2385 'http://twitter.com/statuses/show/id.xml APIを発行して本文を取得
2387 Dim content As String = ""
2389 res = twCon.ShowStatuses(id, content)
2390 Catch ex As Exception
2391 Return "Err:" + ex.Message
2395 Case HttpStatusCode.OK
2397 Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(content))
2399 While rd.EOF = False
2400 If rd.IsStartElement("favorited") Then
2401 If rd.ReadElementContentAsBoolean() = True Then
2402 Return "" '正常にふぁぼれている
2404 Return "NG(Restricted?)" '正常応答なのにふぁぼれてないので制限っぽい
2411 Return "Err:Invalid XML!"
2413 Catch ex As XmlException
2416 Case HttpStatusCode.Unauthorized
2417 Twitter.AccountState = ACCOUNT_STATE.Invalid
2418 Return "Check your Username/Password."
2419 Case HttpStatusCode.BadRequest
2420 Return "Err:API Limits?"
2422 Return "Err:" + res.ToString
2427 Public Function PostFavRemove(ByVal id As Long) As String
2428 If _endingFlag Then Return ""
2430 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2432 Dim res As HttpStatusCode
2435 res = twCon.DestroyFavorites(id)
2436 Catch ex As Exception
2437 Return "Err:" + ex.Message
2441 Case HttpStatusCode.OK
2443 Case HttpStatusCode.Unauthorized
2444 Twitter.AccountState = ACCOUNT_STATE.Invalid
2445 Return "Check your Username/Password."
2446 Case HttpStatusCode.Forbidden
2447 Return "Err:Update Limits?"
2449 Return "Err:" + res.ToString
2453 '#Region "follower取得"
2454 ' 'Delegate Function GetFollowersDelegate(ByVal Query As Integer) As String
2455 ' 'Private semaphore As Threading.Semaphore = Nothing
2456 ' 'Private threadNum As Integer = 0
2457 ' Private _threadErr As Boolean = False
2459 ' Private Function GetFollowersMethod() As String
2460 ' Dim resStatus As String = ""
2461 ' Dim resMsg As String = ""
2462 ' Dim lineCount As Integer = 0
2463 ' Dim page As Long = -1
2466 ' If _endingFlag Then Exit Do
2467 ' resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _apiHost + _hubServer + _GetFollowers + _cursorQry + page.ToString, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2468 ' If resStatus.StartsWith("OK") = False Then
2469 ' Debug.WriteLine(page.ToString)
2474 ' Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(resMsg))
2477 ' While rd.EOF = False
2478 ' If rd.IsStartElement("screen_name") Then
2479 ' Dim tmp As String = rd.ReadElementString("screen_name").ToLower()
2481 ' If Not tmpFollower.Contains(tmp) Then
2482 ' tmpFollower.Add(tmp)
2486 ' ElseIf rd.IsStartElement("next_cursor") Then
2487 ' page = Long.Parse(rd.ReadElementString("next_cursor"))
2488 ' If page = 0 Then Exit Do
2495 ' Catch ex As Exception
2497 ' TraceOut("NG(XmlException)")
2498 ' Return "NG(XmlException)"
2500 ' Loop While lineCount > 0
2505 'Private Sub GetFollowersCallback(ByVal ar As IAsyncResult)
2506 ' Dim dlgt As GetFollowersDelegate = DirectCast(ar.AsyncState, GetFollowersDelegate)
2509 ' Dim ret As String = dlgt.EndInvoke(ar)
2510 ' If Not ret.Equals("") AndAlso Not _threadErr Then
2514 ' Catch ex As Exception
2516 ' ex.Data("IsTerminatePermission") = False
2519 ' GetTmSemaphore.Release() ' セマフォから出る
2520 ' Interlocked.Decrement(threadNum) ' スレッド数カウンタを-1
2525 '' キャッシュの検証と読み込み -1を渡した場合は読み込みのみ行う(APIエラーでFollowersCountが取得できなかったとき)
2526 'Private Function ValidateCache() As Integer
2530 ' Dim setting As SettingFollower = SettingFollower.Load()
2531 ' follower = setting.Follower
2532 ' If follower.Count = 0 OrElse Not follower(0).Equals(_uid.ToLower()) Then
2533 ' ' 別IDの場合はキャッシュ破棄して読み直し
2536 ' Catch ex As XmlException
2539 ' Catch ex As InvalidOperationException
2544 ' 'If _FollowersCount = -1 Then Return tmpFollower.Count
2545 ' Return follower.Count
2547 ' 'If (_FollowersCount + 1) = tmpFollower.Count Then
2548 ' ' '変動がないので読み込みの必要なし
2550 ' 'ElseIf (_FollowersCount + 1) < tmpFollower.Count Then
2551 ' ' '減っている場合はどこが抜けているのかわからないので全部破棄して読み直し
2552 ' ' tmpFollower.Clear()
2553 ' ' tmpFollower.Add(_uid.ToLower())
2554 ' ' Return _FollowersCount
2559 ' 'Return _FollowersCount - tmpFollower.Count
2563 'Private Sub UpdateCache()
2564 ' Dim setting As New SettingFollower(follower)
2568 ' Public Function GetFollowers(ByVal CacheInvalidate As Boolean) As String
2570 ' Dim sw As New System.Diagnostics.Stopwatch
2574 ' If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2576 ' 'Dim resStatus As String = ""
2577 ' 'Dim resMsg As String = ""
2578 ' 'Dim i As Integer = 0
2579 ' 'Dim DelegateInstance As GetFollowersDelegate = New GetFollowersDelegate(AddressOf GetFollowersMethod)
2580 ' 'Dim threadMax As Integer = 4 ' 最大スレッド数
2581 ' 'Dim followersCount As Integer = 0
2583 ' 'Interlocked.Exchange(threadNum, 0) ' スレッド数カウンタ初期化
2584 ' _threadErr = False
2586 ' tmpFollower.Clear()
2587 ' 'follower.Add(_uid.ToLower())
2588 ' tmpFollower.Add(_uid.ToLower())
2590 ' 'resMsg = DirectCast(CreateSocket.GetWebResponse("https://twitter.com/users/show/" + _uid + ".xml", resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2591 ' 'If resMsg = "" Then
2592 ' ' If resStatus.StartsWith("Err: BadRequest") Then
2593 ' ' Return "Maybe, the requests reached API limit."
2594 ' ' ElseIf resStatus.StartsWith("Err: Unauthorized") Then
2595 ' ' Twitter.AccountState = ACCOUNT_STATE.Invalid
2596 ' ' Return "Check your Username/Password."
2598 ' ' Return resStatus
2602 ' 'Dim xd As XmlDocument = New XmlDocument()
2604 ' ' xd.LoadXml(resMsg)
2605 ' ' followersCount = Integer.Parse(xd.SelectSingleNode("/user/followers_count/text()").Value)
2606 ' 'Catch ex As Exception
2607 ' ' 'If CacheInvalidate OrElse ValidateCache(-1) < 0 Then
2608 ' ' If ValidateCache(-1) < 0 Then
2609 ' ' ' FollowersカウントがAPIで取得できず、なおかつキャッシュから読めなかった
2610 ' ' SyncLock LockObj
2611 ' ' follower.Clear()
2612 ' ' follower.Add(_uid.ToLower())
2614 ' ' Return "Can't get followers_count and invalid cache."
2616 ' ' 'キャッシュを読み出せたのでキャッシュを使う
2617 ' ' SyncLock LockObj
2618 ' ' follower = tmpFollower
2624 ' 'Dim tmp As Integer
2626 ' ''If CacheInvalidate Then
2627 ' 'tmp = followersCount
2629 ' ''tmp = ValidateCache(followersCount)
2634 ' ' i = (tmp + 100) \ 100 ' Followersカウント取得しページ単位に切り上げる。1ページ余分に読む
2636 ' ' ' ' キャッシュの件数に変化がなかった
2639 ' ' ' Console.WriteLine(sw.ElapsedMilliseconds)
2641 ' ' ' SyncLock LockObj
2642 ' ' ' follower = tmpFollower
2645 ' ' Return "" 'ユーザー情報のフォロワー数が0
2649 ' ''semaphore = New System.Threading.Semaphore(threadMax, threadMax) 'スレッド最大数
2651 ' 'For cnt As Integer = 0 To i
2652 ' ' If _endingFlag Then Exit For
2653 ' ' 'semaphore.WaitOne() 'セマフォ取得 threadMax以上ならここでブロックされる
2654 ' ' GetTmSemaphore.WaitOne()
2655 ' ' 'Interlocked.Increment(threadNum) 'スレッド数カウンタを+1
2656 ' ' 'DelegateInstance.BeginInvoke(cnt + 1, New System.AsyncCallback(AddressOf GetFollowersCallback), DelegateInstance)
2657 ' ' Dim ret As String = GetFollowersMethod(cnt + 1)
2658 ' ' 'Interlocked.Decrement(threadNum) 'スレッド数カウンタを-1
2659 ' ' GetTmSemaphore.Release()
2660 ' ' If _threadErr Then Exit For
2663 ' '''全てのスレッドの終了を待つ(スレッド数カウンタが0になるまで待機)
2665 ' '' Thread.Sleep(50)
2666 ' ''Loop Until Interlocked.Add(threadNum, 0) = 0
2668 ' ''semaphore.Close()
2670 ' Dim ret As String = GetFollowersMethod()
2671 ' If _endingFlag Then Return ""
2673 ' If _threadErr Then
2674 ' If ValidateCache() > 0 Then
2676 ' For Each name As String In tmpFollower
2677 ' If Not follower.Contains(name) Then follower.Add(name)
2680 ' If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2681 ' ret = "Can't get followers. Use cache."
2683 ' ' エラーが発生しているならFollowersリストクリア
2686 ' follower.Add(_uid.ToLower())
2688 ' ret = "Can't get followers."
2692 ' follower = tmpFollower
2697 ' If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2701 ' 'Console.WriteLine(sw.ElapsedMilliseconds)
2704 ' TabInformations.GetInstance.RefreshOwl(follower)
2710 'Public Sub RefreshOwl()
2711 ' TabInformations.GetInstance.RefreshOwl(follower)
2714 'Public Sub RefreshOwlApi()
2715 ' TabInformations.GetInstance.RefreshOwl(followerId)
2718 Public ReadOnly Property Username() As String
2720 Return twCon.AuthenticatedUsername
2724 Public ReadOnly Property Password() As String
2726 Return twCon.Password
2730 Private Shared _accountState As ACCOUNT_STATE = ACCOUNT_STATE.Valid
2731 Public Shared Property AccountState() As ACCOUNT_STATE
2733 Return _accountState
2735 Set(ByVal value As ACCOUNT_STATE)
2736 _accountState = value
2740 'Public Property NextThreshold() As Integer
2742 ' Return _nextThreshold
2744 ' Set(ByVal value As Integer)
2745 ' _nextThreshold = value
2749 'Public Property NextPages() As Integer
2753 ' Set(ByVal value As Integer)
2754 ' _nextPages = value
2758 Public ReadOnly Property InfoTwitter() As String
2764 'Public Property UseAPI() As Boolean
2768 ' Set(ByVal value As Boolean)
2773 ' Public Sub GetWedata()
2774 ' Dim resStatus As String = ""
2775 ' Dim resMsg As String = ""
2777 ' resMsg = DirectCast(CreateSocket.GetWebResponse(wedataUrl, resStatus, timeOut:=10 * 1000), String) 'タイムアウト時間を10秒に設定
2778 ' If resMsg.Length = 0 Then Exit Sub
2780 ' Dim rs As New System.IO.StringReader(resMsg)
2782 ' Dim mode As Integer = 0 '0:search name 1:search data 2:read data
2783 ' Dim name As String = ""
2787 ' While rs.Peek() > -1
2792 ' If ln.StartsWith(" ""name"": ") Then
2793 ' name = ln.Substring(13, ln.Length - 2 - 13)
2797 ' If ln = " ""data"": {" Then
2801 ' If ln = " }," Then
2804 ' If ln.EndsWith(",") Then ln = ln.Substring(0, ln.Length - 1)
2806 ' Case "SplitPostReply"
2807 ' If ln.StartsWith(" ""tagfrom"": """) Then
2808 ' _splitPost = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2810 ' Case "SplitPostRecent"
2811 ' If ln.StartsWith(" ""tagfrom"": """) Then
2812 ' _splitPostRecent = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2815 ' If ln.StartsWith(" ""tagto"": """) Then
2816 ' _statusIdTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2819 ' If ln.StartsWith(" ""tagfrom"": """) Then
2820 ' _isProtect = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2823 ' If ln.StartsWith(" ""tagfrom"": """) Then
2824 ' _isReplyEng = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2826 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2827 ' _isReplyJpn = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2829 ' If ln.StartsWith(" ""tagto"": """) Then
2830 ' _isReplyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2833 ' ' If ln.StartsWith(" ""tagfrom"": """) Then
2834 ' ' _parseStar = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2836 ' ' If ln.StartsWith(" ""tagfrom2"": """) Then
2837 ' ' _parseStarEmpty = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2839 ' ' If ln.StartsWith(" ""tagto"": """) Then
2840 ' ' _parseStarTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2843 ' If ln.StartsWith(" ""tagfrom"": """) Then
2844 ' _followerList = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2846 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2847 ' _followerMbr1 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2849 ' If ln.StartsWith(" ""tagfrom3"": """) Then
2850 ' _followerMbr2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2852 ' If ln.StartsWith(" ""tagto"": """) Then
2853 ' _followerMbr3 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2856 ' If ln.StartsWith(" ""tagfrom"": """) Then
2857 ' _splitDM = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2860 ' If ln.StartsWith(" ""tagfrom"": """) Then
2861 ' _parseDM1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2863 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2864 ' _parseDM11 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2866 ' If ln.StartsWith(" ""tagto"": """) Then
2867 ' _parseDM2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2870 ' If ln.StartsWith(" ""tagfrom"": """) Then
2871 ' _parseDate = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2873 ' If ln.StartsWith(" ""tagto"": """) Then
2874 ' _parseDateTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2877 ' If ln.StartsWith(" ""tagfrom"": """) Then
2878 ' _parseMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2880 ' If ln.StartsWith(" ""tagto"": """) Then
2881 ' _parseMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2883 ' Case "GetImagePath"
2884 ' If ln.StartsWith(" ""tagfrom"": """) Then
2885 ' _parseImg = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2887 ' If ln.StartsWith(" ""tagto"": """) Then
2888 ' _parseImgTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2891 ' If ln.StartsWith(" ""tagfrom"": """) Then
2892 ' _parseNick = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2894 ' If ln.StartsWith(" ""tagto"": """) Then
2895 ' _parseNickTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2898 ' If ln.StartsWith(" ""tagfrom"": """) Then
2899 ' _parseName = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2901 ' If ln.StartsWith(" ""tagto"": """) Then
2902 ' _parseNameTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2905 ' ' If ln.StartsWith(" ""tagfrom"": """) Then
2906 ' ' _getSiv = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2908 ' ' If ln.StartsWith(" ""tagto"": """) Then
2909 ' ' _getSivTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2912 ' If ln.StartsWith(" ""tagfrom"": """) Then
2913 ' _getAuthKey = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2915 ' If ln.StartsWith(" ""tagto"": """) Then
2916 ' _getAuthKeyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2918 ' Case "InfoTwitter"
2919 ' If ln.StartsWith(" ""tagfrom"": """) Then
2920 ' _getInfoTwitter = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2922 ' If ln.StartsWith(" ""tagto"": """) Then
2923 ' _getInfoTwitterTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2925 ' Case "GetProtectMsg"
2926 ' If ln.StartsWith(" ""tagfrom"": """) Then
2927 ' _parseProtectMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2929 ' If ln.StartsWith(" ""tagto"": """) Then
2930 ' _parseProtectMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2933 ' If ln.StartsWith(" ""tagfrom"": """) Then
2934 ' _parseDMcountFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2936 ' If ln.StartsWith(" ""tagto"": """) Then
2937 ' _parseDMcountTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2940 ' If ln.StartsWith(" ""tagfrom"": """) Then
2941 ' _parseSourceFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2943 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2944 ' _parseSource2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2946 ' If ln.StartsWith(" ""tagto"": """) Then
2947 ' _parseSource2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2949 ' Case "RemoveClass"
2950 ' If ln.StartsWith(" ""tagfrom"": """) Then
2951 ' _removeClass = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2961 ' GenerateAnalyzeKey()
2965 Public WriteOnly Property GetIcon() As Boolean
2966 Set(ByVal value As Boolean)
2971 Public WriteOnly Property TinyUrlResolve() As Boolean
2972 Set(ByVal value As Boolean)
2973 _tinyUrlResolve = value
2977 'Public WriteOnly Property SelectedProxyType() As ProxyType
2978 ' Set(ByVal value As ProxyType)
2979 ' _proxyType = value
2983 'Public WriteOnly Property ProxyAddress() As String
2984 ' Set(ByVal value As String)
2985 ' _proxyAddress = value
2989 'Public WriteOnly Property ProxyPort() As Integer
2990 ' Set(ByVal value As Integer)
2991 ' _proxyPort = value
2995 'Public WriteOnly Property ProxyUser() As String
2996 ' Set(ByVal value As String)
2997 ' _proxyUser = value
3001 'Public WriteOnly Property ProxyPassword() As String
3002 ' Set(ByVal value As String)
3003 ' _proxyPassword = value
3007 Public WriteOnly Property RestrictFavCheck() As Boolean
3008 Set(ByVal value As Boolean)
3009 _restrictFavCheck = value
3013 Public WriteOnly Property IconSize() As Integer
3014 Set(ByVal value As Integer)
3019 Public Function MakeShortUrl(ByVal ConverterType As UrlConverter, ByVal SrcUrl As String) As String
3020 Dim src As String = urlEncodeMultibyteChar(SrcUrl)
3021 Dim param As New Dictionary(Of String, String)
3022 Dim content As String = ""
3024 For Each svc As String In _ShortUrlService
3025 If SrcUrl.StartsWith(svc) Then
3026 Return "Can't convert"
3031 If SrcUrl.StartsWith("http://nico.ms/") Then Return "Can't convert"
3033 SrcUrl = HttpUtility.UrlEncode(SrcUrl)
3035 Select Case ConverterType
3036 Case UrlConverter.TinyUrl 'tinyurl
3037 If SrcUrl.StartsWith("http") Then
3038 If "http://tinyurl.com/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3039 ' 明らかに長くなると推測できる場合は圧縮しない
3043 If Not (New HttpVarious).PostData("http://tinyurl.com/api-create.php?url=" + SrcUrl, Nothing, content) Then
3044 Return "Can't convert"
3047 If Not content.StartsWith("http://tinyurl.com/") Then
3048 Return "Can't convert"
3050 Case UrlConverter.Isgd
3051 If SrcUrl.StartsWith("http") Then
3052 If "http://is.gd/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3053 ' 明らかに長くなると推測できる場合は圧縮しない
3057 If Not (New HttpVarious).PostData("http://is.gd/api.php?longurl=" + SrcUrl, Nothing, content) Then
3058 Return "Can't convert"
3061 If Not content.StartsWith("http://is.gd/") Then
3062 Return "Can't convert"
3064 Case UrlConverter.Twurl
3065 If SrcUrl.StartsWith("http") Then
3066 If "http://twurl.nl/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3067 ' 明らかに長くなると推測できる場合は圧縮しない
3071 param.Add("link[url]", SrcUrl)
3072 If Not (New HttpVarious).PostData("http://tweetburner.com/links", param, content) Then
3073 Return "Can't convert"
3076 If Not content.StartsWith("http://twurl.nl/") Then
3077 Return "Can't convert"
3079 Case UrlConverter.Unu
3080 If SrcUrl.StartsWith("http") Then
3081 If "http://u.nu/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3082 ' 明らかに長くなると推測できる場合は圧縮しない
3086 If Not (New HttpVarious).PostData("http://u.nu/unu-api-simple?url=" + SrcUrl, Nothing, content) Then
3087 Return "Can't convert"
3090 If Not content.StartsWith("http://u.nu") Then
3091 Return "Can't convert"
3093 Case UrlConverter.Bitly, UrlConverter.Jmp
3094 Dim BitlyLogin As String = "tweenapi"
3095 Dim BitlyApiKey As String = "R_c5ee0e30bdfff88723c4457cc331886b"
3096 If _bitlyId <> "" Then
3097 BitlyLogin = _bitlyId
3098 BitlyApiKey = _bitlyKey
3100 Const BitlyApiVersion As String = "2.0.1"
3101 If SrcUrl.StartsWith("http") Then
3102 If "http://bit.ly/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
3103 ' 明らかに長くなると推測できる場合は圧縮しない
3107 Dim req As String = ""
3108 If ConverterType = UrlConverter.Bitly Then
3109 req = "http://api.bit.ly/shorten?version="
3111 req = "http://api.j.mp/shorten?version="
3113 req += BitlyApiVersion + _
3114 "&login=" + BitlyLogin + _
3115 "&apiKey=" + BitlyApiKey + _
3116 "&longUrl=" + SrcUrl
3117 If BitlyLogin <> "tweenapi" Then req += "&history=1"
3118 If Not (New HttpVarious).PostData(req, Nothing, content) Then
3119 Return "Can't convert"
3121 'Dim rx As Regex = New Regex("""shortUrl"": ""(?<ShortUrl>.*?)""")
3122 If Regex.Match(content, """shortUrl"": ""(?<ShortUrl>.*?)""").Success Then
3123 content = Regex.Match(content, """shortUrl"": ""(?<ShortUrl>.*?)""").Groups("ShortUrl").Value
3127 If Not content.StartsWith("http://bit.ly") AndAlso Not content.StartsWith("http://j.mp") Then
3128 Return "Can't convert"
3132 Dim ch As Char() = {ControlChars.Cr, ControlChars.Lf}
3133 content = content.TrimEnd(ch)
3134 If src.Length < content.Length Then content = src ' 圧縮の結果逆に長くなった場合は圧縮前のURLを返す
3138 'Public Function MakeShortNicoms(ByVal SrcUrl As String) As String
3139 ' Dim content As String = ""
3141 ' If Not (New HttpVarious).GetData("http://nico.ms/q/" + SrcUrl, Nothing, content) Then
3142 ' Return "Can't convert"
3145 ' If content.StartsWith("http") Then
3148 ' Return "Can't convert"
3154 Public Function GetVersionInfo() As String
3155 Dim content As String = ""
3156 If Not (New HttpVarious).GetData("http://tween.sourceforge.jp/version2.txt?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), Nothing, content) Then
3157 Throw New Exception("GetVersionInfo Failed")
3162 Public Function GetTweenBinary(ByVal strVer As String) As String
3164 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/Tween" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3165 Path.Combine(Application.StartupPath(), "TweenNew.exe")) Then
3166 Return "Err:Download failed"
3168 If Directory.Exists(Path.Combine(Application.StartupPath(), "en")) = False Then
3169 Directory.CreateDirectory(Path.Combine(Application.StartupPath(), "en"))
3171 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenRes" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3172 Path.Combine(Application.StartupPath(), "en\Tween.resourcesNew.dll")) Then
3173 Return "Err:Download failed"
3175 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenUp.gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3176 Path.Combine(Application.StartupPath(), "TweenUp.exe")) Then
3177 Return "Err:Download failed"
3179 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenDll" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
3180 Path.Combine(Application.StartupPath(), "TweenNew.XmlSerializers.dll")) Then
3181 Return "Err:Download failed"
3184 Catch ex As Exception
3185 Return "Err:Download failed"
3190 Public WriteOnly Property ListIcon() As ImageList
3191 Set(ByVal value As ImageList)
3196 Public WriteOnly Property DetailIcon() As Dictionary(Of String, Image)
3197 Set(ByVal value As Dictionary(Of String, Image))
3202 'Public Property DefaultTimeOut() As Integer
3204 ' Return _defaultTimeOut
3206 ' Set(ByVal value As Integer)
3207 ' _defaultTimeOut = value
3211 Public WriteOnly Property CountApi() As Integer
3213 Set(ByVal value As Integer)
3218 Public WriteOnly Property CountApiReply() As Integer
3220 Set(ByVal value As Integer)
3221 _countApiReply = value
3225 ' Public WriteOnly Property UsePostMethod() As Boolean
3226 ' Set(ByVal value As Boolean)
3227 ' _usePostMethod = False
3229 ' 'POSTメソッドが弾かれるためGETに固定(2009/4/9)
3231 ' _ApiMethod = MySocket.REQ_TYPE.ReqPOSTAPI
3233 ' _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
3236 ' _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
3241 Public Property ReadOwnPost() As Boolean
3245 Set(ByVal value As Boolean)
3246 _readOwnPost = value
3250 Public ReadOnly Property FollowersCount() As Integer
3252 Return _followersCount
3256 Public ReadOnly Property FriendsCount() As Integer
3258 Return _friendsCount
3262 Public ReadOnly Property StatusesCount() As Integer
3264 Return _statusesCount
3268 Public ReadOnly Property Location() As String
3274 Public ReadOnly Property Bio() As String
3280 Public WriteOnly Property UseSsl() As Boolean
3281 Set(ByVal value As Boolean)
3282 HttpTwitter.UseSsl = value
3284 _protocol = "https://"
3286 _protocol = "http://"
3291 Public WriteOnly Property BitlyId() As String
3292 Set(ByVal value As String)
3297 Public WriteOnly Property BitlyKey() As String
3298 Set(ByVal value As String)
3303 Public Function GetTimelineApi(ByVal read As Boolean, _
3304 ByVal gType As WORKERTYPE, _
3305 ByVal more As Boolean) As String
3307 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3309 If _endingFlag Then Return ""
3311 Dim countQuery As Integer
3312 Dim res As HttpStatusCode
3313 Dim content As String = ""
3315 If gType = WORKERTYPE.Timeline Then
3317 res = twCon.HomeTimeline(_countApi, minHomeTimeline, 0, content)
3319 res = twCon.HomeTimeline(_countApi, 0, 0, content)
3321 countQuery = _countApi
3324 res = twCon.Mentions(_countApiReply, minMentions, 0, content)
3326 res = twCon.Mentions(_countApiReply, 0, 0, content)
3328 countQuery = _countApiReply
3330 Catch ex As Exception
3331 Return "Err:" + ex.Message
3334 Case HttpStatusCode.OK
3335 Case HttpStatusCode.Unauthorized
3336 Twitter.AccountState = ACCOUNT_STATE.Invalid
3337 Return "Check your Username/Password."
3338 Case HttpStatusCode.BadRequest
3339 Return "Err:API Limits?"
3341 Return "Err:" + res.ToString()
3344 If gType = WORKERTYPE.Timeline Then
3345 Return CreatePostsFromXml(content, gType, Nothing, read, countQuery, Me.minHomeTimeline)
3347 Return CreatePostsFromXml(content, gType, Nothing, read, countQuery, Me.minMentions)
3351 Public Function GetListStatus(ByVal read As Boolean, _
3352 ByVal tab As TabClass, _
3353 ByVal more As Boolean) As String
3355 If _endingFlag Then Return ""
3357 Dim res As HttpStatusCode
3358 Dim content As String = ""
3359 Dim page As Integer = 0
3360 Dim countQuery As Integer = 0
3363 res = twCon.GetListsStatuses(tab.ListInfo.UserId.ToString, tab.ListInfo.Id.ToString, _countApi, tab.OldestId, 0, content)
3365 res = twCon.GetListsStatuses(tab.ListInfo.UserId.ToString, tab.ListInfo.Id.ToString, _countApi, 0, 0, content)
3367 countQuery = _countApi
3368 Catch ex As Exception
3369 Return "Err:" + ex.Message
3372 Case HttpStatusCode.OK
3373 Case HttpStatusCode.Unauthorized
3374 Twitter.AccountState = ACCOUNT_STATE.Invalid
3375 Return "Check your Username/Password."
3376 Case HttpStatusCode.BadRequest
3377 Return "Err:API Limits?"
3379 Return "Err:" + res.ToString()
3382 Return CreatePostsFromXml(content, WORKERTYPE.List, tab, read, countQuery, tab.OldestId)
3385 Private Function CreatePostsFromXml(ByVal content As String, ByVal gType As WORKERTYPE, ByVal tab As TabClass, ByVal read As Boolean, ByVal count As Integer, ByRef minimumId As Long) As String
3386 Dim arIdx As Integer = -1
3387 Dim dlgt(count) As GetIconImageDelegate 'countQueryに合わせる
3388 Dim ar(count) As IAsyncResult 'countQueryに合わせる
3389 Dim xdoc As New XmlDocument
3391 xdoc.LoadXml(content)
3392 Catch ex As Exception
3394 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3395 Return "Invalid XML!"
3398 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3399 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3400 Dim post As New PostClass
3402 post.Id = Long.Parse(xentry.Item("id").InnerText)
3403 If minimumId > post.Id Then minimumId = post.Id
3406 If tab Is Nothing Then
3407 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3409 If TabInformations.GetInstance.ContainsKey(post.Id, tab.TabName) Then Continue For
3413 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3414 If xRnode IsNot Nothing Then
3415 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3416 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)
3418 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3420 post.Data = xRentry.Item("text").InnerText
3421 'Source取得(htmlの場合は、中身を取り出し)
3422 post.Source = xRentry.Item("source").InnerText
3424 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3425 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3426 'post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
3427 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3430 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3431 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3432 post.Name = xRUentry.Item("screen_name").InnerText
3433 post.Nickname = xRUentry.Item("name").InnerText
3434 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3435 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3436 post.IsMe = post.Name.ToLower.Equals(_uid)
3439 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3440 post.RetweetedBy = xUentry.Item("screen_name").InnerText
3442 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)
3444 post.Data = xentry.Item("text").InnerText
3445 'Source取得(htmlの場合は、中身を取り出し)
3446 post.Source = xentry.Item("source").InnerText
3447 Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3448 post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3449 'in_reply_to_user_idを使うか?
3450 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3453 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3454 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3455 post.Name = xUentry.Item("screen_name").InnerText
3456 post.Nickname = xUentry.Item("name").InnerText
3457 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3458 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3459 post.IsMe = post.Name.ToLower.Equals(_uid)
3462 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3463 post.Data = HttpUtility.HtmlDecode(post.Data)
3464 post.Data = post.Data.Replace("<3", "♡")
3466 If post.Source.StartsWith("<") Then
3467 'Dim rgS As New Regex(">(?<source>.+)<")
3468 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
3470 post.Source = mS.Result("${source}")
3475 If gType = WORKERTYPE.Timeline OrElse tab IsNot Nothing Then
3476 post.IsReply = post.ReplyToList.Contains(_uid)
3484 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3486 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3489 If tab IsNot Nothing Then post.RelTabName = tab.TabName
3490 Catch ex As Exception
3492 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3496 '非同期アイコン取得&StatusDictionaryに追加
3498 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3499 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3503 For i As Integer = 0 To arIdx
3505 dlgt(i).EndInvoke(ar(i))
3506 Catch ex As Exception
3507 '最後までendinvoke回す(ゾンビ化回避)
3508 ex.Data("IsTerminatePermission") = False
3513 'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3517 Public Function GetSearch(ByVal read As Boolean, _
3518 ByVal tab As TabClass, _
3519 ByVal more As Boolean) As String
3521 If _endingFlag Then Return ""
3523 Dim res As HttpStatusCode
3524 Dim content As String = ""
3525 Dim page As Integer = 0
3526 If more Then page = tab.SearchPage
3528 res = twCon.Search(tab.SearchWords, tab.SearchLang, 40, page, content)
3529 Catch ex As Exception
3530 Return "Err:" + ex.Message
3533 Case HttpStatusCode.BadRequest
3534 Return "Invalid query"
3535 Case HttpStatusCode.NotFound
3536 Return "Invalid query"
3537 Case HttpStatusCode.PaymentRequired 'API Documentには420と書いてあるが、該当コードがないので402にしてある
3538 Return "Search API Limit?"
3539 Case HttpStatusCode.OK
3541 Return "Err:" + res.ToString
3544 If Not TabInformations.GetInstance.ContainsTab(tab) Then Return ""
3546 Dim arIdx As Integer = -1
3547 Dim dlgt(40) As GetIconImageDelegate 'countQueryに合わせる
3548 Dim ar(40) As IAsyncResult 'countQueryに合わせる
3549 Dim xdoc As New XmlDocument
3551 xdoc.LoadXml(content)
3552 Catch ex As Exception
3554 Return "Invalid ATOM!"
3556 Dim nsmgr As New XmlNamespaceManager(xdoc.NameTable)
3557 nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom")
3558 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr)
3559 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3560 Dim post As New PostClass
3562 post.Id = Long.Parse(xentry.Item("id").InnerText.Split(":"c)(2))
3563 If TabInformations.GetInstance.ContainsKey(post.Id, tab.TabName) Then Continue For
3564 post.PDate = DateTime.Parse(xentry.Item("published").InnerText)
3566 post.Data = xentry.Item("title").InnerText
3567 'Source取得(htmlの場合は、中身を取り出し)
3568 post.Source = xentry.Item("twitter:source").InnerText
3569 post.InReplyToId = 0
3570 post.InReplyToUser = ""
3574 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./search:author", nsmgr), XmlElement)
3576 post.Name = xUentry.Item("name").InnerText.Split(" "c)(0).Trim
3577 post.Nickname = xUentry.Item("name").InnerText.Substring(post.Name.Length).Trim
3578 If post.Nickname.Length > 2 Then
3579 post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2)
3581 post.Nickname = post.Name
3583 post.ImageUrl = CType(xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr), XmlElement).GetAttribute("href")
3584 post.IsProtect = False
3585 post.IsMe = post.Name.ToLower.Equals(_uid)
3588 post.OriginalData = CreateHtmlAnchor(HttpUtility.HtmlEncode(post.Data), post.ReplyToList)
3589 post.Data = HttpUtility.HtmlDecode(post.Data)
3591 If post.Source.StartsWith("<") Then
3592 'Dim rgS As New Regex(">(?<source>.+)<")
3593 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
3595 post.Source = mS.Result("${source}")
3600 post.IsReply = post.ReplyToList.Contains(_uid)
3603 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3605 post.RelTabName = tab.TabName
3606 Catch ex As Exception
3611 '非同期アイコン取得&StatusDictionaryに追加
3613 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3614 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3618 '' 遡るための情報max_idやnext_pageの情報を保持する
3621 For i As Integer = 0 To arIdx
3623 dlgt(i).EndInvoke(ar(i))
3624 Catch ex As Exception
3625 '最後までendinvoke回す(ゾンビ化回避)
3626 ex.Data("IsTerminatePermission") = False
3634 Public Function GetDirectMessageApi(ByVal read As Boolean, _
3635 ByVal gType As WORKERTYPE, _
3636 ByVal more As Boolean) As String
3637 If _endingFlag Then Return ""
3639 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3641 Dim res As HttpStatusCode
3642 Dim content As String = ""
3645 If gType = WORKERTYPE.DirectMessegeRcv Then
3647 res = twCon.DirectMessages(20, minDirectmessage, 0, content)
3649 res = twCon.DirectMessages(20, 0, 0, content)
3653 res = twCon.DirectMessagesSent(20, minDirectmessageSent, 0, content)
3655 res = twCon.DirectMessagesSent(20, 0, 0, content)
3658 Catch ex As Exception
3659 Return "Err:" + ex.Message
3663 Case HttpStatusCode.OK
3664 Case HttpStatusCode.Unauthorized
3665 Twitter.AccountState = ACCOUNT_STATE.Invalid
3666 Return "Check your Username/Password."
3667 Case HttpStatusCode.BadRequest
3668 Return "Err:API Limits?"
3670 Return "Err:" + res.ToString()
3673 Dim arIdx As Integer = -1
3674 Dim dlgt(20) As GetIconImageDelegate 'countQueryに合わせる
3675 Dim ar(20) As IAsyncResult 'countQueryに合わせる
3676 Dim xdoc As New XmlDocument
3678 xdoc.LoadXml(content)
3679 Catch ex As Exception
3681 'MessageBox.Show("不正なXMLです。(DM-LoadXml)")
3682 Return "Invalid XML!"
3685 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./direct_message")
3686 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3687 Dim post As New PostClass
3689 post.Id = Long.Parse(xentry.Item("id").InnerText)
3690 If gType = WORKERTYPE.DirectMessegeRcv Then
3691 If minDirectmessage > post.Id Then minDirectmessage = post.Id
3693 If minDirectmessageSent > post.Id Then minDirectmessageSent = post.Id
3697 If TabInformations.GetInstance.GetTabByType(TabUsageType.DirectMessage).Contains(post.Id) Then Continue For
3701 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)
3703 post.Data = xentry.Item("text").InnerText
3705 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3706 post.Data = HttpUtility.HtmlDecode(post.Data)
3707 post.Data = post.Data.Replace("<3", "♡")
3710 If gType = WORKERTYPE.DirectMessegeRcv Then
3717 Dim xUentry As XmlElement
3718 If gType = WORKERTYPE.DirectMessegeRcv Then
3719 xUentry = CType(xentry.SelectSingleNode("./sender"), XmlElement)
3722 xUentry = CType(xentry.SelectSingleNode("./recipient"), XmlElement)
3725 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3726 post.Name = xUentry.Item("screen_name").InnerText
3727 post.Nickname = xUentry.Item("name").InnerText
3728 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3729 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3730 Catch ex As Exception
3732 'MessageBox.Show("不正なXMLです。(DM-Parse)")
3737 post.IsReply = False
3740 '非同期アイコン取得&StatusDictionaryに追加
3742 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3743 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3747 For i As Integer = 0 To arIdx
3749 dlgt(i).EndInvoke(ar(i))
3750 Catch ex As Exception
3751 '最後までendinvoke回す(ゾンビ化回避)
3752 ex.Data("IsTerminatePermission") = False
3757 '_remainCountApi = sck.RemainCountApi
3758 'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3763 Public Function GetFavoritesApi(ByVal read As Boolean, _
3764 ByVal gType As WORKERTYPE) As String
3766 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3768 If _endingFlag Then Return ""
3770 Dim res As HttpStatusCode
3771 Dim content As String = ""
3773 res = twCon.Favorites(_countApi, content)
3774 Catch ex As Exception
3775 Return "Err:" + ex.Message
3779 Case HttpStatusCode.OK
3780 Case HttpStatusCode.Unauthorized
3781 Twitter.AccountState = ACCOUNT_STATE.Invalid
3782 Return "Check your Username/Password."
3783 Case HttpStatusCode.BadRequest
3784 Return "Err:API Limits?"
3786 Return "Err:" + res.ToString()
3789 Dim arIdx As Integer = -1
3790 Dim dlgt(_countApi) As GetIconImageDelegate 'countQueryに合わせる
3791 Dim ar(_countApi) As IAsyncResult 'countQueryに合わせる
3792 Dim xdoc As New XmlDocument
3794 xdoc.LoadXml(content)
3795 Catch ex As Exception
3797 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3798 Return "Invalid XML!"
3801 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3802 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3803 Dim post As New PostClass
3805 post.Id = Long.Parse(xentry.Item("id").InnerText)
3806 If minFavorites > post.Id Then minFavorites = post.Id
3809 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3812 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3813 If xRnode IsNot Nothing Then
3814 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3815 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)
3817 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3819 post.Data = xRentry.Item("text").InnerText
3820 'Source取得(htmlの場合は、中身を取り出し)
3821 post.Source = xRentry.Item("source").InnerText
3823 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3824 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3825 'in_reply_to_user_idを使うか?
3826 post.IsFav = Boolean.Parse(xRentry.Item("favorited").InnerText)
3829 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3830 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3831 post.Name = xRUentry.Item("screen_name").InnerText
3832 post.Nickname = xRUentry.Item("name").InnerText
3833 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3834 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3835 post.IsMe = post.Name.ToLower.Equals(_uid)
3838 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3839 post.RetweetedBy = xUentry.Item("screen_name").InnerText
3841 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)
3843 post.Data = xentry.Item("text").InnerText
3844 'Source取得(htmlの場合は、中身を取り出し)
3845 post.Source = xentry.Item("source").InnerText
3846 Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3847 post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3848 'in_reply_to_user_idを使うか?
3849 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3852 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3853 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3854 post.Name = xUentry.Item("screen_name").InnerText
3855 post.Nickname = xUentry.Item("name").InnerText
3856 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3857 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3858 post.IsMe = post.Name.ToLower.Equals(_uid)
3861 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3862 post.Data = HttpUtility.HtmlDecode(post.Data)
3863 post.Data = post.Data.Replace("<3", "♡")
3865 If post.Source.StartsWith("<") Then
3866 'Dim rgS As New Regex(">(?<source>.+)<")
3867 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
3869 post.Source = mS.Result("${source}")
3874 post.IsReply = post.ReplyToList.Contains(_uid)
3879 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3883 Catch ex As Exception
3885 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3889 '非同期アイコン取得&StatusDictionaryに追加
3891 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3892 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3896 For i As Integer = 0 To arIdx
3898 dlgt(i).EndInvoke(ar(i))
3899 Catch ex As Exception
3900 '最後までendinvoke回す(ゾンビ化回避)
3901 ex.Data("IsTerminatePermission") = False
3906 '_remainCountApi = sck.RemainCountApi
3907 'If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3912 Public Function GetFollowersApi() As String
3913 If _endingFlag Then Return ""
3914 Dim cursor As Long = -1
3915 Dim tmpFollower As New List(Of Long)(followerId)
3919 Dim ret As String = FollowerApi(cursor)
3922 followerId.AddRange(tmpFollower)
3925 Loop While cursor > 0
3927 TabInformations.GetInstance.RefreshOwl(followerId)
3932 Private Function FollowerApi(ByRef cursor As Long) As String
3933 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3935 Dim res As HttpStatusCode
3936 Dim content As String = ""
3938 res = twCon.FollowerIds(cursor, content)
3939 Catch ex As Exception
3940 Return "Err:" + ex.Message
3944 Case HttpStatusCode.OK
3945 Case HttpStatusCode.Unauthorized
3946 Twitter.AccountState = ACCOUNT_STATE.Invalid
3947 Return "Check your Username/Password."
3948 Case HttpStatusCode.BadRequest
3949 Return "Err:API Limits?"
3951 Return "Err:" + res.ToString()
3954 Dim xdoc As New XmlDocument
3956 xdoc.LoadXml(content)
3957 Catch ex As Exception
3959 Return "Invalid XML!"
3963 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/id_list/ids/id")
3964 followerId.Add(Long.Parse(xentryNode.InnerText))
3966 cursor = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/id_list/next_cursor").InnerText)
3967 Catch ex As Exception
3969 Return "Invalid XML!"
3976 Public Function GetListsApi() As String
3977 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3979 Dim res As HttpStatusCode
3980 Dim content As String = ""
3981 Dim cursor As Long = -1
3983 Dim lists As New List(Of ListElement)
3986 res = twCon.GetLists(Me.Username, cursor, content)
3987 Catch ex As Exception
3988 Return "Err:" + ex.Message
3992 Case HttpStatusCode.OK
3993 Case HttpStatusCode.Unauthorized
3994 Twitter.AccountState = ACCOUNT_STATE.Invalid
3995 Return "Check your Username/Password."
3996 Case HttpStatusCode.BadRequest
3997 Return "Err:API Limits?"
3999 Return "Err:" + res.ToString()
4002 Dim xdoc As New XmlDocument
4004 xdoc.LoadXml(content)
4005 Catch ex As Exception
4007 Return "Invalid XML!"
4011 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/lists_list/lists/list")
4012 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
4013 Dim lst As New ListElement
4014 lst.Description = xentry.Item("description").InnerText
4015 lst.Id = Long.Parse(xentry.Item("id").InnerText)
4016 lst.IsPublic = (xentry.Item("mode").InnerText = "public")
4017 lst.MemberCount = Integer.Parse(xentry.Item("member_count").InnerText)
4018 lst.Name = xentry.Item("name").InnerText
4019 lst.SubscriberCount = Integer.Parse(xentry.Item("subscriber_count").InnerText)
4020 lst.Slug = xentry.Item("slug").InnerText
4021 Dim xUserEntry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
4022 lst.Nickname = xUserEntry.Item("name").InnerText
4023 lst.Username = xUserEntry.Item("screen_name").InnerText
4024 lst.UserId = Long.Parse(xUserEntry.Item("id").InnerText)
4027 cursor = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/lists_list/next_cursor").InnerText)
4028 Catch ex As Exception
4030 Return "Invalid XML!"
4032 Loop While cursor <> 0
4038 res = twCon.GetListsSubscriptions(Me.Username, cursor, content)
4039 Catch ex As Exception
4040 Return "Err:" + ex.Message
4044 Case HttpStatusCode.OK
4045 Case HttpStatusCode.Unauthorized
4046 Twitter.AccountState = ACCOUNT_STATE.Invalid
4047 Return "Check your Username/Password."
4048 Case HttpStatusCode.BadRequest
4049 Return "Err:API Limits?"
4051 Return "Err:" + res.ToString()
4054 Dim xdoc As New XmlDocument
4056 xdoc.LoadXml(content)
4057 Catch ex As Exception
4059 Return "Invalid XML!"
4063 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/lists_list/lists/list")
4064 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
4065 Dim lst As New ListElement
4066 lst.Description = xentry.Item("description").InnerText
4067 lst.Id = Long.Parse(xentry.Item("id").InnerText)
4068 lst.IsPublic = (xentry.Item("mode").InnerText = "public")
4069 lst.MemberCount = Integer.Parse(xentry.Item("member_count").InnerText)
4070 lst.Name = xentry.Item("name").InnerText
4071 lst.SubscriberCount = Integer.Parse(xentry.Item("subscriber_count").InnerText)
4072 lst.Slug = xentry.Item("slug").InnerText
4073 Dim xUserEntry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
4074 lst.Nickname = xUserEntry.Item("name").InnerText
4075 lst.Username = xUserEntry.Item("screen_name").InnerText
4076 lst.UserId = Long.Parse(xUserEntry.Item("id").InnerText)
4079 cursor = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/lists_list/next_cursor").InnerText)
4080 Catch ex As Exception
4082 Return "Invalid XML!"
4084 Loop While cursor <> 0
4086 TabInformations.GetInstance.SubscribableLists = lists
4091 Private Function CreateHtmlAnchor(ByVal Text As String, ByVal AtList As List(Of String)) As String
4092 'Dim retStr As String = HttpUtility.HtmlEncode(Text) '要検証(デコードされて取得されるので再エンコード)
4093 'Dim retStr As String = HttpUtility.HtmlDecode(Text)
4094 Dim retStr As String = ""
4096 'Dim rgUrl As Regex = New Regex("(?<![0-9A-Za-z=])(?:https?|shttp|ftps?)://(?:(?:[-_.!~*'()a-zA-Z0-9;:&=+$,]|%[0-9A-Fa-f" + _
4097 ' "][0-9A-Fa-f])*@)?(?:(?:[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.)" + _
4098 ' "*[a-zA-Z](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.?|[0-9]+\.[0-9]+\.[0-9]+\." + _
4099 ' "[0-9]+)(?::[0-9]*)?(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f]" + _
4100 ' "[0-9A-Fa-f])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-" + _
4101 ' "Fa-f])*)*(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f" + _
4102 ' "])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)*)" + _
4103 ' "*)?(?:\?(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])" + _
4104 ' "*)?(?:#(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)?")
4105 Const rgUrl As String = "(?<before>(?:[^\/""':!=]|^|\:))" + _
4106 "(?<url>(?<protocol>https?://|www\.)" + _
4107 "(?<domain>(?:[\.-]|[^\p{P}])+\.[a-z]{2,}(?::[0-9]+)?)" + _
4108 "(?<path>/[a-z0-9!*'();:&=+$/%#\[\]\-_.,~@]*[a-z0-9)=#/]?)?" + _
4109 "(?<query>\?[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9_&=#])?)"
4111 retStr = Regex.Replace(Text, rgUrl, New MatchEvaluator(AddressOf AutoLinkUrl), RegexOptions.IgnoreCase)
4114 'Dim rg As New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,24}[a-zA-Z0-9_])")
4115 '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)
4116 '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_])")
4118 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>")
4120 'rg = New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20})")
4121 'rg = New Regex("(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})", RegexOptions.Compiled)
4122 Dim m As Match = Regex.Match(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})")
4124 AtList.Add(m.Result("$2").ToLower)
4128 retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})", "$1@<a href=""/$2"">$2</a>")
4131 'Dim rgh As New Regex("(^|[ .!,\-:;<>?])#([^] !""#$%&'()*+,.:;<=>?@\-[\^`{|}~\r\n]+)")
4132 'Dim rgh As New Regex("(^|[^a-zA-Z0-9_/&])[##]([a-zA-Z0-9_]+)", RegexOptions.Compiled)
4133 Dim mhs As MatchCollection = Regex.Matches(retStr, "(^|[^a-zA-Z0-9_/&])[##]([a-zA-Z0-9_]+)")
4134 For Each mt As Match In mhs
4135 If Not IsNumeric(mt.Result("$2")) Then
4136 'retStr = retStr.Replace(mt.Result("$1") + mt.Result("$2"), "<a href=""" + _protocol + "twitter.com/search?q=%23" + mt.Result("$2") + """>#" + mt.Result("$2") + "</a>")
4138 _hashList.Add("#" + mt.Result("$2"))
4142 retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_/&])[##]([a-zA-Z0-9_]+)", New MatchEvaluator(AddressOf AutoLinkHashtag))
4144 retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_/&##@@])sm([0-9]{4,10})", "$1<a href=""http://www.nicovideo.jp/watch/sm$2"">sm$2</a>")
4146 retStr = AdjustHtml(ShortUrlResolve(PreProcessUrl(retStr))) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
4150 Private Function AutoLinkUrl(ByVal m As Match) As String
4151 Dim sb As New StringBuilder(m.Result("${before}<a href="""))
4152 If m.Result("${protocol}").StartsWith("w", StringComparison.OrdinalIgnoreCase) Then
4153 sb.Append("http://")
4155 sb.Append(m.Result("${url}"">")).Append(m.Result("${url}")).Append("</a>")
4159 Private Function AutoLinkHashtag(ByVal m As Match) As String
4160 If IsNumeric(m.Result("$2")) Then Return m.Result("$1#$2")
4161 Dim sb As New StringBuilder(m.Result("$1<a href="""))
4162 Return sb.Append(_protocol).Append("twitter.com/search?q=%23").Append(m.Result("$2"">#$2</a>")).ToString
4165 Public ReadOnly Property RemainCountApi() As Integer
4167 Return twCon.RemainCountApi
4171 Public Function GetInfoApi(ByRef info As ApiInfo) As Boolean
4172 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return True
4174 If _endingFlag Then Return True
4176 'info.MaxCount = twCon.UpperCountApi
4177 'info.RemainCount = twCon.RemainCountApi
4178 'info.ResetTime = twCon.ResetTimeApi
4180 Dim res As HttpStatusCode
4181 Dim content As String = ""
4183 res = twCon.RateLimitStatus(content)
4184 Catch ex As Exception
4188 If res <> HttpStatusCode.OK Then Return False
4190 Dim xdoc As New XmlDocument
4192 xdoc.LoadXml(content)
4193 info.MaxCount = Integer.Parse(xdoc.SelectSingleNode("/hash/hourly-limit").InnerText)
4194 info.RemainCount = Integer.Parse(xdoc.SelectSingleNode("/hash/remaining-hits").InnerText)
4195 info.ResetTime = DateTime.Parse(xdoc.SelectSingleNode("/hash/reset-time").InnerText)
4196 'info.ResetTimeInSeconds = Integer.Parse(xdoc.SelectSingleNode("/hash/reset-time-in-seconds").InnerText)
4198 Catch ex As Exception
4203 Public Function GetHashList() As String()
4204 Dim hashArray As String()
4206 hashArray = _hashList.ToArray
4212 '#Region "デバッグモード解析キー自動生成"
4214 ' Public Sub GenerateAnalyzeKey()
4215 ' '解析キー情報部分のソースをwedataから作成する
4216 ' '生成したソースはプロジェクトのディレクトリにコピーする
4217 ' Dim sw As New System.IO.StreamWriter(".\AnalyzeKey.vb", _
4219 ' System.Text.Encoding.UTF8)
4221 ' sw.WriteLine("Public Module AnalyzeKey")
4222 ' sw.WriteLine("' このファイルはデバッグビルドのTweenにより自動作成されました 作成日時 " + DateAndTime.Now.ToString())
4225 ' sw.WriteLine(" Public _splitPost As String = " + Chr(34) + _splitPost.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4226 ' sw.WriteLine(" Public _splitPostRecent As String = " + Chr(34) + _splitPostRecent.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4227 ' sw.WriteLine(" Public _statusIdTo As String = " + Chr(34) + _statusIdTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4228 ' sw.WriteLine(" Public _splitDM As String = " + Chr(34) + _splitDM.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4229 ' sw.WriteLine(" Public _parseName As String = " + Chr(34) + _parseName.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4230 ' sw.WriteLine(" Public _parseNameTo As String = " + Chr(34) + _parseNameTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4231 ' sw.WriteLine(" Public _parseNick As String = " + Chr(34) + _parseNick.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4232 ' sw.WriteLine(" Public _parseNickTo As String = " + Chr(34) + _parseNickTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4233 ' sw.WriteLine(" Public _parseImg As String = " + Chr(34) + _parseImg.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4234 ' sw.WriteLine(" Public _parseImgTo As String = " + Chr(34) + _parseImgTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4235 ' sw.WriteLine(" Public _parseMsg1 As String = " + Chr(34) + _parseMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4236 ' sw.WriteLine(" Public _parseMsg2 As String = " + Chr(34) + _parseMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4237 ' sw.WriteLine(" Public _parseDM1 As String = " + Chr(34) + _parseDM1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4238 ' sw.WriteLine(" Public _parseDM11 As String = " + Chr(34) + _parseDM11.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4239 ' sw.WriteLine(" Public _parseDM2 As String = " + Chr(34) + _parseDM2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4240 ' sw.WriteLine(" Public _parseDate As String = " + Chr(34) + _parseDate.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4241 ' sw.WriteLine(" Public _parseDateTo As String = " + Chr(34) + _parseDateTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4242 ' sw.WriteLine(" Public _getAuthKey As String = " + Chr(34) + _getAuthKey.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4243 ' sw.WriteLine(" Public _getAuthKeyTo As String = " + Chr(34) + _getAuthKeyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4244 ' 'sw.WriteLine(" Public _parseStar As String = " + Chr(34) + _parseStar.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4245 ' 'sw.WriteLine(" Public _parseStarTo As String = " + Chr(34) + _parseStarTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4246 ' 'sw.WriteLine(" Public _parseStarEmpty As String = " + Chr(34) + _parseStarEmpty.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4247 ' sw.WriteLine(" Public _followerList As String = " + Chr(34) + _followerList.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4248 ' sw.WriteLine(" Public _followerMbr1 As String = " + Chr(34) + _followerMbr1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4249 ' sw.WriteLine(" Public _followerMbr2 As String = " + Chr(34) + _followerMbr2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4250 ' sw.WriteLine(" Public _followerMbr3 As String = " + Chr(34) + _followerMbr3.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4251 ' sw.WriteLine(" Public _getInfoTwitter As String = " + Chr(34) + _getInfoTwitter.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4252 ' sw.WriteLine(" Public _getInfoTwitterTo As String = " + Chr(34) + _getInfoTwitterTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4253 ' sw.WriteLine(" Public _isProtect As String = " + Chr(34) + _isProtect.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4254 ' sw.WriteLine(" Public _isReplyEng As String = " + Chr(34) + _isReplyEng.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4255 ' sw.WriteLine(" Public _isReplyJpn As String = " + Chr(34) + _isReplyJpn.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4256 ' sw.WriteLine(" Public _isReplyTo As String = " + Chr(34) + _isReplyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4257 ' sw.WriteLine(" Public _parseProtectMsg1 As String = " + Chr(34) + _parseProtectMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4258 ' sw.WriteLine(" Public _parseProtectMsg2 As String = " + Chr(34) + _parseProtectMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4259 ' sw.WriteLine(" Public _parseDMcountFrom As String = " + Chr(34) + _parseDMcountFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4260 ' sw.WriteLine(" Public _parseDMcountTo As String = " + Chr(34) + _parseDMcountTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4261 ' sw.WriteLine(" Public _parseSourceFrom As String = " + Chr(34) + _parseSourceFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4262 ' sw.WriteLine(" Public _parseSource2 As String = " + Chr(34) + _parseSource2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4263 ' sw.WriteLine(" Public _parseSourceTo As String = " + Chr(34) + _parseSourceTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4264 ' sw.WriteLine(" Public _removeClass As String = " + Chr(34) + _removeClass.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
4265 ' sw.WriteLine("End Module")
4268 ' 'MessageBox.Show("解析キー情報定義ファイル AnalyzeKey.vbを生成しました")
4274 Public ReadOnly Property AccessToken() As String
4276 Return twCon.AccessToken
4280 Public ReadOnly Property AccessTokenSecret() As String
4282 Return twCon.AccessTokenSecret