public UserLinkData(AccountInfo info, UserSelectorViewModel parent, bool isLink) { this.parent = parent; this.info = info; this._profileImageProvider = new ProfileImageProvider(info); this._IsLink = isLink; }
/// <summary> /// 指定アカウントの依存情報を受信します。 /// </summary> public static void ReceiveInidividualInfo(AccountInfo info) { // アカウント情報の受信 SafeExec(() => UserStorage.Register(info.GetUserByScreenName(info.ScreenName))); // フォロー/フォロワー/ブロックの受信 SafeExec(() => info.GetFriendIds(screenName: info.ScreenName).ForEach(i => info.RegisterFollowing(i))); SafeExec(() => info.GetFollowerIds(screenName: info.ScreenName).ForEach(i => info.RegisterFollower(i))); SafeExec(() => info.GetBlockingIds().ForEach(i => info.RegisterBlocking(i))); }
public static AccountScheduler GetScheduler(AccountInfo info) { if (info == null) throw new ArgumentNullException("info"); AccountScheduler sched; if (schedulers.TryGetValue(info, out sched)) return sched; else return null; }
public TweetWorker(InputBlockViewModel parent, AccountInfo info, string body, long inReplyToId, string attachedImage, string[] tag) { this.parent = parent; this.TweetSummary = info.ScreenName + ": " + body; this.accountInfo = info; this.body = body; this.inReplyToId = inReplyToId; this.attachImagePath = attachedImage; this.tags = tag; }
public AccountScheduler(AccountInfo info) { this._accountInfo = info; this.AddSchedule(new HomeReceiveTask(info)); this.AddSchedule(new MentionReceiveTask(info)); this.AddSchedule(new DirectMessageReceiveTask(info)); this.AddSchedule(new SentDirectMessageReceiveTask(info)); this.AddSchedule(new FavoritesReceiveTask(info)); this.AddSchedule(new MyTweetsTask(info)); ThreadHelper.Halt += this.StopSchedule; }
public static bool DeleteAccount(AccountInfo info) { if (info != null && accounts.Contains(info)) { accounts.Remove(info); OnAccountsChanged(EventArgs.Empty); return true; } else { return false; } }
public TweetWorker(InputBlockViewModel parent, AccountInfo info, string body, long inReplyToId, string attachedImage, string[] tag) { isImageAttached = false; isBodyStandby = false; if (info == null) throw new ArgumentNullException("info"); this.parent = parent; this.TweetSummary = info.ScreenName + ": " + body; this.accountInfo = info; this.body = body; this.inReplyToId = inReplyToId; this.attachImagePath = attachedImage; this.tags = tag; }
/// <summary> /// 接続を開始します。<para /> /// すでに接続が存在する場合は、すでに存在している接続を破棄します。 /// </summary> public static bool RefreshConnection(AccountInfo info) { if (info == null) throw new ArgumentNullException("info", "AccountInfo is not set."); System.Diagnostics.Debug.WriteLine("Refresh connection: " + info.ToString()); UserStreamsConnection ncon; lock (info) { UserStreamsConnection prevCon; // 旧接続の破棄 if (connections.TryGetValue(info, out prevCon)) { connections.Remove(info); if (prevCon != null) prevCon.Dispose(); } // User Streams接続しない設定になっている if (!info.AccountProperty.UseUserStreams) return false; ncon = new UserStreamsConnection(info); if (!connections.TryAdd(info, ncon)) throw new InvalidOperationException("Connection refresh violation."); } var queries = lookupDictionary.Where(v => v.Value == info).Select(v => v.Key).ToArray(); try { ncon.Connect(queries); return true; } catch (Exception e) { connections[info] = null; ncon.Dispose(); ExceptionStorage.Register(e, ExceptionCategory.TwitterError, "User Streams接続に失敗しました。", () => { if (connections.ContainsKey(info) && connections[info] == null) RefreshConnection(info); }); return false; } }
public AccountViewModel(AccountInfo info) { this.Info = info; this._profileImageProvider = new Common.ProfileImageProvider(info); Task.Factory.StartNew(() => UpdatePostChunk()); ViewModelHelper.BindNotification(info.ConnectionStateChangedEvent, this, (o, e) => RaisePropertyChanged(() => ConnectState)); ViewModelHelper.BindNotification(TimeTickCall, this, (o, e) => { Task.Factory.StartNew(() => UpdatePostChunk()); }); ViewModelHelper.BindNotification(PostOffice.OnUnderControlChangedEvent, this, (o, e) => { RaisePropertyChanged(() => IsAccountUnderControlled); RaisePropertyChanged(() => AccountControlReleaseTime); }); }
public AccountScheduler(AccountInfo info) { this._accountInfo = info; this.AddSchedule(new HomeReceiveTask(info)); this.AddSchedule(new MentionReceiveTask(info)); this.AddSchedule(new DirectMessageReceiveTask(info)); this.AddSchedule(new SentDirectMessageReceiveTask(info)); this.AddSchedule(new FavoritesReceiveTask(info)); this.AddSchedule(new MyTweetsTask(info)); Task.Factory.StartNew(() => { try { // テストを飛ばす ApiHelper.ExecApi(() => info.Test()); } catch { } }); ThreadHelper.Halt += () => this.StopSchedule(); }
/// <summary> /// 接続を開始します。<para /> /// すでに接続が存在する場合は、すでに存在している接続を破棄します。 /// </summary> public static bool RefreshConnection(AccountInfo info) { if (info == null) throw new ArgumentNullException("info", "AccountInfo is not set."); var ncon = new UserStreamsConnection(info); if (connections.ContainsKey(info)) { var pcon = connections[info]; // 以前の接続がある connections[info] = ncon; if (pcon != null) pcon.Dispose(); } else { connections.AddOrUpdate(info, ncon); } var queries = lookupDictionary.Where(v => v.Value == info).Select(v => v.Key).ToArray(); try { ncon.Connect(queries); return true; } catch (Exception e) { connections[info] = null; ncon.Dispose(); ExceptionStorage.Register(e, ExceptionCategory.TwitterError, "User Streams接続に失敗しました。", () => { if (connections.ContainsKey(info) && connections[info] == null) RefreshConnection(info); }); return false; } }
private static void RemoveRetweetCore(AccountInfo d, TweetViewModel status) { // リツイートステータスの特定 var rts = TweetStorage.GetAll(vm => vm.Status.User.ScreenName == d.ScreenName && vm.Status is TwitterStatus && ((TwitterStatus)vm.Status).RetweetedOriginal != null && ((TwitterStatus)vm.Status).RetweetedOriginal.Id == status.Status.Id).FirstOrDefault(); if (rts == null || ApiHelper.ExecApi(() => d.DestroyStatus(rts.Status.Id) == null)) throw new ApplicationException(); }
private static void RemoveDMSink(AccountInfo info, long tweetId) { var tweet = ApiHelper.ExecApi(() => info.DestroyDirectMessage(tweetId.ToString())); if (tweet != null) { if (tweet.Id != tweetId) { NotifyStorage.Notify("削除には成功しましたが、ダイレクトメッセージIDが一致しません。(" + tweetId.ToString() + " -> " + tweet.Id.ToString() + ")"); } else { TweetStorage.Remove(tweetId); NotifyStorage.Notify("削除しました:" + tweet.ToString()); } } else { NotifyStorage.Notify("ダイレクトメッセージを削除できませんでした(@" + info.ScreenName + ")"); } }
public MyTweetsTask(AccountInfo info) { this._accountInfo = info; }
/// <summary> /// アカウントを登録します。 /// </summary> /// <param name="accountInfo">登録するアカウント情報</param> public static void RegisterAccount(AccountInfo accountInfo) { if (accountInfo == null) throw new ArgumentNullException("accountInfo"); accounts.Add(accountInfo); OnAccountsChanged(EventArgs.Empty); // アカウント情報のキャッシュ // Task.Factory.StartNew(() => accountInfo.UserViewModel); }
private static void UpdateTweetSink(AccountInfo info, string text, long? inReplyToId = null) { var status = info.UpdateStatus(text, inReplyToId); if (status == null || status.Id == 0) throw new WebException("Timeout or failure sending tweet.", WebExceptionStatus.Timeout); TweetStorage.Register(status); NotifyStorage.Notify("ツイートしました:@" + info.ScreenName + ": " + text); }
private static void UnfavTweetCore(AccountInfo d, TweetViewModel status) { if (ApiHelper.ExecApi(() => d.DestroyFavorites(status.Status.Id)) == null) throw new ApplicationException(); }
private static void RemoveTweetSink(AccountInfo info, long tweetId) { var tweet = ApiHelper.ExecApi(() => info.DestroyStatus(tweetId)); if (tweet != null) { if (tweet.Id != tweetId) { NotifyStorage.Notify("削除には成功しましたが、ツイートIDが一致しません。(" + tweetId.ToString() + " -> " + tweet.Id.ToString() + ")"); } else { if (tweet.InReplyToStatusId != 0) { var s = TweetStorage.Get(tweet.InReplyToStatusId); if (s != null) s.RemoveInReplyToThis(tweetId); } TweetStorage.Remove(tweetId); NotifyStorage.Notify("削除しました:" + tweet.ToString()); } } else { NotifyStorage.Notify("ツイートを削除できませんでした(@" + info.ScreenName + ")"); } }
private static void RetweetCore(AccountInfo d, TweetViewModel status) { if (ApiHelper.ExecApi(() => d.Retweet(status.Status.Id)) == null) throw new ApplicationException(); }
public static void RemoveTweet(AccountInfo info, long tweetId) { var result = Task.Factory.StartNew(() => removeInjection.Execute(new Tuple<AccountInfo, long>(info, tweetId))); var ex = result.Exception; if (ex != null) { NotifyStorage.Notify("ツイートを削除できませんでした(@" + info.ScreenName + ")"); ExceptionStorage.Register(ex, ExceptionCategory.TwitterError, "ツイート削除時にエラーが発生しました"); } }
private static void UpdateDirectMessageSink(AccountInfo info, string target, string body) { var status = info.SendDirectMessage(target, body); if (status == null || status.Id == 0) throw new WebException("Timeout or failure sending tweet.", WebExceptionStatus.Timeout); TweetStorage.Register(status); NotifyStorage.Notify("DMを送信しました: @" + info.ScreenName + " -> @" + target + ": " + body); }
public static int UpdateTweet(AccountInfo info, string text, long? inReplyToId = null) { int retryCount = 0; do { try { updateInjection.Execute(new Tuple<AccountInfo, string, long?>(info, text, inReplyToId)); break; // break roop on succeeded } catch (WebException wex) { if (wex.Status == WebExceptionStatus.ProtocolError) { var hrw = wex.Response as HttpWebResponse; if (hrw != null && hrw.StatusCode == HttpStatusCode.Forbidden) { // 規制? using (var strm = hrw.GetResponseStream()) using (var json = JsonReaderWriterFactory.CreateJsonReader(strm, System.Xml.XmlDictionaryReaderQuotas.Max)) { var xdoc = XDocument.Load(json); System.Diagnostics.Debug.WriteLine(xdoc); var eel = xdoc.Root.Element("error"); if (eel != null) { if (eel.Value.IndexOf("update limit", StringComparison.CurrentCultureIgnoreCase) >= 0) { // User is over daily status update limit. // POST規制 AddUnderControlled(info); throw new TweetFailedException(TweetFailedException.TweetErrorKind.Controlled); } else if (eel.Value.IndexOf("duplicate", StringComparison.CurrentCultureIgnoreCase) >= 0) { // 同じツイートをしようとした if (retryCount == 0) // 複数回投稿している場合はサスペンドする throw new TweetFailedException(TweetFailedException.TweetErrorKind.Duplicated); else break; // 成功 } else { // 何かよくわからない throw new TweetFailedException(TweetFailedException.TweetErrorKind.CommonFailed, eel.Value); } } } } // 何かよくわからない throw new TweetFailedException(TweetFailedException.TweetErrorKind.CommonFailed, wex.Message); } else { if (!Setting.Instance.InputExperienceProperty.AutoRetryOnError) { if (wex.Status == WebExceptionStatus.Timeout) { // タイムアウト throw new TweetFailedException(TweetFailedException.TweetErrorKind.Timeout, "ツイートに失敗しました(タイムアウトしました。Twitterが不調かも)", wex); } else { // 何かがおかしい throw new TweetFailedException(TweetFailedException.TweetErrorKind.CommonFailed, "ツイートに失敗しました(" + (int)wex.Status + ")", wex); } } } } catch (TweetAnnotationException) { throw; } catch (Exception ex) { throw new TweetFailedException(TweetFailedException.TweetErrorKind.CommonFailed, "ツイートに失敗しました(" + ex.Message + ")", ex); } } while (Setting.Instance.InputExperienceProperty.AutoRetryOnError && retryCount++ < Setting.Instance.InputExperienceProperty.AutoRetryMaxCount); var chunk = GetUnderControlChunk(info); if (chunk.Item2 > TwitterDefine.UnderControlWarningThreshold) throw new TweetAnnotationException(TweetAnnotationException.AnnotationKind.NearUnderControl); return chunk.Item2; }
public UnderControlEventArgs(AccountInfo info, bool added) { this.AccountInfo = info; this.Added = added; }
internal static void UpdateDirectMessage(AccountInfo accountInfo, string target, string body) { dmInjection.Execute(new Tuple<AccountInfo, string, string>(accountInfo, target, body)); }
/// <summary> /// 既に存在するアカウント情報を更新します。 /// </summary> /// <param name="prevId">旧アカウント情報</param> /// <param name="newinfo">新しいアカウント情報</param> public static void Update(string prevId, AccountInfo newinfo) { accounts.LockOperate(() => { var prev = Get(prevId); if(prev == null) throw new ArgumentException("アカウント @" + prevId + " は存在しません。"); var idx = accounts.IndexOf(prev); if (idx < 0) throw new ArgumentException("旧アカウント情報が見つかりません。"); accounts[idx] = newinfo; }); OnAccountsChanged(EventArgs.Empty); }
private static void AddUnderControlled(AccountInfo info) { if (underControls.ContainsKey(info)) { NotifyStorage.Notify("[規制管理: @" + info.ScreenName + " は規制されています。解除予想時刻: " + underControls[info].ToString("HH:mm:ss")); return; } var timestamp = DateTime.Now.Subtract(TwitterDefine.UnderControlTimespan); // APIを利用してツイートを遡り受信 var notify = NotifyStorage.NotifyManually("[規制管理: @" + info.ScreenName + " の直近のツイートを受信しています...]"); try { ApiHelper.ExecApi(() => info.GetUserTimeline(count: 150, includeRts: true)) .Guard() .ForEach(i => TweetStorage.Register(i)); notify.Message = "[規制管理:規制開始時刻を割り出しています...]"; // 127tweet/3hours var originate = TweetStorage.GetAll( t => t.Status.User.ScreenName == info.ScreenName && DateTime.Now.Subtract(t.CreatedAt) < TwitterDefine.UnderControlTimespan) .OrderByDescending((t) => t.Status.CreatedAt) .Skip(TwitterDefine.UnderControlCount - 1) .FirstOrDefault(); if (originate == null) { originate = TweetStorage.GetAll( t => t.Status.User.ScreenName == info.ScreenName && DateTime.Now.Subtract(t.CreatedAt) < TwitterDefine.UnderControlTimespan) .OrderByDescending((t) => t.Status.CreatedAt) .LastOrDefault(); } if (originate == null) { NotifyStorage.Notify("[規制管理: @" + info.ScreenName + " はPOST規制されていますが、解除時刻を予想できません。しばらく置いて試してみてください。]"); } else { var release = (originate.Status.CreatedAt + TwitterDefine.UnderControlTimespan); NotifyStorage.Notify("[規制管理: @" + info.ScreenName + " はPOST規制されています。解除予想時刻は " + release.ToString("HH:mm:ss") + " です。]"); underControls.AddOrUpdate(info, release); OnOnUnderControlChanged(new UnderControlEventArgs(info, true)); } } finally { notify.Dispose(); } }
public ProfileImageProvider(AccountInfo relatedInfo) { this._info = relatedInfo; }
private static AccountInfo CheckFallback(AccountInfo d) { if (d == null) throw new ArgumentNullException("d"); AccountInfo origin = d; while ( Setting.Instance.InputExperienceProperty.OfficialRetweetFallback && IsAccountUnderControlled(d) && !String.IsNullOrEmpty(d.AccountProperty.FallbackAccount)) { var fallback = AccountStorage.Get(d.AccountProperty.FallbackAccount); if (fallback == null || fallback == origin) break; d = fallback; } return d; }
private void StealCore(AccountInfo info) { var ibvm = this.Parent.Parent.Parent.Parent.InputBlockViewModel; ibvm.AddUpdateWorker( new InputBlock.TweetWorker(ibvm, info, this.Tweet.TweetText, ((TwitterStatus)this.Tweet.Status).InReplyToStatusId, null, null)); }
private static void FavTweetCore(AccountInfo d, TweetViewModel status) { /* if (ApiHelper.ExecApi(() => d.CreateFavorites(status.Status.Id)) == null) throw new ApplicationException(); */ for (int i = 0; i < 3; i++) { try { if (d.CreateFavorites(status.Status.Id) != null) break; } catch (WebException wex) { var hwr = wex.Response as HttpWebResponse; if (wex.Status == WebExceptionStatus.ProtocolError && hwr != null && hwr.StatusCode == HttpStatusCode.Forbidden) { // あとIt's great that ... ならふぁぼ規制 using (var read = new StreamReader( hwr.GetResponseStream())) { var desc = read.ReadToEnd(); if (desc.Contains("It's great that you like so many updates, but we only allow so many updates to be marked as a favorite per day.")) { throw new FavoriteSuspendedException(); } } } else if (wex.Status == WebExceptionStatus.Timeout) { continue; } else { break; } } } }