Repository navigation
Adding a new host in E2iplayer
A host called myhost consists of:
| file | what |
|---|---|
IPTVPlayer/hosts/hostmyhost.py |
the code. The file name must start with host; everything after it is the host name (lower case). |
IPTVPlayer/icons/logos/myhostlogo.png |
logo in the host list, 120x40 - icon and name side by side |
IPTVPlayer/icons/PlayerSelector/myhost100.pngmyhost120.png, myhost135.png
|
square tiles of the graphical host selection, 100x100, 120x120, 135x135 |
IPTVPlayer/hosts/hostgroups.txt |
one line: the host name in the group(s) it belongs to |
Icons: PNG with 8 bits per channel (palette with transparency or RGBA), no 1/2/4-bit or grayscale PNGs, and keep them small (quantize, e.g. with pngquant/oxipng).
There is no host list to edit anymore - E2iPlayer finds every host*.py in the hosts folder by itself, and a new host is switched on by default.
hostgroups.txt is JSON: group name → list of host names. The groups are worldwide (hosts that work in every country, in addition to their other groups), moviesandseries, cartoonsandanime, sport, live, iptv (IPTV account portals), torrent (torrent hosts - they belong only in this group, it is hidden while torrent playback is off), documentary, science, music, the language groups (polish, english, german, french, russian, hungarian, arabic, greek, latino, italian, swedish, balkans) and others. A host can be in several groups, e.g. moviesandseries and german. Users can change the groups in the GUI later.
The first two lines of every host file:
# -*- coding: utf-8 -*-
# Last Modified: 09.10.2026Line 2 is the date of the last real change (dd.mm.yyyy); update it with every change of the host. The host selection shows it in its info line (Host: myhost, Last Modified: …), so users can tell which version they have. Older notes can stay below it as # <date> - <note> lines.
E2iPlayer imports the file and uses three names from it:
def GetConfigList():
# the host's options (BLUE key in the host list), [] when it has none
return []
def gettytul():
# the main url of the site, also the title of the host
return 'https://helloworld.com/'
class IPTVHost(CHostBase):
# the interface to the GUI; CHostBase implements it on top of your scraper class
def __init__(self):
# scraper object, True when the host has a search history, item types that can always be
# added to favourites ([] = decided per row by its 'good_for_fav' field)
CHostBase.__init__(self, HelloWorld(), False, [])gettytul() must be one return of a fixed string, nothing computed: the host lists read the title straight from the file without importing the host (fast host lists, only opened hosts are loaded). The test tests/test_host_titles.py checks this for every host, so a computed title makes the CI fail. The host itself may still use it, e.g. self.MAIN_URL = gettytul().
PIN protection comes with every host by itself: its settings get Pin protection for this host and an optional own PIN, without any code in the host (IHost.isProtectedByPinCode() / getPinCode() read them). Don't build an own PIN into a host.
The scraper class (HelloWorld here) is derived from CBaseHostClass (IPTVPlayer/components/ihost.py). It holds the current list in self.currList, gives you self.cm (HTTP and parsing, libs/pCommon.py) and self.up (the urlparser), and has these methods for you to fill:
-
handleService(index, refresh, searchPattern, searchType)- called every time the user opens a row.self.currItemis the row that was opened; you fillself.currListwith the rows of the new list. -
getLinksForVideo(cItem)- called when a VIDEO row is opened: returns the links (mirrors/qualities) as[{'name': ..., 'url': ..., 'need_resolve': 0 or 1}]. -
getVideoLinks(url)- called for a link withneed_resolve: 1when the user picks it: returns the playable streams, usually throughself.up.getVideoLinkExt(url). -
getArticleContent(cItem)- the content of the INFO key (optional).
🔗hosthelloworld.zip contains the smallest working host: one folder with three YouTube videos, plus its logo and tiles. The whole host:
from Plugins.Extensions.IPTVPlayer.components.ihost import CBaseHostClass, CHostBase
from Plugins.Extensions.IPTVPlayer.components.iptvplayerinit import TranslateTXT as _
from Plugins.Extensions.IPTVPlayer.tools.iptvtools import printDBG, printExc
def GetConfigList():
return []
def gettytul():
return 'https://helloworld.com/'
class HelloWorld(CBaseHostClass):
def __init__(self):
CBaseHostClass.__init__(self, {'history': 'helloworld', 'cookie': 'helloworld.cookie'})
self.MAIN_URL = gettytul()
self.MENU = [{'category': 'list_videos', 'title': _('Videos')}]
def listVideos(self, cItem):
for title, videoId in (('Big Buck Bunny', 'aqz-KE-bpKQ'), ('Sintel', 'eRsGyueVLvQ'), ('Tears of Steel', 'R6MlUcmOul8')):
self.addVideo({'name': 'category', 'good_for_fav': True, 'title': title,
'url': 'https://www.youtube.com/watch?v=' + videoId,
'icon': 'https://i.ytimg.com/vi/%s/hqdefault.jpg' % videoId,
'desc': _('Open movie by the Blender Foundation')})
def getLinksForVideo(self, cItem):
return self.up.getVideoLinkExt(cItem['url'])
def handleService(self, index, refresh=0, searchPattern='', searchType=''):
CBaseHostClass.handleService(self, index, refresh, searchPattern, searchType)
name = self.currItem.get('name', '')
category = self.currItem.get('category', '')
self.currList = []
if name is None: # the main menu of the host
self.listsTab(self.MENU, {'name': 'category'})
elif category == 'list_videos':
self.listVideos(self.currItem)
else:
printExc()
CBaseHostClass.endHandleService(self, index, refresh)
class IPTVHost(CHostBase):
def __init__(self):
CHostBase.__init__(self, HelloWorld(), False, [])How the navigation works:
- The user opens the host:
handleService()runs withself.currItem = {'name': None}- the host lists its main menu.listsTab()adds each menu entry as a folder. - The user opens "Videos":
handleService()runs with that row asself.currItem, itscategorydecides what to list. - The user opens a video:
getLinksForVideo()returns the links. For a YouTube url the urlparser already knows how to get the stream.
Every row is a dict. title, url, icon and desc are used by E2iPlayer, category and any other key are yours - they come back in cItem when the row is opened. Which keys matter for the watched flag, favourites and downloads is on the page Host standard.
- Copy the files into the plugin folder on the box:
/usr/lib/enigma2/python/Plugins/Extensions/IPTVPlayer/(hosts/,icons/logos/,icons/PlayerSelector/). - Restart the GUI (enigma2) - hosts are loaded only at start.
- Switch on the debug log before you test: Settings → Debug configuration → Debug logs, see How to create debug logs. Every
printDBG()of your host and every exception (printExc()) ends up there. Without the log you are blind. - Open the host. The host list does not import the host, only opening it does. A host that can't be imported (syntax error, missing module) is left out of the host list with the message "Following host are broken or additional python modules are needed."; an error while it is opened shows the last lines of the traceback. The log has the whole traceback.
After every change of the code the GUI has to be restarted again. Check the syntax on the PC first, for both Python versions:
python2 -m py_compile hostmyhost.py
python3 -m py_compile hostmyhost.py
New and fixed hosts come in as a pull request against the branch python3 of oe-mirrors/e2iplayer: fork, branch, commit, push, open the pull request. Please read CONTRIBUTING.md first - the points that matter most for a host:
- Code style: PEP 8, Unix line endings, meaningful names, comments where the logic is not obvious, small functions.
- Python 2.7 and 3: the host should run on both (see Host standard).
-
No heavy dependencies: HTTP through
self.cm(pCommon), no extra Python packages the boxes would have to install. - Existing resolvers first: try to play the links with the urlparser's existing resolvers before writing a new one.
- Stay unnoticed: get past a site's protections the way a browser does, not in a way the site notices.
- Your own work: you must have the rights to what you submit; it is published under the project's license.
- AI: you are responsible for every line, must understand and be able to explain it, and must say in the pull request whether AI helped. Pull requests opened by an AI agent on its own are not accepted.
- Review: every pull request is reviewed - answer the comments, be patient and kind.
In issues, discussions and reviews the Code of Conduct applies.
- A real host for a website: A more complex example of host: building item lists from HTML
- What users expect from a host today: Host standard
Based on the original text by Maxbambi, thank you!
Using E2iPlayer
- Install
- Controls and navigation
- Settings explained
- Playback and subtitles
- Playlists and selection
- Download manager
- Web interface
- Torrents with TorrServer
Captchas
Problems?
For developers