1 ' Tween - Client of Twitter
2 ' Copyright (c) 2007-2011 kiri_feather (@kiri_feather) <kiri.feather@gmail.com>
3 ' (c) 2008-2011 Moz (@syo68k)
4 ' (c) 2008-2011 takeshik (@takeshik) <http://www.takeshik.org/>
5 ' (c) 2010-2011 anis774 (@anis774) <http://d.hatena.ne.jp/anis774/>
6 ' (c) 2010-2011 fantasticswallow (@f_swallow) <http://twitter.com/f_swallow>
9 ' This file is part of Tween.
11 ' This program is free software; you can redistribute it and/or modify it
12 ' under the terms of the GNU General Public License as published by the Free
13 ' Software Foundation; either version 3 of the License, or (at your option)
16 ' This program is distributed in the hope that it will be useful, but
17 ' WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 ' or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 ' You should have received a copy of the GNU General Public License along
22 ' with this program. If not, see <http://www.gnu.org/licenses/>, or write to
23 ' the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
24 ' Boston, MA 02110-1301, USA.
26 Imports System.Diagnostics
30 Imports System.Reflection.MethodBase
31 Imports System.Runtime.Serialization
32 Imports System.Runtime.Serialization.Json
34 Imports System.Text.RegularExpressions
35 Imports System.Threading
38 Imports System.Xml.Linq
41 Implements IDisposable
44 Private Const LATIN_ACCENTS As String = "\xc0-\xd6\xd8-\xf6\xf8-\xff"
45 Private Const NON_LATIN_HASHTAG_CHARS As String = "\u0400-\u04ff\u0500-\u0527\u1100-\u11ff\u3130-\u3185\uA960-\uA97F\uAC00-\uD7AF\uD7B0-\uD7FF"
46 'Private Const CJ_HASHTAG_CHARACTERS As String = "\u30A1-\u30FA\uFF66-\uFF9F\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\u3041-\u3096\u3400-\u4DBF\u4E00-\u9FFF\u20000-\u2A6DF\u2A700-\u2B73F\u2B740-\u2B81F\u2F800-\u2FA1F"
47 Private Const CJ_HASHTAG_CHARACTERS As String = "\u30A1-\u30FA\u30FC\u3005\uFF66-\uFF9F\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\u3041-\u309A\u3400-\u4DBF\p{IsCJKUnifiedIdeographs}"
48 Private Const HASHTAG_BOUNDARY As String = "^|$|\s|「|」|。|\.|!"
49 Private Const HASHTAG_ALPHA As String = "[a-z_" + LATIN_ACCENTS + NON_LATIN_HASHTAG_CHARS + CJ_HASHTAG_CHARACTERS + "]"
50 Private Const HASHTAG_ALPHANUMERIC As String = "[a-z0-9_" + LATIN_ACCENTS + NON_LATIN_HASHTAG_CHARS + CJ_HASHTAG_CHARACTERS + "]"
51 Private Const HASHTAG_TERMINATOR As String = "[^a-z0-9_" + LATIN_ACCENTS + NON_LATIN_HASHTAG_CHARS + CJ_HASHTAG_CHARACTERS + "]"
52 Public Const HASHTAG As String = "(" + HASHTAG_BOUNDARY + ")(#|#)(" + HASHTAG_ALPHANUMERIC + "*" + HASHTAG_ALPHA + HASHTAG_ALPHANUMERIC + "*)(?=" + HASHTAG_TERMINATOR + "|" + HASHTAG_BOUNDARY + ")"
54 Private Const url_valid_domain As String = "(?<domain>(?:[^\p{P}\s][\.\-_](?=[^\p{P}\s])|[^\p{P}\s]){1,}\.[a-z]{2,}(?::[0-9]+)?)"
55 Private Const url_valid_general_path_chars As String = "[a-z0-9!*';:=+$/%#\[\]\-_,~]"
56 Private Const url_balance_parens As String = "(?:\(" + url_valid_general_path_chars + "+\))"
57 Private Const url_valid_url_path_ending_chars As String = "(?:[a-z0-9=_#/\-\+]+|" + url_balance_parens + ")"
58 Private Const pth As String = "(?:" + url_balance_parens +
59 "|@" + url_valid_general_path_chars + "+/" +
60 "|[.,]?" + url_valid_general_path_chars + "+" +
62 Private Const pth2 As String = "(/(?:" +
63 pth + "+" + url_valid_url_path_ending_chars + "|" +
64 pth + "+" + url_valid_url_path_ending_chars + "?|" +
65 url_valid_url_path_ending_chars +
67 Private Const qry As String = "(?<query>\?[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9_&=#])?"
68 Public Const rgUrl As String = "(?<before>(?:[^\""':!=#]|^|\:/))" +
69 "(?<url>(?<protocol>https?://)" +
74 Delegate Sub GetIconImageDelegate(ByVal post As PostClass)
75 Private ReadOnly LockObj As New Object
76 Private followerId As New List(Of Long)
77 Private _GetFollowerResult As Boolean = False
78 Private noRTId As New List(Of Long)
79 Private _GetNoRetweetResult As Boolean = False
81 Private _followersCount As Integer = 0
82 Private _friendsCount As Integer = 0
83 Private _statusesCount As Integer = 0
84 Private _location As String = ""
85 Private _bio As String = ""
86 Private _protocol As String = "https://"
89 Private _uname As String
90 Private _iconSz As Integer
91 Private _getIcon As Boolean
92 Private _dIcon As IDictionary(Of String, Image)
94 Private _tinyUrlResolve As Boolean
95 Private _restrictFavCheck As Boolean
97 Private _hubServer As String
98 Private _readOwnPost As Boolean
99 Private _hashList As New List(Of String)
102 Private _remainCountApi As Integer = -1
104 Private op As New Outputz
105 'max_idで古い発言を取得するために保持(lists分は個別タブで管理)
106 Private minHomeTimeline As Long = Long.MaxValue
107 Private minMentions As Long = Long.MaxValue
108 Private minDirectmessage As Long = Long.MaxValue
109 Private minDirectmessageSent As Long = Long.MaxValue
111 Private twCon As New HttpTwitter
113 Public Event UserIdChanged()
115 'Private _deletemessages As New List(Of PostClass)
117 Public Overloads Function Authenticate(ByVal username As String, ByVal password As String) As String
119 Dim res As HttpStatusCode
120 Dim content As String = ""
122 TwitterApiInfo.Initialize()
124 res = twCon.AuthUserAndPass(username, password, content)
125 Catch ex As Exception
126 Return "Err:" + ex.Message
130 Case HttpStatusCode.OK
131 Twitter.AccountState = ACCOUNT_STATE.Valid
132 _uname = username.ToLower
133 If AppendSettingDialog.Instance.UserstreamStartup Then Me.ReconnectUserStream()
135 Case HttpStatusCode.Unauthorized
136 Twitter.AccountState = ACCOUNT_STATE.Invalid
137 Dim errMsg As String = GetErrorMessageJson(content)
138 If String.IsNullOrEmpty(errMsg) Then
139 Return My.Resources.Unauthorized + Environment.NewLine + content
141 Return "Auth error:" + errMsg
143 Case HttpStatusCode.Forbidden
144 Dim errMsg As String = GetErrorMessageJson(content)
145 If String.IsNullOrEmpty(errMsg) Then
146 Return "Err:Forbidden"
148 Return "Err:" + errMsg
151 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
156 Public Function StartAuthentication(ByRef pinPageUrl As String) As String
159 Dim content As String = ""
161 TwitterApiInfo.Initialize()
163 res = twCon.AuthGetRequestToken(pinPageUrl)
164 Catch ex As Exception
165 Return "Err:" + "Failed to access auth server."
171 Public Overloads Function Authenticate(ByVal pinCode As String) As String
173 Dim res As HttpStatusCode
174 Dim content As String = ""
176 TwitterApiInfo.Initialize()
178 res = twCon.AuthGetAccessToken(pinCode)
179 Catch ex As Exception
180 Return "Err:" + "Failed to access auth acc server."
184 Case HttpStatusCode.OK
185 Twitter.AccountState = ACCOUNT_STATE.Valid
186 _uname = Username.ToLower
187 If AppendSettingDialog.Instance.UserstreamStartup Then Me.ReconnectUserStream()
188 Google.GASender.GetInstance().TrackEventWithCategory("post", "authenticate", Me.UserId)
190 Case HttpStatusCode.Unauthorized
191 Twitter.AccountState = ACCOUNT_STATE.Invalid
192 Dim errMsg As String = GetErrorMessageJson(content)
193 If String.IsNullOrEmpty(errMsg) Then
194 Return "Check the PIN or retry." + Environment.NewLine + content
196 Return "Auth error:" + errMsg
198 Case HttpStatusCode.Forbidden
199 Dim errMsg As String = GetErrorMessageJson(content)
200 If String.IsNullOrEmpty(errMsg) Then
201 Return "Err:Forbidden"
203 Return "Err:" + errMsg
206 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
211 Public Sub ClearAuthInfo()
212 Twitter.AccountState = ACCOUNT_STATE.Invalid
213 TwitterApiInfo.Initialize()
214 twCon.ClearAuthInfo()
217 Public Sub VerifyCredentials()
218 Dim res As HttpStatusCode
219 Dim content As String = ""
222 res = twCon.VerifyCredentials(content)
223 Catch ex As Exception
227 If res = HttpStatusCode.OK Then
228 Twitter.AccountState = ACCOUNT_STATE.Valid
229 Dim user As TwitterDataModel.User
231 user = CreateDataFromJson(Of TwitterDataModel.User)(content)
232 Catch ex As SerializationException
235 twCon.AuthenticatedUserId = user.Id
239 Private Function GetErrorMessageJson(ByVal content As String) As String
241 If Not String.IsNullOrEmpty(content) Then
242 Using jsonReader As XmlDictionaryReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(content), XmlDictionaryReaderQuotas.Max)
243 Dim xElm As XElement = XElement.Load(jsonReader)
244 If xElm.Element("error") IsNot Nothing Then
245 Return xElm.Element("error").Value
253 Catch ex As Exception
258 Public Sub Initialize(ByVal token As String, ByVal tokenSecret As String, ByVal username As String, ByVal userId As Long)
260 If String.IsNullOrEmpty(token) OrElse String.IsNullOrEmpty(tokenSecret) OrElse String.IsNullOrEmpty(username) Then
261 Twitter.AccountState = ACCOUNT_STATE.Invalid
263 TwitterApiInfo.Initialize()
264 twCon.Initialize(token, tokenSecret, username, userId)
265 _uname = username.ToLower
266 If AppendSettingDialog.Instance.UserstreamStartup Then Me.ReconnectUserStream()
269 Public Function PreProcessUrl(ByVal orgData As String) As String
271 Dim posl2 As Integer = 0
272 'Dim IDNConveter As IdnMapping = New IdnMapping()
273 Dim href As String = "<a href="""
276 If orgData.IndexOf(href, posl2, StringComparison.Ordinal) > -1 Then
277 Dim urlStr As String = ""
279 posl1 = orgData.IndexOf(href, posl2, StringComparison.Ordinal)
281 posl2 = orgData.IndexOf("""", posl1, StringComparison.Ordinal)
282 urlStr = orgData.Substring(posl1, posl2 - posl1)
284 If Not urlStr.StartsWith("http://") AndAlso Not urlStr.StartsWith("https://") AndAlso Not urlStr.StartsWith("ftp://") Then
288 Dim replacedUrl As String = IDNDecode(urlStr)
289 If replacedUrl Is Nothing Then Continue Do
290 If replacedUrl = urlStr Then Continue Do
292 orgData = orgData.Replace("<a href=""" + urlStr, "<a href=""" + replacedUrl)
301 Private Function GetPlainText(ByVal orgData As String) As String
302 Return HttpUtility.HtmlDecode(Regex.Replace(orgData, "(?<tagStart><a [^>]+>)(?<text>[^<]+)(?<tagEnd></a>)", "${text}"))
305 ' htmlの簡易サニタイズ(詳細表示に不要なタグの除去)
307 Private Function SanitizeHtml(ByVal orgdata As String) As String
308 Dim retdata As String = orgdata
310 retdata = Regex.Replace(retdata, "<(script|object|applet|image|frameset|fieldset|legend|style).*" & _
311 "</(script|object|applet|image|frameset|fieldset|legend|style)>", "", RegexOptions.IgnoreCase)
313 retdata = Regex.Replace(retdata, "<(frame|link|iframe|img)>", "", RegexOptions.IgnoreCase)
318 Private Function AdjustHtml(ByVal orgData As String) As String
319 Dim retStr As String = orgData
320 'Dim m As Match = Regex.Match(retStr, "<a [^>]+>[#|#](?<1>[a-zA-Z0-9_]+)</a>")
323 ' _hashList.Add("#" + m.Groups(1).Value)
327 retStr = Regex.Replace(retStr, "<a [^>]*href=""/", "<a href=""" + _protocol + "twitter.com/")
328 retStr = retStr.Replace("<a href=", "<a target=""_self"" href=")
329 retStr = retStr.Replace(vbLf, "<br>")
331 '半角スペースを置換(Thanks @anis774)
332 Dim ret As Boolean = False
334 ret = EscapeSpace(retStr)
337 Return SanitizeHtml(retStr)
340 Private Function EscapeSpace(ByRef html As String) As Boolean
341 '半角スペースを置換(Thanks @anis774)
342 Dim isTag As Boolean = False
343 For i As Integer = 0 To html.Length - 1
344 If html(i) = "<"c Then
347 If html(i) = ">"c Then
351 If (Not isTag) AndAlso (html(i) = " "c) Then
352 html = html.Remove(i, 1)
353 html = html.Insert(i, " ")
360 Private Structure PostInfo
361 Public CreatedAt As String
363 Public Text As String
364 Public UserId As String
365 Public Sub New(ByVal Created As String, ByVal IdStr As String, ByVal txt As String, ByVal uid As String)
371 Public Shadows Function Equals(ByVal dst As PostInfo) As Boolean
372 If Me.CreatedAt = dst.CreatedAt AndAlso Me.Id = dst.Id AndAlso Me.Text = dst.Text AndAlso Me.UserId = dst.UserId Then
380 Private Function IsPostRestricted(ByVal status As TwitterDataModel.Status) As Boolean
381 Static _prev As New PostInfo("", "", "", "")
382 Dim _current As New PostInfo("", "", "", "")
384 _current.CreatedAt = status.CreatedAt
385 _current.Id = status.IdStr
386 If status.Text Is Nothing Then
389 _current.Text = status.Text
391 _current.UserId = status.User.IdStr
393 If _current.Equals(_prev) Then
396 _prev.CreatedAt = _current.CreatedAt
397 _prev.Id = _current.Id
398 _prev.Text = _current.Text
399 _prev.UserId = _current.UserId
404 Public Function PostStatus(ByVal postStr As String, ByVal reply_to As Long) As String
406 If _endingFlag Then Return ""
408 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
410 postStr = postStr.Trim()
412 If Regex.Match(postStr, "^DM? +(?<id>[a-zA-Z0-9_]+) +(?<body>.+)", RegexOptions.IgnoreCase Or RegexOptions.Singleline).Success Then
413 Return SendDirectMessage(postStr)
416 Google.GASender.GetInstance().TrackEventWithCategory("post", "status", Me.UserId)
418 Dim res As HttpStatusCode
419 Dim content As String = ""
421 res = twCon.UpdateStatus(postStr, reply_to, content)
422 Catch ex As Exception
423 Return "Err:" + ex.Message
427 Case HttpStatusCode.OK
428 Twitter.AccountState = ACCOUNT_STATE.Valid
429 Dim status As TwitterDataModel.Status
431 status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
432 Catch ex As SerializationException
433 TraceOut(ex.Message + Environment.NewLine + content)
434 Return "Err:Json Parse Error(DataContractJsonSerializer)"
435 Catch ex As Exception
436 TraceOut(ex, GetCurrentMethod.Name & " " & content)
437 Return "Err:Invalid Json!"
439 _followersCount = status.User.FollowersCount
440 _friendsCount = status.User.FriendsCount
441 _statusesCount = status.User.StatusesCount
442 _location = status.User.Location
443 _bio = status.User.Description
445 If IsPostRestricted(status) Then
446 Return "OK:Delaying?"
448 If op.Post(postStr.Length) Then
451 Return "Outputz:Failed"
453 Case HttpStatusCode.NotFound
455 Case HttpStatusCode.Forbidden, HttpStatusCode.BadRequest
456 Dim errMsg As String = GetErrorMessageJson(content)
457 If String.IsNullOrEmpty(errMsg) Then
458 Return "Warn:" + res.ToString
460 Return "Warn:" + errMsg
462 Case HttpStatusCode.Conflict, _
463 HttpStatusCode.ExpectationFailed, _
464 HttpStatusCode.Gone, _
465 HttpStatusCode.LengthRequired, _
466 HttpStatusCode.MethodNotAllowed, _
467 HttpStatusCode.NotAcceptable, _
468 HttpStatusCode.NotFound, _
469 HttpStatusCode.PaymentRequired, _
470 HttpStatusCode.PreconditionFailed, _
471 HttpStatusCode.RequestedRangeNotSatisfiable, _
472 HttpStatusCode.RequestEntityTooLarge, _
473 HttpStatusCode.RequestTimeout, _
474 HttpStatusCode.RequestUriTooLong
475 '仕様書にない400系エラー。サーバまでは到達しているのでリトライしない
476 Return "Warn:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
477 Case HttpStatusCode.Unauthorized
478 Twitter.AccountState = ACCOUNT_STATE.Invalid
479 Dim errMsg As String = GetErrorMessageJson(content)
480 If String.IsNullOrEmpty(errMsg) Then
481 Return My.Resources.Unauthorized
483 Return "Auth err:" + errMsg
486 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
490 Public Function PostStatusWithMedia(ByVal postStr As String, ByVal reply_to As Long, ByVal mediaFile As FileInfo) As String
492 If _endingFlag Then Return ""
494 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
496 postStr = postStr.Trim()
498 Google.GASender.GetInstance().TrackEventWithCategory("post", "status_with_media", Me.UserId)
500 Dim res As HttpStatusCode
501 Dim content As String = ""
503 res = twCon.UpdateStatusWithMedia(postStr, reply_to, mediaFile, content)
504 Catch ex As Exception
505 Return "Err:" + ex.Message
509 Case HttpStatusCode.OK
510 Twitter.AccountState = ACCOUNT_STATE.Valid
511 Dim status As TwitterDataModel.Status
513 status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
514 Catch ex As SerializationException
515 TraceOut(ex.Message + Environment.NewLine + content)
516 Return "Err:Json Parse Error(DataContractJsonSerializer)"
517 Catch ex As Exception
518 TraceOut(ex, GetCurrentMethod.Name & " " & content)
519 Return "Err:Invalid Json!"
521 _followersCount = status.User.FollowersCount
522 _friendsCount = status.User.FriendsCount
523 _statusesCount = status.User.StatusesCount
524 _location = status.User.Location
525 _bio = status.User.Description
527 If IsPostRestricted(status) Then
528 Return "OK:Delaying?"
530 If op.Post(postStr.Length) Then
533 Return "Outputz:Failed"
535 Case HttpStatusCode.NotFound
537 Case HttpStatusCode.Forbidden, HttpStatusCode.BadRequest
538 Dim errMsg As String = GetErrorMessageJson(content)
539 If String.IsNullOrEmpty(errMsg) Then
540 Return "Warn:" + res.ToString
542 Return "Warn:" + errMsg
544 Case HttpStatusCode.Conflict, _
545 HttpStatusCode.ExpectationFailed, _
546 HttpStatusCode.Gone, _
547 HttpStatusCode.LengthRequired, _
548 HttpStatusCode.MethodNotAllowed, _
549 HttpStatusCode.NotAcceptable, _
550 HttpStatusCode.NotFound, _
551 HttpStatusCode.PaymentRequired, _
552 HttpStatusCode.PreconditionFailed, _
553 HttpStatusCode.RequestedRangeNotSatisfiable, _
554 HttpStatusCode.RequestEntityTooLarge, _
555 HttpStatusCode.RequestTimeout, _
556 HttpStatusCode.RequestUriTooLong
557 '仕様書にない400系エラー。サーバまでは到達しているのでリトライしない
558 Return "Warn:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
559 Case HttpStatusCode.Unauthorized
560 Twitter.AccountState = ACCOUNT_STATE.Invalid
561 Dim errMsg As String = GetErrorMessageJson(content)
562 If String.IsNullOrEmpty(errMsg) Then
563 Return My.Resources.Unauthorized
565 Return "Auth err:" + errMsg
568 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
572 Public Function SendDirectMessage(ByVal postStr As String) As String
574 If _endingFlag Then Return ""
576 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
577 If Not TwitterApiInfo.IsDirectMessagePermission Then Return "Auth Err:try to re-authorization."
579 Google.GASender.GetInstance().TrackEventWithCategory("post", "direct_message", Me.UserId)
581 postStr = postStr.Trim()
583 Dim res As HttpStatusCode
584 Dim content As String = ""
586 Dim mc As Match = Regex.Match(postStr, "^DM? +(?<id>[a-zA-Z0-9_]+) +(?<body>.+)", RegexOptions.IgnoreCase Or RegexOptions.Singleline)
589 res = twCon.SendDirectMessage(mc.Groups("body").Value, mc.Groups("id").Value, content)
590 Catch ex As Exception
591 Return "Err:" + ex.Message
595 Case HttpStatusCode.OK
596 Twitter.AccountState = ACCOUNT_STATE.Valid
597 Dim status As TwitterDataModel.Directmessage
599 status = CreateDataFromJson(Of TwitterDataModel.Directmessage)(content)
600 Catch ex As SerializationException
601 TraceOut(ex.Message + Environment.NewLine + content)
602 Return "Err:Json Parse Error(DataContractJsonSerializer)"
603 Catch ex As Exception
604 TraceOut(ex, GetCurrentMethod.Name & " " & content)
605 Return "Err:Invalid Json!"
607 _followersCount = status.Sender.FollowersCount
608 _friendsCount = status.Sender.FriendsCount
609 _statusesCount = status.Sender.StatusesCount
610 _location = status.Sender.Location
611 _bio = status.Sender.Description
613 If op.Post(postStr.Length) Then
616 Return "Outputz:Failed"
618 Case HttpStatusCode.Forbidden, HttpStatusCode.BadRequest
619 Dim errMsg As String = GetErrorMessageJson(content)
620 If String.IsNullOrEmpty(errMsg) Then
621 Return "Warn:" + res.ToString
623 Return "Warn:" + errMsg
625 Case HttpStatusCode.Conflict, _
626 HttpStatusCode.ExpectationFailed, _
627 HttpStatusCode.Gone, _
628 HttpStatusCode.LengthRequired, _
629 HttpStatusCode.MethodNotAllowed, _
630 HttpStatusCode.NotAcceptable, _
631 HttpStatusCode.NotFound, _
632 HttpStatusCode.PaymentRequired, _
633 HttpStatusCode.PreconditionFailed, _
634 HttpStatusCode.RequestedRangeNotSatisfiable, _
635 HttpStatusCode.RequestEntityTooLarge, _
636 HttpStatusCode.RequestTimeout, _
637 HttpStatusCode.RequestUriTooLong
638 '仕様書にない400系エラー。サーバまでは到達しているのでリトライしない
639 Return "Warn:" + res.ToString
640 Case HttpStatusCode.Unauthorized
641 Twitter.AccountState = ACCOUNT_STATE.Invalid
642 Dim errMsg As String = GetErrorMessageJson(content)
643 If String.IsNullOrEmpty(errMsg) Then
644 Return My.Resources.Unauthorized
646 Return "Auth err:" + errMsg
649 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
653 Public Function RemoveStatus(ByVal id As Long) As String
654 If _endingFlag Then Return ""
656 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
658 Google.GASender.GetInstance().TrackEventWithCategory("post", "destroy", Me.UserId)
659 Dim res As HttpStatusCode
662 res = twCon.DestroyStatus(id)
663 Catch ex As Exception
664 Return "Err:" + ex.Message
668 Case HttpStatusCode.OK
669 Twitter.AccountState = ACCOUNT_STATE.Valid
671 Case HttpStatusCode.Unauthorized
672 Twitter.AccountState = ACCOUNT_STATE.Invalid
673 Return My.Resources.Unauthorized
674 Case HttpStatusCode.NotFound
677 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
682 Public Function PostRetweet(ByVal id As Long, ByVal read As Boolean) As String
683 If _endingFlag Then Return ""
684 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
687 Dim target As Long = id
688 If TabInformations.GetInstance.Item(id).RetweetedId > 0 Then
689 target = TabInformations.GetInstance.Item(id).RetweetedId '再RTの場合は元発言をRT
692 Google.GASender.GetInstance().TrackEventWithCategory("post", "retweet", Me.UserId)
693 Dim res As HttpStatusCode
694 Dim content As String = ""
696 res = twCon.RetweetStatus(target, content)
697 Catch ex As Exception
698 Return "Err:" + ex.Message
702 Case HttpStatusCode.Unauthorized
703 'Blockユーザーの発言をRTすると認証エラー返る
704 'Twitter.AccountState = ACCOUNT_STATE.Invalid
705 Return My.Resources.Unauthorized + " or blocked user."
706 Case Is <> HttpStatusCode.OK
707 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
710 Twitter.AccountState = ACCOUNT_STATE.Valid
712 Dim status As TwitterDataModel.Status
714 status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
715 Catch ex As SerializationException
716 TraceOut(ex.Message + Environment.NewLine + content)
717 Return "Err:Json Parse Error(DataContractJsonSerializer)"
718 Catch ex As Exception
719 TraceOut(ex, GetCurrentMethod.Name & " " & content)
720 Return "Err:Invalid Json!"
724 Dim post As PostClass = CreatePostsFromStatusData(status)
725 If post Is Nothing Then Return "Invalid Json!"
729 If TabInformations.GetInstance.ContainsKey(post.StatusId) Then Return ""
732 If post.RetweetedId = 0 Then Return "Invalid Json!"
738 If _readOwnPost Then post.IsRead = True
741 TabInformations.GetInstance.AddPost(post)
746 Public Function RemoveDirectMessage(ByVal id As Long, ByVal post As PostClass) As String
747 If _endingFlag Then Return ""
749 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
750 If Not TwitterApiInfo.IsDirectMessagePermission Then Return "Auth Err:try to re-authorization."
752 Google.GASender.GetInstance().TrackEventWithCategory("post", "destroy_direct_message", Me.UserId)
753 Dim res As HttpStatusCode
756 ' _deletemessages.Add(post)
759 res = twCon.DestroyDirectMessage(id)
760 Catch ex As Exception
761 Return "Err:" + ex.Message
765 Case HttpStatusCode.OK
766 Twitter.AccountState = ACCOUNT_STATE.Valid
768 Case HttpStatusCode.Unauthorized
769 Twitter.AccountState = ACCOUNT_STATE.Invalid
770 Return My.Resources.Unauthorized
771 Case HttpStatusCode.NotFound
774 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
778 Public Function PostFollowCommand(ByVal screenName As String) As String
780 If _endingFlag Then Return ""
782 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
784 Google.GASender.GetInstance().TrackEventWithCategory("post", "follow", Me.UserId)
785 Dim res As HttpStatusCode
786 Dim content As String = ""
789 res = twCon.CreateFriendships(screenName, content)
790 Catch ex As Exception
791 Return "Err:" + ex.Message
795 Case HttpStatusCode.OK
796 Twitter.AccountState = ACCOUNT_STATE.Valid
798 Case HttpStatusCode.Unauthorized
799 Twitter.AccountState = ACCOUNT_STATE.Invalid
800 Return My.Resources.Unauthorized
801 Case HttpStatusCode.Forbidden
802 Dim errMsg As String = GetErrorMessageJson(content)
803 If String.IsNullOrEmpty(errMsg) Then
804 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
806 Return "Err:" + errMsg
809 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
813 Public Function PostRemoveCommand(ByVal screenName As String) As String
815 If _endingFlag Then Return ""
817 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
819 Google.GASender.GetInstance().TrackEventWithCategory("post", "destroy_friendships", Me.UserId)
820 Dim res As HttpStatusCode
821 Dim content As String = ""
824 res = twCon.DestroyFriendships(screenName, content)
825 Catch ex As Exception
826 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
830 Case HttpStatusCode.OK
831 Twitter.AccountState = ACCOUNT_STATE.Valid
833 Case HttpStatusCode.Unauthorized
834 Twitter.AccountState = ACCOUNT_STATE.Invalid
835 Return My.Resources.Unauthorized
836 Case HttpStatusCode.Forbidden
837 Dim errMsg As String = GetErrorMessageJson(content)
838 If String.IsNullOrEmpty(errMsg) Then
839 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
841 Return "Err:" + errMsg
844 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
848 Public Function PostCreateBlock(ByVal screenName As String) As String
850 If _endingFlag Then Return ""
852 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
854 Google.GASender.GetInstance().TrackEventWithCategory("post", "block", Me.UserId)
855 Dim res As HttpStatusCode
856 Dim content As String = ""
859 res = twCon.CreateBlock(screenName, content)
860 Catch ex As Exception
861 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
865 Case HttpStatusCode.OK
866 Twitter.AccountState = ACCOUNT_STATE.Valid
868 Case HttpStatusCode.Unauthorized
869 Twitter.AccountState = ACCOUNT_STATE.Invalid
870 Return My.Resources.Unauthorized
871 Case HttpStatusCode.Forbidden
872 Dim errMsg As String = GetErrorMessageJson(content)
873 If String.IsNullOrEmpty(errMsg) Then
874 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
876 Return "Err:" + errMsg
879 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
883 Public Function PostDestroyBlock(ByVal screenName As String) As String
885 If _endingFlag Then Return ""
887 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
889 Google.GASender.GetInstance().TrackEventWithCategory("post", "destroy_block", Me.UserId)
890 Dim res As HttpStatusCode
891 Dim content As String = ""
894 res = twCon.DestroyBlock(screenName, content)
895 Catch ex As Exception
896 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
900 Case HttpStatusCode.OK
901 Twitter.AccountState = ACCOUNT_STATE.Valid
903 Case HttpStatusCode.Unauthorized
904 Twitter.AccountState = ACCOUNT_STATE.Invalid
905 Return My.Resources.Unauthorized
906 Case HttpStatusCode.Forbidden
907 Dim errMsg As String = GetErrorMessageJson(content)
908 If String.IsNullOrEmpty(errMsg) Then
909 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
911 Return "Err:" + errMsg
914 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
918 Public Function PostReportSpam(ByVal screenName As String) As String
920 If _endingFlag Then Return ""
922 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
924 Google.GASender.GetInstance().TrackEventWithCategory("post", "spam", Me.UserId)
925 Dim res As HttpStatusCode
926 Dim content As String = ""
929 res = twCon.ReportSpam(screenName, content)
930 Catch ex As Exception
931 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
935 Case HttpStatusCode.OK
936 Twitter.AccountState = ACCOUNT_STATE.Valid
938 Case HttpStatusCode.Unauthorized
939 Twitter.AccountState = ACCOUNT_STATE.Invalid
940 Return My.Resources.Unauthorized
941 Case HttpStatusCode.Forbidden
942 Dim errMsg As String = GetErrorMessageJson(content)
943 If String.IsNullOrEmpty(errMsg) Then
944 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
946 Return "Err:" + errMsg
949 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
953 Public Function GetFriendshipInfo(ByVal screenName As String, ByRef isFollowing As Boolean, ByRef isFollowed As Boolean) As String
955 If _endingFlag Then Return ""
957 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
959 Google.GASender.GetInstance().TrackPage("/friendships", Me.UserId)
960 Dim res As HttpStatusCode
961 Dim content As String = ""
963 res = twCon.ShowFriendships(_uname, screenName, content)
964 Catch ex As Exception
965 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
969 Case HttpStatusCode.OK
971 Dim relation = CreateDataFromJson(Of TwitterDataModel.Relationship)(content)
972 isFollowing = relation.Relationship.Source.Following
973 isFollowed = relation.Relationship.Source.FollowedBy
975 Catch ex As SerializationException
976 TraceOut(ex.Message + Environment.NewLine + content)
977 Return "Err:Json Parse Error(DataContractJsonSerializer)"
978 Catch ex As Exception
979 TraceOut(ex, GetCurrentMethod.Name & " " & content)
980 Return "Err:Invalid Json!"
982 Case HttpStatusCode.BadRequest
983 Return "Err:API Limits?"
984 Case HttpStatusCode.Unauthorized
985 Twitter.AccountState = ACCOUNT_STATE.Invalid
986 Return My.Resources.Unauthorized
988 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
992 Public Function GetUserInfo(ByVal screenName As String, ByRef user As TwitterDataModel.User) As String
994 If _endingFlag Then Return ""
996 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
998 Google.GASender.GetInstance().TrackPage("/showuser", Me.UserId)
999 Dim res As HttpStatusCode
1000 Dim content As String = ""
1003 res = twCon.ShowUserInfo(screenName, content)
1004 Catch ex As Exception
1005 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
1009 Case HttpStatusCode.OK
1010 Twitter.AccountState = ACCOUNT_STATE.Valid
1012 user = CreateDataFromJson(Of TwitterDataModel.User)(content)
1013 Catch ex As SerializationException
1014 TraceOut(ex.Message + Environment.NewLine + content)
1015 Return "Err:Json Parse Error(DataContractJsonSerializer)"
1016 Catch ex As Exception
1017 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1018 Return "Err:Invalid Json!"
1021 Case HttpStatusCode.BadRequest
1022 Return "Err:API Limits?"
1023 Case HttpStatusCode.Unauthorized
1024 Twitter.AccountState = ACCOUNT_STATE.Invalid
1025 Dim errMsg As String = GetErrorMessageJson(content)
1026 If String.IsNullOrEmpty(errMsg) Then
1027 Return My.Resources.Unauthorized
1029 Return "Auth err:" + errMsg
1032 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1036 Public Function GetStatus_Retweeted_Count(ByVal StatusId As Long, ByRef retweeted_count As Integer) As String
1038 If _endingFlag Then Return ""
1040 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1042 Google.GASender.GetInstance().TrackPage("/retweet_count", Me.UserId)
1043 Dim res As HttpStatusCode
1044 Dim content As String = ""
1045 Dim xmlBuf As String = ""
1049 ' 注:dev.twitter.comに記述されているcountパラメータは間違い。100が正しい
1050 For i As Integer = 1 To 100
1053 res = twCon.Statusid_retweeted_by_ids(StatusId, 100, i, content)
1054 Catch ex As Exception
1055 Return "Err:" + ex.Message
1059 Case HttpStatusCode.OK
1061 Dim ids As Int64() = CreateDataFromJson(Of Int64())(content)
1062 retweeted_count += ids.Length
1063 If ids.Length < 100 Then Exit For
1064 Catch ex As SerializationException
1065 retweeted_count = -1
1066 TraceOut(ex.Message + Environment.NewLine + content)
1067 Return "Err:Json Parse Error(DataContractJsonSerializer)"
1068 Catch ex As Exception
1069 retweeted_count = -1
1070 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1071 Return "Err:Invalid Json!"
1073 Case HttpStatusCode.BadRequest
1074 retweeted_count = -1
1075 Return "Err:API Limits?"
1076 Case HttpStatusCode.Unauthorized
1077 retweeted_count = -1
1078 Twitter.AccountState = ACCOUNT_STATE.Invalid
1079 Return My.Resources.Unauthorized
1081 retweeted_count = -1
1082 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1088 Public Function PostFavAdd(ByVal id As Long) As String
1089 If _endingFlag Then Return ""
1091 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1093 Google.GASender.GetInstance().TrackEventWithCategory("post", "favorites", Me.UserId)
1094 Dim res As HttpStatusCode
1095 Dim content As String = ""
1097 res = twCon.CreateFavorites(id, content)
1098 Catch ex As Exception
1099 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
1103 Case HttpStatusCode.OK
1104 Twitter.AccountState = ACCOUNT_STATE.Valid
1105 If Not _restrictFavCheck Then Return ""
1106 Case HttpStatusCode.Unauthorized
1107 Twitter.AccountState = ACCOUNT_STATE.Invalid
1108 Return My.Resources.Unauthorized
1109 Case HttpStatusCode.Forbidden
1110 Dim errMsg As String = GetErrorMessageJson(content)
1111 If String.IsNullOrEmpty(errMsg) Then
1112 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
1114 Return "Err:" + errMsg
1117 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1120 'http://twitter.com/statuses/show/id.xml APIを発行して本文を取得
1122 'Dim content As String = ""
1125 res = twCon.ShowStatuses(id, content)
1126 Catch ex As Exception
1127 Return "Err:" + ex.Message
1131 Case HttpStatusCode.OK
1132 Twitter.AccountState = ACCOUNT_STATE.Valid
1133 Dim status As TwitterDataModel.Status
1135 status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
1136 Catch ex As SerializationException
1137 TraceOut(ex.Message + Environment.NewLine + content)
1138 Return "Err:Json Parse Error(DataContractJsonSerializer)"
1139 Catch ex As Exception
1140 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1141 Return "Err:Invalid Json!"
1143 If status.Favorited Then
1146 Return "NG(Restricted?)"
1148 Case HttpStatusCode.Unauthorized
1149 Twitter.AccountState = ACCOUNT_STATE.Invalid
1150 Return My.Resources.Unauthorized
1151 Case HttpStatusCode.BadRequest
1152 Return "Err:API Limits?"
1154 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1159 Public Function PostFavRemove(ByVal id As Long) As String
1160 If _endingFlag Then Return ""
1162 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1164 Google.GASender.GetInstance().TrackEventWithCategory("post", "destroy_favorites", Me.UserId)
1165 Dim res As HttpStatusCode
1166 Dim content As String = ""
1168 res = twCon.DestroyFavorites(id, content)
1169 Catch ex As Exception
1170 Return "Err:" + ex.Message
1174 Case HttpStatusCode.OK
1175 Twitter.AccountState = ACCOUNT_STATE.Valid
1177 Case HttpStatusCode.Unauthorized
1178 Twitter.AccountState = ACCOUNT_STATE.Invalid
1179 Return My.Resources.Unauthorized
1180 Case HttpStatusCode.Forbidden
1181 Dim errMsg As String = GetErrorMessageJson(content)
1182 If String.IsNullOrEmpty(errMsg) Then
1183 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
1185 Return "Err:" + errMsg
1188 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1192 Public Function PostUpdateProfile(ByVal name As String, ByVal url As String, ByVal location As String, ByVal description As String) As String
1193 If _endingFlag Then Return ""
1195 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1197 Google.GASender.GetInstance().TrackEventWithCategory("post", "update_profile", Me.UserId)
1198 Dim res As HttpStatusCode
1199 Dim content As String = ""
1201 res = twCon.UpdateProfile(name, url, location, description, content)
1202 Catch ex As Exception
1203 Return "Err:" + ex.Message
1207 Case HttpStatusCode.OK
1208 Twitter.AccountState = ACCOUNT_STATE.Valid
1210 Case HttpStatusCode.Unauthorized
1211 Twitter.AccountState = ACCOUNT_STATE.Invalid
1212 Return My.Resources.Unauthorized
1213 Case HttpStatusCode.Forbidden
1214 Dim errMsg As String = GetErrorMessageJson(content)
1215 If String.IsNullOrEmpty(errMsg) Then
1216 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
1218 Return "Err:" + errMsg
1221 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1225 Public Function PostUpdateProfileImage(ByVal filename As String) As String
1226 If _endingFlag Then Return ""
1228 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1230 Google.GASender.GetInstance().TrackEventWithCategory("post", "update_profile_image", Me.UserId)
1231 Dim res As HttpStatusCode
1232 Dim content As String = ""
1234 res = twCon.UpdateProfileImage(New FileInfo(filename), content)
1235 Catch ex As Exception
1236 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
1240 Case HttpStatusCode.OK
1241 Twitter.AccountState = ACCOUNT_STATE.Valid
1243 Case HttpStatusCode.Unauthorized
1244 Twitter.AccountState = ACCOUNT_STATE.Invalid
1245 Return My.Resources.Unauthorized
1246 Case HttpStatusCode.Forbidden
1247 Dim errMsg As String = GetErrorMessageJson(content)
1248 If String.IsNullOrEmpty(errMsg) Then
1249 Return "Err:Forbidden(" + GetCurrentMethod.Name + ")"
1251 Return "Err:" + errMsg
1254 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
1258 Public ReadOnly Property Username() As String
1260 Return twCon.AuthenticatedUsername
1264 Public ReadOnly Property UserId As Long
1266 Return twCon.AuthenticatedUserId
1270 Public ReadOnly Property Password() As String
1272 Return twCon.Password
1276 Private Shared _accountState As ACCOUNT_STATE = ACCOUNT_STATE.Valid
1277 Public Shared Property AccountState() As ACCOUNT_STATE
1279 Return _accountState
1281 Set(ByVal value As ACCOUNT_STATE)
1282 _accountState = value
1286 Public WriteOnly Property GetIcon() As Boolean
1287 Set(ByVal value As Boolean)
1292 Public WriteOnly Property TinyUrlResolve() As Boolean
1293 Set(ByVal value As Boolean)
1294 _tinyUrlResolve = value
1298 Public WriteOnly Property RestrictFavCheck() As Boolean
1299 Set(ByVal value As Boolean)
1300 _restrictFavCheck = value
1304 Public WriteOnly Property IconSize() As Integer
1305 Set(ByVal value As Integer)
1311 Public Function GetVersionInfo() As String
1312 Dim content As String = ""
1313 If Not (New HttpVarious).GetData("http://tween.sourceforge.jp/version.txt?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), Nothing, content, GetUserAgentString()) Then
1314 Throw New Exception("GetVersionInfo Failed")
1319 Public Function GetTweenBinary(ByVal strVer As String) As String
1320 Google.GASender.GetInstance().TrackPage("/newversion", Me.UserId)
1323 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/Tween" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1324 Path.Combine(MyCommon.settingPath, "TweenNew.exe")) Then
1325 Return "Err:Download failed"
1328 If Not Directory.Exists(Path.Combine(MyCommon.settingPath, "en")) Then
1329 Directory.CreateDirectory(Path.Combine(MyCommon.settingPath, "en"))
1331 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenResEn" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1332 Path.Combine(Path.Combine(MyCommon.settingPath, "en"), "Tween.resourcesNew.dll")) Then
1333 Return "Err:Download failed"
1335 'その他言語圏のリソース。取得失敗しても継続
1337 Dim curCul As String = ""
1338 If Not Thread.CurrentThread.CurrentUICulture.IsNeutralCulture Then
1339 Dim idx As Integer = Thread.CurrentThread.CurrentUICulture.Name.LastIndexOf("-"c)
1341 curCul = Thread.CurrentThread.CurrentUICulture.Name.Substring(0, idx)
1343 curCul = Thread.CurrentThread.CurrentUICulture.Name
1346 curCul = Thread.CurrentThread.CurrentUICulture.Name
1348 If Not String.IsNullOrEmpty(curCul) AndAlso curCul <> "en" AndAlso curCul <> "ja" Then
1349 If Not Directory.Exists(Path.Combine(MyCommon.settingPath, curCul)) Then
1350 Directory.CreateDirectory(Path.Combine(MyCommon.settingPath, curCul))
1352 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenRes" + curCul + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1353 Path.Combine(Path.Combine(MyCommon.settingPath, curCul), "Tween.resourcesNew.dll")) Then
1354 'Return "Err:Download failed"
1358 Dim curCul2 As String
1359 If Not Thread.CurrentThread.CurrentCulture.IsNeutralCulture Then
1360 Dim idx As Integer = Thread.CurrentThread.CurrentCulture.Name.LastIndexOf("-"c)
1362 curCul2 = Thread.CurrentThread.CurrentCulture.Name.Substring(0, idx)
1364 curCul2 = Thread.CurrentThread.CurrentCulture.Name
1367 curCul2 = Thread.CurrentThread.CurrentCulture.Name
1369 If Not String.IsNullOrEmpty(curCul2) AndAlso curCul2 <> "en" AndAlso curCul2 <> curCul Then
1370 If Not Directory.Exists(Path.Combine(MyCommon.settingPath, curCul2)) Then
1371 Directory.CreateDirectory(Path.Combine(MyCommon.settingPath, curCul2))
1373 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenRes" + curCul2 + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1374 Path.Combine(Path.Combine(MyCommon.settingPath, curCul2), "Tween.resourcesNew.dll")) Then
1375 'Return "Err:Download failed"
1380 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenUp3.gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1381 Path.Combine(MyCommon.settingPath, "TweenUp3.exe")) Then
1382 Return "Err:Download failed"
1385 If Not (New HttpVarious).GetDataToFile("http://tween.sourceforge.jp/TweenDll" + strVer + ".gz?" + Now.ToString("yyMMddHHmmss") + Environment.TickCount.ToString(), _
1386 Path.Combine(MyCommon.settingPath, "TweenNew.XmlSerializers.dll")) Then
1387 Return "Err:Download failed"
1390 Catch ex As Exception
1391 Return "Err:Download failed"
1396 Public Property DetailIcon() As IDictionary(Of String, Image)
1400 Set(ByVal value As IDictionary(Of String, Image))
1405 Public Property ReadOwnPost() As Boolean
1409 Set(ByVal value As Boolean)
1410 _readOwnPost = value
1414 Public ReadOnly Property FollowersCount() As Integer
1416 Return _followersCount
1420 Public ReadOnly Property FriendsCount() As Integer
1422 Return _friendsCount
1426 Public ReadOnly Property StatusesCount() As Integer
1428 Return _statusesCount
1432 Public ReadOnly Property Location() As String
1438 Public ReadOnly Property Bio() As String
1444 Public WriteOnly Property UseSsl() As Boolean
1445 Set(ByVal value As Boolean)
1446 HttpTwitter.UseSsl = value
1448 _protocol = "https://"
1450 _protocol = "http://"
1455 Public Function GetTimelineApi(ByVal read As Boolean, _
1456 ByVal gType As WORKERTYPE, _
1457 ByVal more As Boolean, _
1458 ByVal startup As Boolean) As String
1460 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1462 If _endingFlag Then Return ""
1464 Dim res As HttpStatusCode
1465 Dim content As String = ""
1466 Dim count As Integer = AppendSettingDialog.Instance.CountApi
1467 If gType = WORKERTYPE.Reply Then count = AppendSettingDialog.Instance.CountApiReply()
1468 If AppendSettingDialog.Instance.UseAdditionalCount Then
1469 If more AndAlso AppendSettingDialog.Instance.MoreCountApi <> 0 Then
1470 count = AppendSettingDialog.Instance.MoreCountApi
1471 ElseIf startup AndAlso AppendSettingDialog.Instance.FirstCountApi <> 0 AndAlso gType = WORKERTYPE.Timeline Then
1472 count = AppendSettingDialog.Instance.FirstCountApi
1476 If gType = WORKERTYPE.Timeline Then
1478 res = twCon.HomeTimeline(count, Me.minHomeTimeline, 0, content)
1480 res = twCon.HomeTimeline(count, 0, 0, content)
1484 res = twCon.Mentions(count, Me.minMentions, 0, content)
1486 res = twCon.Mentions(count, 0, 0, content)
1489 Catch ex As Exception
1490 Return "Err:" + ex.Message
1493 Case HttpStatusCode.OK
1494 Twitter.AccountState = ACCOUNT_STATE.Valid
1495 Case HttpStatusCode.Unauthorized
1496 Twitter.AccountState = ACCOUNT_STATE.Invalid
1497 Return My.Resources.Unauthorized
1498 Case HttpStatusCode.BadRequest
1499 Return "Err:API Limits?"
1501 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1504 If gType = WORKERTYPE.Timeline Then
1505 Return CreatePostsFromJson(content, gType, Nothing, read, count, Me.minHomeTimeline)
1507 Return CreatePostsFromJson(content, gType, Nothing, read, count, Me.minMentions)
1511 Public Function GetUserTimelineApi(ByVal read As Boolean,
1512 ByVal count As Integer,
1513 ByVal userName As String,
1514 ByVal tab As TabClass,
1515 ByVal more As Boolean) As String
1517 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1519 If _endingFlag Then Return ""
1521 Dim res As HttpStatusCode
1522 Dim content As String = ""
1524 If count = 0 Then count = 20
1526 If String.IsNullOrEmpty(userName) Then
1527 Dim target As String = tab.User
1528 If target Is Nothing Then Return ""
1529 res = twCon.UserTimeline(0, target, count, 0, 0, content)
1532 res = twCon.UserTimeline(0, userName, count, tab.OldestId, 0, content)
1534 res = twCon.UserTimeline(0, userName, count, 0, 0, content)
1537 Catch ex As Exception
1538 Return "Err:" + ex.Message
1541 Case HttpStatusCode.OK
1542 Twitter.AccountState = ACCOUNT_STATE.Valid
1543 Case HttpStatusCode.Unauthorized
1544 Twitter.AccountState = ACCOUNT_STATE.Valid
1545 Return "Err:@" + userName + "'s Tweets are protected."
1546 Case HttpStatusCode.BadRequest
1547 Return "Err:API Limits?"
1549 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1552 Dim items As List(Of TwitterDataModel.Status)
1554 items = CreateDataFromJson(Of List(Of TwitterDataModel.Status))(content)
1555 Catch ex As SerializationException
1556 TraceOut(ex.Message + Environment.NewLine + content)
1557 Return "Json Parse Error(DataContractJsonSerializer)"
1558 Catch ex As Exception
1559 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1560 Return "Invalid Json!"
1563 For Each status As TwitterDataModel.Status In items
1564 Dim item As PostClass = CreatePostsFromStatusData(status)
1565 If item Is Nothing Then Continue For
1566 If item.StatusId < tab.OldestId Then tab.OldestId = item.StatusId
1568 If item.IsMe AndAlso Not read AndAlso _readOwnPost Then item.IsRead = True
1569 If tab IsNot Nothing Then item.RelTabName = tab.TabName
1570 '非同期アイコン取得&StatusDictionaryに追加
1571 TabInformations.GetInstance.AddPost(item)
1577 Public Function GetStatusApi(ByVal read As Boolean,
1579 ByRef post As PostClass) As String
1580 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1582 If _endingFlag Then Return ""
1584 Google.GASender.GetInstance().TrackPage("/showstatus", Me.UserId)
1585 Dim res As HttpStatusCode
1586 Dim content As String = ""
1589 res = twCon.ShowStatuses(id, content)
1590 Catch ex As Exception
1591 Return "Err:" + ex.Message
1594 Case HttpStatusCode.OK
1595 Twitter.AccountState = ACCOUNT_STATE.Valid
1596 Case HttpStatusCode.Unauthorized
1597 Twitter.AccountState = ACCOUNT_STATE.Invalid
1598 Return My.Resources.Unauthorized
1599 Case HttpStatusCode.BadRequest
1600 Return "Err:API Limits?"
1601 Case HttpStatusCode.Forbidden
1602 Return "Err:Protected user's tweet"
1604 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1607 Dim status As TwitterDataModel.Status
1609 status = CreateDataFromJson(Of TwitterDataModel.Status)(content)
1610 Catch ex As SerializationException
1611 TraceOut(ex.Message + Environment.NewLine + content)
1612 Return "Json Parse Error(DataContractJsonSerializer)"
1613 Catch ex As Exception
1614 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1615 Return "Invalid Json!"
1618 Dim item As PostClass = CreatePostsFromStatusData(status)
1619 If item Is Nothing Then Return "Err:Can't create post"
1621 If item.IsMe AndAlso Not read AndAlso _readOwnPost Then item.IsRead = True
1627 Public Function GetStatusApi(ByVal read As Boolean,
1629 ByVal tab As TabClass) As String
1630 Dim post As PostClass = Nothing
1631 Dim r As String = Me.GetStatusApi(read, id, post)
1634 If tab IsNot Nothing Then post.RelTabName = tab.TabName
1635 '非同期アイコン取得&StatusDictionaryに追加
1636 TabInformations.GetInstance.AddPost(post)
1642 Private Function CreatePostsFromStatusData(ByVal status As TwitterDataModel.Status) As PostClass
1643 Dim post As New PostClass
1644 Dim entities As TwitterDataModel.Entities
1646 post.StatusId = status.Id
1647 If status.RetweetedStatus IsNot Nothing Then
1648 Dim retweeted As TwitterDataModel.RetweetedStatus = status.RetweetedStatus
1650 post.CreatedAt = DateTimeParse(retweeted.CreatedAt)
1653 post.RetweetedId = retweeted.Id
1655 post.TextFromApi = retweeted.Text
1656 entities = retweeted.Entities
1657 'Source取得(htmlの場合は、中身を取り出し)
1658 post.Source = retweeted.Source
1660 Long.TryParse(retweeted.InReplyToStatusId, post.InReplyToStatusId)
1661 post.InReplyToUser = retweeted.InReplyToScreenName
1662 Long.TryParse(status.InReplyToUserId, post.InReplyToUserId)
1663 post.IsFav = TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.RetweetedId)
1664 If retweeted.Geo IsNot Nothing Then post.PostGeo = New PostClass.StatusGeo() With {.Lat = retweeted.Geo.Coordinates(0), .Lng = retweeted.Geo.Coordinates(1)}
1667 Dim user As TwitterDataModel.User = retweeted.User
1669 If user.ScreenName Is Nothing OrElse status.User.ScreenName Is Nothing Then Return Nothing
1671 post.UserId = user.Id
1672 post.ScreenName = user.ScreenName
1673 post.Nickname = user.Name.Trim()
1674 post.ImageUrl = user.ProfileImageUrl
1675 post.IsProtect = user.Protected
1678 post.RetweetedBy = status.User.ScreenName
1679 post.RetweetedByUserId = status.User.Id
1680 post.IsMe = post.RetweetedBy.ToLower.Equals(_uname)
1682 post.CreatedAt = DateTimeParse(status.CreatedAt)
1684 post.TextFromApi = status.Text
1685 entities = status.Entities
1686 'Source取得(htmlの場合は、中身を取り出し)
1687 post.Source = status.Source
1688 Long.TryParse(status.InReplyToStatusId, post.InReplyToStatusId)
1689 post.InReplyToUser = status.InReplyToScreenName
1690 Long.TryParse(status.InReplyToUserId, post.InReplyToUserId)
1692 post.IsFav = status.Favorited
1693 If status.Geo IsNot Nothing Then post.PostGeo = New PostClass.StatusGeo() With {.Lat = status.Geo.Coordinates(0), .Lng = status.Geo.Coordinates(1)}
1696 Dim user As TwitterDataModel.User = status.User
1698 If user.ScreenName Is Nothing Then Return Nothing
1700 post.UserId = user.Id
1701 post.ScreenName = user.ScreenName
1702 post.Nickname = user.Name.Trim()
1703 post.ImageUrl = user.ProfileImageUrl
1704 post.IsProtect = user.Protected
1705 post.IsMe = post.ScreenName.ToLower.Equals(_uname)
1708 post.Text = CreateHtmlAnchor(post.TextFromApi, post.ReplyToList, entities, post.Media)
1709 post.TextFromApi = Me.ReplaceTextFromApi(post.TextFromApi, entities)
1710 post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
1711 post.TextFromApi = post.TextFromApi.Replace("<3", "♡")
1716 post.IsReply = post.ReplyToList.Contains(_uname)
1717 post.IsExcludeReply = False
1722 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.UserId)
1729 Private Function CreatePostsFromJson(ByVal content As String, ByVal gType As WORKERTYPE, ByVal tab As TabClass, ByVal read As Boolean, ByVal count As Integer, ByRef minimumId As Long) As String
1730 Dim items As List(Of TwitterDataModel.Status)
1732 items = CreateDataFromJson(Of List(Of TwitterDataModel.Status))(content)
1733 Catch ex As SerializationException
1734 TraceOut(ex.Message + Environment.NewLine + content)
1735 Return "Json Parse Error(DataContractJsonSerializer)"
1736 Catch ex As Exception
1737 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1738 Return "Invalid Json!"
1741 For Each status As TwitterDataModel.Status In items
1742 Dim post As PostClass = Nothing
1743 post = CreatePostsFromStatusData(status)
1744 If post Is Nothing Then Continue For
1746 If minimumId > post.StatusId Then minimumId = post.StatusId
1749 If tab Is Nothing Then
1750 If TabInformations.GetInstance.ContainsKey(post.StatusId) Then Continue For
1752 If TabInformations.GetInstance.ContainsKey(post.StatusId, tab.TabName) Then Continue For
1757 If post.RetweetedId > 0 AndAlso Me.noRTId.Contains(post.RetweetedByUserId) Then Continue For
1760 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
1762 If tab IsNot Nothing Then post.RelTabName = tab.TabName
1763 '非同期アイコン取得&StatusDictionaryに追加
1764 TabInformations.GetInstance.AddPost(post)
1770 Private Function CreatePostsFromPhoenixSearch(ByVal content As String, ByVal gType As WORKERTYPE, ByVal tab As TabClass, ByVal read As Boolean, ByVal count As Integer, ByRef minimumId As Long, ByRef nextPageQuery As String) As String
1771 Dim items As TwitterDataModel.SearchResult
1773 items = CreateDataFromJson(Of TwitterDataModel.SearchResult)(content)
1774 Catch ex As SerializationException
1775 TraceOut(ex.Message + Environment.NewLine + content)
1776 Return "Json Parse Error(DataContractJsonSerializer)"
1777 Catch ex As Exception
1778 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1779 Return "Invalid Json!"
1782 nextPageQuery = items.NextPage
1784 For Each status As TwitterDataModel.Status In items.Statuses
1785 Dim post As PostClass = Nothing
1786 post = CreatePostsFromStatusData(status)
1787 If post Is Nothing Then Continue For
1789 If minimumId > post.StatusId Then minimumId = post.StatusId
1792 If tab Is Nothing Then
1793 If TabInformations.GetInstance.ContainsKey(post.StatusId) Then Continue For
1795 If TabInformations.GetInstance.ContainsKey(post.StatusId, tab.TabName) Then Continue For
1800 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
1802 If tab IsNot Nothing Then post.RelTabName = tab.TabName
1803 '非同期アイコン取得&StatusDictionaryに追加
1804 TabInformations.GetInstance.AddPost(post)
1807 Return If(String.IsNullOrEmpty(items.ErrMsg), "", "Err:" + items.ErrMsg)
1810 Public Overloads Function GetListStatus(ByVal read As Boolean, _
1811 ByVal tab As TabClass, _
1812 ByVal more As Boolean, _
1813 ByVal startup As Boolean) As String
1815 If _endingFlag Then Return ""
1817 Dim res As HttpStatusCode
1818 Dim content As String = ""
1819 Dim page As Integer = 0
1820 Dim count As Integer
1821 If AppendSettingDialog.Instance.UseAdditionalCount Then
1822 count = AppendSettingDialog.Instance.ListCountApi
1824 If more AndAlso AppendSettingDialog.Instance.MoreCountApi <> 0 Then
1825 count = AppendSettingDialog.Instance.MoreCountApi
1826 ElseIf startup AndAlso AppendSettingDialog.Instance.FirstCountApi <> 0 Then
1827 count = AppendSettingDialog.Instance.FirstCountApi
1829 count = AppendSettingDialog.Instance.CountApi
1833 count = AppendSettingDialog.Instance.CountApi
1837 res = twCon.GetListsStatuses(tab.ListInfo.UserId, tab.ListInfo.Id, count, tab.OldestId, 0, AppendSettingDialog.Instance.IsListStatusesIncludeRts, content)
1839 res = twCon.GetListsStatuses(tab.ListInfo.UserId, tab.ListInfo.Id, count, 0, 0, AppendSettingDialog.Instance.IsListStatusesIncludeRts, content)
1841 Catch ex As Exception
1842 Return "Err:" + ex.Message
1845 Case HttpStatusCode.OK
1846 Twitter.AccountState = ACCOUNT_STATE.Valid
1847 Case HttpStatusCode.Unauthorized
1848 Twitter.AccountState = ACCOUNT_STATE.Invalid
1849 Return My.Resources.Unauthorized
1850 Case HttpStatusCode.BadRequest
1851 Return "Err:API Limits?"
1853 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1856 Return CreatePostsFromJson(content, WORKERTYPE.List, tab, read, count, tab.OldestId)
1860 Private Function CheckReplyToPost(ByVal relPosts As List(Of PostClass)) As PostClass
1861 Dim tmpPost As PostClass = relPosts(0)
1862 Dim lastPost As PostClass = Nothing
1863 Do While tmpPost IsNot Nothing
1864 If tmpPost.InReplyToStatusId = 0 Then Return Nothing
1866 Dim replyToPost = From p In relPosts
1867 Where p.StatusId = tmpPost.InReplyToStatusId
1869 tmpPost = replyToPost.FirstOrDefault()
1874 Public Function GetRelatedResult(ByVal read As Boolean, ByVal tab As TabClass) As String
1875 Google.GASender.GetInstance().TrackPage("/related_statuses", Me.UserId)
1876 Dim rslt As String = ""
1877 Dim relPosts As New List(Of PostClass)
1878 If tab.RelationTargetPost.TextFromApi.Contains("@") AndAlso tab.RelationTargetPost.InReplyToStatusId = 0 Then
1880 Dim p As PostClass = TabInformations.GetInstance.Item(tab.RelationTargetPost.StatusId)
1881 If p IsNot Nothing AndAlso p.InReplyToStatusId > 0 Then
1882 tab.RelationTargetPost = p
1884 rslt = Me.GetStatusApi(read, tab.RelationTargetPost.StatusId, p)
1885 If Not String.IsNullOrEmpty(rslt) Then Return rslt
1886 tab.RelationTargetPost = p
1889 relPosts.Add(tab.RelationTargetPost.Copy)
1890 Dim tmpPost As PostClass = relPosts(0)
1892 rslt = Me.GetRelatedResultsApi(read, tmpPost, tab, relPosts)
1893 If Not String.IsNullOrEmpty(rslt) Then Exit Do
1894 tmpPost = CheckReplyToPost(relPosts)
1895 Loop While tmpPost IsNot Nothing
1897 relPosts.ForEach(Sub(p) TabInformations.GetInstance.AddPost(p))
1901 Private Function GetRelatedResultsApi(ByVal read As Boolean,
1902 ByVal post As PostClass,
1903 ByVal tab As TabClass,
1904 ByVal relatedPosts As List(Of PostClass)) As String
1906 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
1908 If _endingFlag Then Return ""
1910 Dim res As HttpStatusCode
1911 Dim content As String = ""
1913 If post.RetweetedId > 0 Then
1914 res = twCon.GetRelatedResults(post.RetweetedId, content)
1916 res = twCon.GetRelatedResults(post.StatusId, content)
1918 Catch ex As Exception
1919 Return "Err:" + ex.Message
1922 Case HttpStatusCode.OK
1923 Twitter.AccountState = ACCOUNT_STATE.Valid
1924 Case HttpStatusCode.Unauthorized
1925 Twitter.AccountState = ACCOUNT_STATE.Invalid
1926 Return My.Resources.Unauthorized
1927 Case HttpStatusCode.BadRequest
1928 Return "Err:API Limits?"
1930 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
1933 Dim items As List(Of TwitterDataModel.RelatedResult)
1935 items = CreateDataFromJson(Of List(Of TwitterDataModel.RelatedResult))(content)
1936 Catch ex As SerializationException
1937 TraceOut(ex.Message + Environment.NewLine + content)
1938 Return "Json Parse Error(DataContractJsonSerializer)"
1939 Catch ex As Exception
1940 TraceOut(ex, GetCurrentMethod.Name & " " & content)
1941 Return "Invalid Json!"
1944 Dim targetItem As PostClass = post
1945 If targetItem Is Nothing Then
1948 targetItem = targetItem.Copy()
1950 targetItem.RelTabName = tab.TabName
1951 TabInformations.GetInstance.AddPost(targetItem)
1953 Dim replyToItem As PostClass = Nothing
1954 Dim replyToUserName As String = targetItem.InReplyToUser
1955 If targetItem.InReplyToStatusId > 0 AndAlso TabInformations.GetInstance.Item(targetItem.InReplyToStatusId) IsNot Nothing Then
1956 replyToItem = TabInformations.GetInstance.Item(targetItem.InReplyToStatusId).Copy
1957 replyToItem.IsRead = read
1958 If replyToItem.IsMe AndAlso Not read AndAlso _readOwnPost Then replyToItem.IsRead = True
1959 replyToItem.RelTabName = tab.TabName
1962 Dim replyAdded As Boolean = False
1963 For Each relatedData As TwitterDataModel.RelatedResult In items
1964 For Each result As TwitterDataModel.RelatedTweet In relatedData.Results
1965 Dim item As PostClass = CreatePostsFromStatusData(result.Status)
1966 If item Is Nothing Then Continue For
1967 If targetItem.InReplyToStatusId = item.StatusId Then
1968 replyToItem = Nothing
1972 If item.IsMe AndAlso Not read AndAlso _readOwnPost Then item.IsRead = True
1973 If tab IsNot Nothing Then item.RelTabName = tab.TabName
1974 '非同期アイコン取得&StatusDictionaryに追加
1975 relatedPosts.Add(item)
1978 If replyToItem IsNot Nothing Then
1979 relatedPosts.Add(replyToItem)
1980 ElseIf targetItem.InReplyToStatusId > 0 AndAlso Not replyAdded Then
1981 Dim p As PostClass = Nothing
1982 Dim rslt As String = ""
1983 rslt = GetStatusApi(read, targetItem.InReplyToStatusId, p)
1984 If String.IsNullOrEmpty(rslt) Then
1986 p.RelTabName = tab.TabName
1992 '発言者・返信先ユーザーの直近10発言取得
1993 'Dim rslt As String = Me.GetUserTimelineApi(read, 10, "", tab)
1994 'If Not String.IsNullOrEmpty(rslt) Then Return rslt
1995 'If Not String.IsNullOrEmpty(replyToUserName) Then
1996 ' rslt = Me.GetUserTimelineApi(read, 10, replyToUserName, tab)
2001 'MRTとかに対応のためツイート内にあるツイートを指すURLを取り込む
2002 Dim ma As MatchCollection = Regex.Matches(tab.RelationTargetPost.Text, "href=""https?://twitter.com/(#!/)?(?<ScreenName>[a-zA-Z0-9_]+)(/status(es)?/(?<StatusId>[0-9]+))""")
2003 For Each _match As Match In ma
2004 Dim _statusId As Int64
2005 If Int64.TryParse(_match.Groups("StatusId").Value, _statusId) Then
2006 Dim p As PostClass = Nothing
2007 Dim _post As PostClass = TabInformations.GetInstance.Item(_statusId)
2008 If _post Is Nothing Then
2009 Dim rslt = Me.GetStatusApi(read, _statusId, p)
2013 If p IsNot Nothing Then
2015 p.RelTabName = tab.TabName
2023 Public Function GetSearch(ByVal read As Boolean, _
2024 ByVal tab As TabClass, _
2025 ByVal more As Boolean) As String
2027 If _endingFlag Then Return ""
2029 Dim res As HttpStatusCode
2030 Dim content As String = ""
2031 Dim page As Integer = 0
2032 Dim sinceId As Long = 0
2033 Dim count As Integer = 100
2034 If AppendSettingDialog.Instance.UseAdditionalCount AndAlso
2035 AppendSettingDialog.Instance.SearchCountApi <> 0 Then
2036 count = AppendSettingDialog.Instance.SearchCountApi
2038 count = AppendSettingDialog.Instance.CountApi
2041 page = tab.GetSearchPage(count)
2043 sinceId = tab.SinceId
2047 ' TODO:一時的に40>100件に 件数変更UI作成の必要あり
2048 res = twCon.Search(tab.SearchWords, tab.SearchLang, count, page, sinceId, content)
2049 Catch ex As Exception
2050 Return "Err:" + ex.Message
2053 Case HttpStatusCode.BadRequest
2054 Return "Invalid query"
2055 Case HttpStatusCode.NotFound
2056 Return "Invalid query"
2057 Case HttpStatusCode.PaymentRequired 'API Documentには420と書いてあるが、該当コードがないので402にしてある
2058 Return "Search API Limit?"
2059 Case HttpStatusCode.OK
2061 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
2064 If Not TabInformations.GetInstance.ContainsTab(tab) Then Return ""
2065 content = Regex.Replace(content, "[\x00-\x1f-[\x0a\x0d]]+", " ")
2066 Dim xdoc As New XmlDocument
2068 xdoc.LoadXml(content)
2069 Catch ex As Exception
2070 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2071 Return "Invalid ATOM!"
2073 Dim nsmgr As New XmlNamespaceManager(xdoc.NameTable)
2074 nsmgr.AddNamespace("search", "http://www.w3.org/2005/Atom")
2075 nsmgr.AddNamespace("twitter", "http://api.twitter.com/")
2076 nsmgr.AddNamespace("georss", "http://www.georss.org/georss")
2077 For Each xentryNode As XmlNode In xdoc.DocumentElement.SelectNodes("/search:feed/search:entry", nsmgr)
2078 Dim xentry As XmlElement = CType(xentryNode, XmlElement)
2079 Dim post As New PostClass
2081 post.StatusId = Long.Parse(xentry.Item("id").InnerText.Split(":"c)(2))
2082 If TabInformations.GetInstance.ContainsKey(post.StatusId, tab.TabName) Then Continue For
2083 post.CreatedAt = DateTime.Parse(xentry.Item("published").InnerText)
2085 post.TextFromApi = xentry.Item("title").InnerText
2086 'Source取得(htmlの場合は、中身を取り出し)
2087 post.Source = xentry.Item("twitter:source").InnerText
2088 post.InReplyToStatusId = 0
2089 post.InReplyToUser = ""
2090 post.InReplyToUserId = 0
2093 ' Geoが勝手に付加されるバグがいっこうに修正されないので暫定的にGeo情報を無視する
2094 If xentry.Item("twitter:geo").HasChildNodes Then
2095 Dim pnt As String() = CType(xentry.SelectSingleNode("twitter:geo/georss:point", nsmgr), XmlElement).InnerText.Split(" "c)
2096 post.PostGeo = New PostClass.StatusGeo With {.Lat = Double.Parse(pnt(0)), .Lng = Double.Parse(pnt(1))}
2100 Dim xUentry As XmlElement = CType(xentry.SelectSingleNode("./search:author", nsmgr), XmlElement)
2102 post.ScreenName = xUentry.Item("name").InnerText.Split(" "c)(0).Trim
2103 post.Nickname = xUentry.Item("name").InnerText.Substring(post.ScreenName.Length).Trim
2104 If post.Nickname.Length > 2 Then
2105 post.Nickname = post.Nickname.Substring(1, post.Nickname.Length - 2)
2107 post.Nickname = post.ScreenName
2109 post.ImageUrl = CType(xentry.SelectSingleNode("./search:link[@type='image/png']", nsmgr), XmlElement).GetAttribute("href")
2110 post.IsProtect = False
2111 post.IsMe = post.ScreenName.ToLower.Equals(_uname)
2114 post.Text = CreateHtmlAnchor(HttpUtility.HtmlEncode(post.TextFromApi), post.ReplyToList, post.Media)
2115 post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
2120 post.IsReply = post.ReplyToList.Contains(_uname)
2121 post.IsExcludeReply = False
2124 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
2126 post.RelTabName = tab.TabName
2127 If Not more AndAlso post.StatusId > tab.SinceId Then tab.SinceId = post.StatusId
2128 Catch ex As Exception
2129 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2133 'Me._dIcon.Add(post.ImageUrl, Nothing)
2134 TabInformations.GetInstance.AddPost(post)
2139 '' 遡るための情報max_idやnext_pageの情報を保持する
2142 Dim xNode As XmlNode = xdoc.DocumentElement.SelectSingleNode("/search:feed/twitter:warning", nsmgr)
2144 If xNode IsNot Nothing Then
2145 Return "Warn:" + xNode.InnerText + "(" + GetCurrentMethod.Name + ")"
2152 Public Function GetPhoenixSearch(ByVal read As Boolean, _
2153 ByVal tab As TabClass, _
2154 ByVal more As Boolean) As String
2156 If _endingFlag Then Return ""
2158 Dim res As HttpStatusCode
2159 Dim content As String = ""
2160 Dim page As Integer = 0
2161 Dim sinceId As Long = 0
2162 Dim count As Integer = 100
2163 Dim querystr As String = ""
2164 If AppendSettingDialog.Instance.UseAdditionalCount AndAlso
2165 AppendSettingDialog.Instance.SearchCountApi <> 0 Then
2166 count = AppendSettingDialog.Instance.SearchCountApi
2169 page = tab.GetSearchPage(count)
2170 If Not String.IsNullOrEmpty(tab.NextPageQuery) Then
2171 querystr = tab.NextPageQuery
2174 sinceId = tab.SinceId
2178 If String.IsNullOrEmpty(querystr) Then
2179 res = twCon.PhoenixSearch(tab.SearchWords, tab.SearchLang, count, page, sinceId, content)
2181 res = twCon.PhoenixSearch(querystr, content)
2183 Catch ex As Exception
2184 Return "Err:" + ex.Message
2187 Case HttpStatusCode.BadRequest
2188 Return "Invalid query"
2189 Case HttpStatusCode.NotFound
2190 Return "Invalid query"
2191 Case HttpStatusCode.PaymentRequired 'API Documentには420と書いてあるが、該当コードがないので402にしてある
2192 Return "Search API Limit?"
2193 Case HttpStatusCode.OK
2195 Return "Err:" + res.ToString + "(" + GetCurrentMethod.Name + ")"
2198 If Not TabInformations.GetInstance.ContainsTab(tab) Then Return ""
2201 '' 遡るための情報max_idやnext_pageの情報を保持する
2203 Return CreatePostsFromPhoenixSearch(content, WORKERTYPE.PublicSearch, tab, read, count, tab.OldestId, tab.NextPageQuery)
2206 Private Function CreateDirectMessagesFromJson(ByVal content As String, ByVal gType As WORKERTYPE, ByVal read As Boolean) As String
2207 Dim item As List(Of TwitterDataModel.Directmessage)
2209 If gType = WORKERTYPE.UserStream Then
2210 Dim itm As List(Of TwitterDataModel.DirectmessageEvent) = CreateDataFromJson(Of List(Of TwitterDataModel.DirectmessageEvent))(content)
2211 item = New List(Of TwitterDataModel.Directmessage)
2212 For Each dat As TwitterDataModel.DirectmessageEvent In itm
2213 item.Add(dat.Directmessage)
2216 item = CreateDataFromJson(Of List(Of TwitterDataModel.Directmessage))(content)
2218 Catch ex As SerializationException
2219 TraceOut(ex.Message + Environment.NewLine + content)
2220 Return "Json Parse Error(DataContractJsonSerializer)"
2221 Catch ex As Exception
2222 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2223 Return "Invalid Json!"
2226 For Each message As TwitterDataModel.Directmessage In item
2227 Dim post As New PostClass
2229 post.StatusId = message.Id
2230 If gType <> WORKERTYPE.UserStream Then
2231 If gType = WORKERTYPE.DirectMessegeRcv Then
2232 If minDirectmessage > post.StatusId Then minDirectmessage = post.StatusId
2234 If minDirectmessageSent > post.StatusId Then minDirectmessageSent = post.StatusId
2240 If TabInformations.GetInstance.GetTabByType(TabUsageType.DirectMessage).Contains(post.StatusId) Then Continue For
2244 post.CreatedAt = DateTimeParse(message.CreatedAt)
2246 post.TextFromApi = message.Text
2248 post.Text = CreateHtmlAnchor(post.TextFromApi, post.ReplyToList, post.Media)
2249 post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
2250 post.TextFromApi = post.TextFromApi.Replace("<3", "♡")
2254 Dim user As TwitterDataModel.User
2255 If gType = WORKERTYPE.UserStream Then
2256 If twCon.AuthenticatedUsername.Equals(message.Recipient.ScreenName, StringComparison.CurrentCultureIgnoreCase) Then
2257 user = message.Sender
2261 user = message.Recipient
2266 If gType = WORKERTYPE.DirectMessegeRcv Then
2267 user = message.Sender
2271 user = message.Recipient
2277 post.UserId = user.Id
2278 post.ScreenName = user.ScreenName
2279 post.Nickname = user.Name.Trim()
2280 post.ImageUrl = user.ProfileImageUrl
2281 post.IsProtect = user.Protected
2282 Catch ex As Exception
2283 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2284 MessageBox.Show("Parse Error(CreateDirectMessagesFromJson)")
2289 If post.IsMe AndAlso Not read AndAlso _readOwnPost Then post.IsRead = True
2290 post.IsReply = False
2291 post.IsExcludeReply = False
2294 TabInformations.GetInstance.AddPost(post)
2301 Public Function GetDirectMessageApi(ByVal read As Boolean, _
2302 ByVal gType As WORKERTYPE, _
2303 ByVal more As Boolean) As String
2304 If _endingFlag Then Return ""
2306 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2307 If Not TwitterApiInfo.IsDirectMessagePermission Then Return "Auth Err:try to re-authorization."
2309 Dim res As HttpStatusCode
2310 Dim content As String = ""
2313 If gType = WORKERTYPE.DirectMessegeRcv Then
2315 res = twCon.DirectMessages(20, minDirectmessage, 0, content)
2317 res = twCon.DirectMessages(20, 0, 0, content)
2321 res = twCon.DirectMessagesSent(20, minDirectmessageSent, 0, content)
2323 res = twCon.DirectMessagesSent(20, 0, 0, content)
2326 Catch ex As Exception
2327 Return "Err:" + ex.Message
2331 Case HttpStatusCode.OK
2332 Twitter.AccountState = ACCOUNT_STATE.Valid
2333 Case HttpStatusCode.Unauthorized
2334 Twitter.AccountState = ACCOUNT_STATE.Invalid
2335 Return My.Resources.Unauthorized
2336 Case HttpStatusCode.BadRequest
2337 Return "Err:API Limits?"
2339 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2342 Return CreateDirectMessagesFromJson(content, gType, read)
2345 Public Function GetFavoritesApi(ByVal read As Boolean, _
2346 ByVal gType As WORKERTYPE) As String
2348 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2350 If _endingFlag Then Return ""
2352 Dim res As HttpStatusCode
2353 Dim content As String = ""
2354 Dim count As Integer = AppendSettingDialog.Instance.CountApi
2355 If AppendSettingDialog.Instance.UseAdditionalCount AndAlso
2356 AppendSettingDialog.Instance.FavoritesCountApi <> 0 Then
2357 count = AppendSettingDialog.Instance.FavoritesCountApi
2360 res = twCon.Favorites(count, content)
2361 Catch ex As Exception
2362 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2366 Case HttpStatusCode.OK
2367 Twitter.AccountState = ACCOUNT_STATE.Valid
2368 Case HttpStatusCode.Unauthorized
2369 Twitter.AccountState = ACCOUNT_STATE.Invalid
2370 Return My.Resources.Unauthorized
2371 Case HttpStatusCode.BadRequest
2372 Return "Err:API Limits?"
2374 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2377 Dim serializer As New DataContractJsonSerializer(GetType(List(Of TwitterDataModel.Status)))
2378 Dim item As List(Of TwitterDataModel.Status)
2381 item = CreateDataFromJson(Of List(Of TwitterDataModel.Status))(content)
2382 Catch ex As SerializationException
2383 TraceOut(ex.Message + Environment.NewLine + content)
2384 Return "Json Parse Error(DataContractJsonSerializer)"
2385 Catch ex As Exception
2386 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2387 Return "Invalid Json!"
2390 For Each status As TwitterDataModel.Status In item
2391 Dim post As New PostClass
2392 Dim entities As TwitterDataModel.Entities
2395 post.StatusId = status.Id
2398 If TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.StatusId) Then Continue For
2401 If status.RetweetedStatus IsNot Nothing Then
2402 Dim retweeted As TwitterDataModel.RetweetedStatus = status.RetweetedStatus
2403 post.CreatedAt = DateTimeParse(retweeted.CreatedAt)
2406 post.RetweetedId = post.StatusId
2408 post.TextFromApi = retweeted.Text
2409 entities = retweeted.Entities
2410 'Source取得(htmlの場合は、中身を取り出し)
2411 post.Source = retweeted.Source
2413 Long.TryParse(retweeted.InReplyToStatusId, post.InReplyToStatusId)
2414 post.InReplyToUser = retweeted.InReplyToScreenName
2415 Long.TryParse(retweeted.InReplyToUserId, post.InReplyToUserId)
2416 post.IsFav = retweeted.Favorited
2419 Dim user As TwitterDataModel.User = retweeted.User
2420 post.UserId = user.Id
2421 post.ScreenName = user.ScreenName
2422 post.Nickname = user.Name.Trim()
2423 post.ImageUrl = user.ProfileImageUrl
2424 post.IsProtect = user.Protected
2427 post.RetweetedBy = status.User.ScreenName
2428 post.IsMe = post.RetweetedBy.ToLower.Equals(_uname)
2430 post.CreatedAt = DateTimeParse(status.CreatedAt)
2433 post.TextFromApi = status.Text
2434 entities = status.Entities
2435 'Source取得(htmlの場合は、中身を取り出し)
2436 post.Source = status.Source
2437 Long.TryParse(status.InReplyToStatusId, post.InReplyToStatusId)
2438 post.InReplyToUser = status.InReplyToScreenName
2439 Long.TryParse(status.InReplyToUserId, post.InReplyToUserId)
2441 post.IsFav = status.Favorited
2444 Dim user As TwitterDataModel.User = status.User
2445 post.UserId = user.Id
2446 post.ScreenName = user.ScreenName
2447 post.Nickname = user.Name.Trim()
2448 post.ImageUrl = user.ProfileImageUrl
2449 post.IsProtect = user.Protected
2450 post.IsMe = post.ScreenName.ToLower.Equals(_uname)
2453 post.Text = CreateHtmlAnchor(post.TextFromApi, post.ReplyToList, entities, post.Media)
2454 post.TextFromApi = Me.ReplaceTextFromApi(post.TextFromApi, entities)
2455 post.TextFromApi = HttpUtility.HtmlDecode(post.TextFromApi)
2456 post.TextFromApi = post.TextFromApi.Replace("<3", "♡")
2461 post.IsReply = post.ReplyToList.Contains(_uname)
2462 post.IsExcludeReply = False
2467 If followerId.Count > 0 Then post.IsOwl = Not followerId.Contains(post.UserId)
2471 Catch ex As Exception
2472 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2476 TabInformations.GetInstance.AddPost(post)
2483 Private Function ReplaceTextFromApi(ByVal text As String, ByVal entities As TwitterDataModel.Entities) As String
2484 If entities IsNot Nothing Then
2485 If entities.Urls IsNot Nothing Then
2486 For Each m In entities.Urls
2487 If Not String.IsNullOrEmpty(m.DisplayUrl) Then text = text.Replace(m.Url, m.DisplayUrl)
2490 If entities.Media IsNot Nothing Then
2491 For Each m In entities.Media
2492 If Not String.IsNullOrEmpty(m.DisplayUrl) Then text = text.Replace(m.Url, m.DisplayUrl)
2499 Public Function GetFollowersApi() As String
2500 If _endingFlag Then Return ""
2501 Dim cursor As Long = -1
2502 Dim tmpFollower As New List(Of Long)(followerId)
2506 Dim ret As String = FollowerApi(cursor)
2507 If Not String.IsNullOrEmpty(ret) Then
2509 followerId.AddRange(tmpFollower)
2510 _GetFollowerResult = False
2513 Loop While cursor > 0
2515 TabInformations.GetInstance.RefreshOwl(followerId)
2517 _GetFollowerResult = True
2521 Public ReadOnly Property GetFollowersSuccess() As Boolean
2523 Return _GetFollowerResult
2527 Private Function FollowerApi(ByRef cursor As Long) As String
2528 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2530 Dim res As HttpStatusCode
2531 Dim content As String = ""
2533 res = twCon.FollowerIds(cursor, content)
2534 Catch ex As Exception
2535 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2539 Case HttpStatusCode.OK
2540 Twitter.AccountState = ACCOUNT_STATE.Valid
2541 Case HttpStatusCode.Unauthorized
2542 Twitter.AccountState = ACCOUNT_STATE.Invalid
2543 Return My.Resources.Unauthorized
2544 Case HttpStatusCode.BadRequest
2545 Return "Err:API Limits?"
2547 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2551 Dim followers = CreateDataFromJson(Of TwitterDataModel.Ids)(content)
2552 followerId.AddRange(followers.Id)
2553 cursor = followers.NextCursor
2555 Catch ex As SerializationException
2556 TraceOut(ex.Message + Environment.NewLine + content)
2557 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2558 Catch ex As Exception
2559 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2560 Return "Err:Invalid Json!"
2564 Public Function GetNoRetweetIdsApi() As String
2565 If _endingFlag Then Return ""
2566 Dim cursor As Long = -1
2567 Dim tmpIds As New List(Of Long)(noRTId)
2571 Dim ret As String = NoRetweetApi(cursor)
2572 If Not String.IsNullOrEmpty(ret) Then
2574 noRTId.AddRange(tmpIds)
2575 _GetNoRetweetResult = False
2578 Loop While cursor > 0
2580 _GetNoRetweetResult = True
2584 Private Function NoRetweetApi(ByRef cursor As Long) As String
2585 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2587 Dim res As HttpStatusCode
2588 Dim content As String = ""
2590 res = twCon.NoRetweetIds(cursor, content)
2591 Catch ex As Exception
2592 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2596 Case HttpStatusCode.OK
2597 Twitter.AccountState = ACCOUNT_STATE.Valid
2598 Case HttpStatusCode.Unauthorized
2599 Twitter.AccountState = ACCOUNT_STATE.Invalid
2600 Return My.Resources.Unauthorized
2601 Case HttpStatusCode.BadRequest
2602 Return "Err:API Limits?"
2604 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2608 Dim ids = CreateDataFromJson(Of Long())(content)
2609 noRTId.AddRange(ids)
2610 cursor = 0 '0より小さければ何でも良い。
2612 Catch ex As SerializationException
2613 TraceOut(ex.Message + Environment.NewLine + content)
2614 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2615 Catch ex As Exception
2616 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2617 Return "Err:Invalid Json!"
2621 Public ReadOnly Property GetNoRetweetSuccess() As Boolean
2623 Return _GetNoRetweetResult
2627 Public Function ConfigurationApi() As String
2628 Dim res As HttpStatusCode
2629 Dim content As String = ""
2631 res = twCon.GetConfiguration(content)
2632 Catch ex As Exception
2633 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2637 Case HttpStatusCode.OK
2638 Twitter.AccountState = ACCOUNT_STATE.Valid
2639 Case HttpStatusCode.Unauthorized
2640 Twitter.AccountState = ACCOUNT_STATE.Invalid
2641 Return My.Resources.Unauthorized
2642 Case HttpStatusCode.BadRequest
2643 Return "Err:API Limits?"
2645 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2649 AppendSettingDialog.Instance.TwitterConfiguration = CreateDataFromJson(Of TwitterDataModel.Configuration)(content)
2651 Catch ex As SerializationException
2652 TraceOut(ex.Message + Environment.NewLine + content)
2653 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2654 Catch ex As Exception
2655 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2656 Return "Err:Invalid Json!"
2660 Public Function GetListsApi() As String
2661 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2663 Dim res As HttpStatusCode
2664 Dim content As String = ""
2665 Dim cursor As Long = -1
2667 Dim lists As New List(Of ListElement)
2670 res = twCon.GetLists(Me.Username, cursor, content)
2671 Catch ex As Exception
2672 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2676 Case HttpStatusCode.OK
2677 Twitter.AccountState = ACCOUNT_STATE.Valid
2678 Case HttpStatusCode.Unauthorized
2679 Twitter.AccountState = ACCOUNT_STATE.Invalid
2680 Return My.Resources.Unauthorized
2681 Case HttpStatusCode.BadRequest
2682 Return "Err:API Limits?"
2684 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2688 Dim lst = CreateDataFromJson(Of TwitterDataModel.Lists)(content)
2689 lists.AddRange(From le In lst.Lists Select New ListElement(le, Me))
2690 cursor = lst.NextCursor
2691 Catch ex As SerializationException
2692 TraceOut(ex.Message + Environment.NewLine + content)
2693 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2694 Catch ex As Exception
2695 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2696 Return "Err:Invalid Json!"
2698 Loop While cursor <> 0
2704 res = twCon.GetListsSubscriptions(Me.Username, cursor, content)
2705 Catch ex As Exception
2706 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2710 Case HttpStatusCode.OK
2711 Twitter.AccountState = ACCOUNT_STATE.Valid
2712 Case HttpStatusCode.Unauthorized
2713 Twitter.AccountState = ACCOUNT_STATE.Invalid
2714 Return My.Resources.Unauthorized
2715 Case HttpStatusCode.BadRequest
2716 Return "Err:API Limits?"
2718 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2722 Dim lst = CreateDataFromJson(Of TwitterDataModel.Lists)(content)
2723 lists.AddRange(From le In lst.Lists Select New ListElement(le, Me))
2724 cursor = lst.NextCursor
2725 Catch ex As SerializationException
2726 TraceOut(ex.Message + Environment.NewLine + content)
2727 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2728 Catch ex As Exception
2729 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2730 Return "Err:Invalid Json!"
2732 Loop While cursor <> 0
2734 TabInformations.GetInstance.SubscribableLists = lists
2738 Public Function DeleteList(ByVal list_id As String) As String
2739 Dim res As HttpStatusCode
2740 Dim content As String = ""
2742 Google.GASender.GetInstance().TrackEventWithCategory("post", "destroy_list", Me.UserId)
2744 res = twCon.DeleteListID(Me.Username, list_id, content)
2745 Catch ex As Exception
2746 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2750 Case HttpStatusCode.OK
2751 Twitter.AccountState = ACCOUNT_STATE.Valid
2752 Case HttpStatusCode.Unauthorized
2753 Twitter.AccountState = ACCOUNT_STATE.Invalid
2754 Return My.Resources.Unauthorized
2755 Case HttpStatusCode.BadRequest
2756 Return "Err:API Limits?"
2758 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2764 Public Function EditList(ByVal list_id As String, ByVal new_name As String, ByVal isPrivate As Boolean, ByVal description As String, ByRef list As ListElement) As String
2765 Google.GASender.GetInstance().TrackEventWithCategory("get", "update_list", Me.UserId)
2766 Dim res As HttpStatusCode
2767 Dim content As String = ""
2770 res = twCon.UpdateListID(Me.Username, list_id, new_name, isPrivate, description, content)
2771 Catch ex As Exception
2772 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2776 Case HttpStatusCode.OK
2777 Twitter.AccountState = ACCOUNT_STATE.Valid
2778 Case HttpStatusCode.Unauthorized
2779 Twitter.AccountState = ACCOUNT_STATE.Invalid
2780 Return My.Resources.Unauthorized
2781 Case HttpStatusCode.BadRequest
2782 Return "Err:API Limits?"
2784 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2788 Dim le = CreateDataFromJson(Of TwitterDataModel.ListElementData)(content)
2789 Dim newList As New ListElement(le, Me)
2790 list.Description = newList.Description
2791 list.Id = newList.Id
2792 list.IsPublic = newList.IsPublic
2793 list.MemberCount = newList.MemberCount
2794 list.Name = newList.Name
2795 list.SubscriberCount = newList.SubscriberCount
2796 list.Slug = newList.Slug
2797 list.Nickname = newList.Nickname
2798 list.Username = newList.Username
2799 list.UserId = newList.UserId
2801 Catch ex As SerializationException
2802 TraceOut(ex.Message + Environment.NewLine + content)
2803 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2804 Catch ex As Exception
2805 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2806 Return "Err:Invalid Json!"
2811 Public Function GetListMembers(ByVal list_id As String, ByVal lists As List(Of UserInfo), ByRef cursor As Long) As String
2812 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2814 Dim res As HttpStatusCode
2815 Dim content As String = ""
2819 res = twCon.GetListMembers(Me.Username, list_id, cursor, content)
2820 Catch ex As Exception
2821 Return "Err:" + ex.Message
2825 Case HttpStatusCode.OK
2826 Twitter.AccountState = ACCOUNT_STATE.Valid
2827 Case HttpStatusCode.Unauthorized
2828 Twitter.AccountState = ACCOUNT_STATE.Invalid
2829 Return My.Resources.Unauthorized
2830 Case HttpStatusCode.BadRequest
2831 Return "Err:API Limits?"
2833 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2837 Dim users = CreateDataFromJson(Of TwitterDataModel.Users)(content)
2838 Array.ForEach(Of TwitterDataModel.User)(
2840 New Action(Of TwitterDataModel.User)(Sub(u)
2841 lists.Add(New UserInfo(u))
2843 cursor = users.NextCursor
2845 Catch ex As SerializationException
2846 TraceOut(ex.Message + Environment.NewLine + content)
2847 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2848 Catch ex As Exception
2849 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2850 Return "Err:Invalid Json!"
2856 Public Function CreateListApi(ByVal listName As String, ByVal isPrivate As Boolean, ByVal description As String) As String
2857 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2859 Google.GASender.GetInstance().TrackEventWithCategory("post", "create_list", Me.UserId)
2860 Dim res As HttpStatusCode
2861 Dim content As String = ""
2864 res = twCon.CreateLists(listName, isPrivate, description, content)
2865 Catch ex As Exception
2866 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2870 Case HttpStatusCode.OK
2871 Twitter.AccountState = ACCOUNT_STATE.Valid
2872 Case HttpStatusCode.Unauthorized
2873 Twitter.AccountState = ACCOUNT_STATE.Invalid
2874 Return My.Resources.Unauthorized
2875 Case HttpStatusCode.BadRequest
2876 Return "Err:API Limits?"
2878 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2882 Dim le = CreateDataFromJson(Of TwitterDataModel.ListElementData)(content)
2883 TabInformations.GetInstance().SubscribableLists.Add(New ListElement(le, Me))
2885 Catch ex As SerializationException
2886 TraceOut(ex.Message + Environment.NewLine + content)
2887 Return "Err:Json Parse Error(DataContractJsonSerializer)"
2888 Catch ex As Exception
2889 TraceOut(ex, GetCurrentMethod.Name & " " & content)
2890 Return "Err:Invalid Json!"
2894 Public Function ContainsUserAtList(ByVal listId As String, ByVal user As String, ByRef value As Boolean) As String
2897 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
2899 Dim res As HttpStatusCode
2900 Dim content As String = ""
2903 res = Me.twCon.ShowListMember(listId, user, content)
2904 Catch ex As Exception
2905 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2909 Case HttpStatusCode.OK
2910 Twitter.AccountState = ACCOUNT_STATE.Valid
2911 Case HttpStatusCode.Unauthorized
2912 Twitter.AccountState = ACCOUNT_STATE.Invalid
2913 Return My.Resources.Unauthorized
2914 Case HttpStatusCode.BadRequest
2915 Return "Err:API Limits?"
2916 Case HttpStatusCode.NotFound
2920 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2924 Dim u = CreateDataFromJson(Of TwitterDataModel.User)(content)
2927 Catch ex As Exception
2933 Public Function AddUserToList(ByVal listId As String, ByVal user As String) As String
2934 Dim content As String = ""
2935 Dim res As HttpStatusCode
2937 Google.GASender.GetInstance().TrackEventWithCategory("post", "add_user_to_list", Me.UserId)
2939 res = twCon.CreateListMembers(listId, user, content)
2940 Catch ex As Exception
2941 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2945 Case HttpStatusCode.OK
2946 Twitter.AccountState = ACCOUNT_STATE.Valid
2947 Case HttpStatusCode.Unauthorized
2948 Twitter.AccountState = ACCOUNT_STATE.Invalid
2949 Return My.Resources.Unauthorized
2950 Case HttpStatusCode.BadRequest
2951 Return "Err:" + GetErrorMessageJson(content)
2953 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2959 Public Function RemoveUserToList(ByVal listId As String, ByVal user As String) As String
2960 Google.GASender.GetInstance().TrackEventWithCategory("post", "remove_user_from_list", Me.UserId)
2962 Dim content As String = ""
2963 Dim res As HttpStatusCode
2966 res = twCon.DeleteListMembers(listId, user, content)
2967 Catch ex As Exception
2968 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
2972 Case HttpStatusCode.OK
2973 Twitter.AccountState = ACCOUNT_STATE.Valid
2974 Case HttpStatusCode.Unauthorized
2975 Twitter.AccountState = ACCOUNT_STATE.Invalid
2976 Return My.Resources.Unauthorized
2977 Case HttpStatusCode.BadRequest
2978 Return "Err:" + GetErrorMessageJson(content)
2980 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
2987 Public Property fromIndex As Integer
2988 Public Property toIndex As Integer
2989 Public Sub New(ByVal fromIndex As Integer, ByVal toIndex As Integer)
2990 Me.fromIndex = fromIndex
2991 Me.toIndex = toIndex
2994 Public Function CreateHtmlAnchor(ByVal Text As String, ByVal AtList As List(Of String), ByVal media As Dictionary(Of String, String)) As String
2995 If Text Is Nothing Then Return Nothing
2996 Dim retStr As String = Text.Replace(">", "<<<<<tweenだいなり>>>>>").Replace("<", "<<<<<tweenしょうなり>>>>>")
2998 'Const url_valid_domain As String = "(?<domain>(?:[^\p{P}\s][\.\-_](?=[^\p{P}\s])|[^\p{P}\s]){1,}\.[a-z]{2,}(?::[0-9]+)?)"
2999 'Const url_valid_general_path_chars As String = "[a-z0-9!*';:=+$/%#\[\]\-_,~]"
3000 'Const url_balance_parens As String = "(?:\(" + url_valid_general_path_chars + "+\))"
3001 'Const url_valid_url_path_ending_chars As String = "(?:[a-z0-9=_#/\-\+]+|" + url_balance_parens + ")"
3002 'Const pth As String = "(?:" + url_balance_parens +
3003 ' "|@" + url_valid_general_path_chars + "+/" +
3004 ' "|[.,]?" + url_valid_general_path_chars + "+" +
3006 'Const pth2 As String = "(/(?:" +
3007 ' pth + "+" + url_valid_url_path_ending_chars + "|" +
3008 ' pth + "+" + url_valid_url_path_ending_chars + "?|" +
3009 ' url_valid_url_path_ending_chars +
3011 'Const qry As String = "(?<query>\?[a-z0-9!*'();:&=+$/%#\[\]\-_.,~]*[a-z0-9_&=#])?"
3012 'Const rgUrl As String = "(?<before>(?:[^\""':!=#]|^|\:/))" +
3013 ' "(?<url>(?<protocol>https?://)" +
3014 ' url_valid_domain +
3018 'Const rgUrl As String = "(?<before>(?:[^\""':!=#]|^|\:/))" +
3019 ' "(?<url>(?<protocol>https?://|www\.)" +
3020 ' url_valid_domain +
3025 retStr = Regex.Replace(retStr,
3027 New MatchEvaluator(Function(mu As Match)
3028 Dim sb As New StringBuilder(mu.Result("${before}<a href="""))
3029 'If mu.Result("${protocol}").StartsWith("w", StringComparison.OrdinalIgnoreCase) Then
3030 ' sb.Append("http://")
3032 Dim url As String = mu.Result("${url}")
3033 Dim title As String = ShortUrl.ResolveMedia(url, True)
3034 If url <> title Then
3035 title = ShortUrl.ResolveMedia(title, False)
3037 sb.Append(url + """ title=""" + title + """>").Append(url).Append("</a>")
3038 If media IsNot Nothing AndAlso Not media.ContainsKey(url) Then media.Add(url, title)
3041 RegexOptions.IgnoreCase)
3044 retStr = Regex.Replace(retStr,
3045 "(^|[^a-zA-Z0-9_/])([@@]+)([a-zA-Z0-9_]{1,20}/[a-zA-Z][a-zA-Z0-9\p{IsLatin-1Supplement}\-]{0,79})",
3046 "$1$2<a href=""/$3"">$3</a>")
3048 Dim m As Match = Regex.Match(retStr, "(^|[^a-zA-Z0-9_])[@@]([a-zA-Z0-9_]{1,20})")
3050 If Not AtList.Contains(m.Result("$2").ToLower) Then AtList.Add(m.Result("$2").ToLower)
3054 retStr = Regex.Replace(retStr,
3055 "(^|[^a-zA-Z0-9_/])([@@])([a-zA-Z0-9_]{1,20})",
3056 "$1$2<a href=""/$3"">$3</a>")
3059 Dim anchorRange As New List(Of range)
3060 For i As Integer = 0 To retStr.Length - 1
3061 Dim index As Integer = retStr.IndexOf("<a ", i)
3062 If index > -1 AndAlso index < retStr.Length Then
3064 Dim toIndex As Integer = retStr.IndexOf("</a>", index)
3065 If toIndex > -1 Then
3066 anchorRange.Add(New range(index, toIndex + 3))
3071 'retStr = Regex.Replace(retStr,
3072 ' "(^|[^a-zA-Z0-9/&])([##])([0-9a-zA-Z_]*[a-zA-Z_]+[a-zA-Z0-9_\xc0-\xd6\xd8-\xf6\xf8-\xff]*)",
3073 ' New MatchEvaluator(Function(mh As Match)
3074 ' For Each rng As range In anchorRange
3075 ' If mh.Index >= rng.fromIndex AndAlso
3076 ' mh.Index <= rng.toIndex Then Return mh.Result("$0")
3078 ' If IsNumeric(mh.Result("$3")) Then Return mh.Result("$0")
3080 ' _hashList.Add("#" + mh.Result("$3"))
3082 ' Return mh.Result("$1") + "<a href=""" & _protocol & "twitter.com/search?q=%23" + mh.Result("$3") + """>" + mh.Result("$2$3") + "</a>"
3084 ' RegexOptions.IgnoreCase)
3085 retStr = Regex.Replace(retStr,
3087 New MatchEvaluator(Function(mh As Match)
3088 For Each rng As range In anchorRange
3089 If mh.Index >= rng.fromIndex AndAlso
3090 mh.Index <= rng.toIndex Then Return mh.Result("$0")
3093 _hashList.Add("#" + mh.Result("$3"))
3095 Return mh.Result("$1") + "<a href=""" & _protocol & "twitter.com/search?q=%23" + mh.Result("$3") + """>" + mh.Result("$2$3") + "</a>"
3097 RegexOptions.IgnoreCase)
3100 retStr = Regex.Replace(retStr, "(^|[^a-zA-Z0-9_/&##@@>=.])(sm|nm)([0-9]{1,10})", "$1<a href=""http://www.nicovideo.jp/watch/$2$3"">$2$3</a>")
3102 retStr = retStr.Replace("<<<<<tweenだいなり>>>>>", ">").Replace("<<<<<tweenしょうなり>>>>>", "<")
3104 'retStr = AdjustHtml(ShortUrl.Resolve(PreProcessUrl(retStr), True)) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
3105 retStr = AdjustHtml(PreProcessUrl(retStr)) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
3109 Private Class EntityInfo
3110 Public Property StartIndex As Integer
3111 Public Property EndIndex As Integer
3112 Public Property Text As String
3113 Public Property Html As String
3114 Public Property Display As String
3116 Public Function CreateHtmlAnchor(ByRef Text As String, ByVal AtList As List(Of String), ByVal entities As TwitterDataModel.Entities, ByVal media As Dictionary(Of String, String)) As String
3117 Dim ret As String = Text
3119 If entities IsNot Nothing Then
3120 Dim etInfo As New SortedList(Of Integer, EntityInfo)
3122 If entities.Urls IsNot Nothing Then
3123 For Each ent In entities.Urls
3124 If String.IsNullOrEmpty(ent.DisplayUrl) Then
3125 etInfo.Add(ent.Indices(0),
3126 New EntityInfo With {.StartIndex = ent.Indices(0),
3127 .EndIndex = ent.Indices(1),
3129 .Html = "<a href=""" + ent.Url + """>" + ent.Url + "</a>"})
3131 Dim expanded As String = ShortUrl.ResolveMedia(ent.ExpandedUrl, False)
3132 etInfo.Add(ent.Indices(0),
3133 New EntityInfo With {.StartIndex = ent.Indices(0),
3134 .EndIndex = ent.Indices(1),
3136 .Html = "<a href=""" + ent.Url + """ title=""" + expanded + """>" + ent.DisplayUrl + "</a>",
3137 .Display = ent.DisplayUrl})
3138 If media IsNot Nothing AndAlso Not media.ContainsKey(ent.Url) Then media.Add(ent.Url, expanded)
3142 If entities.Hashtags IsNot Nothing Then
3143 For Each ent In entities.Hashtags
3144 Dim hash As String = Text.Substring(ent.Indices(0), ent.Indices(1) - ent.Indices(0))
3145 etInfo.Add(ent.Indices(0),
3146 New EntityInfo With {.StartIndex = ent.Indices(0),
3147 .EndIndex = ent.Indices(1),
3149 .Html = "<a href=""" & _protocol & "twitter.com/search?q=%23" + ent.Text + """>" + hash + "</a>"})
3151 _hashList.Add("#" + ent.Text)
3155 If entities.UserMentions IsNot Nothing Then
3156 For Each ent In entities.UserMentions
3157 Dim screenName As String = Text.Substring(ent.Indices(0) + 1, ent.Indices(1) - ent.Indices(0) - 1)
3158 etInfo.Add(ent.Indices(0) + 1,
3159 New EntityInfo With {.StartIndex = ent.Indices(0) + 1,
3160 .EndIndex = ent.Indices(1),
3161 .Text = ent.ScreenName,
3162 .Html = "<a href=""/" + ent.ScreenName + """>" + screenName + "</a>"})
3163 If Not AtList.Contains(ent.ScreenName.ToLower) Then AtList.Add(ent.ScreenName.ToLower)
3166 If entities.Media IsNot Nothing Then
3167 For Each ent In entities.Media
3168 If ent.Type = "photo" Then
3169 etInfo.Add(ent.Indices(0),
3170 New EntityInfo With {.StartIndex = ent.Indices(0),
3171 .EndIndex = ent.Indices(1),
3173 .Html = "<a href=""" + ent.Url + """ title=""" + ent.ExpandedUrl + """>" + ent.DisplayUrl + "</a>",
3174 .Display = ent.DisplayUrl})
3175 If media IsNot Nothing AndAlso Not media.ContainsKey(ent.Url) Then media.Add(ent.Url, ent.MediaUrl)
3179 If etInfo.Count > 0 Then
3180 Dim idx As Integer = 0
3182 For Each et In etInfo
3183 ret += Text.Substring(idx, et.Key - idx) + et.Value.Html
3184 idx = et.Value.EndIndex
3186 ret += Text.Substring(idx)
3190 ret = Regex.Replace(ret, "(^|[^a-zA-Z0-9_/&##@@>=.])(sm|nm)([0-9]{1,10})", "$1<a href=""http://www.nicovideo.jp/watch/$2$3"">$2$3</a>")
3191 ret = AdjustHtml(ShortUrl.Resolve(PreProcessUrl(ret), False)) 'IDN置換、短縮Uri解決、@リンクを相対→絶対にしてtarget属性付与
3197 Private Sub CreateSource(ByRef post As PostClass)
3198 If post.Source.StartsWith("<") Then
3199 If Not post.Source.Contains("</a>") Then
3200 post.Source += "</a>"
3202 Dim mS As Match = Regex.Match(post.Source, ">(?<source>.+)<")
3204 post.SourceHtml = String.Copy(ShortUrl.Resolve(PreProcessUrl(post.Source), False))
3205 post.Source = HttpUtility.HtmlDecode(mS.Result("${source}"))
3208 post.SourceHtml = ""
3211 If post.Source = "web" Then
3212 post.SourceHtml = My.Resources.WebSourceString
3213 ElseIf post.Source = "Keitai Mail" Then
3214 post.SourceHtml = My.Resources.KeitaiMailSourceString
3216 post.SourceHtml = String.Copy(post.Source)
3221 Public Function GetInfoApi(ByVal info As ApiInfo) As Boolean
3222 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return True
3224 If _endingFlag Then Return True
3226 Dim res As HttpStatusCode
3227 Dim content As String = ""
3229 res = twCon.RateLimitStatus(content)
3230 Catch ex As Exception
3231 TwitterApiInfo.Initialize()
3235 If res <> HttpStatusCode.OK Then Return False
3238 Dim limit = CreateDataFromJson(Of TwitterDataModel.RateLimitStatus)(content)
3239 Dim arg As New ApiInformationChangedEventArgs
3240 arg.ApiInfo.MaxCount = limit.HourlyLimit
3241 arg.ApiInfo.RemainCount = limit.RemainingHits
3242 arg.ApiInfo.ResetTime = DateTimeParse(limit.RestTime)
3243 arg.ApiInfo.ResetTimeInSeconds = limit.RestTimeInSeconds
3244 If info IsNot Nothing Then
3245 arg.ApiInfo.UsingCount = info.UsingCount
3247 info.MaxCount = arg.ApiInfo.MaxCount
3248 info.RemainCount = arg.ApiInfo.RemainCount
3249 info.ResetTime = arg.ApiInfo.ResetTime
3250 info.ResetTimeInSeconds = arg.ApiInfo.ResetTimeInSeconds
3253 RaiseEvent ApiInformationChanged(Me, arg)
3254 TwitterApiInfo.WriteBackEventArgs(arg)
3256 Catch ex As Exception
3257 TraceOut(ex, GetCurrentMethod.Name & " " & content)
3258 TwitterApiInfo.Initialize()
3262 Public Function GetBlockUserIds() As String
3263 If Twitter.AccountState <> ACCOUNT_STATE.Valid Then Return ""
3265 Dim res As HttpStatusCode
3266 Dim content As String = ""
3269 res = twCon.GetBlockUserIds(content)
3270 Catch ex As Exception
3271 Return "Err:" + ex.Message + "(" + GetCurrentMethod.Name + ")"
3275 Case HttpStatusCode.OK
3276 Twitter.AccountState = ACCOUNT_STATE.Valid
3277 Case HttpStatusCode.Unauthorized
3278 Twitter.AccountState = ACCOUNT_STATE.Invalid
3279 Return My.Resources.Unauthorized
3280 Case HttpStatusCode.BadRequest
3281 Return "Err:API Limits?"
3283 Return "Err:" + res.ToString() + "(" + GetCurrentMethod.Name + ")"
3287 Dim Ids = CreateDataFromJson(Of Long())(content)
3288 TabInformations.GetInstance.BlockIds.AddRange(Ids)
3290 Catch ex As SerializationException
3291 TraceOut(ex.Message + Environment.NewLine + content)
3292 Return "Err:Json Parse Error(DataContractJsonSerializer)"
3293 Catch ex As Exception
3294 TraceOut(ex, GetCurrentMethod.Name & " " & content)
3295 Return "Err:Invalid Json!"
3300 Public Function GetHashList() As String()
3301 Dim hashArray As String()
3303 hashArray = _hashList.ToArray
3309 Public ReadOnly Property AccessToken() As String
3311 Return twCon.AccessToken
3315 Public ReadOnly Property AccessTokenSecret() As String
3317 Return twCon.AccessTokenSecret
3321 Public Event ApiInformationChanged(ByVal sender As Object, ByVal e As ApiInformationChangedEventArgs)
3323 Private Sub Twitter_ApiInformationChanged(ByVal sender As Object, ByVal e As ApiInformationChangedEventArgs) Handles Me.ApiInformationChanged
3326 #Region "UserStream"
3327 Public Property TrackWord As String = ""
3328 Public Property AllAtReply As Boolean = False
3330 Public Event NewPostFromStream()
3331 Public Event UserStreamStarted()
3332 Public Event UserStreamStopped()
3333 Public Event UserStreamGetFriendsList()
3334 Public Event PostDeleted(ByVal id As Long)
3335 Public Event UserStreamEventReceived(ByVal eventType As FormattedEvent)
3336 Private _lastUserstreamDataReceived As DateTime
3337 Private WithEvents userStream As TwitterUserstream
3339 Public Class FormattedEvent
3340 Public Property Eventtype As EVENTTYPE
3341 Public Property CreatedAt As DateTime
3342 Public Property [Event] As String
3343 Public Property Username As String
3344 Public Property Target As String
3345 Public Property Id As Int64
3346 Public Property IsMe As Boolean
3349 Public Property StoredEvent As New List(Of FormattedEvent)
3351 Private Class EventTypeTableElement
3352 Public Name As String
3353 Public Type As EVENTTYPE
3355 Public Sub New(ByVal name As String, ByVal type As EVENTTYPE)
3361 Private EventTable As EventTypeTableElement() = {
3362 New EventTypeTableElement("favorite", EVENTTYPE.Favorite), _
3363 New EventTypeTableElement("unfavorite", EVENTTYPE.Unfavorite), _
3364 New EventTypeTableElement("follow", EVENTTYPE.Follow), _
3365 New EventTypeTableElement("list_member_added", EVENTTYPE.ListMemberAdded), _
3366 New EventTypeTableElement("list_member_removed", EVENTTYPE.ListMemberRemoved), _
3367 New EventTypeTableElement("block", EVENTTYPE.Block), _
3368 New EventTypeTableElement("unblock", EVENTTYPE.Unblock), _
3369 New EventTypeTableElement("user_update", EVENTTYPE.UserUpdate), _
3370 New EventTypeTableElement("deleted", EVENTTYPE.Deleted), _
3371 New EventTypeTableElement("list_created", EVENTTYPE.ListCreated), _
3372 New EventTypeTableElement("list_updated", EVENTTYPE.ListUpdated)
3375 Public Function EventNameToEventType(ByVal EventName As String) As EVENTTYPE
3376 Return (From tbl In EventTable Where tbl.Name.Equals(EventName) Select tbl.Type).FirstOrDefault()
3379 Public ReadOnly Property IsUserstreamDataReceived As Boolean
3381 Return Now.Subtract(Me._lastUserstreamDataReceived).TotalSeconds < 31
3385 Private Sub userStream_StatusArrived(ByVal line As String) Handles userStream.StatusArrived
3386 Me._lastUserstreamDataReceived = Now
3387 If String.IsNullOrEmpty(line) Then Exit Sub
3389 Dim isDm As Boolean = False
3392 Using jsonReader As XmlDictionaryReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(line), XmlDictionaryReaderQuotas.Max)
3393 Dim xElm As XElement = XElement.Load(jsonReader)
3394 If xElm.Element("friends") IsNot Nothing Then
3395 Debug.Print("friends")
3397 ElseIf xElm.Element("delete") IsNot Nothing Then
3398 Debug.Print("delete")
3400 If xElm.Element("delete").Element("direct_message") IsNot Nothing AndAlso
3401 xElm.Element("delete").Element("direct_message").Element("id") IsNot Nothing Then
3402 id = CLng(xElm.Element("delete").Element("direct_message").Element("id").Value)
3403 RaiseEvent PostDeleted(id)
3404 ElseIf xElm.Element("delete").Element("status") IsNot Nothing AndAlso
3405 xElm.Element("delete").Element("status").Element("id") IsNot Nothing Then
3406 id = CLng(xElm.Element("delete").Element("status").Element("id").Value)
3407 RaiseEvent PostDeleted(id)
3409 TraceOut("delete:" + line)
3412 For i As Integer = Me.StoredEvent.Count - 1 To 0 Step -1
3413 Dim sEvt As FormattedEvent = Me.StoredEvent(i)
3414 If sEvt.Id = id AndAlso (sEvt.Event = "favorite" OrElse sEvt.Event = "unfavorite") Then
3415 Me.StoredEvent.RemoveAt(i)
3419 ElseIf xElm.Element("limit") IsNot Nothing Then
3422 ElseIf xElm.Element("event") IsNot Nothing Then
3423 Debug.Print("event: " + xElm.Element("event").Value)
3424 CreateEventFromJson(line)
3426 ElseIf xElm.Element("direct_message") IsNot Nothing Then
3427 Debug.Print("direct_message")
3429 ElseIf xElm.Element("scrub_geo") IsNot Nothing Then
3431 TabInformations.GetInstance.ScrubGeoReserve(Long.Parse(xElm.Element("scrub_geo").Element("user_id").Value),
3432 Long.Parse(xElm.Element("scrub_geo").Element("up_to_status_id").Value))
3433 Catch ex As Exception
3434 TraceOut("scrub_geo:" + line)
3440 Dim res As New StringBuilder
3447 CreateDirectMessagesFromJson(res.ToString, WORKERTYPE.UserStream, False)
3449 CreatePostsFromJson(res.ToString, WORKERTYPE.Timeline, Nothing, False, Nothing, Nothing)
3451 Catch ex As NullReferenceException
3452 TraceOut("NullRef StatusArrived: " + line)
3455 RaiseEvent NewPostFromStream()
3458 Private Sub CreateEventFromJson(ByVal content As String)
3459 Dim eventData As TwitterDataModel.EventData = Nothing
3461 eventData = CreateDataFromJson(Of TwitterDataModel.EventData)(content)
3462 Catch ex As SerializationException
3463 TraceOut(ex, "Event Serialize Exception!" + Environment.NewLine + content)
3464 Catch ex As Exception
3465 TraceOut(ex, "Event Exception!" + Environment.NewLine + content)
3468 Dim evt As New FormattedEvent
3469 evt.CreatedAt = DateTimeParse(eventData.CreatedAt)
3470 evt.Event = eventData.Event
3471 evt.Username = eventData.Source.ScreenName
3472 evt.IsMe = evt.Username.ToLower().Equals(Me.Username.ToLower())
3473 evt.Eventtype = EventNameToEventType(evt.Event)
3474 Select Case eventData.Event
3476 If eventData.Target.ScreenName.ToLower.Equals(_uname) Then
3477 If Not Me.followerId.Contains(eventData.Source.Id) Then Me.followerId.Add(eventData.Source.Id)
3479 Exit Sub 'Block後のUndoをすると、SourceとTargetが逆転したfollowイベントが帰ってくるため。
3482 Case "favorite", "unfavorite"
3483 evt.Target = "@" + eventData.TargetObject.User.ScreenName + ":" + HttpUtility.HtmlDecode(eventData.TargetObject.Text)
3484 evt.Id = eventData.TargetObject.Id
3485 If TabInformations.GetInstance.ContainsKey(eventData.TargetObject.Id) Then
3486 Dim post As PostClass = TabInformations.GetInstance.Item(eventData.TargetObject.Id)
3487 If eventData.Event = "favorite" Then
3488 If evt.Username.ToLower.Equals(_uname) Then
3490 TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Add(post.StatusId, post.IsRead, False)
3492 post.FavoritedCount += 1
3493 If Not TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Contains(post.StatusId) Then
3494 If TweenMain.GetInstance().FavEventChangeUnread AndAlso post.IsRead Then
3497 TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).Add(post.StatusId, post.IsRead, False)
3499 If TweenMain.GetInstance().FavEventChangeUnread Then
3500 TabInformations.GetInstance.SetRead(False, TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).TabName, TabInformations.GetInstance.GetTabByType(TabUsageType.Favorites).IndexOf(post.StatusId))
3505 If evt.Username.ToLower.Equals(_uname) Then
3508 post.FavoritedCount -= 1
3509 If post.FavoritedCount < 0 Then post.FavoritedCount = 0
3513 Case "list_member_added", "list_member_removed", "list_updated"
3514 evt.Target = eventData.TargetObject.FullName
3516 If Not TabInformations.GetInstance.BlockIds.Contains(eventData.Target.Id) Then TabInformations.GetInstance.BlockIds.Add(eventData.Target.Id)
3519 If TabInformations.GetInstance.BlockIds.Contains(eventData.Target.Id) Then TabInformations.GetInstance.BlockIds.Remove(eventData.Target.Id)
3526 TraceOut("Unknown Event:" + evt.Event + Environment.NewLine + content)
3528 Me.StoredEvent.Insert(0, evt)
3529 RaiseEvent UserStreamEventReceived(evt)
3532 Private Sub userStream_Started() Handles userStream.Started
3533 Google.GASender.GetInstance().TrackPage("/userstream", Me.UserId)
3534 RaiseEvent UserStreamStarted()
3537 Private Sub userStream_Stopped() Handles userStream.Stopped
3538 RaiseEvent UserStreamStopped()
3541 Public ReadOnly Property UserStreamEnabled As Boolean
3543 Return If(userStream Is Nothing, False, userStream.Enabled)
3547 Public Sub StartUserStream()
3548 If userStream IsNot Nothing Then
3551 userStream = New TwitterUserstream(twCon)
3552 userStream.Start(Me.AllAtReply, Me.TrackWord)
3555 Public Sub StopUserStream()
3556 If userStream IsNot Nothing Then userStream.Dispose()
3557 userStream = Nothing
3558 If Not _endingFlag Then RaiseEvent UserStreamStopped()
3561 Public Sub ReconnectUserStream()
3562 If userStream IsNot Nothing Then
3563 Me.StartUserStream()
3567 Private Class TwitterUserstream
3568 Implements IDisposable
3570 Public Event StatusArrived(ByVal status As String)
3571 Public Event Stopped()
3572 Public Event Started()
3573 Private twCon As HttpTwitter
3575 Private _streamThread As Thread
3576 Private _streamActive As Boolean
3578 Private _allAtreplies As Boolean = False
3579 Private _trackwords As String = ""
3581 Public Sub New(ByVal twitterConnection As HttpTwitter)
3582 twCon = DirectCast(twitterConnection.Clone(), HttpTwitter)
3585 Public Sub Start(ByVal allAtReplies As Boolean, ByVal trackwords As String)
3586 Me.AllAtReplies = allAtReplies
3587 Me.TrackWords = trackwords
3588 _streamActive = True
3589 If _streamThread IsNot Nothing AndAlso _streamThread.IsAlive Then Exit Sub
3590 _streamThread = New Thread(AddressOf UserStreamLoop)
3591 _streamThread.Name = "UserStreamReceiver"
3592 _streamThread.IsBackground = True
3593 _streamThread.Start()
3596 Public ReadOnly Property Enabled() As Boolean
3598 Return _streamActive
3602 Public Property AllAtReplies As Boolean
3604 Return _allAtreplies
3606 Set(ByVal value As Boolean)
3607 _allAtreplies = value
3611 Public Property TrackWords As String
3615 Set(ByVal value As String)
3620 Private Sub UserStreamLoop()
3621 Dim st As Stream = Nothing
3622 Dim sr As StreamReader = Nothing
3623 Dim sleepSec As Integer = 0
3626 If Not MyCommon.IsNetworkAvailable() Then
3627 Thread.Sleep(30 * 1000)
3631 RaiseEvent Started()
3632 Dim res As HttpStatusCode = twCon.UserStream(st, _allAtreplies, _trackwords, GetUserAgentString())
3635 Case HttpStatusCode.OK
3636 Twitter.AccountState = ACCOUNT_STATE.Valid
3637 Case HttpStatusCode.Unauthorized
3638 Twitter.AccountState = ACCOUNT_STATE.Invalid
3643 If st Is Nothing Then
3645 'TraceOut("Stop:stream is Nothing")
3649 sr = New StreamReader(st)
3651 Do While _streamActive AndAlso Not sr.EndOfStream AndAlso Twitter.AccountState = ACCOUNT_STATE.Valid
3652 RaiseEvent StatusArrived(sr.ReadLine())
3656 If sr.EndOfStream OrElse Twitter.AccountState = ACCOUNT_STATE.Invalid Then
3658 'TraceOut("Stop:EndOfStream")
3662 Catch ex As WebException
3663 If ex.Status = WebExceptionStatus.Timeout Then
3664 sleepSec = 30 'TraceOut("Stop:Timeout")
3665 ElseIf ex.Response IsNot Nothing AndAlso CType(ex.Response, HttpWebResponse).StatusCode = 420 Then
3666 'TraceOut("Stop:Connection Limit")
3670 'TraceOut("Stop:WebException " & ex.Status.ToString)
3672 Catch ex As ThreadAbortException
3674 Catch ex As IOException
3676 'TraceOut("Stop:IOException with Active." + Environment.NewLine + ex.Message)
3677 Catch ex As ArgumentException
3678 'System.ArgumentException: ストリームを読み取れませんでした。
3679 'サーバー側もしくは通信経路上で切断された場合?タイムアウト頻発後発生
3681 TraceOut(ex, "Stop:ArgumentException")
3682 Catch ex As Exception
3683 TraceOut("Stop:Exception." + Environment.NewLine + ex.Message)
3687 If _streamActive Then RaiseEvent Stopped()
3688 twCon.RequestAbort()
3689 If sr IsNot Nothing Then sr.Close()
3690 If st IsNot Nothing Then st.Close()
3691 If sleepSec > 0 Then
3692 Dim ms As Integer = 0
3693 Do While _streamActive AndAlso ms < sleepSec * 1000
3700 Loop While Me._streamActive
3702 If _streamActive Then RaiseEvent Stopped()
3703 TraceOut("Stop:EndLoop")
3706 #Region "IDisposable Support"
3707 Private disposedValue As Boolean ' 重複する呼び出しを検出するには
3710 Protected Overridable Sub Dispose(ByVal disposing As Boolean)
3711 If Not Me.disposedValue Then
3713 ' TODO: マネージ状態を破棄します (マネージ オブジェクト)。
3714 _streamActive = False
3715 If _streamThread IsNot Nothing AndAlso _streamThread.IsAlive Then
3716 _streamThread.Abort()
3720 ' TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下の Finalize() をオーバーライドします。
3721 ' TODO: 大きなフィールドを null に設定します。
3723 Me.disposedValue = True
3726 ' TODO: 上の Dispose(ByVal disposing As Boolean) にアンマネージ リソースを解放するコードがある場合にのみ、Finalize() をオーバーライドします。
3727 'Protected Overrides Sub Finalize()
3728 ' ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3733 ' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。
3734 Public Sub Dispose() Implements IDisposable.Dispose
3735 ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3737 GC.SuppressFinalize(Me)
3744 #Region "IDisposable Support"
3745 Private disposedValue As Boolean ' 重複する呼び出しを検出するには
3748 Protected Overridable Sub Dispose(ByVal disposing As Boolean)
3749 If Not Me.disposedValue Then
3751 ' TODO: マネージ状態を破棄します (マネージ オブジェクト)。
3755 ' TODO: アンマネージ リソース (アンマネージ オブジェクト) を解放し、下の Finalize() をオーバーライドします。
3756 ' TODO: 大きなフィールドを null に設定します。
3758 Me.disposedValue = True
3761 ' TODO: 上の Dispose(ByVal disposing As Boolean) にアンマネージ リソースを解放するコードがある場合にのみ、Finalize() をオーバーライドします。
3762 'Protected Overrides Sub Finalize()
3763 ' ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3768 ' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。
3769 Public Sub Dispose() Implements IDisposable.Dispose
3770 ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(ByVal disposing As Boolean) に記述します。
3772 GC.SuppressFinalize(Me)