addon.xml changelog.txt default.py fanart.jpg icon.png License.txt \resources\ settings.xml \language\ \English strings.po \Russian\ strings.po \Ukrainian\ strings.po \lib\ feeds.py \thumbnails\  <?xml version="1.0" encoding="UTF-8"?> <!--   --> <addon id="plugin.video.cnet" version="0.0.1" name="CNET Video Podcasts" provider-name="Roman_V_M"> <!--  --> <requires> <import addon="xbmc.python" version="2.1"/> </requires> <!--  ()  --> <extension point="xbmc.python.pluginsource" library="default.py"> <provides>video</provides> </extension> <!--  --> <extension point="xbmc.addon.metadata"> <summary lang="en">CNET Video Podcasts</summary> <summary lang="ru">- CNET</summary> <summary lang="uk">і- CNET</summary> <description lang="en">Addon for watching CNET video podcasts from XBMC.</description> <description lang="ru">   - CNET  XBMC.</description> <description lang="uk">   і-і CNET  XBMC.</description> <platform>all</platform> </extension> </addon>  <import addon="plugin.video.youtube" version="4.0.0"/> extension point="xbmc.python.pluginsource" means that this is the source plugin for the content, library="default.py" indicates the starting script of the plugin, and video means that it is a video plugin. If the plugin provides access to different content, in the tag you can specify the types of available content separated by spaces. Possible values: video, music and image. These values determine in which section this plugin will be displayed: “Video”, “Music” or “Photo”. Plugin to access different types of content can be displayed in several sections.    executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     . executable, . .:
<extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension>
«». - «», «» «» (video, music image ), - , runtime- ( ).
.
16—22 . XBMC. 23 , .
icon.png
icon.png — () , XBMC. — PNG 256x256 .
fanart.jpg
fanart.jpg — (), . — JPG 1280x720 . : (). , «» , / .
changelog.txt
changelog.txt .
License.txt
License.txt . , . , , XBMC.
default.py
default.py — . «default.py» , ( library= extension), default.py, — , .
- PEP 8, , ____, .
: # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html # import sys, os, urllib2, socket, xml.dom.minidom # XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui # _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') # sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds # def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') # URL-encoded def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name # RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing # ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) # . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) # . . list_item.setProperty('fanart_image', fanart) # URL, . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') # . isFolder=True , (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) # -- , . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) # xbmcplugin.endOfDirectory(addon_id) # . switch_view() # . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') # "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') # "-" # . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: # . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) # . . list_item.setProperty('fanart_image', fanart) # . isFolder=False , . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) # . xbmcplugin.endOfDirectory(addon_id) def main(): # . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') # . feed = get_feed_name() # XBMC ( ), . if feed: # . quality = _addon.getSetting('quality') # . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: # . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) # . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: # ( ), xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) # XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: # XBMC ( ), , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) # . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main()
. .
11—15 — . , , , , PEP 8.
:
11: . , addon.xml, ( ).
12: Addon .
13: runtime- (handle). — , 2- XBMC. addDirectoryItem(). . , - - , - () , XBMC API. , . XBMC ( ) - 3 sys.argv: URL, runtime- (, ), URL-encoded . -, , , sys.argv . , runtime- , addDirectoryItem(), - . URL .
14: URL . URL ''plugin://'' + ( ) + ''/''. URL : "plugin://plugin.video.cnet/". URL ( ) , . , , , XBMC , ( — ) . , , .
(), , . , «», «» «» XBMC « », , , . - , — , — , . , (- ) — XBMC. «» , ( ) . . addDirectoryItem() , . .
15: getAddonInfo('path') , , , , . : Windows, ( , ASCII), , (exeption). , Windows . decode('utf-8'). , , Windows.
getAddonInfo('path') — ( XBMC) . os.path.dirname(__file__) , os.getcwd() . , , , XBMC.
18—19: feeds /resources/lib. cnet.com, URL (dictionary). , , — www.cnet.com/podcasts — , — , , .
22—23: . .getLocalizedString() , UTF-8. , , , , .
26—32: - URL-encoded . - , . , XBMC URL-encoded . URL (. ) URL-encoded .
. , plugin.video.acme, , , . «Action» «Movies» plugin://plugin.video.acme/?=Movies&=Action. addDirectoryItem ( ). , plugin.video.acme, sys.argv[2] «?=Movies&=Action». , , , : XBMC . XBMC (, ), , , (, «Action» «Movies»). .
: , . URL, plugin://.
: xbmcplugin.addDirectoryItem, - , isFolder=False. isFolder=True XBMC , .
35—49: RSS- . XML - . , - (, , ).
52—64: cnet.com — , . .
57: xbmcgui.ListItem. , . , , , () ().
59: . , , .
61: . . , .
63: . , sys.argv[1]. , - . , addDirectoryItem() . isFolder=True XBMC, — , . . , . url , , .
65: . , , .
67: XBMC, .
69: (). , , ( , ), , , , . Container.SetViewMode() , MyVideoNav.xml, MyMusicNav.xml MyPics.xml , .
, . — Youtube.
72—77: . . 500 «» Confluence, 512 — «-» «Aeon-Nox». .
80—89: , . , feed_list(), , URL isFolder False, . . ( ) , .
: isFolder=False , , xbmcplugin.addDirectoryItem. , ( ). xbmcplugin.addDirectoryItem .
92—119: . , . .
101: , . , , .
114: XBMC. _string(), XBMC. .
\resources
\resources — , .
settings.xml
settings.xml — , , XML, , «». «» .
: <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings>
— (labelenum) (HD SD). label= , , . id="" (. 101 default.py).
settings.xml « XBMC Addon Developers Guide » ( ). , , .
XML \userdata\addon_data\ XBMC. Windows , , %AppData%\XBMC, Linux — $HOME/.xbmc.
\language
\language . , , , , strings.po. \English, \Russian \Ukrainian, . . , . , , \English . , , .
strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr " ."
, .po GNU Gettext. XBMC Gettext: .mo, , msgctxt. : XBMC XML, www.transifex.net . -, .po , Gettext.
, getLocalizedString() msgctxt. : XBMC + . , . , , , , , . .
, . , .
, settings.xml .
, XBMC, . .
\lib
\lib , . \lib . , : , . . , . , , , , , , .
\thumbnails
\thumbnails cnet.com. \lib, , .
. XBMC. ( XBMC " "). print xbmc.log().
XBMC.
, XBMC Eclipse + PyDev. .
XBMC . , , . «» .
, , , .
, , Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development
«XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL
XBMC Python API: mirrors.xbmc.org/docs/python-docs
PS
Post factum . . XBMC , . .
XBMC : I — .    executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     .     executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     . 
    executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     .     executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     . 
    executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     .     executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     . 
    executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     .     executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     . 
    executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     .     executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     . 
    executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     .     executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     .     executable, . .: 
 <extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension> 
      «». -       «», «»  «» (video, music  image    ),       -    ,     runtime- (  ). 
 
        . 
 
  16—22         .      XBMC.   23 ,      . 
 
 icon.png 
 icon.png —     () ,     XBMC.   — PNG 256x256           . 
 
 fanart.jpg 
 fanart.jpg —     (),         .   — JPG 1280x720 . :         (). ,  «» , /  . 
 
 changelog.txt 
   changelog.txt       . 
 
 License.txt 
  License.txt    .    ,       .  ,    ,          XBMC. 
 
 default.py 
  default.py —   .   «default.py»  ,         (   library=   extension),    default.py, — ,  . 
      -  PEP 8,   ,           ____,      . 
 
  : # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html #      import sys, os, urllib2, socket, xml.dom.minidom #    XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui #    _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') #    sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds #       def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') #  URL-encoded    def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name #  RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing #      ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) #   . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) # URL,        . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') #     . isFolder=True ,    (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) #   --  ,  . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) #   xbmcplugin.endOfDirectory(addon_id) #    . switch_view() #         . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') #  "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') #  "-" #   . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: #   . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) #  . . list_item.setProperty('fanart_image', fanart) #    . isFolder=False ,     . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) #  . xbmcplugin.endOfDirectory(addon_id) def main(): #   . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') #        . feed = get_feed_name() #      XBMC ( ),     . if feed: #       . quality = _addon.getSetting('quality') #   . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: #   . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) #   . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: #      ( ),      xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) #        XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: #     XBMC ( ),     , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) #     . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main() 
 
   .   . 
 
  11—15 —   .        ,      , ,   ,    PEP 8. 
 
  : 
 
 11:   .      ,   addon.xml,    (      ). 
 
 12:    Addon     . 
 
 13:  runtime-  (handle).  —   ,    2-      XBMC.            addDirectoryItem().        .    ,   -   -   ,   -    () ,                 XBMC API.      ,  .     XBMC       (  ) -  3    sys.argv:   URL, runtime- (,   ),       URL-encoded . -,   ,    ,    sys.argv    .    ,  runtime-    ,  addDirectoryItem(),  -   .   URL     . 
 
 14:   URL .  URL      ''plugin://'' + ( ) + ''/''.  URL     : "plugin://plugin.video.cnet/".  URL        (   )   ,  .  , ,   , XBMC  ,    ( — )        . ,  ,   . 
   (),  ,         .  ,       «», «»  «» XBMC    « »,      ,         ,  .            -  ,      —    ,   —   ,    . ,    (- ) —                XBMC.    «» ,               (  ) .           .  addDirectoryItem()        ,    .    . 
 
 15:  getAddonInfo('path')     ,    , ,      ,     .       :  Windows,       (   ,   ASCII),     ,            (exeption).    ,    Windows   .        decode('utf-8').  ,     ,           Windows. 
   getAddonInfo('path') —    (   XBMC)    .  os.path.dirname(__file__)   ,  os.getcwd()   . ,  ,     ,  XBMC. 
 
 18—19:    feeds   /resources/lib.      cnet.com,  URL        (dictionary). , ,      — www.cnet.com/podcasts —     ,     — ,     ,        . 
 
 22—23:      .  .getLocalizedString()         ,           UTF-8.     ,  ,  ,   ,     . 
 
 26—32: -      URL-encoded .       - ,   .    ,       XBMC              URL-encoded .          URL     (. )  URL-encoded   . 
   . ,     plugin.video.acme,        ,   ,        .      «Action»  «Movies»    plugin://plugin.video.acme/?=Movies&=Action.      addDirectoryItem      (   ). ,           plugin.video.acme,    sys.argv[2]    «?=Movies&=Action».   ,        ,  ,    :   XBMC  .    XBMC       (,    ),    , ,      (,     «Action»  «Movies»).        . 
 :            ,     .         URL,   plugin://. 
 :             xbmcplugin.addDirectoryItem,    -  ,  isFolder=False.  isFolder=True XBMC    ,       . 
 
 35—49:  RSS-     .      XML   - .         ,      -            (, , ). 
 
 52—64:       cnet.com —  ,   .   . 
 
 57:          xbmcgui.ListItem.           ,   .    ,  ,  ,          ()   (). 
 
 59:     .  ,       ,         . 
 
 61:      .            . ,            . 
 
 63:      .      ,   sys.argv[1]. ,      - . ,       addDirectoryItem()  .  isFolder=True  XBMC,     —  , . .         ,       .   url      ,  ,                 . 
 
 65:   .   ,         ,    . 
 
 67:  XBMC,    . 
 
 69:     ().   ,  ,      ( ,  ),         ,   ,     ,     .  Container.SetViewMode()          ,      MyVideoNav.xml, MyMusicNav.xml  MyPics.xml    ,    . 
  ,      .       —  Youtube. 
 
 72—77:    .         .  500   «»   Confluence,   512 —  «-»  «Aeon-Nox».         . 
 
 80—89:    ,      .     ,    feed_list(),   ,  URL           isFolder     False, . .    (  )  ,   . 
 :    isFolder=False        ,          ,      xbmcplugin.addDirectoryItem. ,             (     ).  xbmcplugin.addDirectoryItem  . 
 
 92—119:   . ,     .        . 
 
 101:    ,     .       ,       ,  . 
 
 114:       XBMC.         _string(),        XBMC.     . 
 
 \resources 
  \resources — ,        . 
 
 settings.xml 
 settings.xml —  ,     ,   XML,    ,      «».         «»    . 
 
  : <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings> 
 
          —  (labelenum)      (HD  SD).  label=      ,        ,       .           id="" (.  101 default.py). 
     settings.xml         « XBMC Addon Developers Guide » ( ).       ,       ,         . 
        XML   \userdata\addon_data\     XBMC.  Windows ,  , %AppData%\XBMC,  Linux — $HOME/.xbmc. 
 
 \language 
  \language  .  ,    ,  ,     ,     strings.po.      \English, \Russian  \Ukrainian, . .     ,    . ,   ,      \English    . ,          ,     . 
 
     strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr "     ." 
 
  ,    .po GNU Gettext.  XBMC    Gettext:      .mo,        ,    msgctxt.     :  XBMC        XML,        www.transifex.net          . -,        .po   ,     Gettext. 
    ,     getLocalizedString()    msgctxt.     :    XBMC +   . ,          .  ,           , ,  ,   ,      .        . 
         ,      . ,      . 
                ,         settings.xml      . 
  ,            XBMC,         .              . 
 
 \lib 
   \lib     ,   .  \lib  .     ,        :     ,      . . ,      . ,  , ,     ,  ,   ,    . 
 
 \thumbnails 
   \thumbnails      cnet.com.   \lib,    ,           . 
 
  
     .         XBMC.        (    XBMC   "  ").           print   xbmc.log(). 
        XBMC. 
  , XBMC      Eclipse + PyDev.       . 
 
  
        XBMC .    ,     ,    .        «»   . 
   ,     ,    ,      . 
 
   
 ,   ,   Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development 
  «XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL 
     XBMC Python API: mirrors.xbmc.org/docs/python-docs 
 
 PS 
 Post factum   .       .   XBMC     ,      .          . 
 
  
    XBMC   :  I —     . executable, . .:
<extension point="xbmc.python.script" library="default.py"> <provides>executable</provides> </extension>
«». - «», «» «» (video, music image ), - , runtime- ( ).
.
16—22 . XBMC. 23 , .
icon.png
icon.png — () , XBMC. — PNG 256x256 .
fanart.jpg
fanart.jpg — (), . — JPG 1280x720 . : (). , «» , / .
changelog.txt
changelog.txt .
License.txt
License.txt . , . , , XBMC.
default.py
default.py — . «default.py» , ( library= extension), default.py, — , .
- PEP 8, , ____, .
: # -*- coding: utf-8 -*- # Name: plugin.video.cnet # Licence: GPL v.3: http://www.gnu.org/copyleft/gpl.html # import sys, os, urllib2, socket, xml.dom.minidom # XBMC import xbmc, xbmcplugin, xbmcaddon, xbmcgui # _ADDON_NAME = 'plugin.video.cnet' _addon = xbmcaddon.Addon(id=_ADDON_NAME) _addon_id = int(sys.argv[1]) _addon_url = sys.argv[0] _addon_path = _addon.getAddonInfo('path').decode('utf-8') # sys.path.append(os.path.join(_addon_path, 'resources', 'lib')) import feeds # def _string(string_id): return _addon.getLocalizedString(string_id).encode('utf-8') # URL-encoded def get_feed_name(): paramstring = sys.argv[2] if paramstring: feed_name = feeds.NAMES[paramstring.replace('?feed=', '')] else: feed_name = '' return feed_name # RSS- def rss_parser(url): listing = [] try: HEADER = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/20.0'} request = urllib2.Request(url, None, HEADER) rss = xml.dom.minidom.parse(urllib2.urlopen(request, None, 3)) except urllib2.URLError, socket.timeout: pass else: titles = rss.getElementsByTagName('title') links = rss.getElementsByTagName('link') for title, link in zip(titles[2:], links[2:]): title = title.toxml().replace('<title><![CDATA[', '').replace(']]></title>', '') link = link.toxml().replace('<link>', '').replace('</link>', '') listing.append([title, link]) return listing # ( ). def feed_list(addon_id, addon_url, fanart, thumbpath, feeds): names = dict.keys(feeds) for name in names: thumb = os.path.join(thumbpath, feeds[name]['thumb']) # . list_item = xbmcgui.ListItem(name, thumbnailImage=thumb) # . . list_item.setProperty('fanart_image', fanart) # URL, . url = addon_url + '?feed=' + name.replace(' ', '').replace('*', '') # . isFolder=True , (). xbmcplugin.addDirectoryItem(addon_id, url, list_item, isFolder=True) # -- , . xbmcplugin.addSortMethod(addon_id, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE) # xbmcplugin.endOfDirectory(addon_id) # . switch_view() # . def switch_view(): skin_used = xbmc.getSkinDir() if skin_used == 'skin.confluence': xbmc.executebuiltin('Container.SetViewMode(500)') # "". elif skin_used == 'skin.aeon.nox': xbmc.executebuiltin('Container.SetViewMode(512)') # "-" # . def podcast_list(addon_id, fanart, thumb, listing): for item in listing: # . list_item = xbmcgui.ListItem(item[0], thumbnailImage=thumb) # . . list_item.setProperty('fanart_image', fanart) # . isFolder=False , . xbmcplugin.addDirectoryItem(addon_id, item[1], list_item, isFolder=False) # . xbmcplugin.endOfDirectory(addon_id) def main(): # . thumbpath = os.path.join(_addon_path, 'resources', 'thumbnails') fanart = os.path.join(_addon_path, 'fanart.jpg') # . feed = get_feed_name() # XBMC ( ), . if feed: # . quality = _addon.getSetting('quality') # . listing = rss_parser(url=feeds.FEEDS[feed][quality]) if listing: # . xbmc.log('%s: Started - Opening podcasts List' % _ADDON_NAME, xbmc.LOGNOTICE) thumb = os.path.join(thumbpath, feeds.FEEDS[feed]['thumb']) # . podcast_list(addon_id=_addon_id, fanart=fanart, thumb=thumb, listing=listing) else: # ( ), xbmc.log('%s: Failed to retrieve %s feed data!' % (_ADDON_NAME, feed), xbmc.LOGERROR) # XBMC. xbmc.executebuiltin('Notification(%s,%s)' % (_string(100501), _string(100502))) else: # XBMC ( ), , xbmc.log('%s: Started - Opening feeds List' % _ADDON_NAME, xbmc.LOGNOTICE) # . feed_list(addon_id=_addon_id, addon_url=_addon_url, fanart=fanart, thumbpath=thumbpath, feeds=feeds.FEEDS) if __name__ == '__main__': main()
. .
11—15 — . , , , , PEP 8.
:
11: . , addon.xml, ( ).
12: Addon .
13: runtime- (handle). — , 2- XBMC. addDirectoryItem(). . , - - , - () , XBMC API. , . XBMC ( ) - 3 sys.argv: URL, runtime- (, ), URL-encoded . -, , , sys.argv . , runtime- , addDirectoryItem(), - . URL .
14: URL . URL ''plugin://'' + ( ) + ''/''. URL : "plugin://plugin.video.cnet/". URL ( ) , . , , , XBMC , ( — ) . , , .
(), , . , «», «» «» XBMC « », , , . - , — , — , . , (- ) — XBMC. «» , ( ) . . addDirectoryItem() , . .
15: getAddonInfo('path') , , , , . : Windows, ( , ASCII), , (exeption). , Windows . decode('utf-8'). , , Windows.
getAddonInfo('path') — ( XBMC) . os.path.dirname(__file__) , os.getcwd() . , , , XBMC.
18—19: feeds /resources/lib. cnet.com, URL (dictionary). , , — www.cnet.com/podcasts — , — , , .
22—23: . .getLocalizedString() , UTF-8. , , , , .
26—32: - URL-encoded . - , . , XBMC URL-encoded . URL (. ) URL-encoded .
. , plugin.video.acme, , , . «Action» «Movies» plugin://plugin.video.acme/?=Movies&=Action. addDirectoryItem ( ). , plugin.video.acme, sys.argv[2] «?=Movies&=Action». , , , : XBMC . XBMC (, ), , , (, «Action» «Movies»). .
: , . URL, plugin://.
: xbmcplugin.addDirectoryItem, - , isFolder=False. isFolder=True XBMC , .
35—49: RSS- . XML - . , - (, , ).
52—64: cnet.com — , . .
57: xbmcgui.ListItem. , . , , , () ().
59: . , , .
61: . . , .
63: . , sys.argv[1]. , - . , addDirectoryItem() . isFolder=True XBMC, — , . . , . url , , .
65: . , , .
67: XBMC, .
69: (). , , ( , ), , , , . Container.SetViewMode() , MyVideoNav.xml, MyMusicNav.xml MyPics.xml , .
, . — Youtube.
72—77: . . 500 «» Confluence, 512 — «-» «Aeon-Nox». .
80—89: , . , feed_list(), , URL isFolder False, . . ( ) , .
: isFolder=False , , xbmcplugin.addDirectoryItem. , ( ). xbmcplugin.addDirectoryItem .
92—119: . , . .
101: , . , , .
114: XBMC. _string(), XBMC. .
\resources
\resources — , .
settings.xml
settings.xml — , , XML, , «». «» .
: <?xml version="1.0" encoding="UTF-8"?> <settings> <category label="128"> <setting id="quality" type="labelenum" label="100500" values="HD|SD" default="HD" /> </category> </settings>
— (labelenum) (HD SD). label= , , . id="" (. 101 default.py).
settings.xml « XBMC Addon Developers Guide » ( ). , , .
XML \userdata\addon_data\ XBMC. Windows , , %AppData%\XBMC, Linux — $HOME/.xbmc.
\language
\language . , , , , strings.po. \English, \Russian \Ukrainian, . . , . , , \English . , , .
strings.po: # XBMC Media Center language file msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" msgctxt "#100500" msgid "Quality:" msgstr ":" msgctxt "#100501" msgid "Access error!" msgstr " !" msgctxt "#100502" msgid "Failed to retrieve the feed data." msgstr " ."
, .po GNU Gettext. XBMC Gettext: .mo, , msgctxt. : XBMC XML, www.transifex.net . -, .po , Gettext.
, getLocalizedString() msgctxt. : XBMC + . , . , , , , , . .
, . , .
, settings.xml .
, XBMC, . .
\lib
\lib , . \lib . , : , . . , . , , , , , , .
\thumbnails
\thumbnails cnet.com. \lib, , .
. XBMC. ( XBMC " "). print xbmc.log().
XBMC.
, XBMC Eclipse + PyDev. .
XBMC . , , . «» .
, , , .
, , Wiki XBMC: http://wiki.xbmc.org/index.php?title=Category:Addon_Development
«XBMC Addon Developers Guide»: yadi.sk/d/NvfFuXYw92paL
XBMC Python API: mirrors.xbmc.org/docs/python-docs
PS
Post factum . . XBMC , . .
XBMC : I — .Source: https://habr.com/ru/post/193374/
All Articles