Archive:Create a repository for add-ons: Difference between revisions
>Garbear (→Things you will require: Updated addons_xml_generator.py to work with Python 3) |
>Martijn |
||
Line 9: | Line 9: | ||
You can use <tt>addons_xml_generator.py</tt>[https://raw.github.com/garbear/unqlocked/master/addons_xml_generator.py] to generate the master xml and the MD5. Put it in the folder with all your add-ons (in source code, not zip files) and run it from your Python interpreter. If using a source code server, you can now upload your add-on folder via svn or git to your repository. Every time you update an add-on run the addons_xml_generator.py before uploading the add-ons folder. | You can use <tt>addons_xml_generator.py</tt>[https://raw.github.com/garbear/unqlocked/master/addons_xml_generator.py] to generate the master xml and the MD5. Put it in the folder with all your add-ons (in source code, not zip files) and run it from your Python interpreter. If using a source code server, you can now upload your add-on folder via svn or git to your repository. Every time you update an add-on run the addons_xml_generator.py before uploading the add-ons folder. | ||
addons_xml_generator.py | |||
<source lang="python"> | |||
# * | |||
# * Copyright (C) 2012-2013 Garrett Brown | |||
# * Copyright (C) 2010 j48antialias | |||
# * | |||
# * This Program is free software; you can redistribute it and/or modify | |||
# * it under the terms of the GNU General Public License as published by | |||
# * the Free Software Foundation; either version 2, or (at your option) | |||
# * any later version. | |||
# * | |||
# * This Program is distributed in the hope that it will be useful, | |||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# * GNU General Public License for more details. | |||
# * | |||
# * You should have received a copy of the GNU General Public License | |||
# * along with XBMC; see the file COPYING. If not, write to | |||
# * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |||
# * http://www.gnu.org/copyleft/gpl.html | |||
# * | |||
# * Based on code by j48antialias: | |||
# * https://anarchintosh-projects.googlecode.com/files/addons_xml_generator.py | |||
""" addons.xml generator """ | |||
import os | |||
import sys | |||
# Compatibility with 3.0, 3.1 and 3.2 not supporting u"" literals | |||
if sys.version < '3': | |||
import codecs | |||
def u(x): | |||
return codecs.unicode_escape_decode(x)[0] | |||
else: | |||
def u(x): | |||
return x | |||
class Generator: | |||
""" | |||
Generates a new addons.xml file from each addons addon.xml file | |||
and a new addons.xml.md5 hash file. Must be run from the root of | |||
the checked-out repo. Only handles single depth folder structure. | |||
""" | |||
def __init__( self ): | |||
# generate files | |||
self._generate_addons_file() | |||
self._generate_md5_file() | |||
# notify user | |||
print("Finished updating addons xml and md5 files") | |||
def _generate_addons_file( self ): | |||
# addon list | |||
addons = os.listdir( "." ) | |||
# final addons text | |||
addons_xml = u("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addons>\n") | |||
# loop thru and add each addons addon.xml file | |||
for addon in addons: | |||
try: | |||
# skip any file or .svn folder or .git folder | |||
if ( not os.path.isdir( addon ) or addon == ".svn" or addon == ".git" ): continue | |||
# create path | |||
_path = os.path.join( addon, "addon.xml" ) | |||
# split lines for stripping | |||
xml_lines = open( _path, "r" ).read().splitlines() | |||
# new addon | |||
addon_xml = "" | |||
# loop thru cleaning each line | |||
for line in xml_lines: | |||
# skip encoding format line | |||
if ( line.find( "<?xml" ) >= 0 ): continue | |||
# add line | |||
if sys.version < '3': | |||
addon_xml += unicode( line.rstrip() + "\n", "UTF-8" ) | |||
else: | |||
addon_xml += line.rstrip() + "\n" | |||
# we succeeded so add to our final addons.xml text | |||
addons_xml += addon_xml.rstrip() + "\n\n" | |||
except Exception as e: | |||
# missing or poorly formatted addon.xml | |||
print("Excluding %s for %s" % ( _path, e )) | |||
# clean and add closing tag | |||
addons_xml = addons_xml.strip() + u("\n</addons>\n") | |||
# save file | |||
self._save_file( addons_xml.encode( "UTF-8" ), file="addons.xml" ) | |||
def _generate_md5_file( self ): | |||
# create a new md5 hash | |||
try: | |||
import md5 | |||
m = md5.new( open( "addons.xml", "r" ).read() ).hexdigest() | |||
except ImportError: | |||
import hashlib | |||
m = hashlib.md5( open( "addons.xml", "r", encoding="UTF-8" ).read().encode( "UTF-8" ) ).hexdigest() | |||
# save file | |||
try: | |||
self._save_file( m.encode( "UTF-8" ), file="addons.xml.md5" ) | |||
except Exception as e: | |||
# oops | |||
print("An error occurred creating addons.xml.md5 file!\n%s" % e) | |||
def _save_file( self, data, file ): | |||
try: | |||
# write data to the file (use b for Python 3) | |||
open( file, "wb" ).write( data ) | |||
except Exception as e: | |||
# oops | |||
print("An error occurred saving %s file!\n%s" % ( file, e )) | |||
if ( __name__ == "__main__" ): | |||
# start | |||
Generator() | |||
</source> | |||
== Repository Files == | == Repository Files == |
Revision as of 15:55, 9 February 2013
When you have created your repository, feel free to add it to the 3rd party add-on repositories list.
Things you will require
- Any HTTP server. A popular method is to use the svn or git source code servers of googlecode, gitorious and github.
- A folder containing one or more add-on.
- A master addons.xml file. This file contains metadata about all available add-ons.
- A checksum of the above file.
- A zipped repository add-on for distribution. This allows you to share your repository with others.
You can use addons_xml_generator.py[1] to generate the master xml and the MD5. Put it in the folder with all your add-ons (in source code, not zip files) and run it from your Python interpreter. If using a source code server, you can now upload your add-on folder via svn or git to your repository. Every time you update an add-on run the addons_xml_generator.py before uploading the add-ons folder.
addons_xml_generator.py
# * # * Copyright (C) 2012-2013 Garrett Brown # * Copyright (C) 2010 j48antialias # * # * This Program is free software; you can redistribute it and/or modify # * it under the terms of the GNU General Public License as published by # * the Free Software Foundation; either version 2, or (at your option) # * any later version. # * # * This Program is distributed in the hope that it will be useful, # * but WITHOUT ANY WARRANTY; without even the implied warranty of # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # * GNU General Public License for more details. # * # * You should have received a copy of the GNU General Public License # * along with XBMC; see the file COPYING. If not, write to # * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # * http://www.gnu.org/copyleft/gpl.html # * # * Based on code by j48antialias: # * https://anarchintosh-projects.googlecode.com/files/addons_xml_generator.py """ addons.xml generator """ import os import sys # Compatibility with 3.0, 3.1 and 3.2 not supporting u"" literals if sys.version < '3': import codecs def u(x): return codecs.unicode_escape_decode(x)[0] else: def u(x): return x class Generator: """ Generates a new addons.xml file from each addons addon.xml file and a new addons.xml.md5 hash file. Must be run from the root of the checked-out repo. Only handles single depth folder structure. """ def __init__( self ): # generate files self._generate_addons_file() self._generate_md5_file() # notify user print("Finished updating addons xml and md5 files") def _generate_addons_file( self ): # addon list addons = os.listdir( "." ) # final addons text addons_xml = u("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<addons>\n") # loop thru and add each addons addon.xml file for addon in addons: try: # skip any file or .svn folder or .git folder if ( not os.path.isdir( addon ) or addon == ".svn" or addon == ".git" ): continue # create path _path = os.path.join( addon, "addon.xml" ) # split lines for stripping xml_lines = open( _path, "r" ).read().splitlines() # new addon addon_xml = "" # loop thru cleaning each line for line in xml_lines: # skip encoding format line if ( line.find( "<?xml" ) >= 0 ): continue # add line if sys.version < '3': addon_xml += unicode( line.rstrip() + "\n", "UTF-8" ) else: addon_xml += line.rstrip() + "\n" # we succeeded so add to our final addons.xml text addons_xml += addon_xml.rstrip() + "\n\n" except Exception as e: # missing or poorly formatted addon.xml print("Excluding %s for %s" % ( _path, e )) # clean and add closing tag addons_xml = addons_xml.strip() + u("\n</addons>\n") # save file self._save_file( addons_xml.encode( "UTF-8" ), file="addons.xml" ) def _generate_md5_file( self ): # create a new md5 hash try: import md5 m = md5.new( open( "addons.xml", "r" ).read() ).hexdigest() except ImportError: import hashlib m = hashlib.md5( open( "addons.xml", "r", encoding="UTF-8" ).read().encode( "UTF-8" ) ).hexdigest() # save file try: self._save_file( m.encode( "UTF-8" ), file="addons.xml.md5" ) except Exception as e: # oops print("An error occurred creating addons.xml.md5 file!\n%s" % e) def _save_file( self, data, file ): try: # write data to the file (use b for Python 3) open( file, "wb" ).write( data ) except Exception as e: # oops print("An error occurred saving %s file!\n%s" % ( file, e )) if ( __name__ == "__main__" ): # start Generator()
Repository Files
Repositories are distributed just like any other add-on. In order for you to browse one in XBMC, you'll need to create an add-on and install it. The repository addon extends the xbmc.addon.repository extension point, so in addition to the general XML structure and icons required for an icon, you'll need an <extension> block specfically pointing to your repository. Use the addon.xml of any of the 3rd party add-on repositories as a template. Online repositories should always have zip set to true, both for efficiency of download and for the protection that .zip offers by way of verifying the download (i.e. can we unzip it).
Tips
Using your repo to host images
You may as a developer need to host images from time to time. Something like photobucket or flickr may work, but you can also use your repo. Commit an image to it, and then form the url to it as you would if you were accessing the image via git or svn (like below):
http://xbmc-adult.googlecode.com/svn/trunk/repository.xbmc-adult/icon.png
This can then be accessed easily from python code, or even embedded on the XBMC forums.
How to make an add-on self-updating without distributing a repository file
This is optional. You still need a repository for this, you just distribute the actual zipped plugin or script, as opposed to the repository file. First you need to have a working repository file. Copy the equivalent of this code from the addon.xml of your repository file:
<extension point="xbmc.addon.repository" name="Official XBMC.org Add-on Repository"> <info compressed="true">http://mirrors.xbmc.org/addons/dharma-pre/addons.xml</info> <checksum>http://mirrors.xbmc.org/addons/dharma-pre/addons.xml.md5</checksum> <datadir zip="true">http://mirrors.xbmc.org/addons/dharma-pre</datadir> </extension>
Then simply add it under the other <extension point> entries of your add-on's addon.xml The name= part of this repository extension must never be the same as your add-on.
See also
Development: