Skip to content

Instantly share code, notes, and snippets.



Last active Jan 14, 2016
What would you like to do? script to grab and open direct link to serial or download sequentially by seasons and episodes
# coding: utf8
import re, json, bs4, requests, argparse, os, optparse
from urlparse import parse_qs, urlsplit, urlparse
ALL = -100
URL_PATTERN = re.compile(
class PlayerInterface(object):
def __init__(self, *args):
Pass configuration tuple
:param args: Configurations
def get_episodes_url(self, url, season_list=ALL, episodes_list=ALL):
urls = []
seasons = None
# convert to list if is any other integer value except ALL constant
episodes_list = [episodes_list] if type(episodes_list) is int and not episodes_list == ALL else episodes_list
if type(season_list) is int: # exact season
seasons = [
(value for value in self.filesMap.itervalues()) if season_list is ALL else self.filesMap[season_list]]
elif type(season_list) is list:
seasons = [value for key, value in self.filesMap.iteritems() if key in season_list]
for season in seasons:
urls.extend([value for key, value in season.iteritems() if episodes_list == ALL or key in episodes_list])
return urls
def __init_internal_fields(self, url):
javascript_code = self.__fetch_necessary_part(url)
self.json = json.loads(self.__find_episodes_json_in_code(javascript_code))
self.endpoint = self.__find_endpoint_in_code(javascript_code)
self.filesMap = self.__build_episodes_map(self.json)
def __build_episodes_map(self, json_array):
Makes dictionary object with outer dict object as season and
inner dictionary with episodes list
:json: json of episodes & seasons
:return: dictionary of seasons(outer) and episodes(inner) in json
seasons_list = {}
for json_object in json_array:
season = int(json_object[KEY_EPISODE_SEASON])
if not season in seasons_list:
seasons_list[season] = {}
url = (self.endpoint + json_object[KEY_EPISODE_FILE])
if not hasattr(self, "suggested_folder"):
episode_remote_path = os.path.split(urlparse(url).path)
seasons_list[season][int(json_object[KEY_EPISODE_NUMBER])] = url
return seasons_list
def __find_endpoint_in_code(javascript_code):
Searches for URL Pattern and returns first matched url,
it will be used as endpoint for further
:param javascript_code: part of code where js with episodes json
(10th script in human numeric system)
:return: base url to concatenate with file part url
return, javascript_code).group()
def __find_episodes_json_in_code(javascript_code):
We are parsing specific part of code, so we need to find
json with enumerated episodes
:param javascript_code: part of code where js with episodes json
(10th script in human numeric system)
:return: json with episodes in string type
return javascript_code[str.find(javascript_code, "[{"): str.rfind(javascript_code, "}]") + 2]
def __fetch_necessary_part(url):
Current implementation:
Takes html from url and finds 10th script and returns it
:param url: serial url
:return: (str) 10th script where json with enumerated episodes
r = requests.get(url)
if not 200 <= r.status_code < 300:
raise requests.HTTPError(request=r)
html = bs4.BeautifulSoup(r.text, "html.parser")
return str(html.find_all("script")[9].string)
def find_season_and_episode_in_query(url, season, episode):
Makes dictionary of query: value
query = parse_qs(urlsplit(url).query)
return int(query[KEY_EPISODE_SEASON][0]) if KEY_EPISODE_SEASON in query else season, \
int(query[KEY_EPISODE_NUMBER][0]) if KEY_EPISODE_NUMBER in query else episode
def suggest_folder(url, local_folder_base="~/Movies/"):
episode_remote_path = os.path.split(urlparse(url).path)
remote_dir = episode_remote_path[0]
remote_dir = remote_dir[len("/mp4/"):len(remote_dir)]
return os.path.join(os.path.expanduser(local_folder_base), remote_dir)
def main():
SCRIPT_DESCRIPTION = "Enjoy without paying subscription even if you are not TPS user."
ARG_URL_HELP = "We support 2 types of url normal{serial_id}/ where {serial_id} is " \
"number in real life and with season and episode in query that will be passed as argument to watch"
ARG_SEASONS_HELP = "You can pass as many number as you want separating them by space " \
"for example (season 1 2 3 4 5) or just a number, if you not set this argument " \
"it means all seasons"
parser = argparse.ArgumentParser(description=SCRIPT_DESCRIPTION)
parser.add_argument('URL', type=str, help=ARG_URL_HELP)
parser.add_argument('-s', type=int, default=ALL, nargs='*', required=False, help=ARG_SEASONS_HELP)
parser.add_argument('-e', type=int, default=ALL, nargs='*', required=False,
help="list of episodes enumerated by space to watch")
parser.add_argument("-info", action='store_true', default=False)
parser.add_argument("-save", action='store_true', default=False)
args = parser.parse_args()
api = PlayerInterface()
seasons, episodes = api.find_season_and_episode_in_query(args.URL, args.s, args.e)
urls = api.get_episodes_url(args.URL, seasons, episodes)
commands = []
for url in urls:
"-P", api.suggest_folder(url),
os.system(" ".join(commands))
elif len(urls) is 1:
commands.extend(["open", "\"{0}\"".format(urls[0])] if len(urls) is 1 else [])
os.system(" ".join(commands))
for url in urls: print(url)
if __name__ == "__main__":
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment