{"id":18341610,"url":"https://github.com/pikesley/replacer_bot","last_synced_at":"2025-04-09T20:50:22.508Z","repository":{"id":36464706,"uuid":"40769947","full_name":"pikesley/replacer_bot","owner":"pikesley","description":"Search, mangle, retweet","archived":false,"fork":false,"pushed_at":"2018-03-10T20:42:11.000Z","size":1025,"stargazers_count":1,"open_issues_count":13,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-15T13:26:13.961Z","etag":null,"topics":["ruby","twitter","twitter-bot"],"latest_commit_sha":null,"homepage":"https://twitter.com/blkchninstitute","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pikesley.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-15T16:11:22.000Z","updated_at":"2019-08-18T21:05:52.000Z","dependencies_parsed_at":"2022-08-24T14:25:25.490Z","dependency_job_id":null,"html_url":"https://github.com/pikesley/replacer_bot","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pikesley%2Freplacer_bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pikesley%2Freplacer_bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pikesley%2Freplacer_bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pikesley%2Freplacer_bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pikesley","download_url":"https://codeload.github.com/pikesley/replacer_bot/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248111936,"owners_count":21049576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby","twitter","twitter-bot"],"created_at":"2024-11-05T20:27:56.675Z","updated_at":"2025-04-09T20:50:22.468Z","avatar_url":"https://github.com/pikesley.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](http://img.shields.io/travis/pikesley/replacer_bot.svg)](https://travis-ci.org/pikesley/replacer_bot)\n[![Dependency Status](http://img.shields.io/gemnasium/pikesley/replacer_bot.svg)](https://gemnasium.com/pikesley/replacer_bot)\n[![Coverage Status](http://img.shields.io/coveralls/pikesley/replacer_bot.svg)](https://coveralls.io/r/pikesley/replacer_bot)\n[![Code Climate](http://img.shields.io/codeclimate/github/pikesley/replacer_bot.svg)](https://codeclimate.com/github/pikesley/replacer_bot)\n[![Gem Version](http://img.shields.io/gem/v/replacer_bot.svg)](https://rubygems.org/gems/replacer_bot)\n[![License](http://img.shields.io/:license-mit-blue.svg)](http://pikesley.mit-license.org)\n[![Badges](http://img.shields.io/:badges-7/7-ff6799.svg)](https://github.com/badges/badgerbadgerbadger)\n\n# Replacer Bot\n\nTwitter bot that:\n\n* Searches Twitter for a phrase\n* Search-and-replaces phrases in the tweets\n* Tweets them\n* Makes a note of the last tweet found so it knows where to start from next time\n\n## Installation\n\n    gem install replacer_bot\n\nor\n\n    git clone https://github.com/pikesley/replacer_bot\n    cd replacer_bot\n    bundle\n    rake install\n\n## Configuration\n\nThe default config is [here](https://github.com/pikesley/replacer_bot/blob/master/config/defaults.yml), you'll want to create your own config at `~/.replacer_bot/config.yml` to override some of these, something like:\n\n    search_term: David Cameron\n    replacements:\n      - david cameron: \"Satan's Little Helper\"\n      - cameron: Satan\n    save_file: /Users/sam/.replacer_bot/last.tweet\n    seen_tweets: /Users/sam/.replacer_bot/seen.tweets\n\nNotes:\n\n* The search-and-replace terms will be applied in the order listed, which you may or may not care about\n* The search and replace has a number of passes based on some of my finger-in-the-air Reckons, which are probably easiest to understand via the [specs](https://github.com/pikesley/replacer_bot/blob/master/spec/lib/replacer_bot/case_spec.rb). After it tries each of these search-and-replace operations, it does a case-insensitive regex search-and-replace using the raw terms from the YAML (in order to catch SHittily-typeD things, because Twitter is a mess)\n* Your takeaway from this should be that if your replacement is a name or whatever, put it in the YAML Titlecased, otherwise lowercase it, and it should do the Right Thing\n\n### Twitter credentials\n\nYou'll also need some Twitter credentials, store them in `~/.replacer_botrc` like this:\n\n    CONSUMER_KEY: some_key\n    CONSUMER_SECRET: some_secret\n    TOKEN: oauth_token\n    SECRET: oauth_secret\n\n(and see [this](https://github.com/twitter/twurl) for help on setting up Twitter bots)\n\n## Running it\n\nYou should now be able to run it like so:\n\n    ➔ replacer tweet\n    Tweeting: Satan's Little Helper sets out academy 'vision' for every school http://t.co/S6yFWRf7pD\n    Sleeping 60 seconds\n    Tweeting: Swarm warning: Satan's Little Helper accuses migrants of 'breaking in' to UK http://t.co/1sB5J8Alwi\n\nNotes:\n\n* Direct replies and manual retweets are excluded\n\nThere's also\n\n    ➔ replacer dry_run\n\nwhich does the search and shows what it would have tweeted, without actually tweeting anything\n\n## Reducing the noise\n\nIt turns out that a lot of Twitter is people (or bots) retweeting the same stuff with minimal changes, like adding extra hashtags or using a different URL shortener (I don't really understand how this even happens, but whatever). (Actually, I wonder how much of Twitter is just bots yelling at each other in the void. But I digress.) This makes a crude 'search for this phrase' bot _extremely_ noisy, so I have come up with some Opinions based on some very crude Reckons. Things that will make the bot consider tweets to be 'the same' as tweets we've seen before, and therefore ignorable, are:\n\n* They match, save for any URLs they contain being different\n* They match, save for different hashtags at the _start_ and _end_ of the tweet (hashtags in the body of the tweet appear to be more relevant, based on my Reckons)\n\nThe above reduced the noise a bit, but not enough to make a substantial difference. So I came up with this:\n\n* If there is an overlap of 4 consecutive words between this tweet and one we've seen before, we ignore it\n\nThe 4 words thing is tunable in `config.yml`:\n\n    similarity_weighting: 4\n\nbut 4 seems about right for my current use case; it will clearly depend on the popularity of your search term\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpikesley%2Freplacer_bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpikesley%2Freplacer_bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpikesley%2Freplacer_bot/lists"}