├── repo
└── index.html
├── repository.example
├── icon.png
├── fanart.jpg
└── addon.xml
├── README.md
└── _repo_xml_generator.py
/repo/index.html:
--------------------------------------------------------------------------------
1 | ADDON_ID_HERE-VERSION_NUMBER_HERE.zip
--------------------------------------------------------------------------------
/repository.example/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/kibibit-kodi-repo/master/repository.example/icon.png
--------------------------------------------------------------------------------
/repository.example/fanart.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kibibit/kibibit-kodi-repo/master/repository.example/fanart.jpg
--------------------------------------------------------------------------------
/repository.example/addon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | https://raw.githubusercontent.com/kibibit/kodi-repo/master/zips/addons.xml
6 | https://raw.githubusercontent.com/kibibit/kodi-repo/master/zips/addons.xml.md5
7 | https://raw.githubusercontent.com/kibibit/kodi-repo/master/zips/
8 |
9 |
10 |
11 | kibibit repository
12 | All of our recommended add-ons
13 |
14 | all
15 |
16 | icon.png
17 | fanart.jpg
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BASIC - How to setup for hosting on GitHub Pages
2 |
3 | In order to follow this tutorial, first fork this repository, and then clone your newly forked copy locally.
4 |
5 | First, you'll need to edit the `addon.xml` file within the `/repository.example` folder with your chosen add-on ID, a version number, and your username (or whatever you'd like) for `provider`, as seen on line 2:
6 |
7 | ```XML
8 |
9 | ```
10 |
11 | You also need to replace `YOUR_USERNAME_HERE` and `REPOSITORY_NAME_HERE` with your GitHub username and this repository's name, respectively, as seen on lines 5-7:
12 |
13 | ```XML
14 | https://raw.githubusercontent.com/YOUR_USERNAME_HERE/REPOSITORY_NAME_HERE/master/zips/addons.xml
15 | https://raw.githubusercontent.com/YOUR_USERNAME_HERE/REPOSITORY_NAME_HERE/master/zips/addons.xml.md5
16 | https://raw.githubusercontent.com/YOUR_USERNAME_HERE/REPOSITORY_NAME_HERE/master/zips/
17 | ```
18 |
19 | You should also change the summary and description of your repository, as seen on lines 11-12:
20 |
21 | ```XML
22 | REPO_NAME_HERE
23 | DESCRIPTION OF YOUR REPO HERE
24 | ```
25 |
26 | While not required, it is also recommended to replace `icon.png` and `fanart.jpg` in the `/repository.example` folder with art relevant to your repository or the add-ons contained within. `icon.png` should be 512x512 px, and `fanart.jpg` should be 1920x1080 px, or a similar ratio.
27 |
28 | To build the repository, first rename the `/repository.example` folder to match whatever add-on ID you chose earlier. Place the add-on source folders for whichever add-ons you'd like to be contained in your Kodi repo in the main folder of this repository, and run `_repo_xml_generator.py`.
29 |
30 | This will create zips of all of the desired add-ons, and place them in the `zips` folder, along with a generated `addons.xml` and `addons.xml.md5`. Copy the zip file of your repository, located at `/zips/ADDON_ID_HERE/ADDON_ID_HERE-VERSION_NUMBER_HERE.zip`,
31 | and paste it into the `/repo` folder.
32 |
33 | Inside the `/repo` folder, edit the link inside `index.html` to reflect your add-on's filename, as seen on line 1:
34 |
35 | ```HTML
36 | ADDON_ID_HERE-VERSION_NUMBER_HERE.zip
37 | ```
38 |
39 | After committing and pushing these changes to your repo, go to the "Settings" section for this repository on GitHub. In the first box, labeled "Repository name", change your repository's name. Generally, GitHub Pages repositories are named `YOUR_USERNAME_HERE.github.io`, but it can be whatever you'd like.
40 | Next, scroll down to the "GitHub Pages" section, choose the `master` branch as the source, and click "Save".
41 |
42 | After that, you should be all done!
43 |
44 | If you named this repository `YOUR_USERNAME_HERE.github.io`, your file manager source will be:
45 |
46 | `https://YOUR_USERNAME_HERE.github.io/repo/`
47 |
48 | And if you named it something else, it will be:
49 |
50 | `https://YOUR_USERNAME_HERE.github.io/REPOSITORY_NAME_HERE/repo/`
51 |
52 | # ADVANCED - How to set up for hosting without GitHub Pages
53 |
54 | If you want to host your Kodi repo on a different host besides GitHub Pages, simply download this repository as a `.zip`, and unzip it , rather than forking and cloning it. Continue to follow the rest of the setup procedure, except for the setting up of GitHub Pages. The only differences will be in your `addon.xml` file (lines 5-7), as it will need to reference yourhost, rather than GitHub:
55 |
56 | ```XML
57 | https://YOUR_HOST_URL_HERE/zips/addons.xml
58 | https://YOUR_HOST_URL_HERE/zips/addons.xml.md5
59 | https://YOUR_HOST_URL_HERE/zips/
60 | ```
61 |
62 | And upload the contents of this repository to your host. It is **very important** that `YOUR_HOST_URL_HERE` is the URL to *this* folder.
63 |
64 | After doing so, your file manager source will be:
65 |
66 | `https://YOUR_HOST_URL_HERE/repo/`
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/_repo_xml_generator.py:
--------------------------------------------------------------------------------
1 | """ downloaded from http://xbmc-addons.googlecode.com/svn/addons/ """
2 | """ This is a modded version of the original addons.xml generator """
3 |
4 | """ Put this version in the root folder of your repo and it will """
5 | """ zip up all add-on folders, create a new zip in your zips folder """
6 | """ and then update the md5 and addons.xml file """
7 |
8 | """ Recoded by whufclee (info@totalrevolution.tv) """
9 |
10 | import re
11 | import os
12 | import shutil
13 | import hashlib
14 | import zipfile
15 |
16 | class Generator:
17 | """
18 | Generates a new addons.xml file from each addons addon.xml file
19 | and a new addons.xml.md5 hash file. Must be run from the root of
20 | the checked-out repo. Only handles single depth folder structure.
21 | """
22 | def __init__(self):
23 | # Create the zips folder if it doesn't already exist
24 | zips_path = ('zips')
25 | if not os.path.exists(zips_path):
26 | os.makedirs(zips_path)
27 |
28 | # Comment out this line if you have .pyc or .pyo files you need to keep
29 | self._remove_binaries()
30 |
31 | self._generate_addons_file()
32 | self._generate_md5_file()
33 | print("Finished updating addons xml and md5 files")
34 |
35 | def _create_zips(self, addon_id, version):
36 | xml_path = os.path.join(addon_id, 'addon.xml')
37 | addon_folder = os.path.join('zips', addon_id)
38 | if not os.path.exists(addon_folder):
39 | os.makedirs(addon_folder)
40 |
41 | final_zip = os.path.join('zips', addon_id, '{0}-{1}.zip'.format(addon_id, version))
42 | if not os.path.exists(final_zip):
43 | print("NEW ADD-ON - Creating zip for: {0} v.{1}".format(addon_id, version))
44 | zip = zipfile.ZipFile(final_zip, 'w', compression=zipfile.ZIP_DEFLATED )
45 | root_len = len(os.path.dirname(os.path.abspath(addon_id)))
46 |
47 | ignore = ['.git', '.github', '.gitignore', '.DS_Store', 'thumbs.db', '.idea', 'venv']
48 |
49 | for root, dirs, files in os.walk(addon_id):
50 | # remove any unneeded git artifacts
51 | for i in ignore:
52 | if i in dirs:
53 | try:
54 | dirs.remove(i)
55 | except:
56 | pass
57 | for f in files:
58 | if f.startswith(i):
59 | try:
60 | files.remove(f)
61 | except:
62 | pass
63 |
64 | archive_root = os.path.abspath(root)[root_len:]
65 |
66 | for f in files:
67 | fullpath = os.path.join(root, f)
68 | archive_name = os.path.join(archive_root, f)
69 | zip.write(fullpath, archive_name, zipfile.ZIP_DEFLATED)
70 |
71 | zip.close()
72 |
73 | # Copy over the icon, fanart and addon.xml to the zip directory
74 | copyfiles = ['icon.png', 'fanart.jpg', 'addon.xml']
75 | files = os.listdir(addon_id)
76 | for file in files:
77 | if file in copyfiles:
78 | shutil.copy(os.path.join(addon_id, file), addon_folder)
79 |
80 | # Remove any instances of pyc or pyo files
81 | def _remove_binaries(self):
82 | for parent, dirnames, filenames in os.walk('.'):
83 | for fn in filenames:
84 | if fn.lower().endswith('pyo') or fn.lower().endswith('pyc'):
85 | compiled = os.path.join(parent, fn)
86 | py_file = compiled.replace('.pyo', '.py').replace('.pyc', '.py')
87 | if os.path.exists(py_file):
88 | try:
89 | os.remove(compiled)
90 | print("Removed compiled python file:")
91 | print(compiled)
92 | print('-----------------------------')
93 | except:
94 | print("Failed to remove compiled python file:")
95 | print(compiled)
96 | print('-----------------------------')
97 | else:
98 | print("Compiled python file found but no matching .py file exists:")
99 | print(compiled)
100 | print('-----------------------------')
101 |
102 | def _generate_addons_file(self):
103 | # addon list
104 | addons = os.listdir('.')
105 |
106 | # final addons text
107 | addons_xml = u"\n\n"
108 |
109 | # loop thru and add each addons addon.xml file
110 | for addon in addons:
111 | try:
112 | if not os.path.isdir(addon) or addon == "zips" or addon.startswith('.'):
113 | continue
114 | _path = os.path.join(addon, "addon.xml")
115 | xml_lines = open(_path, "r", encoding='utf-8').read().splitlines()
116 | addon_xml = ""
117 |
118 | # loop thru cleaning each line
119 | ver_found = False
120 | for line in xml_lines:
121 | if line.find( "= 0:
122 | continue
123 | if 'version="' in line and not ver_found:
124 | version = re.compile('version="(.+?)"').findall(line)[0]
125 | ver_found = True
126 | addon_xml += line.rstrip() + "\n"
127 | addons_xml += addon_xml.rstrip() + "\n\n"
128 |
129 | # Create the zip files
130 | self._create_zips(addon, version)
131 |
132 | except Exception as e:
133 | print("Excluding {0} for {1}".format(_path, e))
134 |
135 | # clean and add closing tag
136 | addons_xml = addons_xml.strip() + u"\n\n"
137 | self._save_file(addons_xml.encode('utf-8'), file=os.path.join('zips', 'addons.xml'), decode=True)
138 |
139 | def _generate_md5_file(self):
140 | try:
141 | m = hashlib.md5(open(os.path.join('zips', 'addons.xml'), 'r', encoding='utf-8').read().encode('utf-8')).hexdigest()
142 | self._save_file(m, file=os.path.join('zips', 'addons.xml.md5'))
143 | except Exception as e:
144 | print("An error occurred creating addons.xml.md5 file!\n{0}".format(e))
145 |
146 | def _save_file(self, data, file, decode=False):
147 | try:
148 | if decode:
149 | open(file, 'w', encoding='utf-8').write(data.decode('utf-8'))
150 | else:
151 | open(file, 'w').write(data)
152 | except Exception as e:
153 | print("An error occurred saving {0} file!\n{1}".format(file, e))
154 |
155 |
156 | if __name__ == "__main__":
157 | Generator()
158 |
--------------------------------------------------------------------------------