def main():
    colorama_init()

    parser = ArgumentParser(description=__doc__,
                            formatter_class=RawDescriptionHelpFormatter)
    parser.add_argument('--min-activity',
                        dest='min_activity',
                        type=parse_time_ago,
                        default="1y",
                        help=("Remove followings inactive for a given period"
                              " (m for months, y for years, d for days) "
                              "(default: %(default)s)"))
    parser.add_argument('--target-count',
                        dest='target_count',
                        type=int,
                        help=("Target some following count (will try to stop"
                              " when you have that many followings left)"))
    parser.add_argument('--unfollow',
                        action='store_true',
                        help="Actually unfollow")
    parser.add_argument('--followers',
                        action='store_true',
                        help="Instead of removing people you follow, remove "
                        "people who follow YOU")
    parser.add_argument('--unmutuals',
                        action='store_true',
                        help="Remove people who follow you but that you "
                        "don't follow")
    parser.add_argument('-v',
                        '--verbose',
                        action='store_true',
                        help="Display more things")

    args = parser.parse_args()

    session = requests.Session()

    mastodon = Mastodon(access_token=settings.ACCESS_TOKEN,
                        api_base_url=settings.API_BASE,
                        ratelimit_method='pace')

    current_user = mastodon.account_verify_credentials()
    uid = current_user['id']

    if args.unmutuals:
        args.followers = True

    if args.followers:
        followings_count = current_user['followers_count']
    else:
        followings_count = current_user['following_count']
    local_count = followings_count

    goal_msg = ""
    if args.target_count:
        goal_msg = "(goal: n>={})".format(args.target_count)

    now = datetime.now(tz=timezone.utc)

    def clog(c, s):
        tqdm.write(c + s + Fore.WHITE + Style.NORMAL)

    cprint(Fore.GREEN,
           "Current user: @{} (#{})".format(current_user['username'], uid))
    cprint(
        Fore.GREEN,
        "{}: {} {}".format("Followers" if args.followers else "Followings",
                           followings_count, goal_msg))

    if args.unfollow:
        cprint(Fore.RED, "Action: unfollow")
    else:
        cprint(Fore.YELLOW, "Action: none")

    followings = None
    if args.followers:
        followings = mastodon.account_followers(uid)
    else:
        followings = mastodon.account_following(uid)
    followings = mastodon.fetch_remaining(followings)

    bar = tqdm(list(followings))
    for f in bar:
        fid = f.get('id')
        acct = f.get('acct')
        fullhandle = "@{}".format(acct)

        if '@' in acct:
            inst = acct.split('@', 1)[1].lower()
        else:
            inst = None

        if args.target_count is not None and local_count <= args.target_count:
            clog(Fore.RED + Style.BRIGHT,
                 "{} followings left; stopping".format(local_count))
            break

        title_printed = False

        def title():
            nonlocal title_printed
            if title_printed:
                return
            title_printed = True
            clog(Fore.WHITE + Style.BRIGHT,
                 "Account: {} (#{})".format(f.get('acct'), fid))

        if args.verbose:
            title()
        try:
            bar.set_description(fullhandle.ljust(30, ' '))

            act = False

            if args.unmutuals and inst not in settings.SKIP_INSTANCES:
                try:
                    relations = mastodon.account_relationships(fid)
                    is_mutual = relations[0]["following"] or relations[0][
                        "requested"]

                    if not is_mutual:
                        clog(Fore.YELLOW, "- Unmutual ({})".format(relations))
                        act = True
                except (UserGone, Error, requests.RequestException) as e:
                    act = False
                    clog(Fore.YELLOW, "- Exception ({})".format(e))

            elif args.min_activity and inst not in settings.SKIP_INSTANCES:
                try:
                    last_toot = get_last_toot(mastodon, fid)
                    if last_toot < now - args.min_activity:
                        # force a cache miss to be Sure
                        last_toot = get_last_toot(mastodon, fid, force=True)

                    if last_toot < now - args.min_activity:
                        act = True
                        msg = "(!)"
                        title()
                        clog(Fore.WHITE,
                             "- Last toot: {} {}".format(last_toot, msg))
                    else:
                        msg = "(pass)"
                        if args.verbose:
                            clog(Fore.WHITE,
                                 "- Last toot: {} {}".format(last_toot, msg))
                except UserGone as e:
                    moved = f.get('moved')
                    if moved:
                        # TODO: follow new account and unfollow old
                        act = False
                        title()
                        clog(
                            Fore.YELLOW,
                            "- User moved ({}) [NOT IMPLEMENTED]".format(
                                moved))
                    else:
                        act = True
                        title()
                        clog(Fore.YELLOW, "- User gone ({})".format(e))
                except (Error, requests.RequestException) as e:
                    if inst and inst in settings.ASSUME_DEAD_INSTANCES:
                        act = True
                        title()
                        clog(Fore.YELLOW, "- Instance gone ({})".format(e))
                    else:
                        raise

            if act:
                local_count -= 1

                if args.unfollow:
                    if args.followers:
                        clog(Fore.GREEN + Style.BRIGHT,
                             "- Removing follower {}".format(fullhandle))
                        mastodon.account_block(fid)
                        mastodon.account_unblock(fid)
                    else:
                        clog(Fore.GREEN + Style.BRIGHT,
                             "- Unfollowing {}".format(fullhandle))
                        mastodon.account_unfollow(fid)
                else:
                    clog(Fore.GREEN + Style.BRIGHT,
                         "- (not) unfollowing {}".format(fullhandle))

                clog(Fore.WHITE, ("- {}/{} followings left".format(
                    local_count, followings_count)))
        except Exception as e:
            title()
            clog(Fore.RED, "- Error: {}".format(str(e)))
Example #2
0
#Client key
key = ""

#Client Secret
secret = ""

#Access Token
token = ""

#Instance
instance = 'https://mastodon.social'

############################

lstBots = []

mastodon = Mastodon(key, secret, token, api_base_url=instance)

tl = mastodon.timeline_local(max_id=None, since_id=None, limit=40)
for loop in range(0, 5):
    if len(tl) > 0:
        for x in range(0, len(tl)):
            if tl[x].account.bot == True and lstBots.count(
                    tl[x].account.username) == 0:
                lstBots.append(tl[x].account.username)
                mastodon.account_block(tl[x].account.id)
    tl = mastodon.fetch_next(tl[len(tl) - 1]._pagination_next)

print("From the last 200 toots I've blocked " + str(len(lstBots)) + " bots!")