mirror of
https://github.com/jellyfin/jellyfin-desktop.git
synced 2026-11-09 15:47:10 +00:00
PMP will now download codec binaries from nightlies on playback start if built with -DENABLE_CODECS=on. With "off" (the default), most codecs on demand code will be built, but the list of downloadable codecs will be empty. This uses a hardcoded CODECS_BUILD_NUMBER. This is sort of ok, as long as the list of codecs/names on nightlies doesn't change. If there's a change, it should be updated manually. (Same if new platforms are added etc.) Note that even if this is not changed, the code will download the correct codecs by looking at the FFmpeg version number libmpv is linked against.
279 lines
11 KiB
Python
Executable File
279 lines
11 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Sample CI usage: scripts\common\fetch-binaries.py -p windows -b release -t abc123 -n 33
|
|
# Sample desktop usage: scripts\common\fetch-binaries.py -i ..\plex-dependency-builder\output\Packages\pms-depends-windows-i386-debug-dev.bz2
|
|
|
|
import hashlib
|
|
import optparse
|
|
import ConfigParser
|
|
import os, re
|
|
import platform
|
|
import subprocess
|
|
import sys
|
|
import shutil
|
|
import urllib2
|
|
import base64
|
|
import glob
|
|
|
|
# Edit these to set a new default dependencies build
|
|
default_tag = "auto"
|
|
default_release_build_number = "109"
|
|
default_release_dir = "plexmediaplayer-dependencies-codecs"
|
|
default_branch = "master"
|
|
|
|
def sha1_for_file(path):
|
|
hash=hashlib.sha1()
|
|
fp=file(path, "rb")
|
|
while True:
|
|
data=fp.read(4096)
|
|
if not data:
|
|
break
|
|
hash.update(data)
|
|
return hash.hexdigest()
|
|
|
|
def exec_cmd(args, env={}, supress_output=False):
|
|
""" main exec_cmd function """
|
|
|
|
# forward SSH_AUTH_SOCK, so that ssh-agent works
|
|
if os.name != "nt" and "SSH_AUTH_SOCK" in os.environ:
|
|
env = os.environ
|
|
extra_env={"SSH_AUTH_SOCK":os.environ["SSH_AUTH_SOCK"]}
|
|
env.update(extra_env)
|
|
else:
|
|
env = os.environ
|
|
|
|
cmd = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, env = env)
|
|
output = ''
|
|
while True:
|
|
out = cmd.stdout.read(1)
|
|
if out == '' and cmd.poll() != None:
|
|
break
|
|
if out != '':
|
|
if not supress_output:
|
|
sys.stdout.write(out)
|
|
output += out
|
|
if cmd.wait() != 0:
|
|
raise Exception("Command failed: \"%s\"" % " ".join(args), output)
|
|
return output
|
|
|
|
|
|
platform_map={"linux-synology-i386":"synology-i686",
|
|
"linux-readynas-arm":"ubuntu-arm",
|
|
"linux-debian-4-i386":"debian-i686",
|
|
"linux-control4-arm":"control4-arm",
|
|
"linux-apm-ppc":"apm-ppc",
|
|
"linux-armada-arm7":"armada-arm7",
|
|
"linux-synology-arm":"synology-arm"}
|
|
|
|
def platform_str():
|
|
if "BUILD_TAG" in os.environ:
|
|
for (k, v) in platform_map.iteritems():
|
|
if k in os.environ["BUILD_TAG"]:
|
|
return "linux-"+v
|
|
|
|
return "linux-%s-%s"%(platform.linux_distribution()[0].strip().lower(), platform.machine())
|
|
|
|
def merge_directories(src, dest, move = False):
|
|
for src_dir, dirs, files in os.walk(src):
|
|
dst_dir = src_dir.replace(src, dest)
|
|
if not os.path.exists(dst_dir):
|
|
os.mkdir(dst_dir)
|
|
for file_ in files:
|
|
src_file = os.path.join(src_dir, file_)
|
|
dst_file = os.path.join(dst_dir, file_)
|
|
if os.path.exists(dst_file):
|
|
os.remove(dst_file)
|
|
if move:
|
|
shutil.move(src_file, dst_dir)
|
|
else:
|
|
shutil.copy(src_file, dst_dir)
|
|
if move and os.path.exists(src):
|
|
shutil.rmtree(src)
|
|
|
|
def unpack_and_install(download, inputfile, installed_filepath):
|
|
# Make paths absolute before changing directories
|
|
inputfile = os.path.abspath(inputfile)
|
|
if not os.path.exists(inputfile):
|
|
print "Input file %s does not exist" % inputfile
|
|
sys.exit(1)
|
|
shafile = "%s.sha.txt" % inputfile
|
|
|
|
installed_filepath = os.path.abspath(installed_filepath)
|
|
|
|
# Go to directory.
|
|
old_cwd = os.getcwd()
|
|
os.chdir(options.output)
|
|
|
|
# Check the SHA
|
|
if options.nochecksha:
|
|
print "-- Skipping SHA verification"
|
|
elif os.path.exists(shafile):
|
|
f = open(shafile, "r")
|
|
sha = f.readline().strip()
|
|
computed = sha1_for_file(inputfile)
|
|
if not computed == sha:
|
|
print "-- SHA didn't match: %s != %s" % (sha, computed)
|
|
sys.exit(1)
|
|
else:
|
|
print "-- SHA %s matches" % sha
|
|
|
|
f.close()
|
|
else:
|
|
print "-- ERROR - No SHA file is available to verify the file's integrity"
|
|
sys.exit(1)
|
|
|
|
# Untar the package file
|
|
inputfile_tarfriendly = inputfile
|
|
if os.name == "nt":
|
|
pattern = re.compile(r'([a-z]):\\', re.IGNORECASE)
|
|
inputfile_tarfriendly = pattern.sub('/\\1/', inputfile).replace('\\','/')
|
|
|
|
# The final destination directory is the filename without a version number
|
|
# The version number is the last element in the filename (by convention)
|
|
packagename = os.path.splitext(os.path.basename(inputfile))[0]
|
|
packagename_elements = packagename.split("-")
|
|
del packagename_elements[-1]
|
|
packagename_noversion = "-".join(packagename_elements)
|
|
|
|
if os.path.exists(packagename_noversion):
|
|
shutil.rmtree(packagename_noversion, ignore_errors=True)
|
|
|
|
os.makedirs(packagename_noversion)
|
|
|
|
print "-- Unpacking %s... to %s" % (os.path.basename(inputfile), packagename_noversion)
|
|
if os.name == "nt":
|
|
# Touch files from the package, which often arrive from the future when freshly built on our Windows build machine
|
|
exec_cmd(["tar", "xjf", inputfile_tarfriendly, "-C", packagename_noversion, "--touch", "--strip-components", "1", "--no-same-owner"])
|
|
else:
|
|
exec_cmd(["tar", "xjf", inputfile_tarfriendly, "-C", packagename_noversion, "--strip-components", "1", "--no-same-owner"])
|
|
|
|
if download and installed_filepath:
|
|
# Create the installed stamp file to note our success
|
|
open(installed_filepath, "wb")
|
|
|
|
# Restore directory.
|
|
os.chdir(old_cwd)
|
|
|
|
return packagename
|
|
|
|
if __name__=='__main__':
|
|
parser=optparse.OptionParser()
|
|
|
|
parser.add_option("-p", "--platform", action="store", type="string",
|
|
dest="platform", help="Platform identifier (e.g. windows-i386)", default=None)
|
|
|
|
parser.add_option("-b", "--buildconfig", action="store", type="string",
|
|
dest="buildconfig", help="Build configuration (release or debug). Default is release", default="release")
|
|
|
|
parser.add_option("-t", "--tag", action="store", type="string",
|
|
dest="tag", help="Build tag. Default is %s" % default_tag, default=default_tag)
|
|
|
|
parser.add_option("-n", "--buildnumber", action="store", type="string",
|
|
dest="buildnumber", help="Build number. Default is %s for release builds" % (default_release_build_number), default=None)
|
|
|
|
parser.add_option("-d", "--dir", action="store", type="string",
|
|
dest="dir", help="CI build dir. Default is %s for release builds" % (default_release_dir), default=None)
|
|
|
|
parser.add_option("-i", "--inputfile", action="store", type="string",
|
|
dest="inputfile", help="Dependencies package filename, can be supplied instead of platform, buildconfig, tag and buildnumber", default=None)
|
|
|
|
parser.add_option("-o", "--output", action="store", type="string",
|
|
dest="output", help="Output directory. Default is Dependencies",
|
|
default="Dependencies")
|
|
|
|
parser.add_option("-x", "--nochecksha", action="store_true",
|
|
dest="nochecksha", help="Don't check the SHA. Default is false",
|
|
default=False)
|
|
|
|
parser.add_option("-r", "--branch", action="store", type="string",
|
|
dest="branch", help="Git branch", default=None)
|
|
|
|
(options, args)=parser.parse_args(sys.argv)
|
|
|
|
if not os.path.exists(options.output):
|
|
os.makedirs(options.output)
|
|
|
|
# Fail early if platform is not known
|
|
download = not options.inputfile
|
|
if download and not options.platform:
|
|
print "ERROR - A platform must be specified"
|
|
sys.exit(1)
|
|
|
|
installed_filepath = None
|
|
if download:
|
|
|
|
if not options.buildnumber:
|
|
if options.buildconfig == "release":
|
|
options.buildnumber = default_release_build_number
|
|
else:
|
|
options.buildnumber = default_debug_build_number
|
|
|
|
if not options.dir:
|
|
if options.buildconfig == "release":
|
|
options.dir = default_release_dir
|
|
else:
|
|
options.dir = default_debug_dir
|
|
|
|
installed_filepath = os.path.join(options.output, "konvergo-depends-%s-%s-%s.installed" % (options.platform, options.buildconfig, options.buildnumber))
|
|
if os.path.exists(installed_filepath) and options.buildnumber != "latest":
|
|
print "The required deps bundle was already downloaded and installed."
|
|
print "You can delete %s to force a reinstall." % installed_filepath
|
|
sys.exit(0)
|
|
|
|
# Delete previous installed stamps
|
|
cont = ["-c"]
|
|
for path in glob.iglob(os.path.join(options.output, "konvergo-depends-%s-%s-*.installed") % (options.platform, options.buildconfig)):
|
|
match = re.search("-(\d+)\.installed", path, re.DOTALL)
|
|
if match:
|
|
if not match.group(1) == options.buildnumber:
|
|
cont = []
|
|
os.remove(path)
|
|
|
|
if options.tag == "auto":
|
|
req = urllib2.Request("https://nightlies.plex.tv/directdl/plex-dependencies/%s/%s/hash.txt" % (options.dir, options.buildnumber))
|
|
try:
|
|
match = urllib2.urlopen(req).read().rstrip()
|
|
except urllib2.URLError, err:
|
|
print err
|
|
print "ERROR - Download failed"
|
|
sys.exit(1)
|
|
|
|
options.tag = match
|
|
|
|
base_filename = "konvergo-depends-%s-%s-%s" % (options.platform, options.buildconfig, options.tag)
|
|
filename = "%s.tbz2" % base_filename
|
|
|
|
installed_filepath = os.path.join(options.output, "konvergo-depends-%s-%s-%s.installed" % (options.platform, options.buildconfig, options.buildnumber))
|
|
if os.path.exists(installed_filepath):
|
|
print "%s was already downloaded and installed." % filename
|
|
print "You can delete %s to force a reinstall." % installed_filepath
|
|
sys.exit(0)
|
|
|
|
url = "https://nightlies.plex.tv/directdl/plex-dependencies/%s/%s/%s" % (options.dir, options.buildnumber, filename)
|
|
inputfile = os.path.join(options.output, filename)
|
|
|
|
print "-- Downloading %s ..." % url
|
|
exec_cmd(["wget", "--no-check-certificate"] + cont + ["-O", inputfile, url])
|
|
|
|
shaurl = "%s.sha.txt" % url
|
|
shafile = "%s.sha.txt" % inputfile
|
|
|
|
print "-- Downloading %s ..." % shaurl
|
|
exec_cmd(["wget", "--no-check-certificate"] + ["-O", shafile, shaurl])
|
|
|
|
else:
|
|
inputfile = options.inputfile
|
|
|
|
# Unpack and install
|
|
packagename = unpack_and_install(download, inputfile, installed_filepath)
|
|
|
|
# On OS X, we need to postprocess the dependencies.
|
|
if platform.system() == 'Darwin':
|
|
root = os.path.realpath(os.path.join(os.getcwd()))
|
|
script = os.path.join(root, "scripts", "fix-install-names.py")
|
|
for p in ("lib", "bin", "update_installer"):
|
|
path = os.path.join(root, "Dependencies", "konvergo-depends-" + options.platform + "-" + options.buildconfig, p)
|
|
exec_cmd([script, path])
|
|
|
|
# Done!
|
|
print "-- Done with %s" % packagename
|