Skip to content

Instantly share code, notes, and snippets.

@passy
Created May 7, 2010 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save passy/393682 to your computer and use it in GitHub Desktop.
Save passy/393682 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python2.6
# -*- coding: utf-8 -*-
"""
Serienjunkies Decrypter
~~~~~~~~~~~~~~~~~~~~~~~
Decrypts a serienjunkies.org download page and outputs a list of links. Easily
copy-paste-able.
:copyright: 2010, Pascal Hartig <phartig@rdrei.net>
:license: GPL v3, see doc/LICENSE for more details.
"""
import subprocess
import sys
import re
from httplib2 import Http
from tempfile import NamedTemporaryFile
from urllib import urlencode
FILE_VIEWER = 'display'
class SerienjunkiesDecrypter(object):
"""
Expects a URL as argument. Run :meth:`decrypt` to get a list of
URLs.
"""
_CAPTCHA_RE = re.compile(r'\<IMG SRC="\/secure\/([^\.]+)\.png" WIDTH="100" '
'HEIGHT="60" ALT="" style="border:1px solid #ccc;"\>')
_SECRET_RE = re.compile(r'\<INPUT TYPE="HIDDEN" NAME="s" VALUE="([a-z0-9]+)"\>')
_SJ_DOWNLOAD_LINK_RE = re.compile(r'(http:\/\/download.serienjunkies.org\/go-[a-z0-9]+\/)')
def __init__(self, url):
self.url = url
self.http = Http()
self.proc = None
def decrypt(self):
"""Returns a list of URLs."""
content = self._get_content()
captcha_path = self._get_captcha_path(content)
captcha_file = self._download_captcha(captcha_path)
secret = self._get_secret(content)
captcha_code = self._ask_captcha(captcha_file)
download_page = self._get_download_page(captcha_code, secret)
try:
download_links = self._get_download_links(download_page)
for link in download_links:
print(self._get_rapidshare_link_from_go_link(link))
except InvalidCaptchaError:
# Start over.
print("Invalid captcha or decrypter limit. Try again.")
return self.decrypt()
def _get_content(self):
"""Returns the page content of ``self.url``."""
response, content = self.http.request(self.url)
if response['status'] != '200':
raise DecrypterError("Unexpected server "
"response code: {0}" .format(response['status']))
return content
def _get_captcha_path(self, content):
matches = self._CAPTCHA_RE.search(content)
if matches is not None:
return "http://download.serienjunkies.org/secure/{0}.png".format(
matches.group(1))
else:
raise DecrypterError("Captcha not found!")
def _get_secret(self, content):
matches = self._SECRET_RE.search(content)
if matches is not None:
return matches.group(1)
else:
raise DecrypterError("Secret not found!")
def _download_captcha(self, path, file=None):
"""
Downloads the captcha from ``path`` to ``file``.
If ``file`` is None, a NamedTemporaryFile is created.
"""
file = file or NamedTemporaryFile(delete=False)
response, content = self.http.request(path)
file.write(content)
file.close()
return file
def _ask_captcha(self, file):
"""
Displays the captcha to the user and prompts for the shown
values.
"""
self._display_graphic(file.name)
code = raw_input("CODE: ")
self._terminate_graphic_viewer()
return code
def _get_download_page(self, code, secret):
"""Tries to receive the download page."""
data = {'c': code, 's': secret, 'action': "Download"}
headers = {'Content-type': 'application/x-www-form-urlencoded'}
response, content = self.http.request(self.url, "POST",
headers=headers,
body=urlencode(data))
return content
def _get_download_links(self, content):
"""Extracts the download links from the content and returns a
generator over it. If not found, it raises a ``InvalidCaptchaError``."""
matches = self._SJ_DOWNLOAD_LINK_RE.findall(content)
if len(matches) > 0:
for match in matches:
yield match
else:
raise InvalidCaptchaError()
def _display_graphic(self, filename):
self.proc = subprocess.Popen([FILE_VIEWER, filename])
def _terminate_graphic_viewer(self):
if self.proc:
self.proc.terminate()
def _get_rapidshare_link_from_go_link(self, link):
"""
Accepts a http://download.serienjunkies.org/go-... style URL and turns
it into a valid rapidshare.com link.
"""
# Create a local http object that does not follow redirects.
http = Http()
http.follow_redirects = False
link = link.replace("http://download.serienjunkies.org/",
"http://download.serienjunkies.org/frame/")
response, content = http.request(link, 'HEAD')
return response['location']
class DecrypterError(Exception):
pass
class InvalidCaptchaError(DecrypterError):
pass
if __name__ == '__main__':
decrypter = SerienjunkiesDecrypter(sys.argv[1])
decrypter.decrypt()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment