forked from Josh5/Kodi-Module-Generator
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2ce84d1
Showing
5 changed files
with
295 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/modules.json | ||
/venv/** | ||
/.idea/** | ||
|
||
/cache/** | ||
/out/** | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding:utf-8 -*- | ||
### | ||
# File: build.py | ||
# Project: Kodi-Module-Generator | ||
# File Created: Monday, 10th May 2021 8:52:42 pm | ||
# Author: Josh.5 ([email protected]) | ||
# ----- | ||
# Last Modified: Monday, 10th May 2021 11:34:57 pm | ||
# Modified By: Josh.5 ([email protected]) | ||
### | ||
|
||
# Requirements = `python3 -m pip install pipgrip` | ||
|
||
import json | ||
import os | ||
import shutil | ||
import subprocess | ||
|
||
template_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'template') | ||
out_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'out') | ||
cache_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'cache') | ||
|
||
|
||
def install_module(module_dir, module_name, version): | ||
module_lib_dir = os.path.abspath(os.path.join(module_dir, 'lib')) | ||
if not module_lib_dir: | ||
os.makedirs(module_lib_dir) | ||
|
||
# First install local | ||
cmd = 'python3 -m pip install --user {}=={}'.format(module_name, version) | ||
subprocess.call(cmd, shell=True) | ||
|
||
# Then install to module directory | ||
cmd = 'python3 -m pip install --ignore-installed --no-dependencies --target={} {}=={}'.format(module_lib_dir, | ||
module_name, | ||
version) | ||
subprocess.call(cmd, shell=True) | ||
|
||
|
||
def update_module_data(module_dir, module_name, module_deps_list): | ||
# Read data from module | ||
res = subprocess.check_output('python3 -m pip show {}'.format(module_name), shell=True) | ||
module_version = '' | ||
module_author = '' | ||
module_author_email = '' | ||
module_license = '' | ||
module_summary = '' | ||
module_website = 'https://pypi.org/project/{}/'.format(module_name) | ||
for line in res.splitlines(): | ||
x = str(line.decode("utf-8")) | ||
print(x) | ||
if x.startswith('Version:'): | ||
module_version = x.split(': ')[1].strip() | ||
elif x.startswith('Author:'): | ||
module_author = x.split(': ')[1].strip() | ||
elif x.startswith('Author-email:'): | ||
module_author_email = x.split(': ')[1].strip() | ||
elif x.startswith('License:'): | ||
module_license = x.split(': ')[1].strip() | ||
elif x.startswith('Summary:'): | ||
module_summary = x.split(': ')[1].strip() | ||
|
||
module_xml = os.path.join(module_dir, 'addon.xml') | ||
# Read in the file | ||
with open(module_xml, 'r') as file: | ||
file_data = file.read() | ||
|
||
# Replace the target string with data from pip show | ||
if module_author_email: | ||
module_author = '{} ({})'.format(module_author, module_author_email) | ||
file_data = file_data.replace('PYTHON_MODULE_NAME', module_name) | ||
file_data = file_data.replace('PYTHON_MODULE_VERSION', module_version) | ||
file_data = file_data.replace('PYTHON_MODULE_AUTHOR', module_author) | ||
file_data = file_data.replace('PYTHON_MODULE_LICENSE', module_license) | ||
file_data = file_data.replace('PYTHON_MODULE_SUMMARY', module_summary) | ||
file_data = file_data.replace('PYTHON_MODULE_DESCRIPTION', module_summary) | ||
file_data = file_data.replace('PYTHON_MODULE_WEBSITE', module_website) | ||
|
||
# Append dependencies list | ||
template = ' <import addon="script.module.{}" version="{}" />' | ||
deps_to_add = "" | ||
for dep in module_deps_list: | ||
line = template.format(dep.get('name'), dep.get('version')) | ||
deps_to_add = "{}\n{}".format(deps_to_add, line) | ||
file_data = file_data.replace('PYTHON_MODULE_DEPENDENCIES', deps_to_add) | ||
|
||
# Write the file out again | ||
with open(module_xml, 'w') as file: | ||
file.write(file_data) | ||
|
||
|
||
def sanitize_module(module_name): | ||
module_dir = os.path.join(out_dir, 'script.module.{}'.format(module_name)) | ||
sanitize_script = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'sanitize.sh') | ||
cmd = '{} {}'.format(sanitize_script, module_dir) | ||
subprocess.call(cmd, shell=True) | ||
|
||
|
||
def build_script_module(module_name, version, module_deps): | ||
module_dir = os.path.join(out_dir, 'script.module.{}'.format(module_name)) | ||
if not os.path.exists(module_dir): | ||
os.makedirs(module_dir) | ||
|
||
if not os.path.exists(os.path.join(module_dir, 'addon.xml')): | ||
shutil.copy(os.path.join(template_dir, 'addon.xml'), os.path.join(module_dir, 'addon.xml')) | ||
|
||
if not os.path.exists(os.path.join(module_dir, 'icon.png')): | ||
shutil.copy(os.path.join(template_dir, 'icon.png'), os.path.join(module_dir, 'icon.png')) | ||
|
||
# Install modules | ||
install_module(module_dir, module_name, version) | ||
|
||
# Sanitize module | ||
sanitize_module(module_name) | ||
|
||
# Write addon.xml | ||
update_module_data(module_dir, module_name, module_deps) | ||
|
||
|
||
def process_module_deps_list(deps_list): | ||
for dep in deps_list: | ||
module_name = dep.get('name') | ||
module_version = dep.get('version') | ||
child_deps = dep.get('dependencies', []) | ||
|
||
# Build module for each item found in depends list | ||
process_module_deps_list(child_deps) | ||
|
||
# Build module | ||
print("Building Kodi Python module for {} v{}".format(module_name, module_version)) | ||
build_script_module(module_name, module_version, child_deps) | ||
|
||
|
||
def create_dep_list(module, version): | ||
deps_cache = os.path.join(cache_dir, 'deps-{}-{}.json'.format(module, version)) | ||
|
||
if not os.path.exists(deps_cache): | ||
print("Fetching Dependencies list for {} v{}".format(module, version)) | ||
cmd = 'pipgrip --tree --json unmanic'.format(module, version) | ||
res = subprocess.check_output(cmd, shell=True) | ||
decoded = str(res.decode("utf-8")) | ||
data = json.loads(decoded) | ||
|
||
with open(deps_cache, 'w') as file: | ||
json.dump(data, file, indent=2) | ||
|
||
with open(deps_cache, 'r') as file: | ||
deps_list = json.load(file) | ||
|
||
return deps_list | ||
|
||
|
||
def run(): | ||
if not os.path.exists(template_dir): | ||
os.makedirs(template_dir) | ||
if not os.path.exists(out_dir): | ||
os.makedirs(out_dir) | ||
if not os.path.exists(cache_dir): | ||
os.makedirs(cache_dir) | ||
|
||
try: | ||
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'modules.json'), 'r') as file: | ||
modules = json.load(file) | ||
except Exception as e: | ||
print("No modules configured... - {}".format(str(e))) | ||
modules = [] | ||
|
||
for module_data in modules: | ||
original_module = module_data.get('module') | ||
version = module_data.get('version') | ||
deps_list = create_dep_list(original_module, version) | ||
process_module_deps_list(deps_list) | ||
|
||
|
||
if __name__ == '__main__': | ||
run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#!/bin/bash | ||
|
||
### | ||
# File: sanitize.sh | ||
# Project: Kodi-Module-Generator | ||
# File Created: Monday, 10th May 2021 11:02:32 pm | ||
# Author: Josh.5 ([email protected]) | ||
# ----- | ||
# Last Modified: Monday, 10th May 2021 11:10:23 pm | ||
# Modified By: Josh.5 ([email protected]) | ||
### | ||
|
||
|
||
|
||
addon_root=${@} | ||
lib_dir="${addon_root}/lib" | ||
|
||
|
||
print_step(){ | ||
ten=" " | ||
spaces="${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}" | ||
message=" - ${@}" | ||
message="${message:0:70}${spaces:0:$((70 - ${#message}))}" | ||
echo -ne "${message}" | ||
} | ||
print_sub_step(){ | ||
ten=" " | ||
spaces="${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}${ten}" | ||
message=" - ${@}" | ||
message="${message:0:70}${spaces:0:$((70 - ${#message}))}" | ||
echo -ne "${message}" | ||
} | ||
mark_step(){ | ||
RED="\e[31m" | ||
GREEN="\e[32m" | ||
ENDCOLOR="\e[0m" | ||
status_message="" | ||
[[ ${1} == 'failed' ]] && status_message="${RED}[FAILED]${ENDCOLOR}" | ||
[[ ${1} == 'success' ]] && status_message="${GREEN}[SUCCESS]${ENDCOLOR}" | ||
echo -e "${status_message}" | ||
} | ||
|
||
|
||
# Remove everything except the Python source | ||
remove_extensions=( | ||
"ans" | ||
"bz2" | ||
"db" | ||
"dll" | ||
"exe" | ||
"gz" | ||
"mo" | ||
"pyc" | ||
"pyo" | ||
"so" | ||
"xbt" | ||
"xpr" | ||
) | ||
print_step "Cleaning out unnecessary binary files:" | ||
mark_step | ||
for ext in "${remove_extensions[@]}"; do | ||
print_sub_step "Delete all '*.${ext}' files..." | ||
find "${lib_dir}" -type f -iname "*.${ext}" -delete | ||
[[ $? > 0 ]] && mark_step failed && exit 1 | ||
mark_step success | ||
done | ||
print_step "Cleaning out Python cache directories" | ||
find "${lib_dir}" -type d -name "__pycache__" -exec rm -rf {} + | ||
[[ $? > 0 ]] && mark_step failed && exit 1 | ||
mark_step success | ||
print_step "Cleaning out Python 'dist-info' directories" | ||
find "${lib_dir}" -type d -name "*.dist-info" -exec rm -rf {} + | ||
[[ $? > 0 ]] && mark_step failed && exit 1 | ||
mark_step success | ||
|
||
# Remove Python bin | ||
print_step "Removing 'bin' Python directory" | ||
rm -rf "${lib_dir}/bin" | ||
[[ $? > 0 ]] && mark_step failed && exit 1 | ||
mark_step success | ||
|
||
# Ensure all files are not executable | ||
print_step "Ensure all items in the lib directory are not executable" | ||
find "${lib_dir}" -type f -exec chmod a-x {} + | ||
[[ $? > 0 ]] && mark_step failed && exit 1 | ||
mark_step success | ||
|
||
exit 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||
<addon id="script.module.PYTHON_MODULE_NAME" | ||
name="PYTHON_MODULE_NAME" | ||
version="PYTHON_MODULE_VERSION" | ||
provider-name="PYTHON_MODULE_AUTHOR"> | ||
<requires> | ||
<import addon="xbmc.python" | ||
version="3.0.0"/>PYTHON_MODULE_DEPENDENCIES | ||
</requires> | ||
<extension point="xbmc.python.module" | ||
library="lib"/> | ||
<extension point="xbmc.addon.metadata"> | ||
<summary lang="en_GB">PYTHON_MODULE_SUMMARY</summary> | ||
<description lang="en_GB">PYTHON_MODULE_DESCRIPTION</description> | ||
<license>PYTHON_MODULE_LICENSE</license> | ||
<platform>all</platform> | ||
<website>PYTHON_MODULE_WEBSITE</website> | ||
<source>PYTHON_MODULE_WEBSITE</source> | ||
<assets> | ||
<icon>icon.png</icon> | ||
</assets> | ||
</extension> | ||
</addon> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.