1 ' Tween - Client of Twitter
2 ' Copyright (c) 2007-2009 kiri_feather (@kiri_feather) <kiri_feather@gmail.com>
3 ' (c) 2008-2009 Moz (@syo68k) <http://iddy.jp/profile/moz/>
4 ' (c) 2008-2009 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
34 Delegate Sub GetIconImageDelegate(ByVal post As PostClass)
35 Delegate Function GetTimelineDelegate(ByVal page As Integer, _
36 ByVal read As Boolean, _
37 ByRef endPage As Integer, _
38 ByVal gType As WORKERTYPE, _
39 ByRef getDM As Boolean) As String
40 Delegate Function GetDirectMessageDelegate(ByVal page As Integer, _
41 ByVal read As Boolean, _
42 ByVal endPage As Integer, _
43 ByVal gType As WORKERTYPE) As String
44 Private ReadOnly LockObj As New Object
45 Private GetTmSemaphore As New Threading.Semaphore(8, 8)
47 Private follower As New List(Of String)
48 Private followerId As New List(Of Long)
49 Private tmpFollower As New List(Of String)
51 Private _followersCount As Integer = 0
52 Private _friendsCount As Integer = 0
53 Private _statusesCount As Integer = 0
54 Private _location As String = ""
55 Private _bio As String = ""
56 Private _useSsl As Boolean = True
57 Private _protocol As String = "https://"
58 Private _bitlyId As String = ""
59 Private _bitlyKey As String = ""
62 Private _uid As String
63 Private _pwd As String
64 Private _proxyType As ProxyType
65 Private _proxyAddress As String
66 Private _proxyPort As Integer
67 Private _proxyUser As String
68 Private _proxyPassword As String
70 Private _nextThreshold As Integer
71 Private _nextPages As Integer
73 Private _iconSz As Integer
74 Private _getIcon As Boolean
75 Private _lIcon As ImageList
76 Private _dIcon As Dictionary(Of String, Image)
78 Private _tinyUrlResolve As Boolean
79 Private _restrictFavCheck As Boolean
80 Private _useAPI As Boolean
82 Private _hubServer As String
83 Private _defaultTimeOut As Integer ' MySocketクラスへ渡すタイムアウト待ち時間(秒単位 ミリ秒への換算はMySocketクラス側で行う)
84 Private _countApi As Integer
85 Private _usePostMethod As Boolean
86 Private _ApiMethod As MySocket.REQ_TYPE
87 Private _readOwnPost As Boolean
90 Private _authKey As String 'StatusUpdate、発言削除で使用
91 Private _authKeyDM As String 'DM送信、DM削除で使用
92 Private _signed As Boolean
93 Private _infoTwitter As String = ""
94 Private _dmCount As Integer
95 Private _getDm As Boolean
96 Private _remainCountApi As Integer = -1
98 Private _ShortUrlService() As String = { _
99 "http://tinyurl.com/", _
101 "http://snipurl.com/", _
102 "http://snurl.com/", _
104 "http://qurlyq.com/", _
105 "http://dwarfurl.com/", _
106 "http://icanhaz.com/", _
108 "http://urlenco.de/", _
110 "http://piurl.com/", _
111 "http://linkbee.com/", _
112 "http://traceurl.com/", _
113 "http://twurl.nl/", _
115 "http://rubyurl.com/", _
116 "http://budurl.com/", _
118 "http://twitthis.com/", _
120 "http://tumblr.com/", _
121 "http://www.qurl.com/", _
122 "http://digg.com/", _
124 "http://ustre.am/", _
126 "http://airme.us/", _
127 "http://qurl.com/", _
128 "http://bctiny.com/", _
133 Private Const _apiHost As String = "api."
134 Private Const _baseUrlStr As String = "twitter.com"
135 Private Const _loginPath As String = "/sessions"
136 Private Const _homePath As String = "/home"
137 Private Const _replyPath As String = "/replies"
138 Private Const _DMPathRcv As String = "/inbox"
139 Private Const _DMPathSnt As String = "/sent"
140 Private Const _DMDestroyPath As String = "/direct_messages/destroy/"
141 Private Const _StDestroyPath As String = "/statuses/destroy/"
142 Private Const _postRetweetPath As String = "/1/statuses/retweet/"
143 Private Const _uidHeader As String = "session[username_or_email]="
144 Private Const _pwdHeader As String = "session[password]="
145 Private Const _pageQry As String = "?page="
146 Private Const _cursorQry As String = "?cursor="
147 Private Const _statusHeader As String = "status="
148 Private Const _statusUpdatePathAPI As String = "/statuses/update.xml"
149 Private Const _linkToOld As String = "class=""section_links"" rel=""prev"""
150 Private Const _postFavAddPath As String = "/favorites/create/"
151 Private Const _postFavRemovePath As String = "/favorites/destroy/"
152 Private Const _authKeyHeader As String = "authenticity_token="
153 'Private Const _parseLink1 As String = "<a href="""
154 'Private Const _parseLink2 As String = """>"
155 'Private Const _parseLink3 As String = "</a>"
156 Private Const _GetFollowers As String = "/statuses/followers.xml"
157 Private Const _ShowStatus As String = "/statuses/show/"
158 Private Const _rateLimitStatus As String = "/account/rate_limit_status.xml"
161 Private Const wedataUrl As String = "http://wedata.net/databases/Tween/items.json"
163 Private Function SignIn() As String
164 If _endingFlag Then Return ""
167 Dim account As String = ""
168 Static skipCount As Integer = 0
171 If _signed Then Return ""
172 If Twitter.AccountState <> ACCOUNT_STATE.Valid AndAlso skipCount < 10 Then
174 Return "SignIn -> Check Username/Password in setting."
181 MySocket.ResetCookie()
183 Dim resStatus As String = ""
184 Dim resMsg As String = ""
186 '設定によらずログイン処理はhttps固定
187 resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + "/login", resStatus, MySocket.REQ_TYPE.ReqGET), String)
188 If resMsg.Length = 0 Then
189 'Twitter.AccountState = ACCOUNT_STATE.Invalid
190 Return "SignIn -> " + resStatus
192 Dim authToken As String = ""
193 Dim rg As New Regex("authenticity_token"" type=""hidden"" value=""(?<auth>[a-z0-9]+)""")
194 Dim m As Match = rg.Match(resMsg)
196 authToken = m.Result("${auth}")
198 Return "SignIn -> Can't get token."
201 account = _authKeyHeader + authToken + "&" + _uidHeader + _uid + "&" + _pwdHeader + HttpUtility.UrlEncode(_pwd) + "&" + "remember_me=1"
204 resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + _loginPath, resStatus, MySocket.REQ_TYPE.ReqPOST, account), String)
205 If resStatus.StartsWith("OK") Then
206 'OK (username/passwordが合致しない)
207 Dim msg As String = resStatus
208 If resMsg.Contains("Wrong Username/Email and password combination.") Then
209 msg = "Wrong Username or password."
211 '未知の応答(May be required Chapta)
212 msg = "Wrong Username or password. Try from web."
214 Twitter.AccountState = ACCOUNT_STATE.Invalid
215 Return "SignIn Failed -> " + msg
216 ElseIf resMsg.Contains("https://twitter.com/account/locked") Then '302 FOUND
217 Dim msg As String = "You account is Locked Out."
218 Twitter.AccountState = ACCOUNT_STATE.Invalid
219 Return "SignIn Failed -> " + msg
220 ElseIf resMsg.Contains("https://twitter.com:443/") Then '302 FOUND
222 ElseIf resMsg.Contains("https://twitter.com/") OrElse _
223 resMsg.Contains("http://twitter.com/") Then '302 FOUND
225 ElseIf resStatus.StartsWith("Err:") Then
227 Return "SignIn Failed -> " + resStatus
229 '応答がOK でありサインインできていない場合の未知の応答
230 'TraceOut(True, "SignIn Failed." + vbCrLf + "resStatus:" + resStatus + vbCrLf + "resMsg:" + vbCrLf + resMsg)
231 Twitter.AccountState = ACCOUNT_STATE.Invalid
232 Return "SignIn Failed -> " + "Unknown problems."
234 Twitter.AccountState = ACCOUNT_STATE.Valid
240 Public Function GetTimeline(ByVal page As Integer, _
241 ByVal read As Boolean, _
242 ByRef endPage As Integer, _
243 ByVal gType As WORKERTYPE, _
244 ByRef getDM As Boolean) As String
248 Dim epage As Integer = page
249 GetTmSemaphore.WaitOne()
250 Dim trslt As String = ""
251 trslt = GetTimelineThread(page, read, epage, gType, getDM)
252 If trslt.Length > 0 Then Return trslt
254 If epage < page OrElse gType = WORKERTYPE.Reply Then Return ""
257 '起動時モード or 通常モードの読み込み継続 -> 複数ページ同時取得
258 Dim num As Integer = endPage - page
259 Dim ar(num) As IAsyncResult
260 Dim dlgt(num) As GetTimelineDelegate
262 For idx As Integer = 0 To num
263 dlgt(idx) = New GetTimelineDelegate(AddressOf GetTimelineThread)
264 GetTmSemaphore.WaitOne()
265 ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, getDM, Nothing, Nothing)
267 Dim rslt As String = ""
268 For idx As Integer = 0 To num
269 Dim epage As Integer = 0
270 Dim dm As Boolean = False
271 Dim trslt As String = ""
273 trslt = dlgt(idx).EndInvoke(epage, dm, ar(idx))
274 Catch ex As Exception
275 '最後までendinvoke回す(ゾンビ化回避)
276 ex.Data("IsTerminatePermission") = False
278 rslt = "GetTimelineErr"
280 If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
281 If dm Then getDM = True
286 Private Function GetTimelineThread(ByVal page As Integer, _
287 ByVal read As Boolean, _
288 ByRef endPage As Integer, _
289 ByVal gType As WORKERTYPE, _
290 ByRef getDM As Boolean) As String
292 If _endingFlag Then Return ""
294 Dim retMsg As String = ""
295 Dim resStatus As String = ""
297 Static redirectToTimeline As String = ""
298 Static redirectToReply As String = ""
300 If _signed = False Then
302 If retMsg.Length > 0 Then
307 If _endingFlag Then Return ""
310 Dim pageQuery As String
315 pageQuery = _pageQry + page.ToString
318 If gType = WORKERTYPE.Timeline Then
319 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _homePath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
321 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _replyPath + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
324 If retMsg.Length = 0 Then
330 retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+"")", "${tagStart}")
333 ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
334 ' If idx = -1 Then Exit Do
335 ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
336 ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
337 ' Catch ex As Exception
339 ' TraceOut("TM-Remove: " + retMsg)
340 ' Return "GetTimeline -> Err: Can't parse data."
344 If _endingFlag Then Return ""
347 Dim strSepTmp As String
348 If gType = WORKERTYPE.Timeline Then
349 strSepTmp = _splitPostRecent
351 strSepTmp = _splitPost
357 pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
361 Return "GetTimeline -> Err: tweets count is 0."
364 Dim strSep() As String = {strSepTmp}
365 Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
366 Dim intCnt As Integer = 0
367 Dim listCnt As Integer = 0
369 listCnt = TabInformations.GetInstance.ItemCount
371 Dim dlgt(20) As GetIconImageDelegate
372 Dim ar(20) As IAsyncResult
373 Dim arIdx As Integer = -1
377 For Each strPost As String In posts
381 If page = 1 And gType = WORKERTYPE.Timeline Then
383 'pos1 = strPost.IndexOf(_getSiv, 0)
385 ' pos2 = strPost.IndexOf(_getSivTo, pos1 + _getSiv.Length)
387 ' _authSiv = strPost.Substring(pos1 + _getSiv.Length, pos2 - pos1 - _getSiv.Length)
391 ' Return "GetTimeline -> Err: Can't get Siv."
396 ' Return "GetTimeline -> Err: Can't get Siv."
400 If GetAuthKey(retMsg) < 0 Then
402 Return "GetTimeline -> Err: Can't get auth token."
406 pos1 = retMsg.IndexOf(_getInfoTwitter, StringComparison.Ordinal)
408 pos2 = retMsg.IndexOf(_getInfoTwitterTo, pos1, StringComparison.Ordinal)
410 _infoTwitter = retMsg.Substring(pos1 + _getInfoTwitter.Length, pos2 - pos1 - _getInfoTwitter.Length)
420 Dim post As New PostClass
422 pos1 = strPost.IndexOf("</ol>")
424 strPost = strPost.Substring(0, pos1)
430 pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
431 post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
432 Catch ex As Exception
434 TraceOut("TM-ID:" + strPost)
435 Return "GetTimeline -> Err: Can't get ID."
439 pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
440 pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
441 post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
442 Catch ex As Exception
444 TraceOut("TM-Name:" + strPost)
445 Return "GetTimeline -> Err: Can't get Name."
449 If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
450 post.Nickname = post.Name
453 pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
454 pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
455 post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
456 Catch ex As Exception
458 TraceOut("TM-Nick:" + strPost)
459 Return "GetTimeline -> Err: Can't get Nick."
465 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
468 Dim orgData As String = ""
470 If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
472 pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
473 pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
474 orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
475 Catch ex As Exception
477 TraceOut("TM-VBody:" + strPost)
478 Return "GetTimeline -> Err: Can't get Valentine body."
485 pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
486 pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
487 post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
488 Catch ex As Exception
490 TraceOut("TM-Img:" + strPost)
491 Return "GetTimeline -> Err: Can't get ImagePath."
495 If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
496 post.IsProtect = True
500 If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
501 rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
502 m = rg.Match(strPost)
504 post.RetweetedBy = m.Result("${name}")
506 post.RetweetedBy = ""
508 rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
509 m = rg.Match(strPost)
511 post.RetweetedId = Long.Parse(m.Result("${id}"))
518 pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
522 If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
524 orgData += " <3 you! Do you <3 "
525 pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
526 pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
527 orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
529 pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
533 pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
535 pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
536 orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
540 pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
541 orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
544 Catch ex As Exception
546 TraceOut("TM-VBody2:" + strPost)
547 Return "GetTimeline -> Err: Can't get Valentine body2."
552 pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
553 orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
554 Catch ex As Exception
556 TraceOut("TM-Body:" + strPost)
557 Return "GetTimeline -> Err: Can't get body."
561 ' orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
564 orgData = orgData.Replace("<3", "♡")
568 orgData = PreProcessUrl(orgData)
570 '短縮URL解決処理(orgData書き換え)
571 orgData = ShortUrlResolve(orgData)
574 post.OriginalData = AdjustHtml(orgData)
576 '単純テキストの取り出し(リンクタグ除去)
578 post.Data = GetPlainText(orgData)
579 Catch ex As Exception
581 TraceOut("TM-Link:" + strPost)
582 Return "GetTimeline -> Err: Can't parse links."
586 Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
587 If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
592 pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
594 pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
595 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)
599 Catch ex As Exception
601 TraceOut("TM-Date:" + strPost)
602 Return "GetTimeline -> Err: Can't get date."
605 '取得できなくなったため暫定対応(2/26)
611 'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
612 rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
613 m = rg.Match(strPost)
615 post.Source = m.Result("${name}")
620 ' pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
621 ' If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
623 ' pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
624 ' pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
625 ' post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
627 ' post.Source = "Web"
629 'Catch ex As Exception
631 ' TraceOut("TM-Src:" + strPost)
632 ' Return "GetTimeline -> Err: Can't get src."
635 'Get Reply(in_reply_to_user/id)
636 'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
637 rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
638 m = rg.Match(strPost)
640 post.InReplyToUser = m.Result("${name}")
641 post.InReplyToId = Long.Parse(m.Result("${id}"))
642 post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
646 rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
647 m = rg.Match(orgData)
649 post.ReplyToList.Add(m.Groups(1).Value.ToLower())
652 If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
654 If gType = WORKERTYPE.Reply Then post.IsReply = True
657 If strPost.IndexOf("class=""fav-action fav""") > -1 Then
662 'pos1 = strPost.IndexOf(_parseStar, pos2, StringComparison.Ordinal)
665 ' pos2 = strPost.IndexOf(_parseStarTo, pos1 + _parseStar.Length, StringComparison.Ordinal)
666 ' If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = _parseStarEmpty Then
671 ' Catch ex As Exception
673 ' TraceOut("TM-Fav:" + strPost)
674 ' Return "GetTimeline -> Err: Can't get fav status."
680 If _endingFlag Then Return ""
682 post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
684 If follower.Count > 1 Then
685 post.IsOwl = Not follower.Contains(post.Name.ToLower())
691 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
694 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
695 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
700 If intCnt = posts.Length AndAlso gType = WORKERTYPE.Timeline AndAlso page = 1 Then
701 pos1 = strPost.IndexOf(_parseDMcountFrom, pos2, StringComparison.Ordinal)
704 pos2 = strPost.IndexOf(_parseDMcountTo, pos1 + _parseDMcountFrom.Length, StringComparison.Ordinal)
705 Dim dmCnt As Integer = Integer.Parse(strPost.Substring(pos1 + _parseDMcountFrom.Length, pos2 - pos1 - _parseDMcountFrom.Length))
706 If dmCnt > _dmCount Then
710 Catch ex As Exception
711 Return "GetTimeline -> Err: Can't get DM count."
718 For i As Integer = 0 To arIdx
720 dlgt(i).EndInvoke(ar(i))
721 Catch ex As Exception
722 '最後までendinvoke回す(ゾンビ化回避)
723 ex.Data("IsTerminatePermission") = False
729 If page = 1 AndAlso (TabInformations.GetInstance.ItemCount - listCnt) >= _nextThreshold Then
730 '新着が閾値の件数以上なら、次のページも念のため読み込み
731 endPage = _nextPages + 1
737 GetTmSemaphore.Release()
741 Public Function GetDirectMessage(ByVal page As Integer, _
742 ByVal read As Boolean, _
743 ByVal endPage As Integer, _
744 ByVal gType As WORKERTYPE) As String
751 Dim num As Integer = endPage - page
752 Dim ar(num) As IAsyncResult
753 Dim dlgt(num) As GetDirectMessageDelegate
755 For idx As Integer = 0 To num
756 gType = WORKERTYPE.DirectMessegeRcv
757 dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
758 GetTmSemaphore.WaitOne()
759 ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
761 Dim rslt As String = ""
762 For idx As Integer = 0 To num
763 Dim trslt As String = ""
765 trslt = dlgt(idx).EndInvoke(ar(idx))
766 Catch ex As Exception
767 '最後までendinvoke回す(ゾンビ化回避)
768 ex.Data("IsTerminatePermission") = False
770 rslt = "GetDirectMessageErr"
772 If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
774 For idx As Integer = 0 To num
775 gType = WORKERTYPE.DirectMessegeSnt
776 dlgt(idx) = New GetDirectMessageDelegate(AddressOf GetDirectMessageThread)
777 GetTmSemaphore.WaitOne()
778 ar(idx) = dlgt(idx).BeginInvoke(page + idx, read, endPage + idx, gType, Nothing, Nothing)
780 For idx As Integer = 0 To num
781 Dim trslt As String = ""
783 trslt = dlgt(idx).EndInvoke(ar(idx))
784 Catch ex As Exception
785 '最後までendinvoke回す(ゾンビ化回避)
786 ex.Data("IsTerminatePermission") = False
788 rslt = "GetDirectMessageErr"
790 If trslt.Length > 0 AndAlso rslt.Length = 0 Then rslt = trslt
795 Private Function GetDirectMessageThread(ByVal page As Integer, _
796 ByVal read As Boolean, _
797 ByVal endPage As Integer, _
798 ByVal gType As WORKERTYPE) As String
800 If _endingFlag Then Return ""
802 Dim retMsg As String = ""
803 Dim resStatus As String = ""
805 Static redirectToDmRcv As String = ""
806 Static redirectToDmSnd As String = ""
810 If _signed = False Then
812 If retMsg.Length > 0 Then
817 If _endingFlag Then Return ""
820 Dim pageQuery As String = _pageQry + page.ToString
821 If gType = WORKERTYPE.DirectMessegeRcv Then
822 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathRcv + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
824 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMPathSnt + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
827 If retMsg.Length = 0 Then
833 retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+"")", "${tagStart}")
836 ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
837 ' If idx = -1 Then Exit Do
838 ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
839 ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
840 ' Catch ex As Exception
842 ' TraceOut("DM-Remove: " + retMsg)
843 ' Return "GetDm -> Err: Can't parse data."
847 If _endingFlag Then Return ""
850 'If GetAuthKeyDM(retMsg) < 0 Then
852 ' Return "GetDirectMessage -> Err: Busy(1)"
859 pos1 = retMsg.IndexOf(_splitDM, StringComparison.Ordinal)
861 '0件(メッセージなし。エラーの場合もありうるが判別できないので正常として戻す)
865 Dim strSep() As String = {_splitDM}
866 Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
867 Dim intCnt As Integer = 0 'カウンタ
868 Dim listCnt As Integer = 0
870 listCnt = TabInformations.GetInstance.ItemCount
872 Dim dlgt(20) As GetIconImageDelegate
873 Dim ar(20) As IAsyncResult
874 Dim arIdx As Integer = -1
876 For Each strPost As String In posts
879 If intCnt > 1 Then '1件目はヘッダなので無視
880 'Dim lItem As New MyListItem
881 Dim post As New PostClass()
883 pos1 = strPost.IndexOf("</ol>")
885 strPost = strPost.Substring(0, pos1)
891 pos2 = strPost.IndexOf("""", 0, StringComparison.Ordinal)
892 post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
893 Catch ex As Exception
895 TraceOut("DM-ID:" + strPost)
896 Return "GetDirectMessage -> Err: Can't get ID"
901 pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
902 pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
903 post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
904 Catch ex As Exception
906 TraceOut("DM-Name:" + strPost)
907 Return "GetDirectMessage -> Err: Can't get Name"
912 pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
913 pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
914 post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
915 Catch ex As Exception
917 TraceOut("DM-Nick:" + strPost)
918 Return "GetDirectMessage -> Err: Can't get Nick."
922 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
927 pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
928 pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
929 post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
930 Catch ex As Exception
932 TraceOut("DM-Img:" + strPost)
933 Return "GetDirectMessage -> Err: Can't get ImagePath"
938 pos1 = strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal)
939 If pos1 > -1 Then post.IsProtect = True
940 Catch ex As Exception
942 TraceOut("DM-Protect:" + strPost)
943 Return "GetDirectMessage -> Err: Can't get Protect"
946 Dim orgData As String = ""
950 pos1 = strPost.IndexOf(_parseDM1, pos2, StringComparison.Ordinal)
952 pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
953 orgData = strPost.Substring(pos1 + _parseDM1.Length, pos2 - pos1 - _parseDM1.Length).Trim()
955 pos1 = strPost.IndexOf(_parseDM11, pos2, StringComparison.Ordinal)
956 pos2 = strPost.IndexOf(_parseDM2, pos1, StringComparison.Ordinal)
957 orgData = strPost.Substring(pos1 + _parseDM11.Length, pos2 - pos1 - _parseDM11.Length).Trim()
959 'orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
960 orgData = orgData.Replace("<3", "♡")
961 Catch ex As Exception
963 TraceOut("DM-Body:" + strPost)
964 Return "GetDirectMessage -> Err: Can't get body"
968 orgData = PreProcessUrl(orgData)
970 '短縮URL解決処理(orgData書き換え)
971 orgData = ShortUrlResolve(orgData)
974 post.OriginalData = AdjustHtml(orgData)
976 '単純テキストの取り出し(リンクタグ除去)
978 post.Data = GetPlainText(orgData)
979 Catch ex As Exception
981 TraceOut("DM-Link:" + strPost)
982 Return "GetDirectMessage -> Err: Can't parse links"
988 pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
990 pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
991 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)
995 Catch ex As Exception
997 TraceOut("DM-Date:" + strPost)
998 Return "GetDirectMessage -> Err: Can't get date."
1001 '取得できなくなったため暫定対応(2/26)
1006 'pos1 = strPost.IndexOf(_parseStar, pos2)
1007 'pos2 = strPost.IndexOf("""", pos1 + _parseStar.Length)
1008 'If strPost.Substring(pos1 + _parseStar.Length, pos2 - pos1 - _parseStar.Length) = "empty" Then
1016 If _endingFlag Then Return ""
1019 If gType = WORKERTYPE.DirectMessegeRcv Then
1030 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1031 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1035 For i As Integer = 0 To arIdx
1037 dlgt(i).EndInvoke(ar(i))
1038 Catch ex As Exception
1039 ex.Data("IsTerminatePermission") = False
1047 GetTmSemaphore.Release()
1051 Public Function GetFavorites(ByVal page As Integer, _
1052 ByVal read As Boolean, _
1053 ByRef endPage As Integer, _
1054 ByVal gType As WORKERTYPE, _
1055 ByRef getDM As Boolean) As String
1057 GetTmSemaphore.WaitOne()
1059 If _endingFlag Then Return ""
1061 Dim retMsg As String = ""
1062 Dim resStatus As String = ""
1064 Static redirectToFav As String = ""
1065 Const FAV_PATH As String = "/favorites"
1067 If _signed = False Then
1069 If retMsg.Length > 0 Then
1074 If _endingFlag Then Return ""
1077 Dim pageQuery As String
1082 pageQuery = _pageQry + page.ToString
1085 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + FAV_PATH + pageQuery, resStatus, MySocket.REQ_TYPE.ReqGetApp), String)
1087 If retMsg.Length = 0 Then
1092 ' tr 要素の class 属性を消去
1093 retMsg = Regex.Replace(retMsg, "(?<tagStart><li)(?<cls>\s+class=""[^""]+"")", "${tagStart}")
1096 ' Dim idx As Integer = retMsg.IndexOf(_removeClass, StringComparison.Ordinal)
1097 ' If idx = -1 Then Exit Do
1098 ' Dim idx2 As Integer = retMsg.IndexOf("""", idx + _removeClass.Length, StringComparison.Ordinal) - idx + 1 - 3
1099 ' If idx2 > 0 Then retMsg = retMsg.Remove(idx + 3, idx2)
1100 ' Catch ex As Exception
1102 ' TraceOut("GetFav-Remove: " + retMsg)
1103 ' Return "GetFav -> Err: Can't parse data."
1107 If _endingFlag Then Return ""
1110 Dim strSepTmp As String
1111 strSepTmp = _splitPostRecent
1116 pos1 = retMsg.IndexOf(strSepTmp, StringComparison.Ordinal)
1120 Return "GetTimeline -> Err: tweets count is 0."
1123 Dim strSep() As String = {strSepTmp}
1124 Dim posts() As String = retMsg.Split(strSep, StringSplitOptions.RemoveEmptyEntries)
1125 Dim intCnt As Integer = 0
1126 Dim listCnt As Integer = 0
1128 listCnt = TabInformations.GetInstance.ItemCount
1130 Dim dlgt(20) As GetIconImageDelegate
1131 Dim ar(20) As IAsyncResult
1132 Dim arIdx As Integer = -1
1136 For Each strPost As String In posts
1143 Dim post As New PostClass
1145 pos1 = strPost.IndexOf("</ol>")
1147 strPost = strPost.Substring(0, pos1)
1153 pos2 = strPost.IndexOf(_statusIdTo, 0, StringComparison.Ordinal)
1154 post.Id = Long.Parse(HttpUtility.HtmlDecode(strPost.Substring(0, pos2)))
1155 Catch ex As Exception
1157 TraceOut("TM-ID:" + strPost)
1158 Return "GetTimeline -> Err: Can't get ID."
1162 pos1 = strPost.IndexOf(_parseName, pos2, StringComparison.Ordinal)
1163 pos2 = strPost.IndexOf(_parseNameTo, pos1, StringComparison.Ordinal)
1164 post.Name = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseName.Length, pos2 - pos1 - _parseName.Length))
1165 Catch ex As Exception
1167 TraceOut("TM-Name:" + strPost)
1168 Return "GetTimeline -> Err: Can't get Name."
1172 If strPost.IndexOf("twitter.com/images/heart.png", pos2, StringComparison.Ordinal) > -1 Then
1173 post.Nickname = post.Name
1176 pos1 = strPost.IndexOf(_parseNick, pos2, StringComparison.Ordinal)
1177 pos2 = strPost.IndexOf(_parseNickTo, pos1 + _parseNick.Length, StringComparison.Ordinal)
1178 post.Nickname = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseNick.Length, pos2 - pos1 - _parseNick.Length))
1179 Catch ex As Exception
1181 TraceOut("TM-Nick:" + strPost)
1182 Return "GetTimeline -> Err: Can't get Nick."
1188 ' If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
1191 Dim orgData As String = ""
1193 If strPost.IndexOf("<form action=""/status/update"" id=""heartForm", 0, StringComparison.Ordinal) > -1 Then
1195 pos1 = strPost.IndexOf("<strong>", 0, StringComparison.Ordinal)
1196 pos2 = strPost.IndexOf("</strong>", pos1, StringComparison.Ordinal)
1197 orgData = strPost.Substring(pos1 + 8, pos2 - pos1 - 8)
1198 Catch ex As Exception
1200 TraceOut("TM-VBody:" + strPost)
1201 Return "GetTimeline -> Err: Can't get Valentine body."
1208 pos1 = strPost.IndexOf(_parseImg, pos2, StringComparison.Ordinal)
1209 pos2 = strPost.IndexOf(_parseImgTo, pos1 + _parseImg.Length, StringComparison.Ordinal)
1210 post.ImageUrl = HttpUtility.HtmlDecode(strPost.Substring(pos1 + _parseImg.Length, pos2 - pos1 - _parseImg.Length))
1211 Catch ex As Exception
1213 TraceOut("TM-Img:" + strPost)
1214 Return "GetTimeline -> Err: Can't get ImagePath."
1218 If strPost.IndexOf(_isProtect, pos2, StringComparison.Ordinal) > -1 Then
1219 post.IsProtect = True
1223 If strPost.IndexOf("class=""big-retweet-icon""") > -1 Then
1224 rg = New Regex("class=""shared-content"".+<a href=""/(?<name>[a-zA-Z0-9_]+)""")
1225 m = rg.Match(strPost)
1227 post.RetweetedBy = m.Result("${name}")
1229 post.RetweetedBy = ""
1231 rg = New Regex("&in_reply_to_status_id=(?<id>[0-9]+)&in_reply_to=")
1232 m = rg.Match(strPost)
1234 post.RetweetedId = Long.Parse(m.Result("${id}"))
1236 post.RetweetedId = 0
1241 pos1 = strPost.IndexOf(_parseMsg1, pos2, StringComparison.Ordinal)
1245 If strPost.IndexOf("<div id=""doyouheart", pos2, StringComparison.Ordinal) > -1 Then
1247 orgData += " <3 you! Do you <3 "
1248 pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1249 pos2 = strPost.IndexOf("?", pos1, StringComparison.Ordinal)
1250 orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1252 pos1 = strPost.IndexOf(_parseProtectMsg1, pos2, StringComparison.Ordinal)
1255 orgData += " <3 's "
1256 pos1 = strPost.IndexOf("<a href", pos2, StringComparison.Ordinal)
1258 pos2 = strPost.IndexOf("!", pos1, StringComparison.Ordinal)
1259 orgData += strPost.Substring(pos1, pos2 - pos1 + 1)
1263 pos2 = strPost.IndexOf(_parseProtectMsg2, pos1, StringComparison.Ordinal)
1264 orgData = strPost.Substring(pos1 + _parseProtectMsg1.Length, pos2 - pos1 - _parseProtectMsg1.Length).Trim()
1267 Catch ex As Exception
1269 TraceOut("TM-VBody2:" + strPost)
1270 Return "GetTimeline -> Err: Can't get Valentine body2."
1275 pos2 = strPost.IndexOf(_parseMsg2, pos1, StringComparison.Ordinal)
1276 orgData = strPost.Substring(pos1 + _parseMsg1.Length, pos2 - pos1 - _parseMsg1.Length).Trim()
1277 Catch ex As Exception
1279 TraceOut("TM-Body:" + strPost)
1280 Return "GetTimeline -> Err: Can't get body."
1284 ' orgData = Regex.Replace(orgData, "<a href=""https://twitter\.com/" + post.Name + "/status/[0-9]+"">\.\.\.</a>$", "")
1287 orgData = orgData.Replace("<3", "♡")
1291 orgData = PreProcessUrl(orgData)
1293 '短縮URL解決処理(orgData書き換え)
1294 orgData = ShortUrlResolve(orgData)
1297 post.OriginalData = AdjustHtml(orgData)
1299 '単純テキストの取り出し(リンクタグ除去)
1301 post.Data = GetPlainText(orgData)
1302 Catch ex As Exception
1304 TraceOut("TM-Link:" + strPost)
1305 Return "GetTimeline -> Err: Can't parse links."
1309 Dim ImgTag As New Regex("<img src=.*?/>", RegexOptions.IgnoreCase)
1310 If ImgTag.IsMatch(post.Data) Then post.Data = ImgTag.Replace(post.Data, "<img>")
1315 pos1 = strPost.IndexOf(_parseDate, pos2, StringComparison.Ordinal)
1317 pos2 = strPost.IndexOf(_parseDateTo, pos1 + _parseDate.Length, StringComparison.Ordinal)
1318 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)
1322 Catch ex As Exception
1324 TraceOut("TM-Date:" + strPost)
1325 Return "GetTimeline -> Err: Can't get date."
1328 '取得できなくなったため暫定対応(2/26)
1334 'ToDo: _parseSourceFromを正規表現へ。wedataからの取得へ変更(次版より)
1335 rg = New Regex("<span>.+>(?<name>.+)</a>.*</span>")
1336 m = rg.Match(strPost)
1338 post.Source = m.Result("${name}")
1343 ' pos1 = strPost.IndexOf(_parseSourceFrom, pos2, StringComparison.Ordinal)
1344 ' If pos1 = -1 Then pos1 = strPost.IndexOf(_parseSourceFrom2, pos2, StringComparison.Ordinal)
1346 ' pos1 = strPost.IndexOf(_parseSource2, pos1 + 19, StringComparison.Ordinal)
1347 ' pos2 = strPost.IndexOf(_parseSourceTo, pos1 + 2, StringComparison.Ordinal)
1348 ' post.Source = HttpUtility.HtmlDecode(strPost.Substring(pos1 + 2, pos2 - pos1 - 2))
1350 ' post.Source = "Web"
1352 'Catch ex As Exception
1354 ' TraceOut("TM-Src:" + strPost)
1355 ' Return "GetTimeline -> Err: Can't get src."
1358 'Get Reply(in_reply_to_user/id)
1359 'ToDo: _isReplyEngを正規表現へ。wedataからの取得へ変更(次版より)
1360 rg = New Regex("<a href=""https?:\/\/twitter\.com\/(?<name>[a-zA-Z0-9_]+)\/status\/(?<id>[0-9]+)"">(in reply to )*\k<name>")
1361 m = rg.Match(strPost)
1363 post.InReplyToUser = m.Result("${name}")
1364 post.InReplyToId = Long.Parse(m.Result("${id}"))
1365 post.IsReply = post.InReplyToUser.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1369 rg = New Regex("@<a [^>]*href=""\/(?<1>[a-zA-Z0-9_]+)[^a-zA-Z0-9_]")
1370 m = rg.Match(orgData)
1372 post.ReplyToList.Add(m.Groups(1).Value.ToLower())
1375 If Not post.IsReply Then post.IsReply = post.ReplyToList.Contains(_uid)
1380 If _endingFlag Then Return ""
1382 post.IsMe = post.Name.Equals(_uid, StringComparison.OrdinalIgnoreCase)
1384 If follower.Count > 1 Then
1385 post.IsOwl = Not follower.Contains(post.Name.ToLower())
1393 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
1394 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
1400 For i As Integer = 0 To arIdx
1402 dlgt(i).EndInvoke(ar(i))
1403 Catch ex As Exception
1404 '最後までendinvoke回す(ゾンビ化回避)
1405 ex.Data("IsTerminatePermission") = False
1412 GetTmSemaphore.Release()
1416 Private Function PreProcessUrl(ByVal orgData As String) As String
1417 Dim posl1 As Integer
1418 Dim posl2 As Integer = 0
1419 Dim IDNConveter As IdnMapping = New IdnMapping()
1420 Dim href As String = "<a href="""
1423 If orgData.IndexOf(href, posl2, StringComparison.Ordinal) > -1 Then
1424 Dim urlStr As String = ""
1426 posl1 = orgData.IndexOf(href, posl2, StringComparison.Ordinal)
1427 posl1 += href.Length
1428 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1429 urlStr = orgData.Substring(posl1, posl2 - posl1)
1431 If Not urlStr.StartsWith("http://") AndAlso Not urlStr.StartsWith("https://") AndAlso Not urlStr.StartsWith("ftp://") Then
1435 Dim replacedUrl As String = IDNDecode(urlStr)
1436 If replacedUrl Is Nothing Then Continue Do
1437 If replacedUrl = urlStr Then Continue Do
1439 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + replacedUrl)
1448 Private Function doShortUrlResolve(ByRef orgData As String) As Boolean
1449 Dim replaced As Boolean = False
1450 For Each _svc As String In _ShortUrlService
1451 Dim svc As String = _svc
1452 Dim posl1 As Integer
1453 Dim posl2 As Integer = 0
1456 If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1457 Dim urlStr As String = ""
1459 posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1460 posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1461 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1462 urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1463 Dim Response As String = ""
1464 Dim retUrlStr As String = ""
1465 Dim tmpurlStr As String = urlStr
1466 Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1467 Dim tmpSchemeAndDomain As String = ""
1468 For i As Integer = 0 To 4 'とりあえず5回試す
1469 retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo), String))
1470 If retUrlStr.Length > 0 Then
1471 ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1472 ' 取得試行回数オーバーの場合は取得結果を転送先とする
1473 Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1474 If scd.Success AndAlso scd.Value <> svc Then
1477 tmpurlStr = retUrlStr
1481 If tmpurlStr <> urlStr Then
1482 '少なくとも一度以上転送されている (前回の結果を転送先とする)
1483 retUrlStr = tmpurlStr
1491 If retUrlStr.Length > 0 Then
1492 If Not retUrlStr.StartsWith("http") Then
1493 If retUrlStr.StartsWith("/") Then
1494 retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1495 ElseIf retUrlStr.StartsWith("data:") Then
1498 retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1501 retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1503 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1504 posl2 = 0 '置換した場合は頭から再探索(複数同時置換での例外対応)
1507 Catch ex As Exception
1509 'Return "GetTimeline -> Err: Can't get tinyurl."
1520 Private Sub doShortUrlResolve(ByRef orgData As String)
1521 'Dim replaced As Boolean = False
1523 'Dim posl1 As Integer
1524 'Dim posl2 As Integer = 0
1525 Static urlCache As New Specialized.StringDictionary()
1526 If urlCache.Count > 500 Then urlCache.Clear() '定期的にリセット
1528 Dim rx As New Regex("<a href=""(?<svc>http://.+?/)(?<path>[^""]+)""", RegexOptions.IgnoreCase)
1529 Dim m As MatchCollection = rx.Matches(orgData)
1530 Dim urlList As New List(Of String)
1531 For Each orgUrlMatch As Match In m
1532 Dim orgUrl As String = orgUrlMatch.Result("${svc}")
1533 Dim orgUrlPath As String = orgUrlMatch.Result("${path}")
1534 If Array.IndexOf(_ShortUrlService, orgUrl) > -1 AndAlso _
1535 Not urlList.Contains(orgUrl + orgUrlPath) Then
1536 urlList.Add(orgUrl + orgUrlPath)
1539 For Each orgUrl As String In urlList
1540 If urlCache.ContainsKey(orgUrl) Then
1542 orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + urlCache(orgUrl) + """")
1543 Catch ex As Exception
1548 'urlとして生成できない場合があるらしい
1549 Dim urlstr As String = New Uri(urlEncodeMultibyteChar(orgUrl)).GetLeftPart(UriPartial.Path)
1550 Dim Response As String = ""
1551 Dim retUrlStr As String = ""
1552 Dim tmpurlStr As String = urlstr
1553 retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo, timeOut:=5000), String))
1554 If retUrlStr.StartsWith("http") Then
1555 retUrlStr = retUrlStr.Replace("""", "%22") 'ダブルコーテーションがあるとURL終端と判断されるため、これだけ再エンコード
1556 orgData = orgData.Replace("<a href=""" + orgUrl + """", "<a href=""" + retUrlStr + """")
1557 urlCache.Add(orgUrl, retUrlStr)
1559 Catch ex As Exception
1565 'For Each ma As Match In m
1566 ' svc = ma.Result("${svc}")
1568 ' If orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal) > -1 Then
1569 ' Dim urlStr As String = ""
1571 ' posl1 = orgData.IndexOf("<a href=""" + svc, posl2, StringComparison.Ordinal)
1572 ' posl1 = orgData.IndexOf(svc, posl1, StringComparison.Ordinal)
1573 ' posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
1574 ' urlStr = New Uri(urlEncodeMultibyteChar(orgData.Substring(posl1, posl2 - posl1))).GetLeftPart(UriPartial.Path)
1575 ' Dim Response As String = ""
1576 ' Dim retUrlStr As String = ""
1577 ' Dim tmpurlStr As String = urlStr
1578 ' Dim SchemeAndDomain As Regex = New Regex("http://.+?/+?")
1579 ' Dim tmpSchemeAndDomain As String = ""
1580 ' For i As Integer = 0 To 4 'とりあえず5回試す
1581 ' retUrlStr = urlEncodeMultibyteChar(DirectCast(CreateSocket.GetWebResponse(tmpurlStr, Response, MySocket.REQ_TYPE.ReqGETForwardTo, timeOut:=2000), String))
1582 ' If retUrlStr.Length > 0 Then
1583 ' ' 転送先URLが返された (まだ転送されるかもしれないので返値を引数にしてもう一度)
1584 ' ' 取得試行回数オーバーの場合は取得結果を転送先とする
1585 ' Dim scd As Match = SchemeAndDomain.Match(retUrlStr)
1586 ' If scd.Success AndAlso scd.Value <> svc Then
1589 ' tmpurlStr = retUrlStr
1593 ' If tmpurlStr <> urlStr Then
1594 ' '少なくとも一度以上転送されている (前回の結果を転送先とする)
1595 ' retUrlStr = tmpurlStr
1603 ' If retUrlStr.Length > 0 Then
1604 ' If Not retUrlStr.StartsWith("http") Then
1605 ' If retUrlStr.StartsWith("/") Then
1606 ' retUrlStr = urlEncodeMultibyteChar(svc + retUrlStr.Substring(1))
1607 ' ElseIf retUrlStr.StartsWith("data:") Then
1610 ' retUrlStr = urlEncodeMultibyteChar(retUrlStr.Insert(0, svc))
1613 ' retUrlStr = urlEncodeMultibyteChar(retUrlStr)
1615 ' orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + retUrlStr)
1616 ' posl2 = 0 '置換した場合は頭から再探索(複数同時置換での例外対応)
1619 ' Catch ex As Exception
1621 ' 'Return "GetTimeline -> Err: Can't get tinyurl."
1631 Private Function ShortUrlResolve(ByVal orgData As String) As String
1632 If _tinyUrlResolve Then
1634 Static Dim sw As New Stopwatch()
1635 Static Dim c As Integer = 0
1638 doShortUrlResolve(orgData)
1641 'Loop While doShortUrlResolve(orgData)
1645 Console.WriteLine("ShortUrlResolve: " + c.ToString() + " / " + sw.Elapsed.ToString)
1651 Private Function GetPlainText(ByVal orgData As String) As String
1652 Return HttpUtility.HtmlDecode(Regex.Replace(orgData, "(?<tagStart><a [^>]+>)(?<text>[^<]+)(?<tagEnd></a>)", "${text}"))
1654 ''単純テキストの取り出し(リンクタグ除去)
1655 'If orgData.IndexOf(_parseLink1, StringComparison.Ordinal) = -1 Then
1656 ' retStr = HttpUtility.HtmlDecode(orgData)
1658 ' Dim posl1 As Integer
1659 ' Dim posl2 As Integer
1660 ' Dim posl3 As Integer = 0
1666 ' posl1 = orgData.IndexOf(_parseLink1, posl3, StringComparison.Ordinal)
1667 ' If posl1 = -1 Then Exit Do
1669 ' If (posl3 + _parseLink3.Length <> posl1) Or posl3 = 0 Then
1670 ' If posl3 <> 0 Then
1671 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length, posl1 - posl3 - _parseLink3.Length))
1673 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(0, posl1))
1676 ' posl2 = orgData.IndexOf(_parseLink2, posl1, StringComparison.Ordinal)
1677 ' posl3 = orgData.IndexOf(_parseLink3, posl2, StringComparison.Ordinal)
1678 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl2 + _parseLink2.Length, posl3 - posl2 - _parseLink2.Length))
1680 ' retStr += HttpUtility.HtmlDecode(orgData.Substring(posl3 + _parseLink3.Length))
1686 ' htmlの簡易サニタイズ(詳細表示に不要なタグの除去)
1688 Private Function SanitizeHtml(ByVal orgdata As String) As String
1689 Dim retdata As String = orgdata
1691 ' <script ~ </script>
1692 Dim rx As Regex = New Regex( _
1693 "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
1694 "</(script|object|applet|image|frameset|fieldset|legend|style)>", RegexOptions.IgnoreCase)
1695 retdata = rx.Replace(retdata, "")
1698 rx = New Regex("<(frame|link|iframe|img)>", RegexOptions.IgnoreCase)
1699 retdata = rx.Replace(retdata, "")
1704 Private Function AdjustHtml(ByVal orgData As String) As String
1705 Dim retStr As String = orgData
1706 retStr = Regex.Replace(retStr, "<a [^>]*href=""/", "<a href=""" + _protocol + "twitter.com/")
1707 retStr = retStr.Replace("<a href=", "<a target=""_self"" href=")
1708 retStr = retStr.Replace(vbLf, "<br>")
1710 Return SanitizeHtml(retStr)
1713 Private Sub GetIconImage(ByVal post As PostClass)
1718 If Not _getIcon Then
1719 post.ImageIndex = -1
1720 TabInformations.GetInstance.AddPost(post)
1725 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1728 If post.ImageIndex > -1 Then
1729 TabInformations.GetInstance.AddPost(post)
1733 Dim resStatus As String = ""
1734 img = DirectCast(CreateSocket.GetWebResponse(post.ImageUrl, resStatus, MySocket.REQ_TYPE.ReqGETBinary), System.Drawing.Image)
1735 If img Is Nothing Then
1736 post.ImageIndex = -1
1737 TabInformations.GetInstance.AddPost(post)
1741 If _endingFlag Then Exit Sub
1743 bmp2 = New Bitmap(_iconSz, _iconSz)
1744 Using g As Graphics = Graphics.FromImage(bmp2)
1745 g.InterpolationMode = Drawing2D.InterpolationMode.High
1746 g.DrawImage(img, 0, 0, _iconSz, _iconSz)
1750 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1751 If post.ImageIndex = -1 Then
1753 _dIcon.Add(post.ImageUrl, img) '詳細表示用ディクショナリに追加
1754 _lIcon.Images.Add(post.ImageUrl, bmp2)
1755 post.ImageIndex = _lIcon.Images.IndexOfKey(post.ImageUrl)
1756 Catch ex As InvalidOperationException
1757 'タイミングにより追加できない場合がある?(キー重複ではない)
1758 post.ImageIndex = -1
1762 TabInformations.GetInstance.AddPost(post)
1763 Catch ex As ArgumentException
1772 Private Function GetAuthKey(ByVal resMsg As String) As Integer
1776 pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1781 pos2 = resMsg.IndexOf(_getAuthKeyTo, pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1783 _authKey = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1791 Private Function GetAuthKeyDM(ByVal resMsg As String) As Integer
1795 pos1 = resMsg.IndexOf(_getAuthKey, StringComparison.Ordinal)
1800 pos2 = resMsg.IndexOf("""", pos1 + _getAuthKey.Length, StringComparison.Ordinal)
1801 _authKeyDM = resMsg.Substring(pos1 + _getAuthKey.Length, pos2 - pos1 - _getAuthKey.Length)
1806 Private Structure PostInfo
1807 Public CreatedAt As String
1809 Public Text As String
1810 Public UserId As String
1811 Public Sub New(ByVal Created As String, ByVal IdStr As String, ByVal txt As String, ByVal uid As String)
1817 Public Shadows Function Equals(ByVal dst As PostInfo) As Boolean
1818 If Me.CreatedAt = dst.CreatedAt AndAlso Me.Id = dst.Id AndAlso Me.Text = dst.Text AndAlso Me.UserId = dst.UserId Then
1826 Private Function IsPostRestricted(ByRef resMsg As String) As Boolean
1827 Static _prev As New PostInfo("", "", "", "")
1828 Dim _current As New PostInfo("", "", "", "")
1831 Dim xd As XmlDocument = New XmlDocument()
1834 _current.CreatedAt = xd.SelectSingleNode("/status/created_at/text()").Value
1835 _current.Id = xd.SelectSingleNode("/status/id/text()").Value
1836 _current.Text = xd.SelectSingleNode("/status/text/text()").Value
1837 _current.UserId = xd.SelectSingleNode("/status/user/id/text()").Value
1839 If _current.Equals(_prev) Then
1842 _prev.CreatedAt = _current.CreatedAt
1843 _prev.Id = _current.Id
1844 _prev.Text = _current.Text
1845 _prev.UserId = _current.UserId
1846 Catch ex As XmlException
1853 Public Function PostStatus(ByVal postStr As String, ByVal reply_to As Long) As String
1855 If _endingFlag Then Return ""
1857 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1859 postStr = postStr.Trim()
1862 Dim dataStr As String
1863 If reply_to = 0 Then
1864 dataStr = _statusHeader + HttpUtility.UrlEncode(postStr) + "&source=Tween"
1866 dataStr = _statusHeader + HttpUtility.UrlEncode(postStr) + "&source=Tween" + "&in_reply_to_status_id=" + HttpUtility.UrlEncode(reply_to.ToString)
1869 Dim resStatus As String = ""
1870 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _statusUpdatePathAPI, resStatus, MySocket.REQ_TYPE.ReqPOSTAPI, dataStr), String)
1872 If resStatus.StartsWith("OK") Then
1873 Dim xd As XmlDocument = New XmlDocument()
1876 Dim xNode As XmlNode = Nothing
1877 xNode = xd.SelectSingleNode("/status/user/followers_count/text()")
1878 If xNode IsNot Nothing Then _followersCount = Integer.Parse(xNode.Value)
1879 xNode = xd.SelectSingleNode("/status/user/friends_count/text()")
1880 If xNode IsNot Nothing Then _friendsCount = Integer.Parse(xNode.Value)
1881 xNode = xd.SelectSingleNode("/status/user/statuses_count/text()")
1882 If xNode IsNot Nothing Then _statusesCount = Integer.Parse(xNode.Value)
1883 xNode = xd.SelectSingleNode("/status/user/location/text()")
1884 If xNode IsNot Nothing Then _location = xNode.Value
1885 xNode = xd.SelectSingleNode("/status/user/description/text()")
1886 If xNode IsNot Nothing Then _bio = xNode.Value
1887 Catch ex As Exception
1890 If Not postStr.StartsWith("D ", StringComparison.OrdinalIgnoreCase) AndAlso _
1891 Not postStr.StartsWith("DM ", StringComparison.OrdinalIgnoreCase) AndAlso _
1892 IsPostRestricted(resMsg) Then
1893 Return "OK:Delaying?"
1895 resStatus = Outputz.Post(CreateSocket, postStr.Length)
1896 If resStatus.Length > 0 Then
1897 Return "Outputz:" + resStatus
1901 ElseIf resStatus.StartsWith("Err: Forbidden") Then
1902 Return "Err:Forbidden(Update Limits?)"
1904 If resStatus.StartsWith("Err: Unauthorized") Then
1905 Twitter.AccountState = ACCOUNT_STATE.Invalid
1906 Return "Check your Username/Password."
1913 Public Function RemoveStatus(ByVal id As Long) As String
1914 If _endingFlag Then Return ""
1916 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1919 Dim resStatus As String = ""
1920 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _StDestroyPath + id.ToString + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
1922 If resMsg.StartsWith("<?xml") = False OrElse resStatus.StartsWith("OK") = False Then
1923 If resStatus.StartsWith("Err: Unauthorized") Then
1924 Twitter.AccountState = ACCOUNT_STATE.Invalid
1925 Return "Check your Username/Password."
1934 Public Function PostRetweet(ByVal id As Long) As String
1935 If _endingFlag Then Return ""
1936 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1939 Dim target As Long = id
1940 If TabInformations.GetInstance.Item(id).RetweetedId > 0 Then
1941 target = TabInformations.GetInstance.Item(id).RetweetedId
1943 Dim resStatus As String = ""
1944 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _apiHost + _hubServer + _postRetweetPath + target.ToString + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
1946 If resMsg.StartsWith("<?xml") = False OrElse resStatus.StartsWith("OK") = False Then
1947 If resStatus.StartsWith("Err: Unauthorized") Then
1948 Twitter.AccountState = ACCOUNT_STATE.Invalid
1949 Return "Check your Username/Password."
1958 Public Function RemoveDirectMessage(ByVal id As Long) As String
1959 If _endingFlag Then Return ""
1961 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1964 Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
1965 Dim resStatus As String = ""
1966 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _DMDestroyPath + id.ToString + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
1968 If resMsg.StartsWith("<?xml") = False OrElse resStatus.StartsWith("OK") = False Then
1969 If resStatus.StartsWith("Err: Unauthorized") Then
1970 Twitter.AccountState = ACCOUNT_STATE.Invalid
1971 Return "Check your Username/Password."
1980 Public Function PostFollowCommand(ByVal id As String) As String
1982 If _endingFlag Then Return ""
1984 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1986 Const PATH_FOLLOW As String = "/friendships/create.xml?screen_name="
1988 Dim resStatus As String = ""
1989 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + PATH_FOLLOW + id, resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
1991 If Not resStatus.StartsWith("OK") Then
1992 If resStatus.StartsWith("Err: Unauthorized") Then
1993 Twitter.AccountState = ACCOUNT_STATE.Invalid
1994 Return "Check your Username/Password."
2003 Public Function PostRemoveCommand(ByVal id As String) As String
2005 If _endingFlag Then Return ""
2007 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2009 Const PATH_REMOVE As String = "/friendships/destroy.xml?screen_name="
2011 Dim resStatus As String = ""
2012 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + PATH_REMOVE + id, resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
2014 If Not resStatus.StartsWith("OK") Then
2015 If resStatus.StartsWith("Err: Unauthorized") Then
2016 Twitter.AccountState = ACCOUNT_STATE.Invalid
2017 Return "Check your Username/Password."
2026 Public Function GetFriendshipInfo(ByVal id As String) As String
2028 If _endingFlag Then Return ""
2030 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2032 Const PATH_FRIENDSHIP As String = "/friendships/show.xml?source_screen_name="
2033 Const QUERY_TARGET As String = "&target_screen_name="
2035 Dim resStatus As String = ""
2036 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + PATH_FRIENDSHIP + _uid + QUERY_TARGET + id, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2038 If Not resStatus.StartsWith("OK") Then
2039 If resStatus.StartsWith("Err: Unauthorized") Then
2040 Twitter.AccountState = ACCOUNT_STATE.Invalid
2041 Return "Check your Username/Password."
2046 Dim xdoc As New XmlDocument
2047 Dim result As String = ""
2049 xdoc.LoadXml(resMsg)
2050 Dim isFollowing As Boolean = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/following").InnerText)
2051 Dim isFollowed As Boolean = Boolean.Parse(xdoc.SelectSingleNode("/relationship/source/followed_by").InnerText)
2053 result = "Following " + id + "." + System.Environment.NewLine
2055 result = "NOT follwing them." + System.Environment.NewLine
2058 result += "Followed by " + id + "."
2060 result += "NOT followed by " + id + "."
2062 result = "Ok. The results are below..." + System.Environment.NewLine + result
2063 Catch ex As Exception
2064 result = "Err: Invalid XML."
2070 ' Contributed by shuyoko <http://twitter.com/shuyoko> BEGIN:
2071 Public Function GetBlackFavId(ByVal id As Long, ByRef blackid As Long) As String
2072 Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
2073 Dim resStatus As String = ""
2074 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse("http://blavotter.hocha.org/blackfav/getblack.php?format=simple&id=" + id.ToString(), resStatus, MySocket.REQ_TYPE.ReqGET), String)
2076 If resStatus.StartsWith("OK") = False Then
2080 blackid = Long.Parse(resMsg)
2085 ' Contributed by shuyoko <http://twitter.com/shuyoko> END.
2087 Public Function PostFavAdd(ByVal id As Long) As String
2088 If _endingFlag Then Return ""
2091 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2094 'Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
2095 Dim resStatus As String = ""
2096 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _postFavAddPath + id.ToString() + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
2098 If resStatus.StartsWith("OK") = False Then
2099 If resStatus.StartsWith("Err: Unauthorized") Then
2100 Twitter.AccountState = ACCOUNT_STATE.Invalid
2101 Return "Check your Username/Password."
2107 If _restrictFavCheck = False Then Return ""
2109 'http://twitter.com/statuses/show/id.xml APIを発行して本文を取得
2111 resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _ShowStatus + id.ToString() + ".xml", resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2114 Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(resMsg))
2116 While rd.EOF = False
2117 If rd.IsStartElement("favorited") Then
2118 If rd.ReadElementContentAsBoolean() = True Then
2119 Return "" '正常にふぁぼれている
2121 Return "NG(Restricted?)" '正常応答なのにふぁぼれてないので制限っぽい
2129 Catch ex As XmlException
2136 Public Function PostFavRemove(ByVal id As Long) As String
2137 If _endingFlag Then Return ""
2140 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2143 'Dim dataStr As String = _authKeyHeader + HttpUtility.UrlEncode(_authKey)
2144 Dim resStatus As String = ""
2145 Dim resMsg As String = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _postFavRemovePath + id.ToString() + ".xml", resStatus, MySocket.REQ_TYPE.ReqPOSTAPI), String)
2147 If resStatus.StartsWith("OK") = False Then
2148 If resStatus.StartsWith("Err: Unauthorized") Then
2149 Twitter.AccountState = ACCOUNT_STATE.Invalid
2150 Return "Check your Username/Password."
2159 #Region "follower取得"
2160 'Delegate Function GetFollowersDelegate(ByVal Query As Integer) As String
2161 'Private semaphore As Threading.Semaphore = Nothing
2162 'Private threadNum As Integer = 0
2163 Private _threadErr As Boolean = False
2165 Private Function GetFollowersMethod() As String
2166 Dim resStatus As String = ""
2167 Dim resMsg As String = ""
2168 Dim lineCount As Integer = 0
2169 Dim page As Long = -1
2172 If _endingFlag Then Exit Do
2173 resMsg = DirectCast(CreateSocket.GetWebResponse("https://" + _hubServer + _GetFollowers + _cursorQry + page.ToString, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2174 If resStatus.StartsWith("OK") = False Then
2179 Using rd As Xml.XmlTextReader = New Xml.XmlTextReader(New System.IO.StringReader(resMsg))
2182 While rd.EOF = False
2183 If rd.IsStartElement("screen_name") Then
2184 Dim tmp As String = rd.ReadElementString("screen_name").ToLower()
2186 If Not tmpFollower.Contains(tmp) Then
2187 tmpFollower.Add(tmp)
2191 ElseIf rd.IsStartElement("next_cursor") Then
2192 page = Long.Parse(rd.ReadElementString("next_cursor"))
2193 If page = 0 Then Exit Do
2200 Catch ex As Exception
2202 TraceOut("NG(XmlException)")
2203 Return "NG(XmlException)"
2205 Loop While lineCount > 0
2210 'Private Sub GetFollowersCallback(ByVal ar As IAsyncResult)
2211 ' Dim dlgt As GetFollowersDelegate = DirectCast(ar.AsyncState, GetFollowersDelegate)
2214 ' Dim ret As String = dlgt.EndInvoke(ar)
2215 ' If Not ret.Equals("") AndAlso Not _threadErr Then
2219 ' Catch ex As Exception
2221 ' ex.Data("IsTerminatePermission") = False
2224 ' GetTmSemaphore.Release() ' セマフォから出る
2225 ' Interlocked.Decrement(threadNum) ' スレッド数カウンタを-1
2230 ' キャッシュの検証と読み込み -1を渡した場合は読み込みのみ行う(APIエラーでFollowersCountが取得できなかったとき)
2231 Private Function ValidateCache() As Integer
2235 Dim setting As SettingFollower = SettingFollower.Load()
2236 follower = setting.Follower
2237 If follower.Count = 0 OrElse Not follower(0).Equals(_uid.ToLower()) Then
2238 ' 別IDの場合はキャッシュ破棄して読み直し
2241 Catch ex As XmlException
2244 Catch ex As InvalidOperationException
2249 'If _FollowersCount = -1 Then Return tmpFollower.Count
2250 Return follower.Count
2252 'If (_FollowersCount + 1) = tmpFollower.Count Then
2255 'ElseIf (_FollowersCount + 1) < tmpFollower.Count Then
2256 ' '減っている場合はどこが抜けているのかわからないので全部破棄して読み直し
2257 ' tmpFollower.Clear()
2258 ' tmpFollower.Add(_uid.ToLower())
2259 ' Return _FollowersCount
2264 'Return _FollowersCount - tmpFollower.Count
2268 Private Sub UpdateCache()
2269 Dim setting As New SettingFollower(follower)
2273 Public Function GetFollowers(ByVal CacheInvalidate As Boolean) As String
2275 Dim sw As New System.Diagnostics.Stopwatch
2279 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2281 'Dim resStatus As String = ""
2282 'Dim resMsg As String = ""
2283 'Dim i As Integer = 0
2284 'Dim DelegateInstance As GetFollowersDelegate = New GetFollowersDelegate(AddressOf GetFollowersMethod)
2285 'Dim threadMax As Integer = 4 ' 最大スレッド数
2286 'Dim followersCount As Integer = 0
2288 'Interlocked.Exchange(threadNum, 0) ' スレッド数カウンタ初期化
2292 'follower.Add(_uid.ToLower())
2293 tmpFollower.Add(_uid.ToLower())
2295 'resMsg = DirectCast(CreateSocket.GetWebResponse("https://twitter.com/users/show/" + _uid + ".xml", resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
2296 'If resMsg = "" Then
2297 ' If resStatus.StartsWith("Err: BadRequest") Then
2298 ' Return "Maybe, the requests reached API limit."
2299 ' ElseIf resStatus.StartsWith("Err: Unauthorized") Then
2300 ' Twitter.AccountState = ACCOUNT_STATE.Invalid
2301 ' Return "Check your Username/Password."
2307 'Dim xd As XmlDocument = New XmlDocument()
2309 ' xd.LoadXml(resMsg)
2310 ' followersCount = Integer.Parse(xd.SelectSingleNode("/user/followers_count/text()").Value)
2311 'Catch ex As Exception
2312 ' 'If CacheInvalidate OrElse ValidateCache(-1) < 0 Then
2313 ' If ValidateCache(-1) < 0 Then
2314 ' ' FollowersカウントがAPIで取得できず、なおかつキャッシュから読めなかった
2317 ' follower.Add(_uid.ToLower())
2319 ' Return "Can't get followers_count and invalid cache."
2321 ' 'キャッシュを読み出せたのでキャッシュを使う
2323 ' follower = tmpFollower
2331 ''If CacheInvalidate Then
2332 'tmp = followersCount
2334 ''tmp = ValidateCache(followersCount)
2339 ' i = (tmp + 100) \ 100 ' Followersカウント取得しページ単位に切り上げる。1ページ余分に読む
2341 ' ' ' キャッシュの件数に変化がなかった
2344 ' ' Console.WriteLine(sw.ElapsedMilliseconds)
2346 ' ' SyncLock LockObj
2347 ' ' follower = tmpFollower
2350 ' Return "" 'ユーザー情報のフォロワー数が0
2354 ''semaphore = New System.Threading.Semaphore(threadMax, threadMax) 'スレッド最大数
2356 'For cnt As Integer = 0 To i
2357 ' If _endingFlag Then Exit For
2358 ' 'semaphore.WaitOne() 'セマフォ取得 threadMax以上ならここでブロックされる
2359 ' GetTmSemaphore.WaitOne()
2360 ' 'Interlocked.Increment(threadNum) 'スレッド数カウンタを+1
2361 ' 'DelegateInstance.BeginInvoke(cnt + 1, New System.AsyncCallback(AddressOf GetFollowersCallback), DelegateInstance)
2362 ' Dim ret As String = GetFollowersMethod(cnt + 1)
2363 ' 'Interlocked.Decrement(threadNum) 'スレッド数カウンタを-1
2364 ' GetTmSemaphore.Release()
2365 ' If _threadErr Then Exit For
2368 '''全てのスレッドの終了を待つ(スレッド数カウンタが0になるまで待機)
2371 ''Loop Until Interlocked.Add(threadNum, 0) = 0
2375 Dim ret As String = GetFollowersMethod()
2376 If _endingFlag Then Return ""
2379 If ValidateCache() > 0 Then
2381 For Each name As String In tmpFollower
2382 If Not follower.Contains(name) Then follower.Add(name)
2385 If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2386 Return "Can't get followers. Use cache."
2388 ' エラーが発生しているならFollowersリストクリア
2391 follower.Add(_uid.ToLower())
2393 Return "Can't get followers."
2398 follower = tmpFollower
2400 If Not _endingFlag AndAlso follower.Count > 1 Then UpdateCache()
2404 'Console.WriteLine(sw.ElapsedMilliseconds)
2412 Public Sub RefreshOwl()
2413 TabInformations.GetInstance.RefreshOwl(follower)
2416 Public Property Username() As String
2420 Set(ByVal value As String)
2421 _uid = value.ToLower
2426 Public Property Password() As String
2430 Set(ByVal value As String)
2436 Private _accountState As ACCOUNT_STATE = ACCOUNT_STATE.Valid
2437 Public Property AccountState() As ACCOUNT_STATE
2439 Return _accountState
2441 Set(ByVal value As ACCOUNT_STATE)
2442 _accountState = value
2446 Public Property NextThreshold() As Integer
2448 Return _nextThreshold
2450 Set(ByVal value As Integer)
2451 _nextThreshold = value
2455 Public Property NextPages() As Integer
2459 Set(ByVal value As Integer)
2464 Public ReadOnly Property InfoTwitter() As String
2470 Public Property UseAPI() As Boolean
2474 Set(ByVal value As Boolean)
2479 Public Property HubServer() As String
2483 Set(ByVal value As String)
2488 Public Sub GetWedata()
2489 Dim resStatus As String = ""
2490 Dim resMsg As String = ""
2492 resMsg = DirectCast(CreateSocket.GetWebResponse(wedataUrl, resStatus, timeOut:=10 * 1000), String) 'タイムアウト時間を10秒に設定
2493 If resMsg.Length = 0 Then Exit Sub
2495 Dim rs As New System.IO.StringReader(resMsg)
2497 Dim mode As Integer = 0 '0:search name 1:search data 2:read data
2498 Dim name As String = ""
2502 While rs.Peek() > -1
2507 If ln.StartsWith(" ""name"": ") Then
2508 name = ln.Substring(13, ln.Length - 2 - 13)
2512 If ln = " ""data"": {" Then
2519 If ln.EndsWith(",") Then ln = ln.Substring(0, ln.Length - 1)
2521 Case "SplitPostReply"
2522 If ln.StartsWith(" ""tagfrom"": """) Then
2523 _splitPost = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2525 Case "SplitPostRecent"
2526 If ln.StartsWith(" ""tagfrom"": """) Then
2527 _splitPostRecent = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2530 If ln.StartsWith(" ""tagto"": """) Then
2531 _statusIdTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2534 If ln.StartsWith(" ""tagfrom"": """) Then
2535 _isProtect = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2538 If ln.StartsWith(" ""tagfrom"": """) Then
2539 _isReplyEng = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2541 If ln.StartsWith(" ""tagfrom2"": """) Then
2542 _isReplyJpn = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2544 If ln.StartsWith(" ""tagto"": """) Then
2545 _isReplyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2548 ' If ln.StartsWith(" ""tagfrom"": """) Then
2549 ' _parseStar = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2551 ' If ln.StartsWith(" ""tagfrom2"": """) Then
2552 ' _parseStarEmpty = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2554 ' If ln.StartsWith(" ""tagto"": """) Then
2555 ' _parseStarTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2558 If ln.StartsWith(" ""tagfrom"": """) Then
2559 _followerList = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2561 If ln.StartsWith(" ""tagfrom2"": """) Then
2562 _followerMbr1 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2564 If ln.StartsWith(" ""tagfrom3"": """) Then
2565 _followerMbr2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2567 If ln.StartsWith(" ""tagto"": """) Then
2568 _followerMbr3 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2571 If ln.StartsWith(" ""tagfrom"": """) Then
2572 _splitDM = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2575 If ln.StartsWith(" ""tagfrom"": """) Then
2576 _parseDM1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2578 If ln.StartsWith(" ""tagfrom2"": """) Then
2579 _parseDM11 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2581 If ln.StartsWith(" ""tagto"": """) Then
2582 _parseDM2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2585 If ln.StartsWith(" ""tagfrom"": """) Then
2586 _parseDate = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2588 If ln.StartsWith(" ""tagto"": """) Then
2589 _parseDateTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2592 If ln.StartsWith(" ""tagfrom"": """) Then
2593 _parseMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2595 If ln.StartsWith(" ""tagto"": """) Then
2596 _parseMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2599 If ln.StartsWith(" ""tagfrom"": """) Then
2600 _parseImg = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2602 If ln.StartsWith(" ""tagto"": """) Then
2603 _parseImgTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2606 If ln.StartsWith(" ""tagfrom"": """) Then
2607 _parseNick = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2609 If ln.StartsWith(" ""tagto"": """) Then
2610 _parseNickTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2613 If ln.StartsWith(" ""tagfrom"": """) Then
2614 _parseName = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2616 If ln.StartsWith(" ""tagto"": """) Then
2617 _parseNameTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2620 ' If ln.StartsWith(" ""tagfrom"": """) Then
2621 ' _getSiv = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2623 ' If ln.StartsWith(" ""tagto"": """) Then
2624 ' _getSivTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2627 If ln.StartsWith(" ""tagfrom"": """) Then
2628 _getAuthKey = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2630 If ln.StartsWith(" ""tagto"": """) Then
2631 _getAuthKeyTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2634 If ln.StartsWith(" ""tagfrom"": """) Then
2635 _getInfoTwitter = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2637 If ln.StartsWith(" ""tagto"": """) Then
2638 _getInfoTwitterTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2640 Case "GetProtectMsg"
2641 If ln.StartsWith(" ""tagfrom"": """) Then
2642 _parseProtectMsg1 = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2644 If ln.StartsWith(" ""tagto"": """) Then
2645 _parseProtectMsg2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2648 If ln.StartsWith(" ""tagfrom"": """) Then
2649 _parseDMcountFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2651 If ln.StartsWith(" ""tagto"": """) Then
2652 _parseDMcountTo = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2655 If ln.StartsWith(" ""tagfrom"": """) Then
2656 _parseSourceFrom = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2658 If ln.StartsWith(" ""tagfrom2"": """) Then
2659 _parseSource2 = ln.Substring(19, ln.Length - 1 - 19).Replace("\", "")
2661 If ln.StartsWith(" ""tagto"": """) Then
2662 _parseSource2 = ln.Substring(16, ln.Length - 1 - 16).Replace("\", "")
2665 If ln.StartsWith(" ""tagfrom"": """) Then
2666 _removeClass = ln.Substring(18, ln.Length - 1 - 18).Replace("\", "")
2676 GenerateAnalyzeKey()
2680 Public WriteOnly Property GetIcon() As Boolean
2681 Set(ByVal value As Boolean)
2686 Public WriteOnly Property TinyUrlResolve() As Boolean
2687 Set(ByVal value As Boolean)
2688 _tinyUrlResolve = value
2692 Public WriteOnly Property SelectedProxyType() As ProxyType
2693 Set(ByVal value As ProxyType)
2698 Public WriteOnly Property ProxyAddress() As String
2699 Set(ByVal value As String)
2700 _proxyAddress = value
2704 Public WriteOnly Property ProxyPort() As Integer
2705 Set(ByVal value As Integer)
2710 Public WriteOnly Property ProxyUser() As String
2711 Set(ByVal value As String)
2716 Public WriteOnly Property ProxyPassword() As String
2717 Set(ByVal value As String)
2718 _proxyPassword = value
2722 Public WriteOnly Property RestrictFavCheck() As Boolean
2723 Set(ByVal value As Boolean)
2724 _restrictFavCheck = value
2728 Public WriteOnly Property IconSize() As Integer
2729 Set(ByVal value As Integer)
2734 Public Function MakeShortUrl(ByVal ConverterType As UrlConverter, ByVal SrcUrl As String) As String
2735 Dim ret As String = ""
2736 Dim resStatus As String = ""
2737 Dim src As String = urlEncodeMultibyteChar(SrcUrl)
2739 For Each svc As String In _ShortUrlService
2740 If SrcUrl.StartsWith(svc) Then
2741 Return "Can't convert"
2745 SrcUrl = HttpUtility.UrlEncode(SrcUrl)
2746 Select Case ConverterType
2747 Case UrlConverter.TinyUrl 'tinyurl
2748 If SrcUrl.StartsWith("http") Then
2749 If "http://tinyurl.com/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2750 ' 明らかに長くなると推測できる場合は圧縮しない
2755 ret = DirectCast(CreateSocket.GetWebResponse("http://tinyurl.com/api-create.php?url=" + SrcUrl, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2756 Catch ex As Exception
2757 Return "Can't convert"
2760 If Not ret.StartsWith("http://tinyurl.com/") Then
2761 Return "Can't convert"
2763 Case UrlConverter.Isgd
2764 If SrcUrl.StartsWith("http") Then
2765 If "http://is.gd/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2766 ' 明らかに長くなると推測できる場合は圧縮しない
2771 ret = DirectCast(CreateSocket.GetWebResponse("http://is.gd/api.php?longurl=" + SrcUrl, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2772 Catch ex As Exception
2773 Return "Can't convert"
2776 If Not ret.StartsWith("http://is.gd/") Then
2777 Return "Can't convert"
2779 Case UrlConverter.Twurl
2780 If SrcUrl.StartsWith("http") Then
2781 If "http://twurl.nl/xxxxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2782 ' 明らかに長くなると推測できる場合は圧縮しない
2787 ret = DirectCast(CreateSocket.GetWebResponse("http://tweetburner.com/links", resStatus, MySocket.REQ_TYPE.ReqPOSTEncode, "link[url]=" + SrcUrl), String)
2788 Catch ex As Exception
2789 Return "Can't convert"
2792 If Not ret.StartsWith("http://twurl.nl/") Then
2793 Return "Can't convert"
2795 Case UrlConverter.Unu
2796 If SrcUrl.StartsWith("http") Then
2797 If "http://u.nu/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2798 ' 明らかに長くなると推測できる場合は圧縮しない
2803 ret = DirectCast(CreateSocket.GetWebResponse("http://u.nu/unu-api-simple?url=" + SrcUrl, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2804 Catch ex As Exception
2805 Return "Can't convert"
2808 If Not ret.StartsWith("http://u.nu") Then
2809 Return "Can't convert"
2811 Case UrlConverter.Bitly, UrlConverter.Jmp
2812 Dim BitlyLogin As String = "tweenapi"
2813 Dim BitlyApiKey As String = "R_c5ee0e30bdfff88723c4457cc331886b"
2814 If _bitlyId <> "" Then
2815 BitlyLogin = _bitlyId
2816 BitlyApiKey = _bitlyKey
2818 Const BitlyApiVersion As String = "2.0.1"
2819 If SrcUrl.StartsWith("http") Then
2820 If "http://bit.ly/xxxx".Length > src.Length AndAlso Not src.Contains("?") AndAlso Not src.Contains("#") Then
2821 ' 明らかに長くなると推測できる場合は圧縮しない
2826 Dim req As String = "http://api.bit.ly/shorten?version=" + BitlyApiVersion + _
2827 "&login=" + BitlyLogin + _
2828 "&apiKey=" + BitlyApiKey + _
2829 "&longUrl=" + SrcUrl
2830 If BitlyLogin <> "tweenapi" Then req += "&history=1"
2831 ret = DirectCast(CreateSocket.GetWebResponse(req, resStatus, MySocket.REQ_TYPE.ReqPOSTEncode), String)
2832 Dim rx As Regex = New Regex("""shortUrl"": ""(?<ShortUrl>.*?)""")
2833 If rx.Match(ret).Success Then
2834 ret = rx.Match(ret).Groups("ShortUrl").Value
2836 Catch ex As Exception
2837 Return "Can't convert"
2840 If Not ret.StartsWith("http://bit.ly") Then
2841 Return "Can't convert"
2843 If ConverterType = UrlConverter.Jmp Then ret = ret.Replace("bit.ly", "j.mp")
2846 Dim ch As Char() = {ControlChars.Cr, ControlChars.Lf}
2847 ret = ret.TrimEnd(ch)
2848 If src.Length < ret.Length Then ret = src ' 圧縮の結果逆に長くなった場合は圧縮前のURLを返す
2853 Public Function GetVersionInfo() As String
2854 Dim resStatus As String = ""
2855 Dim ret As String = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/version2.txt?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus), String)
2856 If ret.Length = 0 Then Throw New Exception("GetVersionInfo: " + resStatus)
2860 Public Function GetTweenBinary(ByVal strVer As String) As String
2861 Dim resStatus As String = ""
2862 Dim ret As String = ""
2863 ret = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/Tween" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFile), String)
2864 If ret = "" OrElse resStatus.StartsWith("OK") Then
2865 '取得OKなら、続いてresources.dllダウンロード
2866 ret = GetTweenResourcesDll(strVer)
2868 Return GetTweenDll(strVer)
2877 Public Function GetTweenUpBinary() As String
2878 Dim resStatus As String = ""
2879 Dim ret As String = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/TweenUp.gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFileUp), String)
2880 If ret = "" OrElse resStatus.StartsWith("OK") Then
2887 Public Function GetTweenResourcesDll(ByVal strver As String) As String
2888 Dim resStatus As String = ""
2889 Dim ret As String = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/TweenRes" + strver + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFileRes), String)
2890 If ret = "" OrElse resStatus.StartsWith("OK") Then
2897 Public Function GetTweenDll(ByVal strVer As String) As String
2898 Dim resStatus As String = ""
2899 Dim ret As String = ""
2900 ret = DirectCast(CreateSocket.GetWebResponse("http://tween.sourceforge.jp/TweenDll" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), resStatus, MySocket.REQ_TYPE.ReqGETFileDll), String)
2901 If ret = "" OrElse resStatus.StartsWith("OK") Then
2910 Private Function CreateSocket() As MySocket
2911 Return New MySocket("UTF-8", _uid, _pwd, _proxyType, _proxyAddress, _proxyPort, _proxyUser, _proxyPassword, _defaultTimeOut)
2914 Public WriteOnly Property ListIcon() As ImageList
2915 Set(ByVal value As ImageList)
2920 Public WriteOnly Property DetailIcon() As Dictionary(Of String, Image)
2921 Set(ByVal value As Dictionary(Of String, Image))
2926 Public Property DefaultTimeOut() As Integer
2928 Return _defaultTimeOut
2930 Set(ByVal value As Integer)
2931 _defaultTimeOut = value
2935 Public WriteOnly Property CountApi() As Integer
2937 Set(ByVal value As Integer)
2942 Public WriteOnly Property UsePostMethod() As Boolean
2943 Set(ByVal value As Boolean)
2944 _usePostMethod = False
2946 'POSTメソッドが弾かれるためGETに固定(2009/4/9)
2948 _ApiMethod = MySocket.REQ_TYPE.ReqPOSTAPI
2950 _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
2953 _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI
2958 Public Property ReadOwnPost() As Boolean
2962 Set(ByVal value As Boolean)
2963 _readOwnPost = value
2967 Public ReadOnly Property FollowersCount() As Integer
2969 Return _followersCount
2973 Public ReadOnly Property FriendsCount() As Integer
2975 Return _friendsCount
2979 Public ReadOnly Property StatusesCount() As Integer
2981 Return _statusesCount
2985 Public ReadOnly Property Location() As String
2991 Public ReadOnly Property Bio() As String
2997 Public WriteOnly Property UseSsl() As Boolean
2998 Set(ByVal value As Boolean)
3001 _protocol = "https://"
3003 _protocol = "http://"
3008 Public WriteOnly Property BitlyId() As String
3009 Set(ByVal value As String)
3014 Public WriteOnly Property BitlyKey() As String
3015 Set(ByVal value As String)
3020 Public Function GetTimelineApi(ByVal read As Boolean, _
3021 ByVal gType As WORKERTYPE) As String
3023 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3025 If _endingFlag Then Return ""
3027 Dim retMsg As String = ""
3028 Dim resStatus As String = ""
3029 Dim sck As MySocket = CreateSocket()
3030 'スレッド取得は行わず、countで調整
3031 Const COUNT_QUERY As String = "count="
3032 Const FRIEND_PATH As String = "/statuses/home_timeline.xml"
3033 Const REPLY_PATH As String = "/statuses/mentions.xml"
3035 If gType = WORKERTYPE.Timeline Then
3036 retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + FRIEND_PATH + "?" + COUNT_QUERY + _countApi.ToString(), resStatus, _ApiMethod), String)
3038 retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + REPLY_PATH + "?" + COUNT_QUERY + _countApi.ToString(), resStatus, _ApiMethod), String)
3042 If resStatus.StartsWith("Err: BadRequest") Then
3043 Return "Maybe, the requests reached API limit."
3044 ElseIf resStatus.StartsWith("Err: Unauthorized") Then
3045 Twitter.AccountState = ACCOUNT_STATE.Invalid
3046 Return "Check your Username/Password."
3052 If gType = WORKERTYPE.Timeline Then Debug.WriteLine(retMsg)
3054 Dim arIdx As Integer = -1
3055 Dim dlgt(_countApi) As GetIconImageDelegate 'countQueryに合わせる
3056 Dim ar(_countApi) As IAsyncResult 'countQueryに合わせる
3057 Dim xdoc As New XmlDocument
3059 xdoc.LoadXml(retMsg)
3060 Catch ex As Exception
3062 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3063 Return "Invalid XML!"
3066 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3067 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3068 Dim post As New PostClass
3070 post.Id = Long.Parse(xentry.Item("id").InnerText)
3073 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3076 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3077 If xRnode IsNot Nothing Then
3078 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3079 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)
3081 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3083 post.Data = xRentry.Item("text").InnerText
3084 'Source取得(htmlの場合は、中身を取り出し)
3085 post.Source = xRentry.Item("source").InnerText
3087 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3088 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3089 post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
3092 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3093 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3094 post.Name = xRUentry.Item("screen_name").InnerText
3095 post.Nickname = xRUentry.Item("name").InnerText
3096 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3097 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3098 post.IsMe = post.Name.ToLower.Equals(_uid)
3101 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3102 post.RetweetedBy = xUentry.Item("screen_name").InnerText
3104 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)
3106 post.Data = xentry.Item("text").InnerText
3107 'Source取得(htmlの場合は、中身を取り出し)
3108 post.Source = xentry.Item("source").InnerText
3109 Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3110 post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3111 'in_reply_to_user_idを使うか?
3112 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3115 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3116 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3117 post.Name = xUentry.Item("screen_name").InnerText
3118 post.Nickname = xUentry.Item("name").InnerText
3119 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3120 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3121 post.IsMe = post.Name.ToLower.Equals(_uid)
3124 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3125 post.Data = HttpUtility.HtmlDecode(post.Data)
3126 post.Data = post.Data.Replace("<3", "♡")
3128 If post.Source.StartsWith("<") Then
3129 Dim rgS As New Regex(">(?<source>.+)<")
3130 Dim mS As Match = rgS.Match(post.Source)
3132 post.Source = mS.Result("${source}")
3137 If gType = WORKERTYPE.Timeline Then
3138 post.IsReply = post.ReplyToList.Contains(_uid)
3146 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3148 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3151 Catch ex As Exception
3153 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3157 '非同期アイコン取得&StatusDictionaryに追加
3159 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3160 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3164 For i As Integer = 0 To arIdx
3166 dlgt(i).EndInvoke(ar(i))
3167 Catch ex As Exception
3168 '最後までendinvoke回す(ゾンビ化回避)
3169 ex.Data("IsTerminatePermission") = False
3174 If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3179 Public Function GetSearch(ByVal read As Boolean, _
3180 ByVal tabName As String) As String
3182 If _endingFlag Then Return ""
3184 Dim retMsg As String = ""
3185 Dim resStatus As String = ""
3186 Dim sck As MySocket = CreateSocket()
3187 Const SEARCH_HOST As String = "search."
3188 Const SEARCH_PATH As String = "/search.atom"
3190 Dim tb As TabClass = TabInformations.GetInstance.Tabs(tabName)
3191 If tb Is Nothing Then Return ""
3192 Dim query As String = tb.SearchQuery
3193 If query = "" Then Return ""
3195 retMsg = DirectCast(sck.GetWebResponse(_protocol + SEARCH_HOST + _hubServer + SEARCH_PATH + "?" + query, resStatus, MySocket.REQ_TYPE.ReqGetAPINoAuth, userAgent:="Tween"), String)
3198 If resStatus.StartsWith("Err: BadRequest") Then
3199 Return "Invalid search query."
3200 ElseIf resStatus.StartsWith("Err: 420") Then '暫定:2010/1/18よりAPI制限で420返るらしい
3201 Return "Maybe, the requests reached API limit."
3207 Dim arIdx As Integer = -1
3208 Dim dlgt(_countApi) As GetIconImageDelegate 'countQueryに合わせる
3209 Dim ar(_countApi) As IAsyncResult 'countQueryに合わせる
3210 Dim xdoc As New XmlDocument
3212 xdoc.LoadXml(retMsg)
3213 Catch ex As Exception
3215 Return "Invalid ATOM!"
3217 Dim nsmgr As New XmlNamespaceManager(xdoc.NameTable)
3218 nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom")
3219 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr)
3220 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3221 Dim post As New PostClass
3223 post.Id = Long.Parse(xentry.Item("id").InnerText.Split(":"c)(2))
3224 post.PDate = DateTime.Parse(xentry.Item("published").InnerText)
3226 post.Data = xentry.Item("title").InnerText
3227 'Source取得(htmlの場合は、中身を取り出し)
3228 post.Source = xentry.Item("twitter:source").InnerText
3229 post.InReplyToId = 0
3230 post.InReplyToUser = ""
3234 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./search:author", nsmgr), XmlElement)
3236 post.Name = xUentry.Item("name").InnerText.Split(" "c)(0).Trim
3237 post.Nickname = xUentry.Item("name").InnerText.Substring(post.Name.Length).Trim
3238 If post.Nickname.Length > 2 Then
3239 post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2)
3241 post.Nickname = post.Name
3243 post.ImageUrl = CType(xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr), XmlElement).GetAttribute("href")
3244 post.IsProtect = False
3245 post.IsMe = post.Name.ToLower.Equals(_uid)
3248 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3249 post.Data = HttpUtility.HtmlDecode(post.Data)
3251 If post.Source.StartsWith("<") Then
3252 Dim rgS As New Regex(">(?<source>.+)<")
3253 Dim mS As Match = rgS.Match(post.Source)
3255 post.Source = mS.Result("${source}")
3260 post.IsReply = post.ReplyToList.Contains(_uid)
3263 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
3266 Catch ex As Exception
3271 '非同期アイコン取得&StatusDictionaryに追加
3273 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3274 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3278 For i As Integer = 0 To arIdx
3280 dlgt(i).EndInvoke(ar(i))
3281 Catch ex As Exception
3282 '最後までendinvoke回す(ゾンビ化回避)
3283 ex.Data("IsTerminatePermission") = False
3291 Public Function GetDirectMessageApi(ByVal read As Boolean, _
3292 ByVal gType As WORKERTYPE) As String
3293 If _endingFlag Then Return ""
3295 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3297 Dim retMsg As String = ""
3298 Dim resStatus As String = ""
3299 Dim sck As MySocket = CreateSocket()
3300 'スレッド取得は行わず、countで調整
3301 Const GET_COUNT As Integer = 20
3302 Const RECEIVE_PATH As String = "/direct_messages.xml"
3303 Const SENT_PATH As String = "/direct_messages/sent.xml"
3305 If gType = WORKERTYPE.DirectMessegeRcv Then
3306 retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + RECEIVE_PATH, resStatus, _ApiMethod), String)
3308 retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + SENT_PATH, resStatus, _ApiMethod), String)
3312 If resStatus.StartsWith("Err: BadRequest") Then
3313 Return "Maybe, the requests reached API limit."
3314 ElseIf resStatus.StartsWith("Err: Unauthorized") Then
3315 Twitter.AccountState = ACCOUNT_STATE.Invalid
3316 Return "Check your Username/Password."
3322 Dim arIdx As Integer = -1
3323 Dim dlgt(GET_COUNT) As GetIconImageDelegate 'countQueryに合わせる
3324 Dim ar(GET_COUNT) As IAsyncResult 'countQueryに合わせる
3325 Dim xdoc As New XmlDocument
3327 xdoc.LoadXml(retMsg)
3328 Catch ex As Exception
3330 'MessageBox.Show("不正なXMLです。(DM-LoadXml)")
3331 Return "Invalid XML!"
3334 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./direct_message")
3335 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3336 Dim post As New PostClass
3338 post.Id = Long.Parse(xentry.Item("id").InnerText)
3341 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3345 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)
3347 post.Data = xentry.Item("text").InnerText
3349 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3350 post.Data = HttpUtility.HtmlDecode(post.Data)
3351 post.Data = post.Data.Replace("<3", "♡")
3354 If gType = WORKERTYPE.DirectMessegeRcv Then
3361 Dim xUentry As XmlElement
3362 If gType = WORKERTYPE.DirectMessegeRcv Then
3363 xUentry = CType(xentry.SelectSingleNode("./sender"), XmlElement)
3366 xUentry = CType(xentry.SelectSingleNode("./recipient"), XmlElement)
3369 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3370 post.Name = xUentry.Item("screen_name").InnerText
3371 post.Nickname = xUentry.Item("name").InnerText
3372 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3373 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3374 Catch ex As Exception
3376 'MessageBox.Show("不正なXMLです。(DM-Parse)")
3381 post.IsReply = False
3384 '非同期アイコン取得&StatusDictionaryに追加
3386 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3387 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3391 For i As Integer = 0 To arIdx
3393 dlgt(i).EndInvoke(ar(i))
3394 Catch ex As Exception
3395 '最後までendinvoke回す(ゾンビ化回避)
3396 ex.Data("IsTerminatePermission") = False
3401 If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3406 Public Function GetFavoritesApi(ByVal read As Boolean, _
3407 ByVal gType As WORKERTYPE) As String
3409 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3411 If _endingFlag Then Return ""
3413 Dim retMsg As String = ""
3414 Dim resStatus As String = ""
3415 Dim sck As MySocket = CreateSocket()
3416 'スレッド取得は行わず、countで調整
3417 Const COUNT_QUERY As String = "count="
3418 Const FAV_PATH As String = "/favorites.xml"
3420 retMsg = DirectCast(sck.GetWebResponse(_protocol + _hubServer + FAV_PATH + "?" + COUNT_QUERY + _countApi.ToString(), resStatus, _ApiMethod), String)
3423 If resStatus.StartsWith("Err: BadRequest") Then
3424 Return "Maybe, the requests reached API limit."
3425 ElseIf resStatus.StartsWith("Err: Unauthorized") Then
3426 Twitter.AccountState = ACCOUNT_STATE.Invalid
3427 Return "Check your Username/Password."
3433 Dim arIdx As Integer = -1
3434 Dim dlgt(_countApi) As GetIconImageDelegate 'countQueryに合わせる
3435 Dim ar(_countApi) As IAsyncResult 'countQueryに合わせる
3436 Dim xdoc As New XmlDocument
3438 xdoc.LoadXml(retMsg)
3439 Catch ex As Exception
3441 'MessageBox.Show("不正なXMLです。(TL-LoadXml)")
3442 Return "Invalid XML!"
3445 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("./status")
3446 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
3447 Dim post As New PostClass
3449 post.Id = Long.Parse(xentry.Item("id").InnerText)
3452 If TabInformations.GetInstance.ContainsKey(post.Id) Then Continue For
3455 Dim xRnode As XmlNode = xentry.SelectSingleNode("./retweeted_status")
3456 If xRnode IsNot Nothing Then
3457 Dim xRentry As XmlElement = CType(xRnode, XmlElement)
3458 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)
3460 post.RetweetedId = Long.Parse(xRentry.Item("id").InnerText)
3462 post.Data = xRentry.Item("text").InnerText
3463 'Source取得(htmlの場合は、中身を取り出し)
3464 post.Source = xRentry.Item("source").InnerText
3466 Long.TryParse(xRentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3467 post.InReplyToUser = xRentry.Item("in_reply_to_screen_name").InnerText
3468 'in_reply_to_user_idを使うか?
3469 post.IsFav = Boolean.Parse(xRentry.Item("favorited").InnerText)
3472 Dim xRUentry As XmlElement = CType(xRentry.SelectSingleNode("./user"), XmlElement)
3473 post.Uid = Long.Parse(xRUentry.Item("id").InnerText)
3474 post.Name = xRUentry.Item("screen_name").InnerText
3475 post.Nickname = xRUentry.Item("name").InnerText
3476 post.ImageUrl = xRUentry.Item("profile_image_url").InnerText
3477 post.IsProtect = Boolean.Parse(xRUentry.Item("protected").InnerText)
3478 post.IsMe = post.Name.ToLower.Equals(_uid)
3481 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3482 post.RetweetedBy = xUentry.Item("screen_name").InnerText
3484 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)
3486 post.Data = xentry.Item("text").InnerText
3487 'Source取得(htmlの場合は、中身を取り出し)
3488 post.Source = xentry.Item("source").InnerText
3489 Long.TryParse(xentry.Item("in_reply_to_status_id").InnerText, post.InReplyToId)
3490 post.InReplyToUser = xentry.Item("in_reply_to_screen_name").InnerText
3491 'in_reply_to_user_idを使うか?
3492 post.IsFav = Boolean.Parse(xentry.Item("favorited").InnerText)
3495 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./user"), XmlElement)
3496 post.Uid = Long.Parse(xUentry.Item("id").InnerText)
3497 post.Name = xUentry.Item("screen_name").InnerText
3498 post.Nickname = xUentry.Item("name").InnerText
3499 post.ImageUrl = xUentry.Item("profile_image_url").InnerText
3500 post.IsProtect = Boolean.Parse(xUentry.Item("protected").InnerText)
3501 post.IsMe = post.Name.ToLower.Equals(_uid)
3504 post.OriginalData = CreateHtmlAnchor(post.Data, post.ReplyToList)
3505 post.Data = HttpUtility.HtmlDecode(post.Data)
3506 post.Data = post.Data.Replace("<3", "♡")
3508 If post.Source.StartsWith("<") Then
3509 Dim rgS As New Regex(">(?<source>.+)<")
3510 Dim mS As Match = rgS.Match(post.Source)
3512 post.Source = mS.Result("${source}")
3517 post.IsReply = post.ReplyToList.Contains(_uid)
3522 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.Uid)
3526 Catch ex As Exception
3528 'MessageBox.Show("不正なXMLです。(TL-Parse)")
3532 '非同期アイコン取得&StatusDictionaryに追加
3534 dlgt(arIdx) = New GetIconImageDelegate(AddressOf GetIconImage)
3535 ar(arIdx) = dlgt(arIdx).BeginInvoke(post, Nothing, Nothing)
3539 For i As Integer = 0 To arIdx
3541 dlgt(i).EndInvoke(ar(i))
3542 Catch ex As Exception
3543 '最後までendinvoke回す(ゾンビ化回避)
3544 ex.Data("IsTerminatePermission") = False
3549 If _ApiMethod = MySocket.REQ_TYPE.ReqGetAPI Then _remainCountApi = sck.RemainCountApi
3554 Public Function GetFollowersApi() As String
3555 If _endingFlag Then Return ""
3556 Dim page As Long = -1
3561 Dim ret As String = FollowerApi(page)
3562 If ret <> "" Then Return ret
3567 Private Function FollowerApi(ByRef page As Long) As String
3568 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3570 Dim retMsg As String = ""
3571 Dim resStatus As String = ""
3572 Dim curCount As Integer = followerId.Count
3574 Const FOLLOWER_PATH As String = "/followers/ids.xml"
3576 retMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + FOLLOWER_PATH + _cursorQry + page.ToString(), resStatus, _ApiMethod), String)
3579 If resStatus.StartsWith("Err: Unauthorized") Then
3580 Twitter.AccountState = ACCOUNT_STATE.Invalid
3581 Return "Check your Username/Password."
3587 Dim xdoc As New XmlDocument
3589 xdoc.LoadXml(retMsg)
3590 Catch ex As Exception
3592 MessageBox.Show("The data was broken. Please retry later.(FollowerApi-LoadXml)")
3593 Return "Invalid XML!"
3597 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/id_list/ids/id")
3598 followerId.Add(Long.Parse(xentryNode.InnerText))
3600 page = Long.Parse(xdoc.DocumentElement.SelectSingleNode("/id_list/next_cursor").InnerText)
3601 Catch ex As Exception
3603 MessageBox.Show("The data was broken. Please retry later.(FollowerApi-Parse)")
3604 Return "Invalid XML!"
3611 Private Function CreateHtmlAnchor(ByVal Text As String, ByVal AtList As List(Of String)) As String
3612 Dim retStr As String = HttpUtility.HtmlEncode(Text) '要検証(デコードされて取得されるので再エンコード)
3615 Dim rgUrl As Regex = New Regex("(?<![0-9A-Za-z])(?:https?|shttp|ftps?)://(?:(?:[-_.!~*'()a-zA-Z0-9;:&=+$,]|%[0-9A-Fa-f" + _
3616 "][0-9A-Fa-f])*@)?(?:(?:[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.)" + _
3617 "*[a-zA-Z](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?\.?|[0-9]+\.[0-9]+\.[0-9]+\." + _
3618 "[0-9]+)(?::[0-9]*)?(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f]" + _
3619 "[0-9A-Fa-f])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-" + _
3620 "Fa-f])*)*(?:/(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f" + _
3621 "])*(?:;(?:[-_.!~*'()a-zA-Z0-9:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)*)" + _
3622 "*)?(?:\?(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])" + _
3623 "*)?(?:#(?:[-_.!~*'()a-zA-Z0-9;/?:@&=+$,]|%[0-9A-Fa-f][0-9A-Fa-f])*)?")
3625 retStr = rgUrl.Replace(Text, "<a href=""$&"">$&</a>")
3627 Dim rg As New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20}/[a-zA-Z0-9_\-]{1,24}[a-zA-Z0-9_])")
3628 Dim m As Match = rg.Match(retStr)
3630 retStr = rg.Replace(retStr, "$1@<a href=""/$2"">$2</a>")
3632 rg = New Regex("(^|[ -/:-@[-^`{-~])@([a-zA-Z0-9_]{1,20})")
3633 m = rg.Match(retStr)
3635 AtList.Add(m.Result("$2").ToLower)
3639 retStr = rg.Replace(retStr, "$1@<a href=""/$2"">$2</a>")
3642 Dim rgh As New Regex("(^|[ .!,\-:;<>?])#([^] !""#$%&'()*+,.:;<=>?@\-[\^`{|}~\r\n]+)")
3643 Dim mh As Match = rgh.Match(retStr)
3644 If mh.Success AndAlso Not IsNumeric(mh.Result("$2")) Then
3645 retStr = rgh.Replace(retStr, "$1<a href=""" + _protocol + "twitter.com/search?q=%23$2"">#$2</a>")
3649 retStr = AdjustHtml(ShortUrlResolve(PreProcessUrl(retStr))) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
3653 Public ReadOnly Property RemainCountApi() As Integer
3655 Return _remainCountApi
3659 Public Function GetMaxCountApi() As Integer
3660 Dim _maxcnt As Integer = 0
3661 Dim resMsg As String = ""
3662 Dim resStatus As String = ""
3663 resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3664 Dim xdoc As New XmlDocument
3666 xdoc.LoadXml(resMsg)
3667 _maxcnt = Integer.Parse(xdoc.SelectSingleNode("/hash/hourly-limit").InnerText)
3668 Catch ex As Exception
3674 Public Function GetRemainCountApi() As Integer
3675 Dim _remain As Integer = 0
3676 Dim resMsg As String = ""
3677 Dim resStatus As String = ""
3678 resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3679 Dim xdoc As New XmlDocument
3681 xdoc.LoadXml(resMsg)
3682 _remain = Integer.Parse(xdoc.SelectSingleNode("/hash/remaining-hits").InnerText)
3683 Catch ex As Exception
3689 Public Function GetResetTimeApi() As DateTime
3691 Dim resMsg As String = ""
3692 Dim resStatus As String = ""
3693 resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3694 Dim xdoc As New XmlDocument
3696 xdoc.LoadXml(resMsg)
3697 _tm = DateTime.Parse(xdoc.SelectSingleNode("/hash/reset-time").InnerText)
3698 Catch ex As Exception
3704 Public Function GetInfoApi(ByRef info As ApiInfo) As Boolean
3706 Dim resMsg As String = ""
3707 Dim resStatus As String = ""
3708 resMsg = DirectCast(CreateSocket.GetWebResponse(_protocol + _hubServer + _rateLimitStatus, resStatus, MySocket.REQ_TYPE.ReqGetAPI), String)
3709 Dim xdoc As New XmlDocument
3711 xdoc.LoadXml(resMsg)
3712 info.MaxCount = Integer.Parse(xdoc.SelectSingleNode("/hash/hourly-limit").InnerText)
3713 info.RemainCount = Integer.Parse(xdoc.SelectSingleNode("/hash/remaining-hits").InnerText)
3714 info.ResetTime = DateTime.Parse(xdoc.SelectSingleNode("/hash/reset-time").InnerText)
3715 info.ResetTimeInSeconds = Integer.Parse(xdoc.SelectSingleNode("/hash/reset-time-in-seconds").InnerText)
3716 Catch ex As Exception
3722 #Region "デバッグモード解析キー自動生成"
3724 Public Sub GenerateAnalyzeKey()
3725 '解析キー情報部分のソースをwedataから作成する
3726 '生成したソースはプロジェクトのディレクトリにコピーする
3727 Dim sw As New System.IO.StreamWriter(".\AnalyzeKey.vb", _
3729 System.Text.Encoding.UTF8)
3731 sw.WriteLine("Public Module AnalyzeKey")
3732 sw.WriteLine("' このファイルはデバッグビルドのTweenにより自動作成されました 作成日時 " + DateAndTime.Now.ToString())
3735 sw.WriteLine(" Public _splitPost As String = " + Chr(34) + _splitPost.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3736 sw.WriteLine(" Public _splitPostRecent As String = " + Chr(34) + _splitPostRecent.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3737 sw.WriteLine(" Public _statusIdTo As String = " + Chr(34) + _statusIdTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3738 sw.WriteLine(" Public _splitDM As String = " + Chr(34) + _splitDM.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3739 sw.WriteLine(" Public _parseName As String = " + Chr(34) + _parseName.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3740 sw.WriteLine(" Public _parseNameTo As String = " + Chr(34) + _parseNameTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3741 sw.WriteLine(" Public _parseNick As String = " + Chr(34) + _parseNick.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3742 sw.WriteLine(" Public _parseNickTo As String = " + Chr(34) + _parseNickTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3743 sw.WriteLine(" Public _parseImg As String = " + Chr(34) + _parseImg.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3744 sw.WriteLine(" Public _parseImgTo As String = " + Chr(34) + _parseImgTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3745 sw.WriteLine(" Public _parseMsg1 As String = " + Chr(34) + _parseMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3746 sw.WriteLine(" Public _parseMsg2 As String = " + Chr(34) + _parseMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3747 sw.WriteLine(" Public _parseDM1 As String = " + Chr(34) + _parseDM1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3748 sw.WriteLine(" Public _parseDM11 As String = " + Chr(34) + _parseDM11.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3749 sw.WriteLine(" Public _parseDM2 As String = " + Chr(34) + _parseDM2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3750 sw.WriteLine(" Public _parseDate As String = " + Chr(34) + _parseDate.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3751 sw.WriteLine(" Public _parseDateTo As String = " + Chr(34) + _parseDateTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3752 sw.WriteLine(" Public _getAuthKey As String = " + Chr(34) + _getAuthKey.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3753 sw.WriteLine(" Public _getAuthKeyTo As String = " + Chr(34) + _getAuthKeyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3754 'sw.WriteLine(" Public _parseStar As String = " + Chr(34) + _parseStar.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3755 'sw.WriteLine(" Public _parseStarTo As String = " + Chr(34) + _parseStarTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3756 'sw.WriteLine(" Public _parseStarEmpty As String = " + Chr(34) + _parseStarEmpty.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3757 sw.WriteLine(" Public _followerList As String = " + Chr(34) + _followerList.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3758 sw.WriteLine(" Public _followerMbr1 As String = " + Chr(34) + _followerMbr1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3759 sw.WriteLine(" Public _followerMbr2 As String = " + Chr(34) + _followerMbr2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3760 sw.WriteLine(" Public _followerMbr3 As String = " + Chr(34) + _followerMbr3.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3761 sw.WriteLine(" Public _getInfoTwitter As String = " + Chr(34) + _getInfoTwitter.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3762 sw.WriteLine(" Public _getInfoTwitterTo As String = " + Chr(34) + _getInfoTwitterTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3763 sw.WriteLine(" Public _isProtect As String = " + Chr(34) + _isProtect.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3764 sw.WriteLine(" Public _isReplyEng As String = " + Chr(34) + _isReplyEng.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3765 sw.WriteLine(" Public _isReplyJpn As String = " + Chr(34) + _isReplyJpn.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3766 sw.WriteLine(" Public _isReplyTo As String = " + Chr(34) + _isReplyTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3767 sw.WriteLine(" Public _parseProtectMsg1 As String = " + Chr(34) + _parseProtectMsg1.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3768 sw.WriteLine(" Public _parseProtectMsg2 As String = " + Chr(34) + _parseProtectMsg2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3769 sw.WriteLine(" Public _parseDMcountFrom As String = " + Chr(34) + _parseDMcountFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3770 sw.WriteLine(" Public _parseDMcountTo As String = " + Chr(34) + _parseDMcountTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3771 sw.WriteLine(" Public _parseSourceFrom As String = " + Chr(34) + _parseSourceFrom.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3772 sw.WriteLine(" Public _parseSource2 As String = " + Chr(34) + _parseSource2.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3773 sw.WriteLine(" Public _parseSourceTo As String = " + Chr(34) + _parseSourceTo.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3774 sw.WriteLine(" Public _removeClass As String = " + Chr(34) + _removeClass.Replace(Chr(34), Chr(34) + Chr(34)) + Chr(34))
3775 sw.WriteLine("End Module")
3778 'MessageBox.Show("解析キー情報定義ファイル AnalyzeKey.vbを生成しました")