Created
May 7, 2010 16:34
-
-
Save passy/393682 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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