#!/usr/bin/python # # netflix-enqueue.py # Author: Jacob Hoffman-Andrews # Date: Wed Aug 10 18:42:13 PDT 2005 # # Given a set of words W on the commandline # - Log in to Netflix # - Search for W # - Add the first search result to your Netflix queue # # Example: # echo -e "MY_USER_NAME\nMY_PASSWORD\n" > ~/.netflix-login-info # chmod go-r ~/.netflix-login-info # ./netflix-enqueue.py the good, the bad, and the ugly # # Requirements: # Python 2.0 + # Wget 1.9 + # # I chose to use Wget rather than urllib because Wget has good support for both # cookies and SSL. # # Caveats: # - Storing your password on disk is dangerous, use a disposable # - If you have wget 1.10 + and your certificates are misconfigured, # you not be able to log in because wget can not verify the # certificates at https://www.netflix.com/. The quick hack fix is # to add --no-check-certificate to the commandline in my_wget. # The real fix is to make sure you have the CA certs available to # wget somewhere. # - This script has not been security reviewed, and allowing it to be run # remotely will probably expose you to some nasty security holes. import os import sys import re import atexit cookies_file = "/tmp/netflix-cookies.%d" % os.getpid() def cleanup(): os.system("rm -f " + cookies_file) class LoginError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) class WgetError(Exception): def __init__(self, value): self.value = value def __str__(self): return repr(self.value) def wget(args): command = """wget -q -O - --load-cookies %s --save-cookies %s %s""" \ % (cookies_file, cookies_file, args) os.system("touch " + cookies_file) pipe = os.popen(command) data = pipe.read() status = pipe.close() if status: raise WgetError("status %d with args `%s'" % (status, args)) return data def login(username, password): cleanup() atexit.register(cleanup) # Fetch the homepage to prime our cookies file before logging in. Otherwise # login fails. Also this lets us check if there's maintenance going on homepage = wget("http://www.netflix.com/") if re.search("scheduled maintenance", homepage): raise LoginError("scheduled maintenance on the Netflix server") post_data = "nextpage=http%3A%2F%2Fwww.netflix.com%2FDefault" post_data += "&movieid=&trkid=&RememberMe=True" post_data += "&SubmitButton=Click+Here+to+Continue" post_data += "&email=%s&password1=%s" % (username, password) loginpage = wget('--post-data "%s" https://www.netflix.com/Login ' \ % post_data) if re.search('class="error"', loginpage): raise LoginError("probably bad user or pass") # Upon successful login, the fvinc cookie is set to "P987349573498573947" or # similar. In some failure cases (not detected above), it is set to "Y" cookies = open(cookies_file, "r").read() if not re.search('fvinc.P[0-9]', cookies): raise LoginError("didn't get the necessary cookie") return True # Emits a list of URLs which, when fetched, will add a movie to your queue. # These are in the order they appeared in the search results. def get_search_results(movie): data = wget('"http://www.netflix.com/Search?v1=%s"' % movie) results = re.findall('(http://www.netflix.com/AddToQueue\?movieid=\d+)', data) return results # Emits the name of the movie enqueued, or "Already in Queue" def enqueue(url): data = wget("'%s'" % url) m = re.search(">(.*) has been added to your Queue", data) if m: return m.group(1) m = re.search(">The (\d+) discs for '([^']*)' have been added to your Queue.", data) if m: return "%s (%d discs)" % (m.group(2), m.group(1)) elif re.search("is already in", data): return "Already in queue" else: return None def die(explanation): print(explanation) sys.exit(1) def main(argv): if len(argv) > 1: movie = " ".join(argv[1:]) else: movie = sys.stdin.read() login_info = open("%s/.netflix-login-info" % os.environ["HOME"], "r") username = login_info.readline().rstrip() password = login_info.readline().rstrip() login_info.close() if len(movie) == 0: die("Failure: Empty movie name") movie = re.sub("[^a-zA-z0-9- ]+", " ", movie) try: login(username, password) results = get_search_results(movie) if len(results) == 0: die("Failure: Couldn't find %s" % movie) enqueued_name = enqueue(results[0]) if not enqueued_name: die("Failure: Couldn't enqueue %s" % movie) print("Success: %s" % enqueued_name) except LoginError, (problem): die("Failure: Couldn't log in as %s: %s" % (username, problem)) except WgetError, (problem): die("Failure: Wget error: %s" % problem) main(sys.argv)