Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
b183f3e
changing the image size of snaps re: #5
agermanidis Feb 21, 2015
11502ad
changing setup.py dependency from PIL to Pillow
agermanidis Feb 21, 2015
91e851c
changing setup.py dependency from PIL to Pillow
agermanidis Feb 21, 2015
e36d8f4
Added duration to send_snap() and post_story()
Gnewt Feb 21, 2015
c92e7a3
passing capture_snaps=True to get_snaps() will now save snaps in the …
Feb 22, 2015
599026c
added example for saving snaps
Feb 22, 2015
26970e0
cleaned up branch
Feb 22, 2015
442b76f
cleaned up branch
Feb 22, 2015
67687e1
fixed imports
Feb 22, 2015
1b843ff
Merge branch 'capturesnaps' of github.com:EthanBlackburn/SnapchatBot …
Feb 22, 2015
d44a19d
Merge pull request #7 from Gnewt/master
agermanidis Feb 22, 2015
4d10441
Fixing #12
agermanidis Feb 22, 2015
e8bf47b
fixed indentation issue
agermanidis Feb 22, 2015
86c8729
moved save snap functionality form get_snaps to utils.save_snap()
Feb 22, 2015
ad337f9
removed old code
Feb 22, 2015
919f63a
Merge pull request #9 from EthanBlackburn/capturesnaps
agermanidis Feb 22, 2015
3946b7e
Added Capture bot to Readme
agermanidis Feb 22, 2015
9817a36
readme fix
agermanidis Feb 22, 2015
52b25d0
fixed error that prevented snaps from being saved
Feb 23, 2015
07bc001
Merge pull request #14 from EthanBlackburn/fixSaveImages
agermanidis Feb 23, 2015
3f7cd9c
erge branch 'master' of https://github.com/agermanidis/SnapchatAgent
agermanidis Feb 23, 2015
e21e52c
Update snap.py
agermanidis Feb 23, 2015
0853118
adding quality parameter on im.save re: #5
agermanidis Feb 23, 2015
f437e5e
Merge branch 'master' of https://github.com/agermanidis/SnapchatAgent
agermanidis Feb 23, 2015
be337ae
Update utils.py
N07070 Feb 24, 2015
71112bc
Update utils.py
N07070 Feb 25, 2015
1b36b7c
Merge pull request #20 from N07070/patch-3
agermanidis Feb 25, 2015
f29ff05
Update utils.py
N07070 Feb 26, 2015
200ee11
Merge pull request #21 from N07070/patch-1
agermanidis Feb 26, 2015
f73c6b8
Improved error messaging for login
Feb 28, 2015
0908202
Merge pull request #22 from Samze/master
agermanidis Feb 28, 2015
8f286ca
added delete_story method to SnapchatBot (#17)
agermanidis Mar 3, 2015
74643eb
Merge branch 'master' of https://github.com/agermanidis/SnapchatAgent
agermanidis Mar 3, 2015
030892b
Update README.md
agermanidis Mar 3, 2015
1713bd7
login hotfix
agermanidis Mar 4, 2015
d8aa115
Merge branch 'master' of https://github.com/agermanidis/SnapchatBot
agermanidis Mar 4, 2015
6f0d2ef
login works again re: #26
agermanidis Mar 4, 2015
4c8819c
adding mascot
agermanidis Mar 5, 2015
48febfc
making save a method of Snap instead of a utility function
agermanidis Mar 9, 2015
b2e2b11
Added Snap#open method
agermanidis Mar 9, 2015
1359a3e
Snap#save and Snap#open work properly
agermanidis Mar 9, 2015
08da570
fix #31
agermanidis Mar 9, 2015
aa8a4b6
Added RandoBot
PhlexPlexico Mar 10, 2015
c3bb58c
Forgot splash image.
PhlexPlexico Mar 10, 2015
3697346
Changed .discard to .remove
PhlexPlexico Mar 10, 2015
241e235
Update utils.py
jfach Mar 12, 2015
12528c9
Merge pull request #38 from Jfach/patch-2
agermanidis Mar 12, 2015
8f2d56d
Merge pull request #34 from PhlexPlexico/master
agermanidis Mar 13, 2015
8748ce2
readme fixes
agermanidis Mar 13, 2015
3b3fbd8
Brought back CaptureBot description
agermanidis Mar 13, 2015
56c50c7
Added get_my_stories, get_friend_stories, clear_stories methods
agermanidis Mar 13, 2015
daa139a
Merge branch 'master' of github.com:agermanidis/SnapchatBot
agermanidis Mar 13, 2015
bd014f7
Removing unused method
agermanidis Mar 13, 2015
cb9c078
bringing back process_stories() -- oops
agermanidis Mar 13, 2015
d081a75
Update bot.py
N07070 Mar 14, 2015
e9f745b
Merge pull request #42 from N07070/patch-3
agermanidis Mar 14, 2015
703739e
adds support for zipped videos #18
agermanidis Mar 16, 2015
04ca6c3
fixing merge conflicts
agermanidis Mar 16, 2015
f9b316a
adding mp4 extension so pysnap won't complain #18
agermanidis Mar 16, 2015
c5e1b8f
fix for #45
agermanidis Mar 17, 2015
8783fcf
Fixing #53
agermanidis Mar 23, 2015
e2171cd
Potential fix for #54
krissrex Mar 25, 2015
04fef25
Merge pull request #57 from krissrex/patch-1
agermanidis Mar 25, 2015
862caf2
Update README.md
agermanidis Oct 27, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# SnapchatBot: Python library for building bots that live on Snapchat
<h1 style='color: red'>This repo is deprecated due to changes in Snapchat's unofficial API.</h1>

![SnapchatBot](http://i.imgur.com/s8XADUn.png?1)

# SnapchatBot: A library for making bots that live on Snapchat

Introducing SnapchatBot, an easy way to program Snapchat accounts to do anything you want.
SnapchatBot can be used to easily create image-based notification services, chatbots, search interfaces,
SnapchatBot can be used to create image-based notification services, chatbots, search interfaces,
and any kind of intelligent agent that uses picture messages as its interaction mode.

## Bots Included
Expand All @@ -15,7 +19,13 @@ Sends back everything you send it.
*(source at examples/storifierbot.py)*

Takes all the snaps sent to it and adds them to its story. It can be used to collect responses
from multiple people around a single theme, much like a Twitter hashtag.
from multiple people around a single theme, much like a Twitter
hashtag.

#### The Capture Bot (by [EthanBlackburn](https://github.com/EthanBlackburn))
*(source at examples/capturebot.py)*

Saves all snaps received to the current working directory.

#### The Auto-Welcomer Bot
*(source at examples/autowelcomebot.py)*
Expand All @@ -42,11 +52,16 @@ Posts popular GIFs taken from the [Giphy](http://giphy.com) home page to its sto

When you add the Connector to your friends, it links you with a stranger who's also added it. Every snap sent to the Connector will then arrive at the stranger's inbox, and all snaps sent from the stranger to the Connector will come to you. It's like ChatRoulette on Snapchat.

#### The Rando Bot (by [PhlexPlexico](https://github.com/Phlexplexico))
*(source at examples/randobot.py)*

When you add RandoBot to your friends, it throws you in a list of people who've also added it. When you send it a snap, it will send your snap to a random person in the list. Similar to the [Rando](http://techcrunch.com/2014/03/22/rip-rando/) app.

## Installation

$ python setup.py install

You also need to have [ffmpeg](https://www.ffmpeg.org/) and [ImageMagick](http://www.imagemagick.org/) installed.
You also need to have [ffmpeg](https://www.ffmpeg.org/), [ImageMagick](http://www.imagemagick.org/), and [libjpeg](http://libjpeg.sourceforge.net/) installed.

## How to build your own bots

Expand All @@ -57,6 +72,9 @@ You also need to have [ffmpeg](https://www.ffmpeg.org/) and [ImageMagick](http:/
* `SnapchatBot#delete_friend(username)` -- deletes user with username `username` from the bot's friends
* `SnapchatBot#block(username)` -- blocks user with username `username`
* `SnapchatBot#get_snaps(mark_viewed = True)` -- gets snaps in the bot's inbox that haven't been viewed yet (use `mark_viewed = False` as a keyword argument if you don't want the bot to mark every snap received as viewed)
* `SnapchatBot#get_my_stories()` -- gets all snaps in the bot's story
* `SnapchatBot#get_friend_stories()` -- gets all the stories of the bot's friends
* `SnapchatBot#clear_stories()` -- deletes all the bot's stories
* `SnapchatBot#mark_viewed(snap)` -- marks `snap` as viewed
* `SnapchatBot#get_friends()` -- gets the bot's friends
* `SnapchatBot#get_added_me()` -- gets all users that have added the bot to their friends
Expand Down
16 changes: 16 additions & 0 deletions examples/capturebot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from argparse import ArgumentParser
from snapchat_bots import SnapchatBot

class CaptureBot(SnapchatBot):
def on_snap(self, sender, snap):
snap.save()

if __name__ == '__main__':
parser = ArgumentParser("Capture Bot")
parser.add_argument('-u', '--username', required=True, type=str, help="Username of the account to run the bot on")
parser.add_argument('-p', '--password', required=True, type=str, help="Password of the account to run the bot on")

args = parser.parse_args()

bot = CaptureBot(args.username, args.password)
bot.listen(timeout=60)
60 changes: 60 additions & 0 deletions examples/randobot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from argparse import ArgumentParser
from snapchat_bots import SnapchatBot, Snap
import random

class RandoBot(SnapchatBot):
def initialize(self):
self.connections = self.get_friends()
#If your bot ever gets blocked, uncomment these lines.
#Of course, make sure you have your old users backed up
#to the users.txt file! So you must uncomment the first
#three lines, while logged into the blocked bot, then
#uncomment the rest to re-add all users from the old bot.
#with open('users.txt', 'w') as file:
# for item in self.connections:
# print>>file, item
#f = open('users.txt', 'r')
#for line in f:
# self.add_friend(line)
# print(line)
print(self.connections)

def connect(self,user):
self.log("Added user: %s to the array!" % (user))
self.connections.append(user)

def on_friend_add(self,friend):
self.add_friend(friend)
self.connect(friend)

def on_friend_delete(self,friend):
self.delete_friend(friend)
self.connections.remove(friend)

def find_random_user(self,username):
if len(self.connections) <= 1:
return None
newuser = random.choice(self.connections)
while(newuser == username):
newuser = random.choice(self.connections)
return newuser

def on_snap(self,sender,snap):
connection = self.find_random_user(sender)
if sender not in self.connections:
self.send_snap([sender], Snap.from_file("../resources/rando_addme.png"))
if connection:
self.send_snap([connection],snap)
print("%s sent snap to %s" % (sender,[connection]))
else:
self.send_snap([sender], Snap.from_file("../resources/rando_welcome.png"))

if __name__ == '__main__':
parser = ArgumentParser("RandoBot Bot")
parser.add_argument('-u', '--username', required=True, type=str, help="Username of the account to run the bot on")
parser.add_argument('-p', '--password', required=True, type=str, help="Password of the account to run the bot on")

args = parser.parse_args()

bot = RandoBot(args.username, args.password)
bot.listen(timeout=33)
Binary file added resources/rando_addme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/rando_welcome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
packages=['snapchat_bots'],
install_requires=[
'schedule>=0.3.1',
'requests>=2.5.1',
'PIL>=1.1.7',
'requests>=2.5.3',
'Pillow>=2.7.0',
'pysnap>=0.1.1'
],
dependency_links = ['https://github.com/martinp/pysnap/tarball/master#egg=pysnap-0.1.1'],
Expand Down
Empty file modified snapchat_bots/__init__.py
100644 → 100755
Empty file.
124 changes: 106 additions & 18 deletions snapchat_bots/bot.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import logging, time, uuid
import logging, time, uuid, requests, base64
from pysnap import Snapchat
from pysnap.utils import make_request_token, timestamp
from snap import Snap
from constants import DEFAULT_TIMEOUT
from constants import DEFAULT_TIMEOUT, STATIC_TOKEN, BASE_URL

FORMAT = '[%(asctime)-15s] %(message)s'
logging.basicConfig(format=FORMAT)
Expand All @@ -12,11 +13,22 @@ class SnapchatBot(object):
def __init__(self, username, password, **kwargs):
self.bot_id = uuid.uuid4().hex[0:4]

self.auth_token = STATIC_TOKEN

self.username = username
self.password = password

r = self._make_request("/loq/login", {
'username': self.username,
'password': self.password
})

result = r.json()
self.auth_token = result['updates_response']['auth_token']

self.client = Snapchat()
self.client.login(username, password)
self.client.username = username
self.client.auth_token = self.auth_token

self.current_friends = self.get_friends()
self.added_me = self.get_added_me()
Expand All @@ -28,7 +40,7 @@ def log(self, message, level=logging.DEBUG):
logger.log(level, "[%s-%s] %s" % (self.__class__.__name__, self.bot_id, message))

@staticmethod
def process_snap(snap_obj, data):
def process_snap(snap_obj, data, is_story = False):
media_type = snap_obj["media_type"]
sender = snap_obj["sender"]
snap_id = snap_obj['id']
Expand All @@ -37,7 +49,8 @@ def process_snap(snap_obj, data):
snap_id=snap_id,
media_type=media_type,
duration=duration,
sender=sender)
sender=sender,
is_story=is_story)
return snap

def mark_viewed(self, snap):
Expand Down Expand Up @@ -79,11 +92,7 @@ def get_added_me(self):
return map(lambda fr: fr['name'], updates["added_friends"])

def send_snap(self, recipients, snap):
self.log("Preparing to send snap %s" % snap.snap_id)

if not snap.uploaded:
self.log("Uploading snap %s" % snap.snap_id)
snap.upload(self)
media_id = self._upload_snap(snap)

if type(recipients) is not list:
recipients = [recipients]
Expand All @@ -92,15 +101,26 @@ def send_snap(self, recipients, snap):

self.log("Sending snap %s to %s" % (snap.snap_id, recipients_str))

self.client.send(snap.media_id, recipients_str)
self.client.send(media_id, recipients_str, snap.duration)

def post_story(self, snap):
if not snap.uploaded:
self.log("Uploading snap")
snap.upload(self)
media_id = self._upload_snap(snap)
response = self.client.send_to_story(media_id, snap.duration, snap.media_type)

try:
snap.story_id = response['json']['story']['id']
except:
pass

def delete_story(self, snap):
print snap.story_id
if snap.story_id is None:
return

self.log("Posting snap as story")
self.client.send_to_story(snap.media_id, media_type=snap.media_type)
self.client._request('delete_story', {
'username': self.username,
'story_id': snap.story_id
})

def add_friend(self, username):
self.client.add_friend(username)
Expand All @@ -111,8 +131,7 @@ def delete_friend(self, username):
def block(self, username):
self.client.block(username)

def get_snaps(self, mark_viewed=True):
snaps = self.client.get_snaps()
def process_snaps(self, snaps, mark_viewed = True):
ret = []

for snap_obj in snaps:
Expand All @@ -132,3 +151,72 @@ def get_snaps(self, mark_viewed=True):
ret.append(snap)

return ret

def process_stories(self, stories):
ret = []
for snap_obj in stories:
media_key = base64.b64decode(snap_obj['media_key'])
media_iv = base64.b64decode(snap_obj['media_iv'])
data = self.client.get_story_blob(snap_obj['media_id'],
media_key,
media_iv)
if data is None:
continue
snap_obj['sender'] = self.username
snap = self.process_snap(snap_obj, data, is_story = True)
ret.append(snap)
return ret

def get_snaps(self, mark_viewed=True):
snaps = self.client.get_snaps()
return self.process_snaps(snaps)

def get_my_stories(self):
response = self.client._request('stories', {
'username': self.username
})
stories = map(lambda s: s['story'], response.json()['my_stories'])
return self.process_stories(stories)

def get_friend_stories(self):
response = self.client._request('stories', {
'username': self.username
})
ret = []
stories_per_friend = map(lambda s: s['stories'], response.json()['friend_stories'])
for stories_obj in stories_per_friend:
stories = map(lambda so: so['story'], stories_obj)
ret.extend(self.process_stories(stories))
return ret

def clear_stories(self):
for story in self.get_my_stories():
self.delete_story(story)

def _upload_snap(self, snap):
if not snap.uploaded:
snap.media_id = self.client.upload(snap.file.name)
snap.uploaded = True

return snap.media_id

def _make_request(self, path, data = None, method = 'POST', files = None):
if data is None:
data = {}

headers = {
'User-Agent': 'Snapchat/8.1.1 (iPhone5,1; iOS 8.1.3; gzip)',
'Accept-Language': 'en-US;q=1, en;q=0.9',
'Accept-Locale': 'en'
}

now = timestamp()

if method == 'POST':
data['timestamp'] = now
data['req_token'] = make_request_token(self.auth_token, str(now))
resp = requests.post(BASE_URL + path, data = data, files = files, headers = headers)
else:
resp = requests.get(BASE_URL + path, params = data, headers = headers)

return resp
5 changes: 4 additions & 1 deletion snapchat_bots/constants.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
BASE_URL = 'https://feelinsonice-hrd.appspot.com'
STATIC_TOKEN = 'm198sOkJEn37DjqZ32lpRu76xmw288xSQ9'

DEFAULT_TIMEOUT = 15
DEFAULT_DURATION = 5

SNAP_IMAGE_DIMENSIONS = (290, 600)
SNAP_IMAGE_DIMENSIONS = (1334, 750)

MEDIA_TYPE_UNKNOWN = -1
MEDIA_TYPE_IMAGE = 0
Expand Down
3 changes: 3 additions & 0 deletions snapchat_bots/exceptions.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
class UnknownMediaType(Exception):
pass

class CannotOpenFile(Exception):
pass
Loading