Skip to content

Instantly share code, notes, and snippets.

@ozodrukh

ozodrukh/player_get.py

Last active Jan 14, 2016
Embed
What would you like to do?
Player.uz 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
KEY_EPISODE_NUMBER = "episode"
KEY_EPISODE_SEASON = "season"
KEY_EPISODE_FILE = "file"
URL_PATTERN = re.compile(
ur'https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)')
class PlayerInterface(object):
def __init__(self, *args):
"""
Pass configuration tuple
:param args: Configurations
"""
pass
def get_episodes_url(self, url, season_list=ALL, episodes_list=ALL):
self.__init_internal_fields(url)
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
@staticmethod
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 re.search(URL_PATTERN, javascript_code).group()
@staticmethod
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]
@staticmethod
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)
@staticmethod
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
@staticmethod
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 player.uz without paying subscription even if you are not TPS user."
ARG_URL_HELP = "We support 2 types of url normal http://player.uz/{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()
print(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 = []
if args.save:
for url in urls:
commands.extend([
"wget","-c",
"-P", api.suggest_folder(url),
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))
else:
for url in urls: print(url)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment