├── .gitignore ├── LICENSE ├── README.md ├── config.ini ├── cron.in ├── like_my_gf.py └── like_my_gf.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | bin/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # Installer logs 26 | pip-log.txt 27 | pip-delete-this-directory.txt 28 | 29 | # Unit test / coverage reports 30 | htmlcov/ 31 | .tox/ 32 | .coverage 33 | .cache 34 | nosetests.xml 35 | coverage.xml 36 | 37 | # Translations 38 | *.mo 39 | 40 | # Mr Developer 41 | .mr.developer.cfg 42 | .project 43 | .pydevproject 44 | 45 | # Rope 46 | .ropeproject 47 | 48 | # Django stuff: 49 | *.log 50 | *.pot 51 | 52 | # Sphinx documentation 53 | docs/_build/ 54 | 55 | config 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Yan Cao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Like-My-GF 2 | This is an auto-robot to like my girlfriend's post on Instagram. 3 | 4 | ## Why This? 5 | My girlfriend always complains that I don't care about what she's doing, I don't like her post on Instagram / Wechat / Weibo... and I don't comment on her posts, bla bla bla. 6 | 7 | Being a programmer, I don't really have much ~~interest~~ time to review every social network. So I build this. Although now she knows that I'm using this to like her post. But she's pretty happy about it (don't ask me why) and never complained again. So I'm very happy with this tool. 8 | 9 | ## Requires 10 | * httplib2 11 | * simplejson 12 | * [python-instagram](https://github.com/Instagram/python-instagram) 13 | 14 | All of these can be installed from pip install 15 | 16 | ## Configurations 17 | * Copy the config.ini to config, fill in your Instagram API info 18 | * Setup Target name and path etc... 19 | * Test run, first time run will like about 20 (Instagram's max paginate num of posts), so be aware that the target might think you are crazy. 20 | * Setup the cron, I'm running it every 2 min. 21 | 22 | ## To do 23 | 1. Setup email alert everytime robot found a new post, include the photo in the email. 24 | 2. Support more social media. Weibo, Wechat, Facebook...(This gonna be endless) 25 | 3. Maybe if anyone else want to use this, I can setup a web api and allow others to register their target. I can setup an engine to do it. 26 | 27 | ## Note 28 | As I used to work on Instagram teams, it wasn't really in my interest to update this repo anymore because the little convinience that I offer might be abused by spammers and hurt more people, (plus add more work on me and my teammates 😜). 29 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [Client] 2 | client_id = 663798b919084fc7ac8c3e905e0b4381 3 | client_secret = 99f30eab3bd148a39345f9b2d2ff8971 4 | redirect_uri = http://yancao.me 5 | 6 | [Target] 7 | username = pmpmpmpm13 8 | 9 | [Access Token] 10 | access_token = None 11 | 12 | [Path] 13 | log_path = /home/yanc/Dropbox/log/ 14 | -------------------------------------------------------------------------------- /cron.in: -------------------------------------------------------------------------------- 1 | */2 * * * * /home/yanc/Documents/Like-My-GF/like_my_gf.sh 2 | -------------------------------------------------------------------------------- /like_my_gf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from instagram.client import InstagramAPI 4 | from ConfigParser import SafeConfigParser 5 | import argparse 6 | import datetime 7 | import logging 8 | 9 | config_parser = SafeConfigParser() 10 | config_parser.read('config') 11 | 12 | arg_parser = argparse.ArgumentParser(description='Auto-like my GF\'s Instagram') 13 | arg_parser.add_argument('-v', '--verbose', action='store_true', help='Increase output verbosity') 14 | args = arg_parser.parse_args() 15 | 16 | CONFIG = dict( client_id = config_parser.get('Client', 'client_id'), 17 | client_secret = config_parser.get('Client', 'client_secret'), 18 | redirect_uri = config_parser.get('Client', 'redirect_uri'), 19 | ) 20 | OTHER = dict( scope = ['likes'], 21 | access_token = config_parser.get('Access Token', 'access_token'), 22 | target = config_parser.get('Target', 'username'), 23 | log_path = config_parser.get('Path', 'log_path')+'like_my_gf.log', 24 | ) 25 | 26 | if args.verbose: 27 | logging.basicConfig(filename=OTHER['log_path'], level=logging.DEBUG) 28 | else: 29 | logging.basicConfig(filename=OTHER['log_path'], level=logging.INFO) 30 | 31 | 32 | def get_auth(): 33 | unauth_api = InstagramAPI(**CONFIG) 34 | redirect_uri = unauth_api.get_authorize_login_url(scope = OTHER['scope']) 35 | 36 | print "Visit this page and authorize access in your browser:\n", redirect_uri 37 | code = raw_input('Please type in the access code you got\n') 38 | OTHER['access_token'], me = unauth_api.exchange_code_for_access_token(code) 39 | 40 | with open('config', 'w') as cf: 41 | config_parser.set('Access Token', 'access_token', OTHER['access_token']) 42 | config_parser.write(cf) 43 | 44 | def auth_request(): 45 | api = InstagramAPI(access_token=OTHER['access_token']) 46 | target_ids = api.user_search(OTHER['target']) 47 | 48 | target_id = None 49 | for search_hit in target_ids: 50 | if search_hit.username == OTHER['target']: 51 | target_id = search_hit.id 52 | break 53 | 54 | if target_id == None: 55 | logging.error('Did not find user, please check username') 56 | return [] 57 | 58 | my_name = api.user().username 59 | logging.debug('Starting check recent media') 60 | recent_media, url = api.user_recent_media(user_id=target_id, count = 20) 61 | liked_media = [] 62 | for media in recent_media: 63 | logging.debug('Processing media %s' % media.id) 64 | users = api.media_likes(media.id) 65 | will_like = True 66 | for user in users: 67 | if user.username == my_name: 68 | will_like = False 69 | break 70 | if will_like: 71 | logging.debug('Liking media %s' % media.id) 72 | api.like_media(media.id) 73 | liked_media.append(media) 74 | else: 75 | logging.debug('Already liked media %s, aborting like' % media.id) 76 | 77 | return liked_media 78 | 79 | if __name__ == '__main__': 80 | if OTHER['access_token'] == 'None': # Not mistake, but default token is 'None' but not None 81 | get_auth() 82 | liked_media = auth_request() 83 | if len(liked_media) > 0: 84 | logging.info('-'*10+str(datetime.datetime.now())+'-'*10) 85 | logging.info('-'*10+'Liked '+str(len(liked_media))+' medias'+'-'*10) 86 | 87 | # TODO 88 | # 1. Send email 89 | -------------------------------------------------------------------------------- /like_my_gf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | APPDIR=$HOME/src/git/ 4 | export PYTHONPATH=$APPDIR/Like-My-GF:$APPDIR 5 | 6 | cd $APPDIR/Like-My-GF 7 | ./like_my_gf.py 8 | --------------------------------------------------------------------------------