2018-01-14 00:35:28 +01:00
|
|
|
import argparse
|
|
|
|
|
2018-05-13 13:06:45 +02:00
|
|
|
from yaml import load
|
|
|
|
try:
|
|
|
|
from yaml import CLoader as Loader
|
|
|
|
except ImportError:
|
|
|
|
from yaml import Loader
|
|
|
|
|
|
|
|
|
|
|
|
configdata = None
|
|
|
|
|
2018-01-14 00:35:28 +01:00
|
|
|
|
2018-01-30 21:43:19 +01:00
|
|
|
class Options(object):
|
|
|
|
"""
|
|
|
|
Options used when invoking the script from another Python script.
|
|
|
|
|
|
|
|
Simple container class used when calling get_media() from another Python
|
|
|
|
script. The variables corresponds to the command line parameters parsed
|
|
|
|
in main() when the script is called directly.
|
|
|
|
|
|
|
|
When called from a script there are a few more things to consider:
|
|
|
|
|
|
|
|
* Logging is done to 'log'. main() calls setup_log() which sets the
|
|
|
|
logging to either stdout or stderr depending on the silent level.
|
|
|
|
A user calling get_media() directly can either also use setup_log()
|
|
|
|
or configure the log manually.
|
|
|
|
|
|
|
|
* Progress information is printed to 'progress_stream' which defaults to
|
|
|
|
sys.stderr but can be changed to any stream.
|
|
|
|
|
|
|
|
* Many errors results in calls to system.exit() so catch 'SystemExit'-
|
|
|
|
Exceptions to prevent the entire application from exiting if that happens.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self):
|
2018-05-13 13:06:45 +02:00
|
|
|
self.default = {}
|
|
|
|
|
|
|
|
def set(self, key, value):
|
|
|
|
self.default[key] = value
|
|
|
|
|
|
|
|
def get(self, key):
|
|
|
|
if key in self.default:
|
|
|
|
return self.default[key]
|
|
|
|
|
|
|
|
def get_variable(self):
|
|
|
|
return self.default
|
2018-01-30 21:43:19 +01:00
|
|
|
|
|
|
|
|
2018-01-14 00:35:28 +01:00
|
|
|
def parser(version):
|
|
|
|
parser = argparse.ArgumentParser(prog="svtplay-dl")
|
|
|
|
general = parser.add_argument_group()
|
|
|
|
|
|
|
|
general.add_argument('--version', action='version', version='%(prog)s {0}'.format(version))
|
2018-05-13 02:32:39 +02:00
|
|
|
general.add_argument("-o", "--output", metavar="output", default=None, help="outputs to the given filename or folder")
|
2018-01-14 00:35:28 +01:00
|
|
|
general.add_argument("-f", "--force", action="store_true", dest="force", default=False,
|
|
|
|
help="overwrite if file exists already")
|
|
|
|
general.add_argument("-r", "--resume", action="store_true", dest="resume", default=False,
|
|
|
|
help="resume a download (RTMP based ones)")
|
|
|
|
general.add_argument("-l", "--live", action="store_true", dest="live", default=False,
|
|
|
|
help="enable for live streams (RTMP based ones)")
|
|
|
|
general.add_argument("-c", "--capture_time", default=-1, type=int, metavar="capture_time",
|
|
|
|
help="define capture time in minutes of a live stream")
|
|
|
|
general.add_argument("-s", "--silent", action="store_true", dest="silent", default=False, help="be less verbose")
|
|
|
|
general.add_argument("--silent-semi", action="store_true", dest="silent_semi", default=False,
|
|
|
|
help="only show a message when the file is downloaded")
|
|
|
|
general.add_argument("-u", "--username", default=None, help="username")
|
|
|
|
general.add_argument("-p", "--password", default=None, help="password")
|
|
|
|
general.add_argument("-t", "--thumbnail", action="store_true", dest="thumbnail", default=False,
|
|
|
|
help="download thumbnail from the site if available")
|
|
|
|
general.add_argument("-g", "--get-url", action="store_true", dest="get_url", default=False,
|
|
|
|
help="do not download any video, but instead print the URL.")
|
|
|
|
general.add_argument("--dont-verify-ssl-cert", action="store_false", dest="ssl_verify", default=True,
|
|
|
|
help="Don't attempt to verify SSL certificates.")
|
|
|
|
general.add_argument("--http-header", dest="http_headers", default=None, metavar="header1=value;header2=value2",
|
|
|
|
help="A header to add to each HTTP request.")
|
|
|
|
general.add_argument("--remux", dest="remux", default=False, action="store_true",
|
|
|
|
help="Remux from one container to mp4 using ffmpeg or avconv")
|
|
|
|
general.add_argument("--exclude", dest="exclude", default=None, metavar="WORD1,WORD2,...",
|
|
|
|
help="exclude videos with the WORD(s) in the filename. comma separated.")
|
|
|
|
general.add_argument("--proxy", dest="proxy", default=None,
|
|
|
|
metavar="proxy", help="Use the specified HTTP/HTTPS/SOCKS proxy. To enable experimental "
|
|
|
|
"SOCKS proxy, specify a proper scheme. For example "
|
|
|
|
"socks5://127.0.0.1:1080/.")
|
|
|
|
general.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False,
|
|
|
|
help="explain what is going on")
|
|
|
|
|
|
|
|
quality = parser.add_argument_group("Quality")
|
|
|
|
quality.add_argument("-q", "--quality", default=0, metavar="quality",
|
|
|
|
help="choose what format to download based on bitrate / video resolution."
|
|
|
|
"it will download the best format by default")
|
|
|
|
quality.add_argument("-Q", "--flexible-quality", default=0, metavar="amount", dest="flexibleq",
|
|
|
|
help="allow given quality (as above) to differ by an amount")
|
|
|
|
quality.add_argument("-P", "--preferred", default=None, metavar="preferred",
|
|
|
|
help="preferred download method (dash, hls, hds, http or rtmp)")
|
|
|
|
quality.add_argument("--list-quality", dest="list_quality", action="store_true", default=False,
|
|
|
|
help="list the quality for a video")
|
|
|
|
quality.add_argument("--stream-priority", dest="stream_prio", default=None, metavar="dash,hls,hds,http,rtmp",
|
|
|
|
help="If two streams have the same quality, choose the one you prefer")
|
|
|
|
|
|
|
|
subtitle = parser.add_argument_group("Subtitle")
|
|
|
|
subtitle.add_argument("-S", "--subtitle", action="store_true", dest="subtitle", default=False,
|
|
|
|
help="download subtitle from the site if available")
|
|
|
|
subtitle.add_argument("-M", "--merge-subtitle", action="store_true", dest="merge_subtitle", default=False,
|
2018-01-30 23:10:22 +01:00
|
|
|
help="merge subtitle with video/audio file with corresponding ISO639-3 language code."
|
|
|
|
"this invokes --remux automatically. use with -S for external also.")
|
2018-01-14 00:35:28 +01:00
|
|
|
subtitle.add_argument("--force-subtitle", dest="force_subtitle", default=False, action="store_true",
|
|
|
|
help="download only subtitle if its used with -S")
|
|
|
|
subtitle.add_argument("--require-subtitle", dest="require_subtitle", default=False, action="store_true",
|
|
|
|
help="download only if a subtitle is available")
|
|
|
|
subtitle.add_argument("--all-subtitles", dest="get_all_subtitles", default=False, action="store_true",
|
|
|
|
help="Download all available subtitles for the video")
|
|
|
|
subtitle.add_argument("--raw-subtitles", dest="get_raw_subtitles", default=False, action="store_true",
|
|
|
|
help="also download the subtitles in their native format")
|
|
|
|
subtitle.add_argument("--convert-subtitle-colors", dest="convert_subtitle_colors", default=False,
|
|
|
|
action="store_true",
|
|
|
|
help='converts the color information in subtitles, to <font color=""> tags')
|
|
|
|
|
|
|
|
alleps = parser.add_argument_group("All")
|
|
|
|
alleps.add_argument("-A", "--all-episodes", action="store_true", dest="all_episodes", default=False,
|
|
|
|
help="try to download all episodes")
|
|
|
|
alleps.add_argument("--all-last", dest="all_last", default=-1, type=int, metavar="NN",
|
|
|
|
help="get last NN episodes instead of all episodes")
|
|
|
|
alleps.add_argument("--include-clips", dest="include_clips", default=False, action="store_true",
|
|
|
|
help="include clips from websites when using -A")
|
|
|
|
|
|
|
|
cmorep = parser.add_argument_group("C More")
|
|
|
|
cmorep.add_argument("--cmore-operatorlist", dest="cmoreoperatorlist", default=False, action="store_true",
|
|
|
|
help="show operatorlist for cmore")
|
|
|
|
cmorep.add_argument("--cmore-operator", dest="cmoreoperator", default=None, metavar="operator")
|
|
|
|
|
|
|
|
parser.add_argument('urls', nargs="*")
|
|
|
|
options = parser.parse_args()
|
2018-01-30 21:43:19 +01:00
|
|
|
|
2018-01-14 00:39:16 +01:00
|
|
|
return parser, options
|
|
|
|
|
|
|
|
|
2018-05-13 13:06:45 +02:00
|
|
|
def setup_defaults():
|
|
|
|
options = Options()
|
|
|
|
options.set("output", None)
|
|
|
|
options.set("resume", False)
|
|
|
|
options.set("live", False)
|
|
|
|
options.set("capture_time", -1)
|
|
|
|
options.set("silent", False)
|
|
|
|
options.set("force", False)
|
|
|
|
options.set("quality", 0)
|
|
|
|
options.set("flexibleq", 0)
|
|
|
|
options.set("list_quality", False)
|
|
|
|
options.set("other", None)
|
|
|
|
options.set("subtitle", False)
|
|
|
|
options.set("username", None)
|
|
|
|
options.set("password", None)
|
|
|
|
options.set("thumbnail", False)
|
|
|
|
options.set("all_episodes", False)
|
|
|
|
options.set("all_last", -1)
|
|
|
|
options.set("merge_subtitle", False)
|
|
|
|
options.set("force_subtitle", False)
|
|
|
|
options.set("require_subtitle", False)
|
|
|
|
options.set("get_all_subtitles", False)
|
|
|
|
options.set("get_raw_subtitles", False)
|
|
|
|
options.set("convert_subtitle_colors", False)
|
|
|
|
options.set("preferred", None)
|
|
|
|
options.set("verbose", False)
|
|
|
|
options.set("output_auto", False)
|
|
|
|
options.set("service", None)
|
|
|
|
options.set("cookies", None)
|
|
|
|
options.set("exclude", None)
|
|
|
|
options.set("get_url", False)
|
|
|
|
options.set("ssl_verify", True)
|
|
|
|
options.set("http_headers", None)
|
|
|
|
options.set("stream_prio", None)
|
|
|
|
options.set("remux", False)
|
|
|
|
options.set("silent_semi", False)
|
|
|
|
options.set("proxy", None)
|
|
|
|
options.set("filename", "{title}.s{season}e{episode}.{episodename}-{id}-{service}.{ext}")
|
2018-05-20 13:16:00 +02:00
|
|
|
return _special_settings(options)
|
|
|
|
|
|
|
|
|
|
|
|
def parsertoconfig(config, parser):
|
|
|
|
config.set("output", parser.output)
|
|
|
|
config.set("configfile", parser.configfile)
|
|
|
|
config.set("resume", parser.resume)
|
|
|
|
config.set("live", parser.live)
|
|
|
|
config.set("capture_time", parser.capture_time)
|
|
|
|
config.set("silent", parser.silent)
|
|
|
|
config.set("force", parser.force)
|
|
|
|
config.set("quality", parser.quality)
|
|
|
|
config.set("flexibleq", parser.flexibleq)
|
|
|
|
config.set("list_quality", parser.list_quality)
|
|
|
|
config.set("subtitle", parser.subtitle)
|
|
|
|
config.set("merge_subtitle", parser.merge_subtitle)
|
|
|
|
config.set("silent_semi", parser.silent_semi)
|
|
|
|
config.set("username", parser.username)
|
|
|
|
config.set("password", parser.password)
|
|
|
|
config.set("thumbnail", parser.thumbnail)
|
|
|
|
config.set("all_episodes", parser.all_episodes)
|
|
|
|
config.set("all_last", parser.all_last)
|
|
|
|
config.set("force_subtitle", parser.force_subtitle)
|
|
|
|
config.set("require_subtitle", parser.require_subtitle)
|
|
|
|
config.set("preferred", parser.preferred)
|
|
|
|
config.set("verbose", parser.verbose)
|
|
|
|
config.set("exclude", parser.exclude)
|
|
|
|
config.set("get_url", parser.get_url)
|
|
|
|
config.set("ssl_verify", parser.ssl_verify)
|
|
|
|
config.set("http_headers", parser.http_headers)
|
|
|
|
config.set("stream_prio", parser.stream_prio)
|
|
|
|
config.set("remux", parser.remux)
|
|
|
|
config.set("get_all_subtitles", parser.get_all_subtitles)
|
|
|
|
config.set("get_raw_subtitles", parser.get_raw_subtitles)
|
|
|
|
config.set("convert_subtitle_colors", parser.convert_subtitle_colors)
|
|
|
|
config.set("include_clips", parser.include_clips)
|
|
|
|
config.set("cmoreoperatorlist", parser.cmoreoperatorlist)
|
|
|
|
config.set("cmoreoperator", parser.cmoreoperator)
|
|
|
|
config.set("proxy", parser.proxy)
|
|
|
|
return _special_settings(config)
|
|
|
|
|
|
|
|
|
|
|
|
def _special_settings(config):
|
|
|
|
if config.get("require_subtitle"):
|
|
|
|
if config.get("merge_subtitle"):
|
|
|
|
config.set("merge_subtitle", True)
|
|
|
|
else:
|
|
|
|
config.set("subtitle", True)
|
|
|
|
if config.get("merge_subtitle"):
|
|
|
|
config.set("remux", True)
|
|
|
|
|
|
|
|
if config.get("silent_semi"):
|
|
|
|
config.set("silent", True)
|
|
|
|
|
|
|
|
if config.get("proxy"):
|
|
|
|
config.set("proxy", config.get("proxy").replace("socks5", "socks5h", 1))
|
|
|
|
config.set("proxy", dict(http=config.get("proxy"),
|
|
|
|
https=config.get("proxy")))
|
|
|
|
return config
|
2018-05-13 13:06:45 +02:00
|
|
|
|
|
|
|
|
|
|
|
def merge(old, new):
|
|
|
|
z = old.copy()
|
|
|
|
z.update(new)
|
|
|
|
return z
|
|
|
|
|
|
|
|
|
|
|
|
def readconfig(options, configfile, service=None, preset=None):
|
|
|
|
global configdata
|
|
|
|
|
|
|
|
if configdata is None:
|
|
|
|
print("config is not cached")
|
|
|
|
with open(configfile) as fd:
|
|
|
|
data = fd.read()
|
|
|
|
configdata = load(data, Loader=Loader)
|
|
|
|
if configdata:
|
|
|
|
print("config is cached!")
|
|
|
|
|
|
|
|
if "default" in configdata:
|
|
|
|
options = merge(options, configdata["default"])
|
|
|
|
|
|
|
|
if service and "service" in configdata and service in configdata["service"]:
|
|
|
|
options = merge(options, configdata["service"][service])
|
|
|
|
|
|
|
|
if preset and "presets" in configdata and preset in configdata["presets"]:
|
|
|
|
options = merge(options, configdata["presets"][preset])
|
|
|
|
|
2018-01-14 00:39:16 +01:00
|
|
|
return options
|