diff --git a/addon.xml b/addon.xml index 7d51a73..e53e56d 100644 --- a/addon.xml +++ b/addon.xml @@ -1,7 +1,7 @@ diff --git a/changelog.txt b/changelog.txt index 3b23fe7..da1d3d3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,11 @@ +1.4.0 +- Add login feature - Will download the subtitles from Torec with registered +user credentials +- Save session on cookie and rerty with it next time, if session not valid +will try to re-login and get new session +- Fix cookie permissions +- Added tests for both movies and tvshows download + 1.3.1 - Fixed broken download due to site changes and added some future changes protection diff --git a/resources/lib/TorecSubtitlesDownloader.py b/resources/lib/TorecSubtitlesDownloader.py index ddc37f8..568d1e8 100644 --- a/resources/lib/TorecSubtitlesDownloader.py +++ b/resources/lib/TorecSubtitlesDownloader.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import os import cookielib import datetime import re @@ -8,10 +9,12 @@ import zlib import json import itertools +import random import bs4 import xbmc +import xbmcaddon from SubtitleHelper import log class SubtitleOption(object): @@ -78,13 +81,19 @@ class FirefoxURLHandler(object): Firefox user agent class """ def __init__(self): - cookie = "torec.cookie" - cj = cookielib.MozillaCookieJar(cookie) + self.__addon__ = xbmcaddon.Addon(id="service.subtitles.torec") + self.__addonname__ = self.__addon__.getAddonInfo('id') + + dataroot = xbmc.translatePath('special://profile/addon_data/%s' % self.__addonname__ ).decode('utf-8') + cookie = os.path.join(dataroot, "torec.cookie") + self.cj = cookielib.LWPCookieJar(cookie) + if os.path.exists(cookie): + self.cj.load(ignore_discard=True) self.opener = urllib2.build_opener( urllib2.HTTPRedirectHandler(), urllib2.HTTPHandler(), - urllib2.HTTPCookieProcessor(cj) + urllib2.HTTPCookieProcessor(self.cj) ) self.opener.addheaders = [ ( @@ -96,20 +105,29 @@ def __init__(self): ] def login(self): - username = __addon__.getSetting("username") - password = __addon__.getSetting("password") + username = self.__addon__.getSetting("username") + password = self.__addon__.getSetting("password") + log(__name__, "Checking if the user filled login credentials on Settings") + if not username or not password: + log(__name__, "No login creds, failing back to guest") + return False + + log(__name__, "Settings filled with username and password, trying to login") login_data_ = { - "ref": "/Default.asp?", - "Form": "True", - "site": "true", + "form": "true", "username": username, "password": password, - "login": "submit" } login_data = urllib.urlencode(login_data_) - login_url = "http://www.torec.net/login.asp" + rnd_float = random.uniform(0.1, 0.9) + login_url = 'http://www.torec.net/ajax/login/t7/loginProcess.asp?rnd={0}'.format(rnd_float) + log(__name__, "Login URL: %s" % login_url) + # For debug, not for prod - will pring credentials to log. + #log(__name__, "Login params: %s" % login_data) response = self.opener.open(login_url, login_data) - content = ''.join(response.readlines()) + content = ''.join(response.read()) + log(__name__, "Response: %s" % content) + self.cj.save(ignore_discard=True) return username in content class TorecGuestTokenGenerator(): @@ -267,13 +285,16 @@ def _confirm_download_code(self, sub_id, option_id): response = self.opener.open("%s/ajax/sub/t7/guest_dl_code.asp" % self.BASE_URL, urllib.urlencode(params)) response_data = response.read() - def _try_get_download_link(self, sub_id, option_id, guest_token): + def _try_get_download_link(self, sub_id, option_id, guest_token, is_login=False): + if guest_token is None: + guest_token = "" + encoded_params = urllib.urlencode({ "sub_id": sub_id, "code": option_id, "sh": "yes", "guest": guest_token, - "timewaited": 13 + "timewaited": -1 if is_login else 13 }) response = self.opener.open("%s/ajax/sub/t7/downloadun.asp" % self.BASE_URL, encoded_params) @@ -303,9 +324,38 @@ def _get_download_link_with_regular_token(self, sub_id, option_id): return download_link + def _get_download_link_with_login(self, sub_id, option_id): + # Checking if we have cookie - if so, we will try to use it + log(__name__, "Checking if we have cookie") + cookie_root = 'www.torec.net' + cookie_name = 'Torec%5FNC%5Fsite' + if cookie_root in self.cj._cookies and \ + cookie_name in self.cj._cookies[cookie_root]['/'] and \ + self.__addon__.getSetting("username") in self.cj._cookies[cookie_root]['/'][cookie_name].value: + log(__name__, "Cookie found. Trying to get link") + download_link = self._try_get_download_link(sub_id, option_id, None, True) + if download_link: + return download_link + + # Checking if the user has credentials, if so - logging in and downloading, + # If not (or the login failed) - failing back to guest user download + log(__name__, "Trying to login") + if self.login(): + log(__name__, "Logged in. Trying to get link") + download_link = self._try_get_download_link(sub_id, option_id, None, True) + if download_link: + return download_link + + return None + def get_download_link(self, sub_id, option_id): self._confirm_download_code(sub_id, option_id) + # Will try to download with logged in user + download_link = self._get_download_link_with_login(sub_id, option_id) + if download_link: + return download_link + log(__name__, "trying to retrieve download link with skewed generated guest token") generated_time_skewed_guest_token = TorecGuestTokenGenerator(sub_id, True).generate_ticket() download_link = self._try_get_download_link(sub_id, option_id, generated_time_skewed_guest_token) diff --git a/tests/movie_tests.py b/tests/movie_tests.py index 119e98a..6668863 100644 --- a/tests/movie_tests.py +++ b/tests/movie_tests.py @@ -74,4 +74,4 @@ def _assert_subtitle_data(self, subtitleData, fileName): break if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main(verbosity=2) diff --git a/tests/xbmc.py b/tests/xbmc.py index a0fb433..c82bf72 100644 --- a/tests/xbmc.py +++ b/tests/xbmc.py @@ -7,4 +7,7 @@ def log(message, level): print(message) def sleep(msec): - time.sleep(msec / 1000.0) \ No newline at end of file + time.sleep(msec / 1000.0) + +def translatePath(path): + return "/tmp" diff --git a/tests/xbmcaddon.py b/tests/xbmcaddon.py index c1dbc1f..6cf7cb1 100644 --- a/tests/xbmcaddon.py +++ b/tests/xbmcaddon.py @@ -1,3 +1,22 @@ class Addon(object): - def getAddonInfo(self, type): - pass + def __init__(self, id=None): + pass + + def getAddonInfo(self, type): + if type == "id": + return "Torec" + pass + + def openSetting(self): + """ Can simulate openSettings xbmc call """ + print "Settings" + + def getSetting(self, kind): + """ For unittest - you can return real user credentials + to check user login. + returning Nano or empty string will skip login + """ + if kind == "username": + return "A" + elif kind == "password": + return "X"