def interactive_login(self): try: if (not hasattr(self, "domain")): domain = input( "{0}: Enter the instance domain [mastodon.social]: ". format(self.name)) domain = domain.strip() if (domain == ""): domain = "mastodon.social" self.config.domain = domain # We have to generate these two together, if just one is # specified in the config file it's no good. if (not hasattr(self, "client_id") or not hasattr(self, "client_secret")): client_name = input( "{0}: Enter a name for this bot or service [{0}]: ".format( self.name)) client_name = client_name.strip() if (client_name == ""): client_name = self.name self.config.client_id, self.config.client_secret = Mastodon.create_app( client_name, api_base_url="https://" + self.config.domain) # TODO handle failure self.config.save() if (not hasattr(self, "access_token")): email = input("{0}: Enter the account email: ".format( self.name)) email = email.strip() password = getpass.getpass( "{0}: Enter the account password: "******"https://" + self.config.domain) self.config.access_token = mastodon.log_in(email, password) self.config.save() except ValueError as e: self.log( "login", "Could not authenticate with {0} as '{1}':".format( self.config.domain, email)) self.log("login", str(e)) self.log("debug", "using the password {0}".format(password)) return False return True except KeyboardInterrupt: return False
def regulusaurum_done(): refresh_token = request.args.get("code", default=None, type=str) host_domain = request.cookies.get("host_domain", "") client_keys = get_client_keys(root_dir, host_domain) if not refresh_token == None: access_token = process_refresh_token( host_domain, client_keys[0], client_keys[1], refresh_token) response = make_response(redirect(url_for("regulusaurum_dashboard"))) api = Mastodon(access_token=access_token, host_domain=host_domain) result = api.verify_credentials().json() account_id = result["id"] response.set_cookie("account_id", value=account_id) screen_name = result["username"] response.set_cookie("screen_name", screen_name) return response else: return redirect(url_for("regulusaurum_info", requireLogin=0))
def login(request): # User posts instance name in form. # POST page redirects user to instance, where they log in. # Instance redirects user to oauth_after_login view. # oauth_after_login view saves credential in session, then redirects to home. if request.method == "GET": form = OAuthLoginForm() return render(request, 'setup/login-oauth.html', {'form': form}) elif request.method == "POST": form = OAuthLoginForm(request.POST) redirect_uris = request.build_absolute_uri(reverse('oauth_callback')) if form.is_valid(): api_base_url = form.cleaned_data['instance'] tmp_base = parse.urlparse(api_base_url.lower()) if tmp_base.netloc == '': api_base_url = parse.urlunparse( ('https', tmp_base.path, '', '', '', '')) else: api_base_url = api_base_url.lower() request.session['instance'] = api_base_url try: client = Client.objects.get(api_base_id=api_base_url) except (Client.DoesNotExist, Client.MultipleObjectsReturned): (client_id, client_secret) = Mastodon.create_app( 'brutaldon', api_base_url=api_base_url, redirect_uris=redirect_uris) client = Client(api_base_id=api_base_url, client_id=client_id, client_secret=client_secret) client.save() request.session['client_id'] = client.client_id request.session['client_secret'] = client.client_secret mastodon = Mastodon(client_id=client.client_id, client_secret=client.client_secret, api_base_url=api_base_url) return redirect( mastodon.auth_request_url(redirect_uris=redirect_uris)) else: return render(request, 'setup/login.html', {'form': form}) else: return redirect(login)
def perform_create(self, serializer): post = serializer.save() # Set category try: category = str(self.request.data['category']) except: category = "" if category: category = Category.objects.get(slug=category) post.category = category # Add tags try: tag_string = self.request.data['tags'] except: tag_string = "" if tag_string: post = add_tags(post, tag_string) post.published = True post.save() # Ignore this. # Experimenting with submitting posts using ActivityPub. # try: # submit_post(post) # except: # pass # Mastodon mastodon_login() # Login using generated auth mastodon = Mastodon( client_id = 'clientcred.txt', access_token = 'usercred.txt', api_base_url="https://lumenwrites.com" ) hashtags = "" if tag_string: tags = tag_string.split(",") for tag in tags: tag = tag.strip() hashtags += "#"+tag+" " toot = post.body + "\n" + hashtags mastodon.toot(toot)
def get_usercontext(request): if is_logged_in(request): try: client = Client.objects.get( api_base_id=request.session['instance']) user = Account.objects.get(username=request.session['username']) except (Client.DoesNotExist, Client.MultipleObjectsReturned, Account.DoesNotExist, Account.MultipleObjectsReturned): raise NotLoggedInException() mastodon = Mastodon(client_id=client.client_id, client_secret=client.client_secret, access_token=user.access_token, api_base_url=client.api_base_id, ratelimit_method="throw") return user, mastodon else: return None, None
def main(): clientcred_file = BOT_NAME + '_clientcred.secret' usercred_file = BOT_NAME + '_usercred.secret' args = parse_args() if args.register: register(args, clientcred_file, usercred_file) sys.exit(0) mastodon = Mastodon(client_id=clientcred_file, access_token=usercred_file, api_base_url=BASE_URL) instance = mastodon.instance() print('Successfully logged into instance "{0}".'.format(instance.title)) run_bot(mastodon)
def __init__( # pylint: disable=too-many-arguments self, root: Path, config: Config, builders: List[Builder], access_token: str, base_url: str, **kwargs: Any, ): super().__init__(root, config, builders, **kwargs) self.base_url = base_url self.client = Mastodon( access_token=access_token, api_base_url=base_url, )
def handler(event, context): access_token = os.environ.get('MASTODON_ACCESS_TOKEN', '') api_base_url = os.environ.get('MASTODON_BASE_URL', '') if not access_token or not api_base_url: print( 'You must set both a MASTODON_ACCESS_TOKEN and MASTODON_BASE_URL environment variable' ) exit(1) mastodon = Mastodon(access_token=access_token, api_base_url=api_base_url) hour = int( datetime.datetime.now(pytz.timezone('Europe/London')).strftime('%I')) print(str(hour)) photo = mastodon.media_post('images/' + str(hour) + '.jpg') mastodon.status_post(('BONG ' * hour).rstrip(), media_ids=photo)
def register(): os.mkdir(CONFIG_ROOT) Mastodon.create_app( 'fd', api_base_url=BASE_URL, to_file=CLIENT_SECRET, ) mastodon = Mastodon( client_id=CLIENT_SECRET, api_base_url=BASE_URL, ) mastodon.log_in( secureconfig.USERNAME, secureconfig.PASSWORD, to_file=USER_SECRET, ) return mastodon
def recent_artworks(count=7) -> list[tuple[str, str]]: """ Return a list of (post_url, thumbnail_url) tuples for recent public media posts on donphan, with the most popular (most faves) closer to the middle """ CACHE_KEY = "www.codl.fr:4:artworks:{}".format(count) r = get_redis() cached = r.get(CACHE_KEY) if not cached: access_token = app.config.get("DONPHAN_ACCESS_TOKEN") if not access_token: raise NoMastodonAccess() session = requests.Session() session.headers.update({"user-agent": "www.codl.fr"}) m = Mastodon( access_token=access_token, api_base_url="https://donphan.social/", session=session, ) me = m.me() statuses = m.account_statuses(me["id"], only_media=True, exclude_replies=True, limit=40) artworks = list() for status in filter( lambda a: not a["sensitive"] and a["visibility"] == "public", sorted(statuses, key=lambda a: a["favourites_count"], reverse=True), ): artwork = (status["url"], status["media_attachments"][0]["preview_url"]) artworks.append(artwork) artworks = list(reversed(artworks)) if len(artworks) > count: break r.set(CACHE_KEY, pickle.dumps(artworks), ex=3600) else: artworks = pickle.loads(cached) return artworks
def main(): mastodon = Mastodon( client_id="app_key.txt", access_token="user_key.txt", api_base_url = "https://theboss.tech") print('川柳bot稼働中') while True: toot_result = my_time_line.toot_before_hour() if toot_result is None: print('マイトート取得エラー') time.sleep(600) continue if toot_result == True: print('スリープ') time.sleep(600) continue counter_sum = time_line_trend.hour_trend() for word, cnt in counter_sum.most_common(): if toot_word_file.is_toot_word(word): continue result = wiki_senryu.createSenryu(word) if result.errormessage == '': break if len(counter_sum) == 0: print('ローカルタイムライン取得エラー') time.sleep(600) continue toot_text = '川柳投稿テスト' + '\n' toot_text += 'Wikipediaより「' + result.word + '」で一句' + '\n' toot_text += requests.get(result.url).url + '\n' toot_text += result.url + '\n' toot_text += result.senryu + '\n' toot_text += result.furigana + '\n' toot_word_file.write_word(word) print(toot_text) mastodon.toot(toot_text)
def get_api() -> Mastodon: try: api = Mastodon( client_id = AUTH_CLIENT_ID, client_secret = AUTH_CLIENT_SECRET, access_token = AUTH_ACCESS_TOKEN, api_base_url = BASE_URL, ) except Exception as ex: log.critical( 'Error getting the Mastodon API. The service will be stopped.\n' f'{" Details ".center(80, "=")}\n{ex}\n' f'{"="*80}' ) sys.exit(1) else: return api
def main(): config_file = get_config_file() if not os.path.isfile(config_file): setup(config_file) config = read_config(config_file) masto = Mastodon(api_base_url=config['url'], client_id=config['client_id'], client_secret=config['client_secret'], access_token=config['access_token']) for feed in config['feeds']: for entry in get_feed(feed['url'], config['updated']): masto.status_post(feed['template'].format(**entry)[0:49999999999]) save_config(config, config_file)
def __init__(self): self.__initialize_environment_variables() self.listener = Listener() try: Mastodon.create_app(self.client_name, to_file='clientcred.secret') self.mastodon = Mastodon(client_id='clientcred.secret') self.mastodon.log_in(self.email, self.password, to_file='usercred.secret') except Exception as e: raise print self.mastodon.public_stream(self.listener).next()
def setup(config_file): url = input('What is your Mastodon Instance URL? ') have_app = yes_no('Do you have your app credentials already?') if have_app: name = 'feediverse' client_id = input('What is your app\'s client id: ') client_secret = input('What is your client secret: ') access_token = input('access_token: ') else: print("Ok, I'll need a few things in order to get your access token") name = input('app name (e.g. feediverse): ') client_id, client_secret = Mastodon.create_app( api_base_url=url, client_name=name, #scopes=['read', 'write'], website='https://github.com/edsu/feediverse') username = input('mastodon username (email): ') password = input('mastodon password (not stored): ') m = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=url) access_token = m.log_in(username, password) feed_url = input('RSS/Atom feed URL to watch: ') old_posts = yes_no('Shall already existing entries be tooted, too?') config = { 'name': name, 'url': url, 'client_id': client_id, 'client_secret': client_secret, 'access_token': access_token, 'feeds': [{ 'url': feed_url, 'template': '{title} {url}' }] } if not old_posts: config['updated'] = datetime.now(tz=timezone.utc).isoformat() save_config(config, config_file) print("") print("Your feediverse configuration has been saved to {}".format( config_file)) print("Add a line line this to your crontab to check every 15 minutes:") print("*/15 * * * * /usr/local/bin/feediverse") print("")
def toot(): img = request.args.get('img') text = request.form['maintext'] vsbl = request.form['visibility'] mstdn = Mastodon(client_id=session['client_id'], client_secret=session['client_secret'], access_token=session['access_token'], api_base_url=session['uri']) path = "./static/out/" + img + ".png" media_files = [mstdn.media_post(media, "image/png") for media in [path]] status = mstdn.status_post(status=text, media_ids=media_files, visibility=vsbl) url = status['url'] return render_template('toot.html', toot_url=url, status="logout", site_url=app.config['SITE_URL'])
def main(config, callback, data_dir, exclude_user, timeline): cfg = json.load(open(config)) while (True): try: Streamer(config=config, client=Mastodon( access_token=cfg["mastodon_token"], api_base_url=cfg["mastodon_instance"], ), callback=callback, exclude_user=exclude_user, data_dir=data_dir).process(timeline=timeline) except Exception as e: print(str(e)) time.sleep(10)
def get_mastodon(request): if not (request.session.has_key('instance') and request.session.has_key('username')): raise NotLoggedInException() try: client = Client.objects.get(api_base_id=request.session['instance']) user = Account.objects.get(username=request.session['username']) except (Client.DoesNotExist, Client.MultipleObjectsReturned, Account.DoesNotExist, Account.MultipleObjectsReturned): raise NotLoggedInException() mastodon = Mastodon(client_id=client.client_id, client_secret=client.client_secret, access_token=user.access_token, api_base_url=client.api_base_id, ratelimit_method="pace") return mastodon
def push(id): c = mysql.connection.cursor() c.execute("SELECT client_id, client_secret, secret FROM credentials WHERE id = (SELECT credentials_id FROM bots WHERE handle = %s)", (id,)) login = c.fetchone() client = Mastodon( client_id = login[0], client_secret = login[1], access_token = login[2], api_base_url = "https://{}".format(id.split("@")[2]) ) c.execute("SELECT push_private_key, push_secret, replies_enabled FROM bots WHERE handle = %s", (id,)) bot = c.fetchone() if not bot[2]: return "Replies disabled." params = { 'privkey': int(bot[0].rstrip("\0")), 'auth': bot[1] } push_object = client.push_subscription_decrypt_push(request.data, params, request.headers['Encryption'], request.headers['Crypto-Key']) notification = client.notifications(id = push_object['notification_id']) me = client.account_verify_credentials()['id'] # first, check how many times the bot has posted in this thread. # if it's over 15, don't reply. # this is to stop endless reply chains between two bots. try: context = client.status_context(notification['status']['id']) my_posts = 0 for post in context['ancestors']: if post['account']['id'] == me: my_posts += 1 if my_posts >= 15: # don't reply return "Didn't reply." except: # failed to fetch context # assume we haven't been participating in this thread pass functions.make_post([id, notification['status']['id'], notification['status']['visibility'], "@" + notification['account']['acct']]) return "Success!"
def set_inbox_auth(): code = request.args.get('code') autoSend = request.args.get('autoSend') secr = request.args.get('secr') #print(code,autoSend, secr) if secr and not re.match('[a-z]{0,16}', secr): abort(422) client = Mastodon(client_id=CLIENT_ID, client_secret=CLIENT_SEC, api_base_url='https://' + DOMAIN) token = client.log_in( code=code, redirect_uri= f"{REDIRECT_URI}?autoSend={autoSend or ''}&secr={secr or ''}", scopes=['read:accounts', 'write:statuses'] if autoSend else ['read:accounts']) info = client.account_verify_credentials() acct = info.acct u = User.query.filter_by(acct=acct).first() if not u: u = User(acct) db.session.add(u) u.secr = secr or u.secr or ''.join( random.choice(string.ascii_lowercase) for i in range(16)) u.disp = info.display_name u.url = info.url u.avat = info.avatar if autoSend: client.status_post( f"[自动发送] 我创建了一个匿名提问箱,欢迎提问~\n{WORK_URL}/askMe/{acct}/{u.secr}", visibility='public') db.session.commit() return redirect(f"/askMe/{acct}/{u.secr}")
def fetchTimeline(app_data, maxId, minId=0, maxToots=1000, mastodonInstance=None): if mastodonInstance is None: mastodonInstance = Mastodon(client_id=app_data["username"], client_secret=app_data["password"], access_token=app_data["name"] + "_usercred.secret", api_base_url=app_data["base_url"] ) toots = [] try: last_earliest_id = maxId toots += mastodonInstance.timeline_local(max_id=last_earliest_id, limit=40) while len(toots) > 0 and len(toots) < maxToots and toots[-1]["id"] < last_earliest_id and toots[-1]["id"] > minId: last_earliest_id = toots[-1]["id"] toots += mastodonInstance.timeline_local(max_id=last_earliest_id, limit=40) except: pass return toots
def main(): ''' メインルーチン ''' # Mastodon初期化 mastodon = Mastodon(client_id=CID_FILE, access_token=TOKEN_FILE, api_base_url=URL) # 対象アカウントのユーザーIDを取得する。 user_list = mastodon.account_search(USERNAME, limit=1) user_id = user_list[0]['id'] # 対象アカウントの最新トゥート10件を取得する user_toots = mastodon.account_statuses(user_id, limit=1) # トゥートのアプリ名があれば表示する if user_toots[0]['reblog'] is None: print(check_appname(user_toots[0])) # 通常のトゥートの場合 else: print(check_appname(user_toots[0]['reblog'])) # ブーストされたトゥートの場合
def bottoot(): ''' 更新されたニュースをトゥートする ''' try: # アクセスするインスタンスとアカウントを指定 mastodon = Mastodon(access_token=os.getenv("ACCESS_TOKEN"), client_id=os.getenv("CLIENT_ID"), client_secret=os.getenv("CLIENT_SECRET"), api_base_url=os.getenv("MSTDN_URL")) # データベースのセッション生成 Session = sessionmaker(bind=engine) session = Session() # NewsListテーブルの投稿されていないものをトゥートする newslists = session.query(NewsList).filter_by(isnew=True).all() for newslist in newslists: # トゥートする mastodon.status_post( # 未収載 visibility = 'unlisted', # 非公開 visibility='private', # 隠すテキスト spoiler_text = '最新のニュース', status = newslist.title + "\n" \ + "https://shadowverse.jp" + newslist.url + "\n\n" \ + '#OfficialNews' ) # 投稿したのでチェックを外す newslist.isnew = False # それを反映させる session.add(newslist) # 連続投稿にならないように1秒休ませる sleep(1) # コミット(データ追加を実行) session.commit() except: # エラー内容の出力 sys.stderr.write(traceback.format_exc()) finally: session.close()
def parse(self, response): # Mastodon token and domain mastodon = Mastodon( access_token = "asdf", api_base_url = "https://domain.com/" ) string = self.title.strip() + " by " + self.poet.strip() + "\n\n" imported = response.css('.poem-content::text') text = imported.getall() string += text[0].strip() + "\n" for i in range(1, len(string)): if(len(string) < 450 and text[i] != "\n" and text[i] != "\n\n" and text[i] != "\n\n\n" and text[i] != "I\n" and text[i] != "II\n" and text[i] != "*\n"): string += text[i].strip() + "\n" mastodon.status_post(string)
def login(instance, client_id, client_secret): """ Login to a Mastodon instance. Returns a valid Mastodon token if success, likely raises a Mastodon exception otherwise. """ # temporary object to aquire the token mastodon = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url="https://" + instance) print("Click the link to authorize login.") print(mastodon.auth_request_url()) print() code = input("Enter the code you received >") return mastodon.log_in(code=code)
def login(): """Log in to the Mastodon instance and store creds into a file. Once the credentials are stored in a file you do not need to connect again, the file will be used. """ print("Creating Mastodon connection…") mastodon = Mastodon(client_id = settings.CLIENT_CREDS_FILE, api_base_url = settings.API_BASE_URL) password = input("Enter password for {} Mastodon account: ".format(settings.EMAIL)) print("Logging in to Mastodon instance with account {} and password {}…".format(settings.EMAIL, password)) print(mastodon.log_in( settings.EMAIL, password, to_file = settings.USER_CREDS_FILE, ))
def do_post_mastodon(tweet_text, image_file, image_mime_type): if not DO_MASTODON: return '' api = Mastodon(client_secret=CLIENT_SECRET, access_token=ACCESS_TOKEN, api_base_url='https://mastodon.cloud') with open(image_file, 'rb') as f: content = f.read(-1) media_id = 0 post_result = api.media_post(media_file=content, mime_type=image_mime_type, description=tweet_text) media_id = int(post_result['id']) if media_id != 0: status = api.status_post(status=tweet_text, media_ids=media_id) else: status = api.status_post(status=tweet_text) return "Tooted: \"{0}\"\n".format(tweet_text)
def main(argv): # init mastodon from mastodon import Mastodon usercred = {} try: with open('usercred.secret', 'r') as f: usercred = json.load(f) except: print("No usercred.secret file found") exit() mastodon = Mastodon( # replace values/files with your own client_id='clientcred.secret', access_token=usercred['token'], api_base_url=usercred['url'] ) try: opts, args = getopt.getopt(argv, "trpslc", ["toot", "reply", "print", "scrape", "loop", "clear"]) except getopt.GetoptError: usage() sys.exit(2) for opt, arg in opts: if opt in ('-t', '--toot'): toot(mastodon) elif opt in ('-r', '--reply'): reply(mastodon) elif opt in ('-p', '--print'): console() elif opt in ('-s', '--scrape'): scrape(mastodon) elif opt in ('-l', '--loop'): while 1: cur_time = floor(time.time()) i = 0 while floor(time.time()) - cur_time <= 1800: reply(mastodon) time.sleep(10) toot(mastodon) scrape(mastodon) elif opt in ('-c', '--clear'): mastodon.notifications_clear()
def update_icon(bot): try: db = MySQLdb.connect(host=cfg['db_host'], user=cfg['db_user'], passwd=cfg['db_pass'], db=cfg['db_name'], use_unicode=True, charset="utf8mb4") except: print("Failed to connect to database.") return url = "https://{}".format(bot['handle'].split("@")[2]) try: r = requests.head(url, timeout=10, allow_redirects=True) if r.status_code != 200: raise except: print("{} is down - can't update icon for {}.".format( url, bot['handle'])) return client = Mastodon(client_id=bot['client_id'], client_secret=bot['client_secret'], access_token=bot['secret'], api_base_url=url) c = db.cursor() try: avatar = client.account_verify_credentials()['avatar'] except: c.execute( "UPDATE bots SET icon_update_time = CURRENT_TIMESTAMP() WHERE handle = %s", (bot['handle'], )) db.commit() c.close() return c.execute( "UPDATE bots SET icon = %s, icon_update_time = CURRENT_TIMESTAMP() WHERE handle = %s", (avatar, bot['handle'])) db.commit() c.close()
def send_toot(MASTODON_ACCESS_TOKEN, MASTODON_API_BASE_URL, text, filenames): try: mastodon = Mastodon(access_token=MASTODON_ACCESS_TOKEN, api_base_url=MASTODON_API_BASE_URL) #mastodon.toot(text) #media1 = mastodon.media_post("space_status.jpg", "image/jpeg", description="jpg") #media2 = mastodon.media_post("space_status.png", "image/png", description="png") #[media1, media2] media = [] for i in range(len(filenames)): media.append( mastodon.media_post(filenames[i], "image/png", description="png")) mastodon.status_post(text, media_ids=media) except: print("not send")