def checkError(self): code = self.connection.errorFlag if code != 0: self.errorCheckTimer.Stop() if code == 1000: simpleDialog.errorDialog( _("アクセストークンが不正です。設定メニューのアカウントマネージャから、再度アカウントの追加を行ってください。")) elif code == 2000: simpleDialog.errorDialog( _("APIの実行回数が上限に達しました。しばらくたってから、再度実行してください。")) elif code == 500: simpleDialog.errorDialog( _("ツイキャスAPIが500エラーを返しました。しばらく待ってから、再度接続してください。")) elif code == 2001: simpleDialog.errorDialog(_("現在TCVは使用できません。開発者に連絡してください。")) sys.exit(-1) else: detail = { 1001: "Validation Error", 1002: "Invalid WebHook URL", 2002: "Protected", 2003: "Duplicate", 2004: "Too Many Comments", 2005: "Out Of Scope", 2006: "Email Unverified", 400: "Bad Request", 403: "Forbidden", 404: "Not Found", } simpleDialog.errorDialog( _("ツイキャスAPIとの通信中にエラーが発生しました。詳細:%s") % (detail[code])) self.disconnect()
def getFollowList(token,target): auth = tweepy.OAuth1UserHandler(constants.TWITTER_CONSUMER_KEY, constants.TWITTER_CONSUMER_SECRET) auth.set_access_token(*token) try: twitterApi = tweepy.API(auth,proxy=os.environ['HTTPS_PROXY']) except KeyError: twitterApi = tweepy.API(auth) ret = [] try: user = twitterApi.get_user(screen_name=target) friendsCount = user.friends_count friends = tweepy.Cursor(twitterApi.get_friends,screen_name=target,include_user_entities=False,skip_status=True,count=200).items() for friend in friends: ret.append(friend.screen_name) return ret except tweepy.TooManyRequests: log.error("rateLimitError") return ret except tweepy.TweepyException as e: log.error(e) log.error("%s" %(e.response)) simpleDialog.errorDialog(_("Twitterからフォローリストを取得できませんでした。指定したユーザが存在しないか、フォローしていない非公開アカウントである可能性があります。")) return None except Exception as e: log.error(e) simpleDialog.errorDialog(_("Twitterからフォローリストを取得できませんでした。しばらくたってから再度お試しください。状況が改善しない場合には、開発者までお問い合わせください。")) return None
def post(self, event): account = self.account.GetValue() item = globalVars.app.postItem.getItem(self.item.GetValue()) if not globalVars.app.postItem.login(account): return point = self.count.GetValue() * item.point if point > globalVars.app.postItem.getPoint(account): simpleDialog.errorDialog( _("アカウント「%s」の所有ポイント数が不足しているため、アイテムを投下できません。") % account) return if globalVars.app.config.getboolean("general", "checkPoint", True): key = globalVars.app.config["advanced_ids"][account].replace( ":", "-") last = globalVars.app.config.getint("item_posted_time", key, 0) now = time.time() if now - last > 86400: # 24時間以上経過している newPoint = point else: # 24時間経過していない newPoint = globalVars.app.config.getint("item_point", key, 0) + point if newPoint > 100: d = simpleDialog.yesNoDialog( _("確認"), _("24時間以内に%dポイント使用しようとしています。100ポイント以上使用した場合であっても、自動チャージされるのは100ポイントのみです。処理を続行しますか?" ) % (newPoint)) if d == wx.ID_NO: return if now - last > 86400: globalVars.app.config["item_posted_time"][key] = int(now) globalVars.app.config["item_point"][key] = newPoint globalVars.app.postItem.postItem(account, item, self.count.GetValue()) self.account.SetFocus()
def exchandler(type, exc, tb): msg = traceback.format_exception(type, exc, tb) try: for i in globalVars.app.Manager.timers: i.Stop() globalVars.app.Manager.livePlayer.exit() except: pass if type == requests.exceptions.ConnectionError: simpleDialog.errorDialog( _("通信に失敗しました。インターネット接続を確認してください。プログラムを終了します。")) elif type == requests.exceptions.ProxyError: simpleDialog.errorDialog( _("通信に失敗しました。プロキシサーバーの設定を確認してください。プログラムを終了します。")) else: if not hasattr(sys, "frozen"): print("".join(msg)) winsound.Beep(1000, 1000) try: globalVars.app.say(str(msg[-1])) except: pass else: simpleDialog.winDialog( "error", "An error has occured. Contact to the developer for further assistance. Detail:" + "\n".join(msg[-2:])) try: f = open("errorLog.txt", "a") f.writelines(msg) f.close() except: pass os._exit(1)
def login(self, account): if account in self.sessions.keys(): return True id = globalVars.app.config["advanced_ids"][account] pw = globalVars.app.config["advanced_passwords"][account] if "c:" not in id: result = twitterLogin.login(id, pw) elif "c:" in id: result = twitcastingLogin.login(id.replace("c:", ""), pw) if type(result) == int: messages = { errorCodes.LOGIN_TWITCASTING_ERROR: _("ログイン中にエラーが発生しました。"), errorCodes.LOGIN_TWITCASTING_WRONG_ACCOUNT: _("設定されたユーザ名またはパスワードが不正です。設定を確認してください。"), errorCodes.LOGIN_TWITTER_WRONG_ACCOUNT: _("Twitterユーザ名またはパスワードが不正です。設定を確認してください。"), errorCodes.LOGIN_RECAPTCHA_NEEDED: _("reCAPTCHAによる認証が必要です。ブラウザからTwitterにログインし、認証を行ってください。"), errorCodes.LOGIN_TWITTER_ERROR: _("ログイン中にエラーが発生しました。"), errorCodes.LOGIN_CONFIRM_NEEDED: _("認証が必要です。ブラウザで操作を完了してください。"), } simpleDialog.errorDialog(messages[result]) return False self.sessions[account] = result try: with open(constants.SESSION_FILE_NAME, "wb") as f: pickle.dump(self.sessions, f) except Exception as e: self.log.error("Session data save error:" + str(e)) return True
def __init__(self): """アプリを初期化する。""" super().__init__() #実行環境の取得(exeファイルorインタプリタ) self.frozen = hasattr(sys, "frozen") #各種初期設定 self.InitLogger() self.LoadSettings() try: if self.config["general"]["locale"] != None: locale.setlocale(locale.LC_TIME, self.config["general"]["locale"]) else: locale.setlocale(locale.LC_TIME) except: locale.setlocale(locale.LC_TIME) self.config["general"]["locale"] = "" self.SetTimeZone() self.InitTranslation() self.InitSpeech() # ログのファイルハンドラーが利用可能でなければ警告を出す if not self.log.hasHandlers(): simpleDialog.errorDialog( _("ログ機能の初期化に失敗しました。下記のファイルへのアクセスが可能であることを確認してください。") + "\n" + os.path.abspath(constants.LOG_FILE_NAME))
def record(self, userName): """指定したユーザのライブを録画。 :param userName: ユーザ名 :type userName: str """ self.loadUserList() userInfo = self.getUserInfo(userName) if userInfo == None: return if userInfo["user"]["id"] in self.users.keys(): if userInfo["user"]["is_live"]: movie = self.getCurrentLive(userInfo["user"]["screen_id"]) if movie == None: return r = recorder.Recorder(self, movie["movie"]["hls_url"], movie["broadcaster"]["screen_id"], movie["movie"]["created"], movie["movie"]["id"]) if r.isRecordedByAnotherThread(): simpleDialog.errorDialog(_("このユーザのライブはすでに録画中です。")) return r.start() return simpleDialog.errorDialog(_("このユーザはすでに登録されています。")) return self.users[userInfo["user"]["id"]] = { "user": userInfo["user"]["screen_id"], "name": userInfo["user"]["name"], "specific": True, "baloon": False, "record": True, "openBrowser": False, "sound": False, "soundFile": "", "remove": (datetime.datetime.now() + datetime.timedelta(hours=10)).timestamp(), } self.saveUserList() wx.CallAfter( globalVars.app.hMainView.addLog, _("ユーザ名を指定して録画"), _("%sを、録画対象として追加しました。この登録は一定時間経過後に自動で削除されます。") % userInfo["user"]["screen_id"]) if userInfo["user"]["is_live"]: movie = self.getCurrentLive(userName) if movie == None: return r = recorder.Recorder(self, movie["movie"]["hls_url"], movie["broadcaster"]["screen_id"], movie["movie"]["created"], movie["movie"]["id"]) r.start()
def getFollowingUsers(self, user, account): self.log.debug("Getting follow list...") ret = [] pagination = "" while True: try: client = self.tokenManager.getClient(account) if pagination: response = client.get_users_following( user, user_fields="protected", max_results=1000, pagination_token=pagination) else: response = client.get_users_following( user, user_fields="protected", max_results=1000) except tweepy.Unauthorized as e: self.showTokenError() return [] except Exception as e: self.log.error(traceback.format_exc()) simpleDialog.errorDialog(_("フォロー中のユーザの取得に失敗しました。詳細:%s") % e) return [] self.log.debug(response) if response.data: ret += response.data meta = response.meta if "next_token" not in meta.keys(): break pagination = meta["next_token"] return ret
def getUserInfo(self, user, showNotFound=True): """ユーザ情報を取得 :param user: ユーザ名またはユーザID :type user: str :param showNotFound: 見つからなかったときにエラーを表示 :type showNotFound: bool """ try: req = requests.get("https://apiv2.twitcasting.tv/users/%s" % user, headers=self.header) except requests.RequestException as e: self.log.error(traceback.format_exc()) return if req.status_code != 200: if req.json()["error"]["code"] == 1000: self.showTokenError() return elif req.status_code == 404: if showNotFound: simpleDialog.errorDialog(_("指定したユーザが見つかりません。")) return else: self.showError(req.json()["error"]["code"]) return return req.json()
def showError(self, code): if code == errorCodes.CONNECTION_ERROR: simpleDialog.errorDialog( _("Twitterとの接続に失敗しました。インターネット接続に問題がない場合は、しばらくたってから再度お試しください。この問題が再度発生する場合は、開発者までお問い合わせください。" )) elif code == errorCodes.INVALID_RECEIVED: simpleDialog.errorDialog(_("Twitterからの応答が不正です。開発者までご連絡ください。"))
def login(self, account): if account in self.sessions.keys(): return True id = globalVars.app.config["advanced_ids"][account] pw = globalVars.app.config["advanced_passwords"][account] if "c:" not in id: result = twitterLogin.login(id, pw) elif "c:" in id: result = twitcastingLogin.login(id.replace("c:", ""), pw) if type(result) == int: messages = { errorCodes.LOGIN_TWITCASTING_ERROR: _("ログイン中にエラーが発生しました。"), errorCodes.LOGIN_TWITCASTING_WRONG_ACCOUNT: _("設定されたユーザ名またはパスワードが不正です。設定を確認してください。"), errorCodes.LOGIN_TWITTER_WRONG_ACCOUNT: _("Twitterユーザ名またはパスワードが不正です。設定を確認してください。"), errorCodes.LOGIN_RECAPTCHA_NEEDED: _("reCAPTCHAによる認証が必要です。ブラウザからTwitterにログインし、認証を行ってください。"), errorCodes.LOGIN_TWITTER_ERROR: _("ログイン中にエラーが発生しました。"), errorCodes.LOGIN_CONFIRM_NEEDED: _("認証が必要です。ブラウザで操作を完了してください。"), } simpleDialog.errorDialog(messages[result]) return False self.sessions[account] = result self.saveSessionData() return True
def play(self): if self.livePlayer == None: self.livePlayer = soundPlayer.player.player() self.livePlayer.setAmp( globalVars.app.config.getint("livePlay", "defaultVolume", 100)) self.livePlayer.setHlsTimeout( globalVars.app.config.getint("livePlay", "audioDelay", 7)) self.changeDevice(globalVars.app.config["livePlay"]["device"]) if self.livePlayer.getStatus() != PLAYER_STATUS_PLAYING: if self.connection.movieInfo["movie"]["hls_url"] == None: simpleDialog.errorDialog(_("再生URLを取得できません。")) return setSource = self.livePlayer.setSource( self.connection.movieInfo["movie"]["hls_url"]) if setSource == False: simpleDialog.errorDialog(_("再生に失敗しました。")) return self.livePlayer.play() globalVars.app.say(_("再生")) self.MainView.menu.EnableMenu("PLAY", False) self.MainView.menu.EnableMenu("STOP", True) self.MainView.menu.EnableMenu("VOLUME_UP", True) self.MainView.menu.EnableMenu("VOLUME_DOWN", True) self.MainView.menu.EnableMenu("RESET_VOLUME", True) self.playStatusTimer.Start(playstatusTimerInterval)
def close(self, event=None): result = globalVars.app.accountManager.hasDefaultAccount() if result == False and self.hListCtrl.GetItemCount() > 0: simpleDialog.errorDialog(_("通信用アカウントが設定されていません。")) return else: self.wnd.Destroy()
def deleteComment(self): selected = self.MainView.commentList.GetFocusedItem() result = self.connection.deleteComment(self.connection.comments[selected]) if result == False: simpleDialog.errorDialog(_("コメントの削除に失敗しました。このコメントを削除する権限がありません。")) else: del self.connection.comments[selected] self.MainView.commentList.DeleteItem(selected)
def delete(self, event): index = self.hListCtrl.GetFocusedItem() ext = self.hListCtrl.GetItemText(index, 0) if "<default" in ext: simpleDialog.errorDialog(_("デフォルト設定は削除できません。")) return del (self.config[ext]) self.hListCtrl.DeleteItem(index)
def viewProfile(self, event): id = self.historyList.GetItemText(self.historyList.GetFocusedItem(), 0) user = globalVars.app.Manager.connection.getUserObject(id) if len(user) == 0: simpleDialog.errorDialog(_("プロフィールの取得に失敗しました。")) return d = views.viewBroadcaster.Dialog(user) d.Initialize(_("プロフィール")) d.Show() self.wnd.SetFocus()
def clearFavorites(self): self.favorites.clear() try: favoritesData.write_text("\n".join(self.favorites)) except Exception as e: simpleDialog.errorDialog( _("お気に入りデータの保存に失敗しました。以下のファイルへのアクセスが可能であることを確認してください。") + "\n" + os.path.abspath(constants.FAVORITES_FILE_NAME)) traceback.print_exc() self.log.warning("Failed to write favorites data. detail:" + traceback.format_exc())
def _save(self): conf = self.app.config for obj, v in self.iniDic.items(): if v[0] == configType.DIC: conf[v[1]][v[2]] = list(v[3].keys())[obj.GetSelection()] else: conf[v[1]][v[2]] = obj.GetValue() if conf.write() != errorCodes.OK: simpleDialog.errorDialog( _("設定の保存に失敗しました。下記のファイルへのアクセスが可能であることを確認してください。") + "\n" + os.path.abspath(constants.SETTING_FILE_NAME))
def save(self): self.log.debug("Saving token data") try: with open(self._file, "wb") as f: pickle.dump(self._data, f) except Exception as e: self.log.error(traceback.format_exc()) simpleDialog.errorDialog(_("認証情報の保存に失敗しました。")) return False self.log.debug("saved: %s" % self._file) return True
def saveAsFile(self): tmplst = copy.deepcopy(self.tokens) for i in tmplst: i["access_token"] = base64.b64encode(i["access_token"].encode()).decode() try: with open(constants.TOKEN_FILE_NAME, "wb") as f: pickle.dump(tmplst, f) except Exception as e: simpleDialog.errorDialog(_("アカウント情報の書き込みに失敗しました。以下のファイルへのアクセスが可能であることを確認してください。") + "\n" + os.path.abspath(constants.TOKEN_FILE_NAME)) traceback.print_exc() self.log.warning("Failed to save account information. detail: %s" %traceback.format_exc())
def clearHistory(self): self.history.clear() try: historyData.write_text("\n".join(self.history)) except Exception as e: simpleDialog.errorDialog( _("履歴データの保存に失敗しました。以下のファイルへのアクセスが可能であることを確認してください。") + "\n" + os.path.abspath(constants.HISTORY_FILE_NAME)) traceback.print_exc() self.log.warning("Failed to write history data. detail:" + traceback.format_exc())
def save(self): if hasattr(sys, "frozen"): indent = None else: indent = "\t" try: with open(self._file, "w", encoding="utf-8") as f: json.dump(self._data, f, ensure_ascii=False, indent=indent) self.log.debug("saved: " + self._file) except Exception as e: self.log.error(traceback.format_exc()) simpleDialog.errorDialog(_("ユーザ情報の保存に失敗しました。"))
def post(self, event): account = self.account.GetValue() item = globalVars.app.postItem.getItem(self.item.GetValue()) if not globalVars.app.postItem.login(account): return if self.count.GetValue( ) * item.point > globalVars.app.postItem.getPoint(account): simpleDialog.errorDialog( _("アカウント「%s」の所有ポイント数が不足しているため、アイテムを投下できません。") % account) return globalVars.app.postItem.postItem(account, item, self.count.GetValue()) self.account.SetFocus()
def Validation(self, event): if self.edits[1].GetValue() == "": simpleDialog.errorDialog(_("ユーザ名が入力されていません。")) return if self.edits[0].GetValue() != "": event.Skip() return user = globalVars.app.tc.getUserInfo(self.edits[1].GetValue()) if user == None: return self.edits[0].SetValue(user["user"]["id"]) self.edits[2].SetValue(user["user"]["name"]) event.Skip()
def viewHistory(self, event=None): if len(globalVars.app.Manager.history) == 0: simpleDialog.errorDialog(_("接続履歴がありません。")) return self.parent.Clear() viewHistoryDialog = views.viewHistory.Dialog() viewHistoryDialog.Initialize() ret = viewHistoryDialog.Show() if ret==wx.ID_CANCEL: self.parent.createStartScreen() return globalVars.app.Manager.connect(globalVars.app.Manager.history[viewHistoryDialog.GetValue()]) return
def viewFavorites(self, event=None): if len(globalVars.app.Manager.favorites) == 0: simpleDialog.errorDialog(_("お気に入りライブが登録されていません。")) return self.parent.Clear() viewFavoritesDialog = views.viewFavorites.Dialog() viewFavoritesDialog.Initialize() ret = viewFavoritesDialog.Show() if ret==wx.ID_CANCEL: self.parent.createStartScreen() return globalVars.app.Manager.connect(globalVars.app.Manager.favorites[viewFavoritesDialog.GetValue()]) return
def onCloseButton(self, event): if self.hListCtrl.GetItemCount() == 0: d = simpleDialog.yesNoDialog(_("確認"), _("Twitterアカウントの情報が設定されていません。Twitterとの連携を停止しますか?")) if d == wx.ID_YES: self._shouldExit = True event.Skip() else: return result = globalVars.app.spaces.tokenManager.hasDefaultAccount() if not result and self.hListCtrl.GetItemCount() > 0: simpleDialog.errorDialog(_("規定のアカウントが設定されていません。")) return event.Skip()
def OKButtonEvent(self, event): if self.extensionEdit.GetLineText( 0) == "" or self.pathEdit.GetLineText(0) == "": return if not re.match("^[a-zA-Z0-9\\-$~]+$", self.extensionEdit.GetLineText(0)): simpleDialog.errorDialog( _("入力された拡張子に利用できない文字が含まれています。パスを確認してください。")) return if not os.path.isfile(self.pathEdit.GetLineText(0)): simpleDialog.errorDialog(_("入力された実行ファイルが存在しません。パスを確認してください。")) return event.Skip()
def postItem(self, account, item, count): counter = 0 for i in range(count): if self._postItem(account, item): counter += 1 if counter == 0: simpleDialog.errorDialog(_("アイテムの投下に失敗しました。")) return simpleDialog.dialog( _("完了"), _("%(name)sを%(count)d個投下しました。") % { "name": item.name, "count": counter })
def showError(self, code): """ツイキャスAPIが返すエラーコードに応じてメッセージを出す。Invalid TokenについてはshowTokenError()を使用することを想定しているため未実装。 :param code: エラーコード :type code: int """ if code == 2000: simpleDialog.errorDialog( _("ツイキャスAPIの実行回数が上限に達しました。しばらくたってから、再度実行してください。")) elif code == 500: simpleDialog.errorDialog( _("ツイキャスAPIが500エラーを返しました。しばらく待ってから、再度接続してください。")) elif code == 2001: simpleDialog.errorDialog(_("現在ツイキャスとの連携機能を使用できません。開発者に連絡してください。")) else: detail = { 1001: "Validation Error", 1002: "Invalid WebHook URL", 2002: "Protected", 2003: "Duplicate", 2004: "Too Many Comments", 2005: "Out Of Scope", 2006: "Email Unverified", 400: "Bad Request", 403: "Forbidden", } simpleDialog.errorDialog( _("ツイキャスAPIとの通信中にエラーが発生しました。詳細:%s") % (detail[code]))