Ejemplo n.º 1
0
Archivo: akari.py Proyecto: wodim/akari
def akari_publish(text, **kwargs):
    from twitter import twitter

    akari = Akari(text, **kwargs)
    if cfg('twitter:text_in_status:bool'):
        twitter.post(status=akari.caption, media=akari.filename)
    else:
        twitter.post(media=akari.filename)
Ejemplo n.º 2
0
def unupdate(id):
    resp = twitter.post('statuses/destroy/%d.json' % id)

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully deleted your new tweet')

    return redirect(url_for('show_index'))
Ejemplo n.º 3
0
def unupdate(id):
    resp = twitter.post('statuses/destroy/%d.json' % id)

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully deleted your new tweet')

    return redirect(url_for('show_index'))
Ejemplo n.º 4
0
def delete():
    if g.user is None:
        return redirect(url_for("login", next=request.url))
    ids = request.form.getlist("tweet_id")
    if not ids:
        return redirect(url_for("index"))
    for tweet_id in ids:
        resp = twitter.post("statuses/destroy/{0}.json".format(tweet_id))
        if resp.status != 200:
            flash("There was an error deleting tweet!")
    return render_template("delete.html")
Ejemplo n.º 5
0
def unblock(id):
    resp = twitter.post('blocks/destroy.json', data={'user_id': id})

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully unblocked.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 6
0
def follow(id):
    resp = twitter.post('friendships/create.json', data={'user_id': id})

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully followed, or your request has been sent.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 7
0
def favorite(id):
    resp = twitter.post('favorites/create.json', data={'id': id})

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully favorited.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 8
0
def retweet(id):
    resp = twitter.post('statuses/retweet/%d.json' % id)

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully retweeted.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 9
0
def unfavorite(id):
    resp = twitter.post('favorites/destroy.json', data={'id': id})

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully unfavorited.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 10
0
def retweet(id):
    resp = twitter.post('statuses/retweet/%d.json' % id)

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully retweeted.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 11
0
def update():
    resp = twitter.post('statuses/update.json', data={
        'status': request.form['status'],
        'in_reply_to_status_id': request.form['in_reply_to']
    })

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        flash('Successfully tweeted your new status')

    return redirect(url_for('show_index'))
Ejemplo n.º 12
0
def unretweet(id):
    resp = twitter.get('statuses/show/%d.json?include_my_retweet=1' % id)

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        retweet_id = resp.data['current_user_retweet']['id']
        resp = twitter.post('statuses/destroy/%d.json' % retweet_id)
        if resp.status == 200:
            flash('Successfully unretweeted.')
        else:
            flash('Unretweet failed.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 13
0
def unretweet(id):
    resp = twitter.get('statuses/show/%d.json?include_my_retweet=1' % id)

    if resp.status == 401:
        session.pop('twitter_token')
        flash('Unauthorized account access.')
        return redirect(url_for('show_index'))

    if resp.status != 200:
        for error in resp.data['errors']:
            flash(error['message'])
    else:
        retweet_id = resp.data['current_user_retweet']['id']
        resp = twitter.post('statuses/destroy/%d.json' % retweet_id)
        if resp.status == 200:
            flash('Successfully unretweeted.')
        else:
            flash('Unretweet failed.')

    return redirect(request.referrer or url_for('show_index'))
Ejemplo n.º 14
0
Archivo: akari.py Proyecto: wodim/akari
def akari_cron():
    Akari.warmup()

    # if there's an override, try to post it, but if it fails, continue
    # normally.
    try:
        cron_override = cfg('twitter:cron_override')
        if cron_override and akari_cron_override(cron_override):
            return
    except Exception:
        pass

    from twitter import twitter

    ids = []
    # get a random line. will error out if there are none, which is okay.
    with open('pending.txt', errors='replace') as file:
        for line in file.read().splitlines():
            id_, text = line.split(' ', 1)

            # if the blacklist is enabled, ignore tweets that match it
            blacklist = cfg('twitter:text_blacklist:re_list')
            if any(x.search(text) for x in blacklist):
                continue

            # alright, this tweet is a candidate
            ids.append(id_)

    # this function generates a score for each tweet
    def score(status):
        favs = status.favorite_count
        rts = status.retweet_count
        followers = status.user.followers_count
        if (followers == 0 or  # avoid division by zero later on
                status.user.protected):  # don't post from protected users
            return -1

        # decay coefficient. promotes newer tweets to compensate for the
        # lower amount of favs they have received (fewer people have seen
        # them, in theory)
        diff = (datetime.utcnow() - status.created_at).total_seconds()
        score = utils.decay(diff, cfg('twitter:cron_interval:int') * 60, 1.5)
        score *= (favs + rts * 2) / followers

        # apply penalties. some tweets carry a penalty but are not removed
        # right away, in case there isn't anything better.
        # at least 80% of letters in the status must be /a-zA-Z/
        clean_text = utils.clean(status.text,
                                 urls=True, replies=True, rts=True)
        meat = sum(c in string.ascii_letters for c in clean_text) or -1
        # also, get the author's lang and filter him if it's not in the wl
        lang_wl = cfg('twitter:cron_lang_whitelist:list')
        # filter quoted tweets
        filter_quotes = cfg('twitter:cron_filter_quotes:bool')
        if ((lang_wl and status.user.lang not in lang_wl) or
                (filter_quotes and status.is_quote_status) or
                meat / len(clean_text) < 0.8 or
                followers < (followers_median * 1.5) or
                favs < favs_median):
            score /= 10

        return score

    # 100 at a time is the max statuses_lookup() can do.
    statuses = []
    for i in range(0, len(ids), 100):
        group = ids[i:i + 100]
        statuses.extend(tuple(twitter.api.statuses_lookup(group)))
    followers_median = statistics.median(status.user.followers_count
                                         for status in statuses)
    favs_median = statistics.median(status.favorite_count
                                    for status in statuses
                                    if status.favorite_count > 0)
    statuses.sort(key=score, reverse=True)

    # try to generate an image for the first status. if that fails, keep
    # trying with the next one until you have succeeded or until you have
    # run out of attempts.
    for status in statuses[:10]:
        try:
            caption = utils.clean(status.text,
                                  urls=True, replies=True, rts=True)
            utils.logger.info('Posting "%s" from %s',
                              caption, twitter.status_to_url(status))
            akari = Akari(caption, type='animation', shuffle_results=False)
            break
        except Exception:
            utils.logger.exception('Error generating a caption.')
            continue

    # this will crash it there's no caption available thus far, that's fine,
    # as the amount of tries has been exceeded and there was nothing left to do
    # anyway.
    if cfg('twitter:text_in_status:bool'):
        twitter.post(status=akari.caption, media=akari.filename)
    else:
        twitter.post(media=akari.filename)

    # if a new caption has been successfully published, empty the file
    with open('pending.txt', 'w'):
        pass
Ejemplo n.º 15
0
def process_request(queue):
    request_blacklist = cfg('twitter:request_blacklist:re_list')
    user_images = cfg('twitter:user_images:bool')
    delete_triggers = cfg('twitter:delete_triggers:re_list')
    load_avg_still = cfg('twitter:load_avg_still:int')
    no_results_image = cfg('twitter:no_results_image')
    error_image = cfg('twitter:error_image')

    def process_self_delete(status):
        if not status.in_reply_to_status_id:
            utils.logger.warning('This status has no "in reply to" field.')
            return False

        try:
            status_del = twitter.api.get_status(status.in_reply_to_status_id)
        except tweepy.error.TweepError:
            utils.logger.exception('Failed to get the status pointed by '
                                   'the "in reply to" field.')
            return False

        if not status_del.text.startswith('@%s ' % status.user.screen_name):
            utils.logger.warning('The status pointed by the "in reply to" '
                                 "wasn't in reply to a status made by the "
                                 'user who requested the removal.')
            return False

        try:
            twitter.api.destroy_status(status_del.id)
        except tweepy.error.TweepError:
            utils.logger.exception('Failed to remove the status pointed by '
                                   'the "in reply to" field.')
            return False
        else:
            utils.logger.info('Deleted: %d "%s"', status_del.id,
                              status_del.text)
            return True

    while True:
        status = queue.get()
        print_status(status)

        text = utils.clean(status.text, urls=True, replies=True, rts=True)

        # see if the text in this request is blacklisted. if so do nothing.
        if (request_blacklist
                and any(x.search(text) for x in request_blacklist)):
            utils.logger.warning('Text is blacklisted, request ignored')
            queue.task_done()
            continue

        # see if there's an image (and if that's allowed)
        image_url = None
        try:
            if user_images:
                image_url = status.entities['media'][0]['media_url'] + ':orig'
        except KeyError:
            pass

        # if there's a user-provided image but there's no text and we are
        # generating still images, don't do anything at all (in this case,
        # we would just copy the image around without doing anything useful)
        if image_url and not text and len(cache.get('akari:frames')) < 2:
            utils.logger.warning('Refusing to generate a still image from a '
                                 'still image')
            queue.task_done()
            continue

        # if after being cleaned up the status turns out to be empty and
        # there's no image, return
        if not text and not image_url:
            utils.logger.info('No text and no image. Nothing to do.')
            queue.task_done()
            continue

        if (delete_triggers and any(x.search(text) for x in delete_triggers)):
            if process_self_delete(status):
                queue.task_done()
                continue
        # if removal is not successful, we will generate a caption.

        # apply a strict ratelimit to people with fewer than 25 followers
        rate_limit_slow = utils.ratelimit_hit('twitter', 'global_slow', 5, 60)
        if (status.author.followers_count < 25
                and not rate_limit_slow['allowed']):
            utils.logger.info('%d - Ignoring because of low follower count',
                              status.id)
            queue.task_done()
            continue

        # apply a lax ratelimit to the rest of users
        rate_limit = utils.ratelimit_hit('twitter', 'global', 20, 60)
        if not rate_limit['allowed']:
            utils.logger.info('%d - Ignoring because of ratelimit', status.id)
            queue.task_done()
            continue

        # so we'll generate something for this guy...

        # follow the user if he's new. if he does not follow back, he'll
        # be unfollowed by followers.unfollow_my_unfollowers sometime later.
        if is_eligible(status.author):
            try:
                twitter.api.create_friendship(status.author.screen_name)
            except tweepy.error.TweepError:
                pass

        # if the one-minute load avg is greater than load_avg_still, generate
        # still captions
        try:
            load_avg = os.getloadavg()[0]
            if load_avg_still and load_avg > load_avg_still:
                utils.logger.warning('Load average too high! (%i > %i)',
                                     load_avg, load_avg_still)
                akari_type = 'still'
            else:
                akari_type = 'animation'
        except KeyError:
            pass

        error = False
        try:
            akari = Akari(text,
                          type=akari_type,
                          shuffle_results=True,
                          image_url=image_url)
            text = akari.caption
            image = akari.filename
        except ImageSearchNoResultsError:
            utils.logger.exception('No results')
            msgs = ('I found nothing.', 'No results.',
                    "I didn't find anything.", 'There are no results.')
            text = random.choice(msgs)
            image = no_results_image
            error = True
        except KeyboardInterrupt:
            raise
        except Exception:
            utils.logger.exception('Error composing the image')
            msgs = ("Can't hear ya...", "Ooops, I'm busy at the moment.",
                    "I don't feel so well right now.", 'Sorry, I fell asleep.')
            text = '%s Try again a bit later.' % random.choice(msgs)
            image = error_image
            error = True

        # start building a reply. prepend @nick of whoever we are replying to
        if cfg('twitter:text_in_status:bool') or error:
            reply = '@%s %s' % (status.author.screen_name, text)
        else:
            reply = '@%s' % (status.author.screen_name)

        # post it
        try:
            twitter.post(status=reply,
                         media=image,
                         in_reply_to_status_id=status.id)
        except KeyboardInterrupt:
            raise
        except tweepy.error.TweepError as exc:
            utils.logger.exception('Error posting.')
            if exc.api_code == 326:  # account temporarily locked
                twitter.handle_exception(exc)
        except Exception:
            utils.logger.exception('Error posting.')

        queue.task_done()