рдкреНрд░рд╕реНрддрд╛рд╡рдирд╛
рд╣реИрдмреЗ рдкрд░ рдПрдХ рд╕рдорд╛рди рд▓реЗрдЦ рдкрд╣рд▓реЗ рд╣реА
рдкреНрд░рдХрд╛рд╢рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рдЗрд╕рдиреЗ рд╡реАрдбрд┐рдпреЛ рдХреЗ рд╕рд╛рде рд╕рд╛рдЗрдЯ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдкрд░ рдзреНрдпрд╛рди рдХреЗрдВрджреНрд░рд┐рдд рдХрд┐рдпрд╛ - рдкреНрд▓рдЧрдЗрди рдХрд╛ рд╡реНрдпрд╛рдкрд╛рд░рд┐рдХ рддрд░реНрдХ, рдЗрд╕рд▓рд┐рдП рдмреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП, рдФрд░ XBMC рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХреЗ рдореБрджреНрджреЛрдВ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд░рдиреЗ рдореЗрдВ рдЙрдард╛рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдореИрдВ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдПрдХ рдПрдХреНрд╕рдмреАрдПрдорд╕реА рдкреНрд▓рдЧрдЗрди рдореЗрдВ рдкрд╛рдпрдерди рд╕реНрдХреНрд░рд┐рдкреНрдЯ (рдмрд╛рдж рдореЗрдВ - рдкрд╛рдпрдерди) рдХреЛ рдХреНрдпрд╛ рдмрджрд▓ рдЬрд╛рддрд╛ рд╣реИред
рдпрд╣ рдкреНрд▓рдЧрдЗрди рд╕реЗрдЯрд┐рдВрдЧреНрд╕ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рд╕рд╛рдорд╛рдиреНрдп рдпрд╛ рдЙрдЪреНрдЪ рдЧреБрдгрд╡рддреНрддрд╛ рдореЗрдВ рд╕рд╛рдЗрдЯ
www.cnet.com рд╕реЗ рд╡реАрдбрд┐рдпреЛ рдкреЙрдбрдХрд╛рд╕реНрдЯ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП рд╣реИред рдЗрд╕ рдкреНрд▓рдЧрдЗрди рдХрд╛ рдЖрдзрд┐рдХрд╛рд░рд┐рдХ XBMC рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдЙрдкрд▓рдмреНрдз CNET рдкреЙрдбрдХрд╛рд╕реНрдЯ рджрд░реНрд╢рдХ рдкреНрд▓рдЧрдЗрди рд╕реЗ рдХреЛрдИ рд▓реЗрдирд╛-рджреЗрдирд╛ рдирд╣реАрдВ рд╣реИред рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ 0 рд╕реЗ рдПрдХ рдкреНрд░рд╢рд┐рдХреНрд╖рдг рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЗ рд░реВрдк рдореЗрдВ XBMC рдкреНрд▓рдЧрдЗрдиреНрд╕ рдХреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд▓реЗрдЦрди рдХреЗ рдПрдХ рд╕реНрд╡рддрдВрддреНрд░ рдЕрдзреНрдпрдпрди рдХреЗ рднрд╛рдЧ рдХреЗ рд░реВрдк рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред рдкреНрд▓рдЧрдЗрди рд╡рд┐рд╕реНрддреГрдд рджрд░реНрд╢рдХреЛрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧреА рд╣реЛрдиреЗ рдХрд╛ рджрд╛рд╡рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рди рд╣реА рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдЙрддреНрдХреГрд╖реНрдЯ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХреЗ рд▓рд┐рдПред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ, рдФрд░ рдЗрд╕рдореЗрдВ "рдЧрдВрднреАрд░" рдкреНрд▓рдЧрдЗрдиреНрд╕ рдореЗрдВ рдирд┐рд╣рд┐рдд рдЕрдзрд┐рдХрд╛рдВрд╢ рддрддреНрд╡ рд╣реИрдВ: рдореЗрдЯрд╛рдбрд╛рдЯрд╛ рдХреЗ рд╕рд╛рде рдПрдХ рдПрдХреНрд╕рдПрдордПрд▓ рдлрд╛рдЗрд▓, рдПрдХ рдореБрдЦреНрдп рд╕реНрдХреНрд░рд┐рдкреНрдЯ, рдПрдХ рдмрд╛рд╣рд░реА рдЖрдпрд╛рддрд┐рдд рдореЙрдбреНрдпреВрд▓, рдПрдХ рд╕реЗрдЯрд┐рдВрдЧ рдкреИрдирд▓, рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдлрд╛рдЗрд▓реЗрдВ, рд╕рдВрд╕рд╛рдзрди рдлрд╛рдЗрд▓реЗрдВ (рдЪрд┐рддреНрд░)ред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдкреНрд▓рдЧрдЗрди рдФрд░ рдпрд╣ рд▓реЗрдЦ рджреЛрдиреЛрдВ рд╢реБрд░реБрдЖрддреА рдкреНрд▓рдЧрдЗрди рд▓реЗрдЦрдХреЛрдВ рдФрд░ рдЕрдиреБрднрд╡реА рдкрд╛рдпрдерди рдкреНрд░реЛрдЧреНрд░рд╛рдорд░реНрд╕ рдХреЗ рд▓рд┐рдП рдПрдХ рд╢реБрд░реБрдЖрддреА рдмрд┐рдВрджреБ рдХреЗ рд░реВрдк рдореЗрдВ рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдЬреЛ рдПрдХреНрд╕рдмреАрдПрдорд╕реА рдХреЗ рд▓рд┐рдП рдкреНрд▓рдЧрдЗрдиреНрд╕ рд▓рд┐рдЦрдиреЗ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рд╣реЛрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред
рдкреВрд░рд╛ рдкреНрд▓рдЧрдЗрди
рдпрд╣рд╛рдБ рд╕реЗ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛
рд╣реИ ред
рдиреЛрдЯ: рд╢рдмреНрдж "рд╕реЗрд╡рд╛" рдХрд╛ рдЙрдкрдпреЛрдЧ рдкрд╛рда рдореЗрдВ рдХреБрдЫ рдлрд╝рд╛рдЗрд▓реЛрдВ рдФрд░ рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ XBMC рдРрд╕реЗ рдлрд╝реЛрд▓реНрдбрд░ рдФрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдЦреЛрдЬрддрд╛ рд╣реИ рдЬреЛ рд╕реАрдзреЗ рдкреНрд▓рдЧрдЗрди рдХреЛрдб рдореЗрдВ рдЙрдиреНрд╣реЗрдВ рдЗрдВрдЧрд┐рдд рдХрд┐рдП рдмрд┐рдирд╛ред "рд╕реЗрд╡рд╛"! = "рдЖрд╡рд╢реНрдпрдХ", рдФрд░ рд╕рд░рд▓ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдореЗрдВ рдХреЛрдИ рд╕реЗрд╡рд╛ рдлрд╝рд╛рдЗрд▓реЗрдВ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВред
рд╕рд╛рдорд╛рдиреНрдп рдЬрд╛рдирдХрд╛рд░реА
рдЕрдЬрдЧрд░ рдХреЛ XBMC рдкреНрд▓рдЧрдЗрдиреНрд╕ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред Windows рдХреЗ рддрд╣рдд XBMC 2.7 рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд╕рд╛рде рд╕рдВрдХрд▓рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд▓рд┐рдирдХреНрд╕ рдХреЗ рддрд╣рдд, рдЬреИрд╕рд╛ рдХрд┐ рдореИрдВ рдЗрд╕реЗ рд╕рдордЭрддрд╛ рд╣реВрдВ, рдкрд╛рдпрдерди рд╕рдВрд╕реНрдХрд░рдг рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЧрдП рд╕реНрдерд╛рдкрд┐рдд рд╡рд┐рдХрд╛рд╕ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИред рдХрд┐рд╕реА рднреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдкреНрд▓рдЧ-рдЗрди рдХреЛрдб рд▓рд┐рдЦрддреЗ рд╕рдордп, рдЖрдкрдХреЛ рдкрд╛рдпрдерди 2.7 рдХреА рд╡рд╛рдХреНрдп рд░рдЪрдирд╛ рдФрд░ рдХреНрд╖рдорддрд╛рдУрдВ рдкрд░ рдзреНрдпрд╛рди рджреЗрдирд╛ рдЪрд╛рд╣рд┐рдПред
XBMC рдореЗрдВ рдкрд╛рдпрдерди рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рд╣реИ: рд▓рдЧрднрдЧ рдкреВрд░реЗ рдорд╛рдирдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИ, рд╕рд┐рд╡рд╛рдп, рд╢рд╛рдпрдж, рдЯрд┐рдВрдХрд░ / ttk / tix (рдЬреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдпрд╣рд╛рдВ рдмрд╣реБрдд рд╣реА рд╢рд╛рдирджрд╛рд░ рд╣реИрдВ)ред XBMC рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд╛рдВрдЪ рдореЙрдбреНрдпреВрд▓ рдЬреЛрдбрд╝реЗ рдЧрдП рд╣реИрдВ: xbmc, xbmcgui, xbmcplugin, xbmcaddon рдФрд░ xbmcvfs, рдЬреЛ рдПрдХ рд╕рд╛рде XBMC рдкрд╛рдпрдерди рдПрдкреАрдЖрдИ рдмрдирд╛рддреЗ рд╣реИрдВред рдореЙрдбреНрдпреВрд▓ рдкрд░ рдПрдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╕рдВрджрд░реНрдн
рдпрд╣рд╛рдВ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛
рд╣реИ ред рджреБрд░реНрднрд╛рдЧреНрдп рд╕реЗ, рдкреНрд░рдорд╛рдг рдкрддреНрд░ рдореЗрдВ рдЧрд▓рддрд┐рдпрд╛рдВ рд╣реИрдВред
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХрдВрд╕реЛрд▓ рдХреЗ рдмрдЬрд╛рдп рдкреНрд░рд┐рдВрдЯ рд╕реНрдЯреЗрдЯрдореЗрдВрдЯ XBMC рд▓реЙрдЧ рдХреЛ рд╕реВрдЪрдирд╛ рд╕реНрддрд░ рдХреЗ рд╕рд╛рде рд▓рд┐рдЦрддрд╛ рд╣реИ, рдЬрд┐рд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреЗ рджреМрд░рд╛рди рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдЙрдЯрдкреБрдЯ рд╡реЗрд░рд┐рдПрдмрд▓ рдорд╛рди рдХреЗ рд▓рд┐рдПред
рд╢рдмреНрджрд╛рд╡рд▓реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛: рд╢реБрд░реВ рдореЗрдВ, рдПрдХреНрд╕рдмреАрдПрдорд╕реА рдХреЗ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдиреЗ рдХрд┐рд╕реА рднреА рдРрдб-рдСрди рдХреЗ рд▓рд┐рдП "рдПрдбрдСрди" рд╢рдмреНрдж рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛, рдЬреЛ рдмрджрд▓реЗ рдореЗрдВ рдкреНрд▓рдЧ-рдЗрди (рд╕рд╛рдордЧреНрд░реА рд╕реНрд░реЛрддреЛрдВ), рд╕реНрдХреНрд░рд┐рдкреНрдЯ (рдкреНрд░реЛрдЧреНрд░рд╛рдо), рд╕реНрдХреНрд░реИрдкрд░реНрд╕ (рдореАрдбрд┐рдпрд╛ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд▓рд┐рдП рд▓реЛрдбрд░) рдФрд░ рдЕрдиреНрдп рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рд╣реИрдВред рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╕рдордп рдХреЗ рд╕рд╛рде, "рдПрдбрдСрди" рдФрд░ "рдкреНрд▓рдЧ-рдЗрди" рдХреА рдЕрд╡рдзрд╛рд░рдгрд╛рдПрдВ рднреНрд░рдорд┐рдд рд╣реЛрддреА рд╣реИрдВ, рдФрд░ рдЕрдм рд╡реЗ рдЕрдХреНрд╕рд░ рдХрд┐рд╕реА рднреА рдРрдб-рдСрди рдХреЛ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧ рдХреА рдЬрд╛рддреА рд╣реИрдВред
рдЖрдИрдбреАрдИ рд╕реЗрдЯрдЕрдк
рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рд╣реА рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдкрд╛рдпрдерди рдореЗрдВ XBMC рдкреНрд▓рдЧрдЗрдиреНрд╕ рд▓рд┐рдЦреЗ рдЧрдП рд╣реИрдВред рдЗрд╕ рднрд╛рд╖рд╛ рдореЗрдВ рдПрдХ рдХрд╛рд░реНрдпрдХреНрд░рдо рдЕрдирд┐рд╡рд╛рд░реНрдп рд░реВрдк рд╕реЗ рдПрдХ рдкрд╛рда рдлрд╝рд╛рдЗрд▓ рд╣реИ рдЬрд┐рд╕реЗ рдЖрдк рдХрд┐рд╕реА рднреА рдкрд╛рда рд╕рдВрдкрд╛рджрдХ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЬреЛ рд╡рд┐рдВрдбреЛрдЬ рдиреЛрдЯрдкреИрдб рд╕реЗ рд╢реБрд░реВ рд╣реЛрддрд╛ рд╣реИ рдФрд░ "рдЙрдиреНрдирдд рд╡рд┐рдХрд▓реНрдк" рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИ, рдЬреИрд╕реЗ рдХрд┐ рдиреЛрдЯрдкреИрдб ++ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдХрд┐рд╕реА рднреА рдЕрдзрд┐рдХ рдпрд╛ рдХрдо рдЬрдЯрд┐рд▓ рдХреЛрдб рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП, IDE (рдПрдХреАрдХреГрдд рд╡рд┐рдХрд╛рд╕ рдкрд░реНрдпрд╛рд╡рд░рдг) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ, рдЬреЛ рдХрдИ рд╕реБрд╡рд┐рдзрд╛рдПрдВ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ: рдХреЛрдб рд╣рд╛рдЗрд▓рд╛рдЗрдЯрд┐рдВрдЧ, рдХреАрд╡рд░реНрдб рдкреВрд░рд╛ рдХрд░рдирд╛, рдХреЛрдб рдмреНрд░рд╛рдЙрдЬрд╝рд░, рд╡рд╕реНрддреБрдУрдВ рдкрд░ рдПрдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд╕рдВрджрд░реНрдн, рдЖрджрд┐ред рдХрдИ рдкрд╛рдпрдерди рдкреНрд░реЛрдЧреНрд░рд╛рдорд░ рдЕрдХреНрд╕рд░ рдПрдХ рдЧреБрдЪреНрдЫрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдЧреНрд░рд╣рдг + PyDev, рд▓реЗрдХрд┐рди рд╡реНрдпрдХреНрддрд┐рдЧрдд рд░реВрдк рд╕реЗ, рдореИрдВ рд▓рд╛рдЗрдЯрд░ PyScripter рдХреЛ рдкрд╕рдВрдж рдХрд░рддрд╛ рд╣реВрдВ, рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдкреВрд░реНрдг рдЖрдИрдбреАрдИ рдХреЗ рд▓рдЧрднрдЧ рд╕рднреА рдХрд╛рд░реНрдп рд╣реИрдВ, рд╕рд┐рд╡рд╛рдп, рд╢рд╛рдпрдж, рдХреЛрдб (рдХреЛрдб рддрд╣)ред рдпрд╣ рд╕рдЪ рд╣реИ рдХрд┐ рдкрд░рд┐рдпреЛрдЬрдирд╛ 2012 рд╕реЗ рд╡рд┐рдХрд╕рд┐рдд рдирд╣реАрдВ рд╣реЛ рд░рд╣реА рд╣реИ, рд▓реЗрдХрд┐рди рдкрд╛рдпрдерди 2.x рдХреЗ рд▓рд┐рдП рдЗрд╕рдХреА рдХреНрд╖рдорддрд╛рдПрдВ рдкрд░реНрдпрд╛рдкреНрдд рд╕реЗ рдЕрдзрд┐рдХ рд╣реИрдВред
рдЖрдИрдбреАрдИ рдореЗрдВ рдкрд╛рдпрдерди рдореЗрдВ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдХреА рд╕реБрд╡рд┐рдзрд╛ рдХреЗ рд▓рд┐рдП, рдЕрдЪреНрдЫреЗ рд▓реЛрдЧреЛрдВ (рдореЗрд░реЗ рд╕рд╣рд┐рдд) рдиреЗ
рдкрд╛рдпрдерди рдкреНрд▓рдЧ-рдЗрди рдХрд╛ рдПрдХ
рд╕реЗрдЯ рд╕рдВрдХрд▓рд┐рдд рдХрд┐рдпрд╛ рд╣реИ рдЬреЛ рдПрдХреНрд╕рдмреАрдПрдорд╕реА рдкрд╛рдпрдерди рдПрдкреАрдЖрдИ рдХреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдореЙрдбреНрдпреВрд▓ рдХреА рдирдХрд▓ рдХрд░рддрд╛ рд╣реИред рдЗрди рдореЙрдбреНрдпреВрд▓ рдХреЛ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдЖрдпрд╛рдд рдкрдереЛрдВ рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП ("рдЧреБрдг"> "PYTHONPATH"> "рд╕реНрд░реЛрдд рдлрд╝реЛрд▓реНрдбрд░реНрд╕" рдЧреНрд░рд╣рдг / PyDev рдпрд╛ "рдЕрддрд┐рд░рд┐рдХреНрдд рдкрд╛рдпрдерди рдкрде ..." PyScripter рдореЗрдВ), рдФрд░ рд╣рдореЗрдВ рд▓рд╛рдн рдорд┐рд▓рддрд╛ рд╣реИ - рдХреЛрдб рдкреВрд░рд╛ рд╣реЛрдиреЗ рдФрд░ рдХрдХреНрд╖рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рдорджрдж рдХрд╛рдо рдХрд░рдирд╛ рд╢реБрд░реВред XBMC рдкрд╛рдпрдерди рдПрдкреАрдЖрдИ рддрд░реАрдХреЗ рдФрд░ рдЕрдиреНрдп рддрддреНрд╡ред
рдЪреЗрддрд╛рд╡рдиреА: рдпреЗ рд╕реНрдЯрдм рдореЙрдбреНрдпреВрд▓ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдЙрдкрдпреЛрдЧреА рдХреЛрдб рдирд╣реАрдВ рд╣реИ, рдФрд░ рдЖрдИрдбреАрдИ рд╕реЗ рд╕реАрдзреЗ рдЙрдиреНрд╣реЗрдВ рд╕рдВрджрд░реНрднрд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЛ рдЪрд▓рд╛рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рдкрд░рд┐рдгрд╛рдо рджреЗрдЧрд╛ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЬреЛ рд▓реЛрдЧ рдЪрд╛рд╣рддреЗ рд╣реИрдВ рд╡реЗ рдЗрди рдореЙрдбреНрдпреВрд▓реЛрдВ рдореЗрдВ рдбрд┐рдмрдЧрд┐рдВрдЧ рдХреЛрдб рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ рдЬреЛ рдПрдХреНрд╕рдмреАрдПрдорд╕реА рдкрд╛рдпрдерди рдПрдкреАрдЖрдИ рдХреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдХрд╛рд░реНрдпреЛрдВ рдФрд░ рддрд░реАрдХреЛрдВ рдХреЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рдЕрдиреБрдХрд░рдг рдХрд░рддреЗ рд╣реИрдВред
рдкреНрд▓рдЧрдЗрди рд╕рдВрд░рдЪрдирд╛
рдореЗрд░реЗ "рдкреНрд░рд╢рд┐рдХреНрд╖рдг" рдкреНрд▓рдЧрдЗрди рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдВрд░рдЪрдирд╛ рд╣реИ:
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\
рдЕрдм рдЗрди рд╕рднреА рдлрд╝рд╛рдЗрд▓реЛрдВ рдФрд░ рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдХреЗ рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХред
addon.xml
addon.xml рдкреНрд▓рдЧ-рдЗрди рд╕реЗрд╡рд╛ рдлрд╝рд╛рдЗрд▓ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд XBMC рдкреНрд▓рдЧ-рдЗрди рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдирдХрд╛рд░реА рд▓реЗрддрд╛ рд╣реИред рдпрд╣ рдХреЗрд╡рд▓ рдЖрд╡рд╢реНрдпрдХ рдкреНрд▓рдЧ-рдЗрди рдлрд╝рд╛рдЗрд▓ рд╣реИ, рдФрд░ рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рдХреЗ рдкреНрд▓рдЧ-рдЗрди (рд╕реНрдХреНрд░реИрдкрд░реНрд╕, рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА, рдЖрджрд┐) рдореЗрдВ рдкреНрд░реЛрдЧреНрд░рд╛рдо рдХреЛрдб рдпрд╛ рдЕрдиреНрдп рд╕реЗрд╡рд╛ рдлрд╛рдЗрд▓реЗрдВ рдмрд┐рд▓реНрдХреБрд▓ рдирд╣реАрдВ рд╣реЛ рд╕рдХрддреА рд╣реИрдВред
рдлрд╝рд╛рдЗрд▓ рд╕рд╛рдордЧреНрд░реА: <?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>
рдЕрдм рд╕рд╛рдордЧреНрд░реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХред рд▓рд╛рдЗрди рдирдВрдмрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЗрд╕ рд╕реБрд╡рд┐рдзрд╛ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЯреЗрдХреНрд╕реНрдЯ рдПрдбрд┐рдЯрд░ рдореЗрдВ рдлрд╝рд╛рдЗрд▓ рдЦреЛрд▓реЗрдВред
рд▓рд╛рдЗрдиреЛрдВ 3-6 рдореЗрдВ рдкреНрд▓рдЧрдЗрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмреБрдирд┐рдпрд╛рджреА рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИ: рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛ рдЬреЛ рдкреНрд▓рдЧрдЗрди рдлрд╝реЛрд▓реНрдбрд░ рдХреЗ рдирд╛рдо рд╕реЗ рдореЗрд▓ рдЦрд╛рддрд╛ рд╣реИ; рд╕рдВрд╕реНрдХрд░рдг; XBMC рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдирд╛рдо; рдкреНрд▓рдЧрдЗрди рдХреЗ рд▓реЗрдЦрдХред
рд▓рд╛рдЗрдиреЛрдВ 8-10 рдореЗрдВ рдмрд╛рд╣рд░реА рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИ - рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд▓рдЧрдЗрди рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдЕрдиреНрдп рдШрдЯрдХред рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдЗрд╕ рдкреНрд▓рдЧрдЗрди рдХреЛ рдХреЗрд╡рд▓ XBMC рдкрд╛рдпрдерди рдПрдкреАрдЖрдИ рд╕рдВрд╕реНрдХрд░рдг 2.1 рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ рд╕рдВрд╕реНрдХрд░рдг XBMC 13.x (рдЧреЛрдердо) рдореЗрдВ рд╕рдорд░реНрдерд┐рдд рд╣реИред
рдпрджрд┐ рдЖрдкрдХреЗ рдкреНрд▓рдЧ-рдЗрди рдХреЛ рдХрд┐рд╕реА рдЕрдиреНрдп рдкреНрд▓рдЧ-рдЗрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рд╣рдо рдЗрд╕реЗ рдЙрд╕реА рдЯреИрдЧ рдореЗрдВ рдпрд╣рд╛рдБ рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдХрд┐рд╕реА рдХрд╛рд░рдг рд╕реЗ рдЖрдкрдХреЗ рдкреНрд▓рдЧрдЗрди рдХреЛ Youtube рдкреНрд▓рдЧрдЗрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рддреЛ рдирд┐рдореНрди рдЯреИрдЧ рдХреЛ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:
<import addon="plugin.video.youtube" version="4.0.0"/>
рдкреНрд▓рдЧрдЗрди рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╕рдордп рд╕реИрджреНрдзрд╛рдВрддрд┐рдХ рд░реВрдк рд╕реЗ, рд▓рд╛рдкрддрд╛ рдирд┐рд░реНрднрд░рддрд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рд╕реНрдерд╛рдкрд┐рдд рдХреА рдЬрд╛рдиреА рдЪрд╛рд╣рд┐рдПред
12-14 рд▓рд╛рдЗрдиреЛрдВ рдореЗрдВ рдкреНрд▓рдЧрдЗрди рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрддреА рд╣реИред
extension point="xbmc.python.pluginsource"
рдЕрд░реНрде рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рд╕рд╛рдордЧреНрд░реА рд╕реНрд░реЛрдд рдкреНрд▓рдЧрдЗрди рд╣реИ,
library="default.py"
рдПрдХ рдкреНрд▓рдЧрдЗрди рдЖрд░рдВрдн рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╡реАрдбрд┐рдпреЛ рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рд╡реАрдбрд┐рдпреЛ рдкреНрд▓рдЧрдЗрди рд╣реИред рдпрджрд┐ рдкреНрд▓рдЧрдЗрди рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕рд╛рдордЧреНрд░реА рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ, рддреЛ рдЯреИрдЧ рдореЗрдВ рдЖрдк рд░рд┐рдХреНрдд рд╕реНрдерд╛рди рджреНрд╡рд╛рд░рд╛ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдЙрдкрд▓рдмреНрдз рд╕рд╛рдордЧреНрд░реА рдХреЗ рдкреНрд░рдХрд╛рд░ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рдВрднрд╛рд╡рд┐рдд рдореВрд▓реНрдп рд╡реАрдбрд┐рдпреЛ, рд╕рдВрдЧреАрдд рдФрд░ рдЫрд╡рд┐ рд╣реИрдВред рдпреЗ рдорд╛рди рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдкреНрд▓рдЧрдЗрди рдХрд┐рд╕ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛: "рд╡реАрдбрд┐рдпреЛ", "рд╕рдВрдЧреАрдд" рдпрд╛ "рдлреЛрдЯреЛ"ред рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреА рд╕рд╛рдордЧреНрд░реА рддрдХ рдкрд╣реБрдБрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд▓рдЧрдЗрди рдХрдИ рд╡рд░реНрдЧреЛрдВ рдореЗрдВ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдЬреИрд╕рд╛ рдХрд┐ рдкрд╣рд▓реЗ рд╣реА рдЙрд▓реНрд▓реЗрдЦ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, "xbmc.python.pluginsource" рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рд╕рд╛рдордЧреНрд░реА рд╕реНрд░реЛрдд рдкреНрд▓рдЧрдЗрди рд╣реИред рдпрд╣реА рд╣реИ, XBMC рдбреЗрд╡рд▓рдкрд░реНрд╕ рдХреА рд╢рдмреНрджрд╛рд╡рд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдпрд╣ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдФрд░ рдЕрдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рдРрдб-рдСрди рдХреЗ рд╡рд┐рдкрд░реАрдд рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкреНрд▓рдЧ-рдЗрди рд╣реИред рд╕реНрд░реЛрдд рдкреНрд▓рдЧ-рдЗрди рдФрд░ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкреНрд▓рдЧ-рдЗрди (рд╕реЙрдлрд╝реНрдЯрд╡реЗрдпрд░ рдкреНрд▓рдЧ-рдЗрди) рдХреЗ рдмреАрдЪ рдореБрдЦреНрдп рдЕрдВрддрд░ рдпрд╣ рд╣реИ рдХрд┐ рд╕реНрд░реЛрдд рдкреНрд▓рдЧ-рдЗрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдмрд╣реБ-рд╕реНрддрд░реАрдп рд╕реВрдЪрд┐рдпреЛрдВ (рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛) рдХреЗ рд░реВрдк рдореЗрдВ рдорд▓реНрдЯреАрдореАрдбрд┐рдпрд╛ рд╕рд╛рдордЧреНрд░реА рдХреЗ рд╕рд╛рде рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдлрд╝реЛрд▓реНрдбрд░ (рдЖрднрд╛рд╕реА рдФрд░ / рдпрд╛ рд╡рд╛рд╕реНрддрд╡рд┐рдХ) рдФрд░ рдлрд╛рдЗрд▓реЗрдВ (рд╕реНрдерд╛рдиреАрдп рдФрд░ / рдпрд╛) рд╣реЛрддреА рд╣реИрдВред рдиреЗрдЯрд╡рд░реНрдХ рдкрд░), рдЬрдмрдХрд┐ рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдПрдХ рдордирдорд╛рдирд╛ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рдПрдкреАрдЖрдИ рдХреА рдХреНрд╖рдорддрд╛рдУрдВ рдХреЗ рднреАрддрд░) рдпрд╛ рдмрд┐рд▓реНрдХреБрд▓ рдирд╣реАрдВред рдкреНрд░реЛрдЧреНрд░рд╛рдо рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рджреЛрд╣рд░реЗ рдЙрджреНрдзрд░рдг рдЪрд┐рд╣реНрдиреЛрдВ рдореЗрдВ рдкреИрд░рд╛рдореАрдЯрд░ "xbmc.python.script" рдФрд░ рдЯреИрдЧ рдореЗрдВ рджрд┐рдЦреЗрдЧрд╛
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 тАФ .