def __init__(self):
        xbmcplugin.setContent(HANDLE, 'audio')

        self.curl = HTTPComm()
        self.name = ARGS.get('foldername', None)
        self.mode = ARGS.get('mode', None)
        self.thumbnailImage = 'special://home/addons/%s/icon.png' % ADDON_ID
    def __init__(self):
        xbmcplugin.setContent(HANDLE, 'audio')

        self.curl = HTTPComm()
        self.name = ARGS.get('foldername', None)
        self.mode = ARGS.get('mode', None)
        self.thumbnailImage = 'special://home/addons/%s/icon.png' % ADDON_ID
    def __init__(self):
        xbmcplugin.setContent(HANDLE, 'audio')

        self.curl = HTTPComm()

        self.name = ARGS.get('foldername', None)
        self.mode = ARGS.get('mode', None)
class musicAddonXbmc:
    # settings used for multithreading
    threadMax = 8
    workQueue = Queue.Queue()

    # Resolves path to where plugin settings and cache will be stored
    addonProfilePath = xbmc.translatePath(
        ADDON.getAddonInfo('profile')).decode('utf-8')

    # Init CURL thingy
    curler = HTTPComm()

    # regex used to find all streams in a .pls
    re_playlistStreams = re.compile("File\d=([^\n]+)\s*Title\d=([^\n]+)",
                                    re.M | re.I)

    #dictBitrate = {1: 40, 2: 64, 3: 128, 4: 256}
    dictBitrate = [40, 64, 128, 256]

    # list of channels used when caching and retrieving from cache
    channelsList = []

    # unique listenkey if a premium member
    listenKey = ''

    # stores how many new channels/channelart was found
    newChannels = 0

    def __init__(self):
        # If stats is allowed and its been at least 24 hours since last checkin
        #if (ADDON.getSetting('allowstats') == "true") and (
        #        self.checkFileTime(self._checkinFile, self._addonProfilePath, 86400) == True):
        #    open(self._checkinFile, "w")
        #
        #    account = 'public'
        #    if ADDON.getSetting('username') != "":
        #        account = 'premium'
        #
        #    xbmc.log('Submitting stats', xbmc.LOGNOTICE)
        #    self._httpComm.get('http://stats.qualisoft.dk/?plugin=' + ADDON.getAddonInfo(
        #        'id') + '&version=' + __version__ + '&account=' + account + '&key=' + parser.get('plugin',
        #                                                                                         'checkinkey'))
        #
        xbmc.log("[PLUGIN] %s v%s (%s)" % (__plugin__, __version__, __date__),
                 xbmc.LOGNOTICE)

    """
     Let's get some tunes!
    """

    def run(self):
        threads = []

        # check if cache has expired
        if not ADDON.getSetting("forceupdate") == "true"\
            and not int(ADDON.getSetting("cacheexpire_days")) == 0\
            and self.checkFileTime(pluginConfig.get('cache', 'cacheChannels'),
                                   ADDON.getSetting("cacheexpire_days")):
            ADDON.setSetting(id="forceupdate", value="true")

        if ADDON.getSetting("forceupdate") == "true":
            channels = []
            html = ""

            # if username is set, try to login and go for premium channels
            if ADDON.getSetting('username') != "":
                loginData = urllib.urlencode({
                    'member_session[username]':
                    ADDON.getSetting('username'),
                    'member_session[password]':
                    ADDON.getSetting('password')
                })

                # post login info and get frontpage html
                html = self.curler.request(pluginConfig.get('urls', 'login'),
                                           'post', loginData)

                # if we could not reach di.fm at all
                if not bool(html):
                    xbmc.log('di.fm could not be reached', xbmc.LOGWARNING)
                    xbmcgui.Dialog().ok(ADDON.getLocalizedString(30100),
                                        ADDON.getLocalizedString(30101),
                                        ADDON.getLocalizedString(30102),
                                        ADDON.getLocalizedString(30103))
                    xbmcplugin.endOfDirectory(HANDLE, succeeded=True)
                    return True

                channels = json.loads(
                    self.curler.request(
                        pluginConfig.get(
                            'streams', 'premium%sk' % self.dictBitrate[int(
                                ADDON.getSetting('bitrate'))]), 'get'))

                premiumConfig = self.getPremiumConfig()

                # if premiumConfig['listenKey'] is blank, we did not log in correctly
                if premiumConfig['listenKey'] == '':
                    xbmc.log('Login did not succeed', xbmc.LOGWARNING)
                    xbmcgui.Dialog().ok(ADDON.getLocalizedString(30170),
                                        ADDON.getLocalizedString(30171),
                                        ADDON.getLocalizedString(30172))
                    xbmcplugin.endOfDirectory(HANDLE, succeeded=True)
                    return True

                # if we should get the favorites or all channels
                if ADDON.getSetting("usefavorites") == 'true':
                    channels = self.getFavoriteChannels(html, channels)
                    if len(channels) == 0:
                        xbmcgui.Dialog().ok(ADDON.getLocalizedString(30180),
                                            ADDON.getLocalizedString(30181),
                                            ADDON.getLocalizedString(30182))
                        xbmcplugin.endOfDirectory(HANDLE, succeeded=True)
                        return True

                # add listenkey to playlist urls
                for channel in channels:
                    channel['playlist'] = '%s?%s' % (
                        channel['playlist'], premiumConfig['listenKey'])

            # go for free/public channels
            else:
                html = self.curler.request(
                    pluginConfig.get('urls', 'frontpage'), 'get')

                # if we could not reach di.fm at all
                if not html:
                    xbmc.log(u'di.fm could not be reached', xbmc.LOGWARNING)
                    xbmcgui.Dialog().ok(ADDON.getLocalizedString(30100),
                                        ADDON.getLocalizedString(30101),
                                        ADDON.getLocalizedString(30102),
                                        ADDON.getLocalizedString(30103))
                    xbmcplugin.endOfDirectory(HANDLE, succeeded=True)
                    return True

                channels = json.loads(
                    self.curler.request(pluginConfig.get('streams', 'public'),
                                        'get'))

            re_channelData = re.compile(
                "NS\('AudioAddict'\).Channels\s*=\s*([^;]+);", re.M | re.I)
            channelMeta = json.loads(re_channelData.findall(html)[0])

            # put each playlist in a worker queue for threading
            for channel in channels:
                self.workQueue.put(channel)

            # starts 8 threads to download streams for each channel
            while not self.workQueue.empty():
                xbmc.log(
                    'Worker queue size is %s' % (str(self.workQueue.qsize())),
                    xbmc.LOGNOTICE)

                if threading.activeCount(
                ) < self.threadMax and not self.workQueue.empty():
                    threads.append(
                        scraperThread(self, self.workQueue.get(), channelMeta,
                                      len(channels)))
                    threads[-1].start()
                else:
                    time.sleep(0.1)

            # wait for all threads to finish before continuing
            for t in threads:
                t.join()

            # Saves channels to cache and reset the "force update" flag
            if len(channels) > 0:
                pickle.dump(self.channelsList,
                            open(
                                os.path.join(
                                    self.addonProfilePath,
                                    pluginConfig.get('cache',
                                                     'cacheChannels')), "w"),
                            protocol=0)
                ADDON.setSetting(id="forceupdate", value="false")

        # else load channels from cache file
        else:
            self.channelsList = pickle.load(
                open(
                    os.path.join(self.addonProfilePath,
                                 pluginConfig.get('cache', 'cacheChannels')),
                    "r"))

            for channel in self.channelsList:
                self.addItem(channel['name'], channel['streamUrl'],
                             channel['description'], channel['bitrate'],
                             channel['asset'], channel['isNew'],
                             len(self.channelsList))

        # Should channels be sorted A-Z?
        if ADDON.getSetting('sortaz') == "true":
            xbmcplugin.addSortMethod(HANDLE,
                                     sortMethod=xbmcplugin.SORT_METHOD_LABEL)

        # tell XMBC there are no more items to list
        xbmcplugin.endOfDirectory(HANDLE, succeeded=True)

        if self.newChannels > 0:
            xbmcgui.Dialog().ok(
                ADDON.getLocalizedString(30130),
                ADDON.getLocalizedString(30131) +
                str(self.newChannels) + ADDON.getLocalizedString(30132),
                ADDON.getLocalizedString(30133),
                ADDON.getLocalizedString(30134))

        return True

    """
     Parses a playlist (if needed) and calls the function that adds it to the GUI
    """

    def addChannel(self, channel, channelMeta, channelCount):
        # set to true if new channelart is downloaded
        isNew = 0

        if not os.path.exists(self.addonProfilePath + str(channel['id']) +
                              '.png'):
            isNew = 1
            self.newChannels += 1
            self.getChannelAsset(str(channel['id']),
                                 channelMeta[str(channel['id'])]['asset_url'])

        if ADDON.getSetting('randomstream') == "true":
            playlist = self.curler.request(
                channel['playlist'] + self.listenKey, 'get')

            playlistStreams = self.re_playlistStreams.findall(playlist)

            # gets a random stream from the channels playlist
            streamUrl = playlistStreams[randrange(len(playlistStreams))][0]
        else:
            streamUrl = channel['playlist'] + self.listenKey

        bitrate = 40

        if ADDON.getSetting('username') != "":
            bitrate = self.dictBitrate[int(ADDON.getSetting('bitrate'))]

        # stores channel in list to be cached later
        co = {
            'name': channel['name'],
            'streamUrl': streamUrl,
            'description': channel['description'],
            'bitrate': bitrate,
            'asset': self.addonProfilePath + str(channel['id']) + '.png',
            'isNew': isNew
        }
        self.channelsList.append(dict(co))

        self.addItem(channel['name'], streamUrl, channel['description'],
                     bitrate,
                     self.addonProfilePath + str(channel['id']) + '.png',
                     isNew, channelCount)

    """ Returns a bool
     Adds item to the XBMC GUI
    """

    def addItem(self, channelTitle, streamUrl, streamDescription, bitrate,
                icon, isNewChannel, totalItems):
        # tart it up a bit if it's a new channel
        if isNewChannel:
            li = xbmcgui.ListItem(label="[COLOR FF007EFF]" + channelTitle +
                                  "[/COLOR]",
                                  thumbnailImage=icon)
            xbmc.log(
                u"New channel found: %s" %
                channelTitle.encode('ascii', 'xmlcharrefreplace'),
                xbmc.LOGERROR)
        else:
            li = xbmcgui.ListItem(label=channelTitle, thumbnailImage=icon)

        # 256kb/sec is MP3
        if bitrate == 256 and ADDON.getSetting('username') != "":
            li.setProperty("mimetype", 'audio/mpeg')
        else:
            li.setProperty("mimetype", 'audio/aac')

        li.setInfo(type="Music",
                   infoLabels={
                       "Genre": channelTitle,
                       "Comment": streamDescription,
                       "Size": bitrate * 1024
                   })
        li.setProperty("IsPlayable", "true")

        xbmcplugin.addDirectoryItem(handle=HANDLE,
                                    url=streamUrl,
                                    listitem=li,
                                    isFolder=False,
                                    totalItems=totalItems)

        return True

    """ Returns a bool
     Will check if channel asset/art is present in cache - if not, try to download
    """

    def getChannelAsset(self, channelId, assetUrl):
        try:
            data = self.curler.request(assetUrl, 'get')
            filepath = self.addonProfilePath + channelId + '.png'
            open(filepath, 'wb').write(data)
            xbmc.log('Found new channel art for with ID %s' % str(channelId),
                     xbmc.LOGINFO)
        except Exception:
            sys.exc_clear(
            )  # Clears all exceptions so the script will continue to run
            xbmcgui.Dialog().ok(ADDON.getLocalizedString(30160),
                                ADDON.getLocalizedString(30161),
                                ADDON.getLocalizedString(30162) + channelId)
            xbmc.log(
                ADDON.getLocalizedString(30160) + " " +
                ADDON.getLocalizedString(30161) + str(channelId) + " " +
                ADDON.getLocalizedString(30162) + str(channelId),
                xbmc.LOGERROR)
            return False

        return True

    """ Return a list containing a dictonary
     Filters out all channels that are not in the favorites list
    """

    def getFavoriteChannels(self, html, allChannels):
        channels = []
        re_favoriteData = re.compile(
            "NS\('AudioAddict.API.Config.member'\).Favorites\s*=\s*([^;]+);",
            re.M | re.I)
        m = re_favoriteData.findall(html)

        # if favorites list is empty, return empty list
        if m[0] == '[]':
            return channels
        else:
            favorites = json.loads(re_favoriteData.findall(html)[0])

        # sort favorites after user selected positions
        favorites = sorted(favorites, key=lambda k: k['position'])

        for fav in favorites:
            for channel in allChannels:
                if fav['channel_id'] == channel['id']:
                    channels.append(dict(channel))

        return channels

    """ Return a list containing a dictonary or false
     Returns the logged in users premium config
    """

    def getPremiumConfig(self):
        try:
            if ADDON.getSetting("forceupdate") == "true":

                # Login to api.audioaddict.com to retrieve useful data
                # Documentation: http://tobiass.eu/api-doc.html#13

                loginData = urllib.urlencode({
                    'username':
                    ADDON.getSetting('username'),
                    'password':
                    ADDON.getSetting('password')
                })
                # Download and save response
                jsonResponse = self.curler.request(
                    pluginConfig.get('urls', 'apiAuthenticate'), 'post',
                    loginData)
                jsonData = json.loads(jsonResponse)
                pickle.dump(jsonData,
                            open(
                                os.path.join(
                                    self.addonProfilePath,
                                    pluginConfig.get('cache',
                                                     'cachePremiumConfig')),
                                "w"),
                            protocol=0)

                # Load needed data into premiumConfig
                premiumConfig = {'listenKey': jsonData['listen_key']}

            else:
                # Load data from local cache

                jsonData = pickle.load(
                    open(
                        os.path.join(
                            self.addonProfilePath,
                            pluginConfig.get('cache', 'cachePremiumConfig')),
                        "r"))
                premiumConfig = {'listenKey': jsonData['listen_key']}

            return premiumConfig

        except Exception:
            sys.exc_clear(
            )  # Clears all exceptions so the script will continue to run
            return False

    """ Return a bool
     Checks if a file is older than x days
    """

    def checkFileTime(self, filename, days):
        if not os.path.exists(self.addonProfilePath):
            os.makedirs(self.addonProfilePath)
            return True

        daysInSecs = int(days) * 60 * 60 * 24

        file = os.path.join(self.addonProfilePath, filename)

        # If file exists, check timestamp
        if os.path.exists(file):
            if os.path.getmtime(file) > (time.time() - daysInSecs):
                xbmc.log(
                    u'It has not been %s days since %s was last updated' %
                    (days, file), xbmc.LOGNOTICE)
                return False
            else:
                xbmc.log(u'The cache file %s + has expired' % file,
                         xbmc.LOGNOTICE)
                return True
        # If file does not exist, return true so the file will be created by scraping the page
        else:
            xbmc.log(u'The cache file %s does not exist' % file,
                     xbmc.LOGNOTICE)
            return True
class Main:

    def __init__(self):
        xbmcplugin.setContent(HANDLE, 'audio')

        self.curl = HTTPComm()
        self.name = ARGS.get('foldername', None)
        self.mode = ARGS.get('mode', None)
        self.thumbnailImage = 'special://home/addons/%s/icon.png' % ADDON_ID


    def run(self):

        if self.mode is None:

            # Create streams directory
            url = self.build_url({'mode': 'folder', 'foldername': 'streams'})
            li = xbmcgui.ListItem(ADDON.getLocalizedString(30100), iconImage='DefaultFolder.png')
            xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=li, isFolder=True)

            # Create queue directory
            url = self.build_url({'mode': 'folder', 'foldername': 'queue'})
            li = xbmcgui.ListItem(ADDON.getLocalizedString(30101), iconImage='DefaultFolder.png')
            xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=li, isFolder=True)
            xbmcplugin.endOfDirectory(HANDLE)

        elif self.mode[0] == 'folder' and self.name[0] == 'streams':

            streams = self.get_streams()
            for stream in streams:
                li = xbmcgui.ListItem(stream['name'], iconImage='DefaultAudio.png', thumbnailImage=self.thumbnailImage)
                li.setInfo(type="Music", infoLabels={"Size": stream['bitrate'] * 1024})
                li.setProperty("IsPlayable", "true")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url=stream['url'], listitem=li, isFolder=False)

            xbmcplugin.endOfDirectory(HANDLE)

        elif self.mode[0] == 'folder' and self.name[0] == 'queue':

            history = self.get_history()

            # Currently Playing
            self.add_heading(ADDON.getLocalizedString(30200))
            for item in history[0]:
                li = xbmcgui.ListItem(item["artist"] + " - " + item["song"], thumbnailImage=self.thumbnailImage)
                li.setProperty("IsPlayable", "false")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)


            # Queue
            self.add_heading(ADDON.getLocalizedString(30201), True)
            for item in history[1]:
                li = xbmcgui.ListItem(item["artist"] + " - " + item["song"], thumbnailImage=self.thumbnailImage)
                li.setProperty("IsPlayable", "false")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)


            # History
            self.add_heading(ADDON.getLocalizedString(30202), True)
            for item in history[2]:
                li = xbmcgui.ListItem(item["artist"] + " - " + item["song"], thumbnailImage=self.thumbnailImage)
                li.setProperty("IsPlayable", "false")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)

            xbmcplugin.endOfDirectory(HANDLE)

        else:

            # Add items
            url = 'http://necta.pedroja.tech/necta192.mp3'
            li = xbmcgui.ListItem(ADDON.getLocalizedString(30199), iconImage='DefaultAudio.png')


            xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=li, isFolder=False)
            xbmcplugin.endOfDirectory(HANDLE)


    def build_url(self, query):
        return BASE_URL + '?' + urllib.urlencode(query)

    def get_streams(self):
        streams = []
        xml = self.curl.request(pluginConfig.get('urls', 'stream_xml'), 'get')
        dom = minidom.parseString(xml)

        for node in dom.getElementsByTagName('stream'):
            id = node.attributes["id"].value
            name = node.getElementsByTagName('name')[0].firstChild.nodeValue
            url = node.getElementsByTagName('url')[0].firstChild.nodeValue
            bitrate = int(node.getElementsByTagName('bitrate')[0].firstChild.nodeValue)
            country = node.getElementsByTagName('country')[0].firstChild.nodeValue
            type = node.getElementsByTagName('type')[0].firstChild.nodeValue

            streams.append({"id": id, "name": name, "url": url, 'bitrate': bitrate, 'country': country, 'type': type})

        streams = sorted(streams, key=lambda d: (d['name'][:6].lower(), -d['bitrate'])) #itemgetter('bitrate')
        return streams

    def get_history(self):
        current = []
        queue = []
        history = []

        xml = self.curl.request(pluginConfig.get('urls', 'history_xml'), 'get')
        dom = minidom.parseString(xml)

        # Currently Playing

        currentsong = dom.getElementsByTagName('now')[0]
        artist = currentsong.getElementsByTagName('artist')[0].firstChild.nodeValue
        song = currentsong.getElementsByTagName('song')[0].firstChild.nodeValue
        current.append({"artist": artist, "song": song})

        # Read queue

        for entry in dom.getElementsByTagName('queue')[0].getElementsByTagName('entry'):
            artist = entry.getElementsByTagName('artist')[0].firstChild.nodeValue
            song = entry.getElementsByTagName('song')[0].firstChild.nodeValue
            play_start = entry.getElementsByTagName('playstart')[0].firstChild.nodeValue
            queue.append({"artist": artist, "song": song, "play_start": play_start})

        # Read history

        for entry in dom.getElementsByTagName('history')[0].getElementsByTagName('entry'):
            artist = entry.getElementsByTagName('artist')[0].firstChild.nodeValue
            song = entry.getElementsByTagName('song')[0].firstChild.nodeValue
            play_start = entry.getElementsByTagName('playstart')[0].firstChild.nodeValue
            history.append({"artist": artist, "song": song, "play_start": play_start})

        return [current, queue, history]

    def add_heading(self, title, linebreak=False):
        # Linebreak
        if linebreak:
            li = xbmcgui.ListItem(thumbnailImage=self.thumbnailImage)
            li.setProperty("IsPlayable", "false")
            xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)

        li = xbmcgui.ListItem(label="[COLOR FF007EFF]" + title + "[/COLOR]", thumbnailImage=self.thumbnailImage)
        li.setProperty("IsPlayable", "false")
        xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)
class Main:

    def __init__(self):
        xbmcplugin.setContent(HANDLE, 'audio')

        self.curl = HTTPComm()
        self.name = ARGS.get('foldername', None)
        self.mode = ARGS.get('mode', None)
        self.thumbnailImage = 'special://home/addons/%s/icon.png' % ADDON_ID


    def run(self):

        if self.mode is None:

            # Create streams directory
            url = self.build_url({'mode': 'folder', 'foldername': 'streams'})
            li = xbmcgui.ListItem(ADDON.getLocalizedString(30100), iconImage='DefaultFolder.png')
            xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=li, isFolder=True)

            # Create queue directory
            url = self.build_url({'mode': 'folder', 'foldername': 'queue'})
            li = xbmcgui.ListItem(ADDON.getLocalizedString(30101), iconImage='DefaultFolder.png')
            xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=li, isFolder=True)
            xbmcplugin.endOfDirectory(HANDLE)

        elif self.mode[0] == 'folder' and self.name[0] == 'streams':

            streams = self.get_streams()
            for stream in streams:
                li = xbmcgui.ListItem(stream['name'], iconImage='DefaultAudio.png', thumbnailImage=self.thumbnailImage)
                li.setInfo(type="Music", infoLabels={"Size": stream['bitrate'] * 1024})
                li.setProperty("IsPlayable", "true")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url=stream['url'], listitem=li, isFolder=False)

            xbmcplugin.endOfDirectory(HANDLE)

        elif self.mode[0] == 'folder' and self.name[0] == 'queue':

            history = self.get_history()

            # Currently Playing
            self.add_heading(ADDON.getLocalizedString(30200))
            for item in history[0]:
                li = xbmcgui.ListItem(item["artist"] + " - " + item["song"], thumbnailImage=self.thumbnailImage)
                li.setProperty("IsPlayable", "false")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)


            # Queue
            self.add_heading(ADDON.getLocalizedString(30201), True)
            for item in history[1]:
                li = xbmcgui.ListItem(item["artist"] + " - " + item["song"], thumbnailImage=self.thumbnailImage)
                li.setProperty("IsPlayable", "false")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)


            # History
            self.add_heading(ADDON.getLocalizedString(30202), True)
            for item in history[2]:
                li = xbmcgui.ListItem(item["artist"] + " - " + item["song"], thumbnailImage=self.thumbnailImage)
                li.setProperty("IsPlayable", "false")
                xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)

            xbmcplugin.endOfDirectory(HANDLE)

        else:

            # Add items
            url = 'http://no.scenemusic.net:9000/necta.m3u'
            li = xbmcgui.ListItem(ADDON.getLocalizedString(30199), iconImage='DefaultAudio.png')


            xbmcplugin.addDirectoryItem(handle=HANDLE, url=url, listitem=li, isFolder=False)
            xbmcplugin.endOfDirectory(HANDLE)


    def build_url(self, query):
        return BASE_URL + '?' + urllib.urlencode(query)

    def get_streams(self):
        streams = []
        xml = self.curl.request(pluginConfig.get('urls', 'stream_xml'), 'get')
        dom = minidom.parseString(xml)

        for node in dom.getElementsByTagName('stream'):
            id = node.attributes["id"].value
            name = node.getElementsByTagName('name')[0].firstChild.nodeValue
            url = node.getElementsByTagName('url')[0].firstChild.nodeValue
            bitrate = int(node.getElementsByTagName('bitrate')[0].firstChild.nodeValue)
            country = node.getElementsByTagName('country')[0].firstChild.nodeValue
            type = node.getElementsByTagName('type')[0].firstChild.nodeValue

            streams.append({"id": id, "name": name, "url": url, 'bitrate': bitrate, 'country': country, 'type': type})

        streams = sorted(streams, key=lambda d: (d['name'][:6].lower(), -d['bitrate'])) #itemgetter('bitrate')
        return streams

    def get_history(self):
        current = []
        queue = []
        history = []

        xml = self.curl.request(pluginConfig.get('urls', 'history_xml'), 'get')
        dom = minidom.parseString(xml)

        # Currently Playing

        currentsong = dom.getElementsByTagName('now')[0]
        artist = currentsong.getElementsByTagName('artist')[0].firstChild.nodeValue
        song = currentsong.getElementsByTagName('song')[0].firstChild.nodeValue
        current.append({"artist": artist, "song": song})

        # Read queue

        for entry in dom.getElementsByTagName('queue')[0].getElementsByTagName('entry'):
            artist = entry.getElementsByTagName('artist')[0].firstChild.nodeValue
            song = entry.getElementsByTagName('song')[0].firstChild.nodeValue
            play_start = entry.getElementsByTagName('playstart')[0].firstChild.nodeValue
            queue.append({"artist": artist, "song": song, "play_start": play_start})

        # Read history

        for entry in dom.getElementsByTagName('history')[0].getElementsByTagName('entry'):
            artist = entry.getElementsByTagName('artist')[0].firstChild.nodeValue
            song = entry.getElementsByTagName('song')[0].firstChild.nodeValue
            play_start = entry.getElementsByTagName('playstart')[0].firstChild.nodeValue
            history.append({"artist": artist, "song": song, "play_start": play_start})

        return [current, queue, history]

    def add_heading(self, title, linebreak=False):
        # Linebreak
        if linebreak:
            li = xbmcgui.ListItem(thumbnailImage=self.thumbnailImage)
            li.setProperty("IsPlayable", "false")
            xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)

        li = xbmcgui.ListItem(label="[COLOR FF007EFF]" + title + "[/COLOR]", thumbnailImage=self.thumbnailImage)
        li.setProperty("IsPlayable", "false")
        xbmcplugin.addDirectoryItem(handle=HANDLE, url="nnn", listitem=li, isFolder=False)
Beispiel #7
0
class musicAddonXbmc:
    _addonProfilePath = xbmc.translatePath(
        "special://profile/plugin_data/music/Sky.fm/").decode(
            'utf-8')  # Dir where plugin settings and cache will be stored

    _cacheStreams = _addonProfilePath + "cache_streamlist.dat"
    _cacheListenkey = _addonProfilePath + "cache_listenkey.dat"
    _checkinFile = _addonProfilePath + "cache_lastcheckin.dat"

    _baseUrl = parser.get('urls', 'baseUrl')
    _loginUrl = parser.get('urls', 'loginUrl')
    _listenkeyUrl = parser.get('urls', 'listenkeyUrl')

    _publicStreamsJson40k = parser.get(
        'urls', 'publicStreamsJson40k')  # Public AAC 40k/sec AAC+ JSON url
    _premiumStreamsJson40k = parser.get(
        'urls', 'premiumStreamsJson40k')  # AAC 40k/sec AAC+ JSON url
    _premiumStreamsJson64k = parser.get(
        'urls', 'premiumStreamsJson64k')  # AAC 64k/sec AAC+ JSON url
    _premiumStreamsJson128k = parser.get(
        'urls', 'premiumStreamsJson128k')  # AAC 128k/sec AAC+ JSON url
    _premiumStreamsJson256k = parser.get(
        'urls', 'premiumStreamsJson256k')  # MP3 256k/sec AAC+ JSON url
    _favoritesStreamJson40k = parser.get(
        'urls',
        'favoritesStreamJson40k')  # Favorites AAC 40k/sec AAC+ playlist url
    _favoritesStreamJson64k = parser.get(
        'urls',
        'favoritesStreamJson64k')  # Favorites AAC 64k/sec AAC+ playlist url
    _favoritesStreamJson128k = parser.get(
        'urls',
        'favoritesStreamJson128k')  # Favorites AAC 128k/sec AAC+ playlist url
    _favoritesStreamJson256k = parser.get(
        'urls',
        'favoritesStreamJson256k')  # Favorites MP3 256k/sec AAC+ playlist url

    _httpComm = HTTPComm()  # Init CURL thingy
    _frontpageHtml = ""

    _newChannels = 0
    _bitrate = 40
    _streamMimeType = 'audio/aac'

    def __init__(self):
        # If stats is allowed and its been at least 24 hours since last checkin
        if (ADDON.getSetting('allowstats') == "true") and (self.checkFileTime(
                self._checkinFile, self._addonProfilePath, 86400) == True):
            open(self._checkinFile, "w")

            account = 'public'
            if ADDON.getSetting('username') != "":
                account = 'premium'

            xbmc.log('Submitting stats', xbmc.LOGNOTICE)
            self._httpComm.get('http://stats.qualisoft.dk/?plugin=' +
                               ADDON.getAddonInfo('id') + '&version=' +
                               __version__ + '&account=' + account + '&key=' +
                               parser.get('plugin', 'checkinkey'))

        xbmc.log("[PLUGIN] %s v%s (%s)" % (__plugin__, __version__, __date__),
                 xbmc.LOGNOTICE)

    # Let's get some tunes!
    def start(self):
        jsonList = []  # list that data from the JSON will be put in
        streamList = [
        ]  # the final list of channels, with small custom additions

        # Check if cachefile has expired
        if ADDON.getSetting("forceupdate") == "true" or (
            (int(ADDON.getSetting("cacheexpire")) * 60) != 0
                and self.checkFileTime(
                    self._cacheStreams, self._addonProfilePath,
                    (int(ADDON.getSetting("cacheexpire")) * 60)) == True):
            listenkey = ""  # will contain the premium listenkey

            if ADDON.getSetting('username') != "" and ADDON.getSetting(
                    "usefavorites"
            ) == 'false':  # if username is set and not using favorites
                xbmc.log("Going for Premium streams", xbmc.LOGNOTICE)

                # Checks if forceupdate is set and if the listenkey cachefile exists
                if ADDON.getSetting(
                        "forceupdate") == "true" or not os.path.exists(
                            self._cacheListenkey):
                    listenkey = self.getListenkey()
                    pickle.dump(listenkey,
                                open(self._cacheListenkey, "w"),
                                protocol=0)  # saves listenkey for further use
                else:
                    listenkey = pickle.load(open(self._cacheListenkey, "r"))

                if ADDON.getSetting('bitrate') == '0':
                    self._bitrate = 40
                    jsonList = self.getJSONChannelList(
                        self._premiumStreamsJson40k)
                    streamList = self.customizeStreamListAddMenuitem(
                        jsonList, listenkey)
                elif ADDON.getSetting('bitrate') == '1':
                    self._bitrate = 64
                    jsonList = self.getJSONChannelList(
                        self._premiumStreamsJson64k)
                    streamList = self.customizeStreamListAddMenuitem(
                        jsonList, listenkey)
                elif ADDON.getSetting('bitrate') == '2':
                    self._bitrate = 128
                    jsonList = self.getJSONChannelList(
                        self._premiumStreamsJson128k)
                    streamList = self.customizeStreamListAddMenuitem(
                        jsonList, listenkey)
                else:
                    self._bitrate = 256
                    self._streamMimeType = 'audio/mpeg'
                    jsonList = self.getJSONChannelList(
                        self._premiumStreamsJson256k)
                    streamList = self.customizeStreamListAddMenuitem(
                        jsonList, listenkey)

                xbmc.log("Bitrate set to " + str(self._bitrate),
                         xbmc.LOGNOTICE)

            elif ADDON.getSetting('username') != "" and ADDON.getSetting(
                    "usefavorites"
            ) == 'true':  # if username is set and wants to use favorites
                xbmc.log("Going for Premium favorite streams", xbmc.LOGNOTICE)
                listenkey = self.getListenkey()
                if ADDON.getSetting('bitrate') == '0':
                    self._bitrate = 40
                    streamList = self.getFavoriteStreamsList(
                        self._favoritesStreamJson40k + "?" + listenkey)
                elif ADDON.getSetting('bitrate') == '1':
                    self._bitrate = 64
                    streamList = self.getFavoriteStreamsList(
                        self._favoritesStreamJson64k + "?" + listenkey)
                elif ADDON.getSetting('bitrate') == '2':
                    self._bitrate = 128
                    streamList = self.getFavoriteStreamsList(
                        self._favoritesStreamJson128k + "?" + listenkey)
                else:
                    self._bitrate = 256
                    self._streamMimeType = 'audio/mpeg'
                    streamList = self.getFavoriteStreamsList(
                        self._favoritesStreamJson256k + "?" + listenkey)

                xbmc.log("Bitrate set to " + str(self._bitrate),
                         xbmc.LOGNOTICE)

                for channel in streamList:
                    self.addItem(
                        channel['name'], channel['playlist'],
                        channel["description"], channel['bitrate'],
                        self._addonProfilePath + "art_" + channel['key'] +
                        ".png", channel['isNew'])

            else:
                xbmc.log("Going for Public streams", xbmc.LOGNOTICE)
                jsonList = self.getJSONChannelList(self._publicStreamsJson40k)
                streamList = self.customizeStreamListAddMenuitem(
                    jsonList, "")  # sending a blank string as listenkey

            # save streams to cachefile
            pickle.dump(streamList, open(self._cacheStreams, "w"), protocol=0)

            if (self._newChannels > 0):  # Yay! New channels found
                xbmc.log(
                    ADDON.getLocalizedString(30130) + " " +
                    ADDON.getLocalizedString(30131) + str(self._newChannels) +
                    ADDON.getLocalizedString(30132) + " " +
                    ADDON.getLocalizedString(30133) + " " +
                    ADDON.getLocalizedString(30134), xbmc.LOGNOTICE)
                xbmcgui.Dialog().ok(
                    ADDON.getLocalizedString(30130),
                    ADDON.getLocalizedString(30131) + str(self._newChannels) +
                    ADDON.getLocalizedString(30132),
                    ADDON.getLocalizedString(30133),
                    ADDON.getLocalizedString(30134))

        else:
            xbmc.log("Using cached streams", xbmc.LOGNOTICE)
            streamList = pickle.load(open(self._cacheStreams, "r"))

            # Add streams to GUI
            for channel in streamList:
                self.addItem(
                    channel['name'].encode('utf-8'), channel['playlist'],
                    channel["description"], channel['bitrate'],
                    self._addonProfilePath + "art_" + channel['key'] + ".png",
                    channel['isNew'])

        # If streams should be sorted A-Z
        if ADDON.getSetting('sortaz') == "true":
            xbmcplugin.addSortMethod(HANDLE,
                                     sortMethod=xbmcplugin.SORT_METHOD_LABEL)

        # End of channel list
        xbmcplugin.endOfDirectory(HANDLE, succeeded=True)

        # Resets the 'Force refresh' setting
        ADDON.setSetting(id="forceupdate", value="false")

        return True

    """return list - False if it fails
	Gets the favorites playlist and returns the streams as a list
	Also every channel is added to the GUI from here, as the progress indication
	in the GUI would not reflect that something is actually happening till the very end
	"""

    def customizeStreamListAddMenuitem(self, list, listenkey):
        # Precompiling regexes
        streamurl_re = re.compile('File\d+=([^\n]*)',
                                  re.I)  # streams in .pls file

        streamList = []

        # Will add list elements to a new list, with a few additions
        for channel in list:
            channel['key'] = self.makeChannelIconname(
                channel['name']
            )  # customize the key that is used to find channelart
            channel[
                'isNew'] = False  # is used to highlight when it's a new channel
            channelArt = "art_" + channel['key'] + ".png"
            channel['bitrate'] = self._bitrate
            channel["description"] = channel["description"].encode('utf-8')

            if ADDON.getSetting(
                    'username'
            ) != "":  # append listenkey to playlist url if username is set
                channel['playlist'] = self.getFirstStream(
                    channel['playlist'] + "?" + listenkey, streamurl_re)
            else:
                channel['playlist'] = self.getFirstStream(
                    channel['playlist'], streamurl_re)

            if (not os.path.isfile(self._addonProfilePath + channelArt)
                ):  # if channelart is not in cache
                xbmc.log(
                    "Channelart for " +
                    channel['name'].encode("ascii", "ignore") +
                    " not found in cache at " + self._addonProfilePath +
                    channelArt, xbmc.LOGNOTICE)
                self.getChannelArt(channel['id'], "art_" + channel['key'])
                channel['isNew'] = True
                self._newChannels = self._newChannels + 1

            streamList.append(channel)

            # I'd have prefeered it if I didn't have to add menuitem from within this method
            # but I have to, too give the user some visual feedback that stuff is happening
            self.addItem(
                channel['name'].encode('utf-8'), channel['playlist'],
                channel["description"], self._bitrate,
                self._addonProfilePath + "art_" + channel['key'] + ".png",
                channel['isNew'])

        return streamList  # returns the channellist so it can be saved to cache

    """return bool
	Will check if channelart/icon is present in cache - if not, try to download
	"""

    def getChannelArt(self, channelId, channelKey):
        channelArt_re = re.compile(
            'data-id="' + str(channelId) +
            '">(?:[\n\s]*)<a(?:[^>]*)><img(?:[^>]*)src="([^"]*)"', re.I)

        try:
            if (self._frontpageHtml == ""
                ):  # If frontpage html has not already been downloaded, do it
                self._frontpageHtml = self._httpComm.get(self._baseUrl)

            channelartDict = channelArt_re.findall(self._frontpageHtml)

            # Will download and save the channelart to the cache
            self._httpComm.getImage(
                channelartDict[0],
                self._addonProfilePath + channelKey + ".png")

            return True

        except Exception:
            sys.exc_clear(
            )  # Clears all exceptions so the script will continue to run
            xbmcgui.Dialog().ok(
                ADDON.getLocalizedString(30160),
                ADDON.getLocalizedString(30161),
                ADDON.getLocalizedString(30162) + channelartDict[0])
            xbmc.log(
                ADDON.getLocalizedString(30160) + " " +
                ADDON.getLocalizedString(30161) + channelKey + " " +
                ADDON.getLocalizedString(30162) + channelartDict[0],
                xbmc.LOGERROR)
            return False

        return True

    """return String
	Extracts the premium listenkey from the listenkey page html
	"""

    def getListenkey(self):
        listenkey_re = re.compile('Key is:<br />[^<]*<strong>([\w\d]*)<',
                                  re.DOTALL)

        try:
            logindata = urllib.urlencode({
                'member_session[username]':
                ADDON.getSetting('username'),
                'member_session[password]':
                ADDON.getSetting('password')
            })

            self._httpComm.post(
                self._loginUrl,
                logindata)  # logs in so the listenkey page is accessible

            listenkeyHtml = self._httpComm.get(self._listenkeyUrl)
            listenkeyDict = listenkey_re.findall(listenkeyHtml)

            xbmc.log("Found listenkey", xbmc.LOGNOTICE)
            return listenkeyDict[0]

        except Exception:
            sys.exc_clear(
            )  # Clears all exceptions so the script will continue to run
            xbmcgui.Dialog().ok(ADDON.getLocalizedString(30100),
                                ADDON.getLocalizedString(30101),
                                ADDON.getLocalizedString(30102))
            xbmc.log(
                ADDON.getLocalizedString(30100) + " " +
                ADDON.getLocalizedString(30101) + " " +
                ADDON.getLocalizedString(30102), xbmc.LOGERROR)
            return False

        return False

    """return list - False if it fails
	Will get a HTML page containing JSON data, decode it and return
	"""

    def getJSONChannelList(self, url):
        try:
            jsonData = self._httpComm.get(url)
            jsonData = json.loads(jsonData)
        except Exception:  # Show error message in XBMC GUI if failing to parse JSON
            sys.exc_clear(
            )  # Clears all exceptions so the script will continue to run
            xbmcgui.Dialog().ok(ADDON.getLocalizedString(30100),
                                ADDON.getLocalizedString(30101),
                                ADDON.getLocalizedString(30102))
            xbmc.log(
                ADDON.getLocalizedString(30100) + " " +
                ADDON.getLocalizedString(30101) + " " +
                ADDON.getLocalizedString(30102), xbmc.LOGERROR)
            return False

        return jsonData

    """return list - False if it fails
	Gets the favorites playlist and returns the streams as a list
	"""

    def getFavoriteStreamsList(self, url):
        try:
            favoritesPlaylist = self._httpComm.get(
                url)  # favorites .pls playlist in plaintext
            favoritesList = []  # list that will contain streamlist

            streamurl_re = re.compile('File\d+=([^\n]*)',
                                      re.I)  # first stream in .pls file
            channeltitle_re = re.compile('Title\d+=([^\n]*)', re.I)

            streamTitles = channeltitle_re.findall(favoritesPlaylist)
            streamUrls = streamurl_re.findall(favoritesPlaylist)

            if len(streamUrls) == len(
                    streamTitles
            ):  # only continue if the count of urls and titles are equal

                for i in range(len(streamUrls)):
                    listitem = {}
                    listitem['playlist'] = streamUrls[i]
                    listitem['name'] = streamTitles[i].replace(
                        parser.get('plugin', 'playlistStripName') + " ", ""
                    )  # favorite stream titles has some "fluff" text it that is removed
                    listitem['key'] = self.makeChannelIconname(
                        listitem['name'])
                    listitem['isNew'] = False
                    listitem['bitrate'] = self._bitrate
                    listitem['description'] = ""
                    favoritesList.append(listitem)

            else:
                return False

            return favoritesList

        except Exception:  # Show error message in XBMC GUI if failing to parse JSON
            #sys.exc_clear() # Clears all exceptions so the script will continue to run
            xbmcgui.Dialog().ok(ADDON.getLocalizedString(30120),
                                ADDON.getLocalizedString(30111), url)
            xbmc.log(
                ADDON.getLocalizedString(30120) + " " +
                ADDON.getLocalizedString(30111) + " " + url, xbmc.LOGERROR)
            return False

        return favoritesList

    """return string
	Will take a channelname, lowercase it and remove spaces, dashes and other special characters
	The string returned is normally used as part of the filename for the channelart
	"""

    def makeChannelIconname(self, channelname):
        iconreplacement_re = re.compile(
            '[^a-z0-9]', re.I)  # regex that hits everything but a-z and 0-9
        iconname = string.lower(iconreplacement_re.sub('', channelname))
        return iconname

    """return bool
	Simply adds a music item to the XBMC GUI
	"""

    # Adds item to XBMC itemlist
    def addItem(self, channelTitle, streamUrl, streamDescription,
                streamBitrate, icon, isNewChannel):

        if isNewChannel == True:  # tart it up a bit if it's a new channel
            li = xbmcgui.ListItem(label="[COLOR FF007EFF]" + channelTitle +
                                  "[/COLOR]",
                                  thumbnailImage=icon)
            xbmc.log("New channel found: " + channelTitle, xbmc.LOGERROR)
        else:
            li = xbmcgui.ListItem(label=channelTitle, thumbnailImage=icon)

        li.setProperty("mimetype", self._streamMimeType)
        li.setInfo(type="Music",
                   infoLabels={
                       "label": channelTitle,
                       "Genre": channelTitle,
                       "Comment": streamDescription,
                       "Size": (streamBitrate * 1024)
                   })
        li.setProperty("IsPlayable", "true")
        li.setProperty("IsLive", "true")

        xbmcplugin.addDirectoryItem(handle=HANDLE,
                                    url=streamUrl,
                                    listitem=li,
                                    isFolder=False)

        return True

    """return string
	Gets the first stream from a playlist
	"""

    def getFirstStream(self, playlistUrl, regex):
        plsData = self._httpComm.get(playlistUrl)

        streamurls = regex.findall(plsData)

        return streamurls[0]

    """return bool
	Checks if a file is older than x seconds
	"""

    def checkFileTime(self, tmpfile, cachedir, timesince):
        if not os.path.exists(cachedir):
            os.makedirs(cachedir)
            return False

        # If file exists, check timestamp
        if os.path.exists(tmpfile):
            if os.path.getmtime(tmpfile) > (time.time() - timesince):
                xbmc.log(
                    'It has not been ' + str(timesince / 60) +
                    ' minutes since ' + tmpfile + ' was last updated',
                    xbmc.LOGNOTICE)
                return False
            else:
                xbmc.log('The cachefile ' + tmpfile + ' + has expired',
                         xbmc.LOGNOTICE)
                return True
        # If file does not exist, return true so the file will be created by scraping the page
        else:
            xbmc.log('The cachefile ' + tmpfile + ' does not exist',
                     xbmc.LOGNOTICE)
            return True
Beispiel #8
0
    def getStreams(self):
        global LABELCOLOR
        global HTTPCOMM

        # will be cached
        streamurls = []
        streamtitles = []
        streamisnew = []
        streambitrate = 40
        channelicons = None

        # Precompiling regexes
        iconreplacement_re = re.compile("[ '-]", re.I)  # generic regex for iconnames
        streamurl_re = re.compile("File\d+=([^\n]*)", re.I)  # first stream in .pls file
        channeltitle_re = re.compile("Title\d+=([^\n]*)", re.I)
        channelicon_re = re.compile('="[\d\w\s]+" src="([\d\w:\/\.]+)"', re.I)
        playlist_re = None

        HTTPCOMM = HTTPComm()  # Init CURL thingy

        # Check if cachefiles has expired
        if (
            (int(ADDON.getSetting("cacheexpire")) * 60) != 0
            and self.checkFileTime(STREAMURLSCACHE, (int(ADDON.getSetting("cacheexpire")) * 60)) == True
        ) or ADDON.getSetting("forceupdate") == "true":

            # If username NOT set, get public streams
            if ADDON.getSetting("username") == "":
                xbmc.log("Refreshing public streams", xbmc.LOGNOTICE)

                # Get frontpage of di.fm - if it fails, show a dialog in XBMC
                try:
                    htmlData = HTTPCOMM.get(BASEURL)
                except Exception:
                    xbmcgui.Dialog().ok(
                        ADDON.getLocalizedString(30100),
                        ADDON.getLocalizedString(30101),
                        ADDON.getLocalizedString(30102),
                    )
                    xbmc.log(
                        "Connection error - Could not connect to di.fm - Check your internet connection", xbmc.LOGERROR
                    )
                    return False

                    # precompiling regexes
                playlist_re = re.compile(
                    'AAC-HE</a>[\s\r\n]*<ul>(?:.+?(?!</ul>))<li><a href="([^"]+(?=(?:\.pls))[^"]+)">40k', re.DOTALL
                )

                playlists = playlist_re.findall(htmlData)
                xbmc.log("Found " + str(len(playlists)) + " streams", xbmc.LOGNOTICE)

                channelicons = channelicon_re.findall(htmlData)
                xbmc.log("Found " + str(len(channelicons)) + " pieces of channelart", xbmc.LOGNOTICE)

                if len(playlists) == 0:
                    xbmcgui.Dialog().ok(
                        ADDON.getLocalizedString(30110),
                        ADDON.getLocalizedString(30111),
                        ADDON.getLocalizedString(30112),
                    )
                    return False

                    # output public streams to XBMC
                for index, item in enumerate(playlists):
                    playlist = HTTPCOMM.get(item)
                    if playlist:
                        LABELCOLOR = "FF0000"
                        streamurl = streamurl_re.findall(playlist)
                        streamtitle = channeltitle_re.findall(playlist)
                        streamtitle = streamtitle[0]
                        streamtitle = streamtitle.replace("Digitally Imported - ", "")
                        icon = ART_DIR + string.lower(iconreplacement_re.sub("", streamtitle) + ".png")

                        if not self.getStreamicon(icon, channelicons[index]):  # if False is returned, use plugin icon
                            icon = xbmc.translatePath(os.path.join(ADDON.getAddonInfo("path"), "")) + "icon.png"

                            # will highlight new channels/has new channelart
                        if LABELCOLOR != "FF0000":
                            self.addItem(streamtitle, streamurl[0], streambitrate, icon, LABELCOLOR)
                        else:
                            self.addItem(streamtitle, streamurl[0], streambitrate, icon, False)

                        streamtitles.append(streamtitle)  # for caching
                        streamurls.append(streamurl[0])
                        streamisnew.append(LABELCOLOR)
                    else:
                        xbmcgui.Dialog().ok(ADDON.getLocalizedString(30120), ADDON.getLocalizedString(30111), item)
                        xbmc.log(
                            "Connection timed out - Could not get the playlist from this url:" + item, xbmc.LOGERROR
                        )

                        # Get premium streams
            elif ADDON.getSetting("username") != "":
                logindata = urllib.urlencode(
                    {
                        "member_session[username]": ADDON.getSetting("username"),
                        "member_session[password]": ADDON.getSetting("password"),
                    }
                )

                if ADDON.getSetting("bitrate") == "0":
                    streambitrate = 40
                elif ADDON.getSetting("bitrate") == "1":
                    streambitrate = 64
                else:
                    streambitrate = 128
                xbmc.log("Stream bitrate chosen: " + str(streambitrate), xbmc.LOGNOTICE)

                # Login and get frontpage of di.fm - if it fails, show a dialog in XBMC
                try:
                    htmlData = HTTPCOMM.post(PREMIUMURL, logindata)
                except Exception:
                    xbmcgui.Dialog().ok(
                        ADDON.getLocalizedString(30100),
                        ADDON.getLocalizedString(30101),
                        ADDON.getLocalizedString(30102),
                    )
                    xbmc.log(
                        "Connection error - Could not connect to di.fm - Check your internet connection", xbmc.LOGERROR
                    )
                    return False

                channelicons = channelicon_re.findall(htmlData)

                playlist_re = re.compile(
                    'AAC-HE</a>[\s\r\n]*<ul>(?:.+?(?!</ul>))<li><a href="([^"]+(?=(?:\.pls))[^"]+)">'
                    + str(streambitrate)
                    + "k",
                    re.DOTALL,
                )
                playlists = playlist_re.findall(htmlData)

                if len(playlists) == 0:
                    xbmcgui.Dialog().ok(
                        ADDON.getLocalizedString(30110),
                        ADDON.getLocalizedString(30111),
                        ADDON.getLocalizedString(30112),
                    )
                    return False

                    # output premium streams to XBMC
                if ADDON.getSetting("usefavorites") == "false":
                    xbmc.log("Refreshing premium streams", xbmc.LOGNOTICE)
                    playlists.pop(0)  # removes the favorites playlist
                    for index, item in enumerate(playlists):
                        playlist = HTTPCOMM.get(item)
                        if playlist:
                            LABELCOLOR = "FF0000"
                            streamurl = streamurl_re.findall(playlist)
                            streamtitle = channeltitle_re.findall(playlist)
                            streamtitle = streamtitle[0]
                            streamtitle = streamtitle.replace("Digitally Imported - ", "")
                            icon = ART_DIR + string.lower(iconreplacement_re.sub("", streamtitle) + ".png")

                            if not self.getStreamicon(
                                icon, channelicons[index]
                            ):  # if False is returned, use plugin icon
                                icon = xbmc.translatePath(os.path.join(ADDON.getAddonInfo("path"), "")) + "icon.png"

                                # will highlight new channels/has new channelart
                            if LABELCOLOR != "FF0000":
                                self.addItem(streamtitle, streamurl[0], streambitrate, icon, LABELCOLOR)
                            else:
                                self.addItem(streamtitle, streamurl[0], streambitrate, icon, False)

                            streamtitles.append(streamtitle)  # for caching
                            streamurls.append(streamurl[0])
                            streamisnew.append(LABELCOLOR)
                        else:
                            xbmcgui.Dialog().ok(ADDON.getLocalizedString(30120), ADDON.getLocalizedString(30111), item)
                            xbmc.log(
                                "Connection timed out - Could not get the playlist from this url:" + item, xbmc.LOGERROR
                            )

                            # Output premium favorite streams to XBMC
                elif ADDON.getSetting("usefavorites") == "true":
                    xbmc.log("Refreshing premium favorite streams", xbmc.LOGNOTICE)
                    playlist = HTTPCOMM.get(playlists[0])
                    if playlist:
                        favstreamurls = streamurl_re.findall(playlist)
                        favstreamtitles = channeltitle_re.findall(playlist)
                        for index, item in enumerate(favstreamurls):
                            LABELCOLOR = "FF0000"
                            streamtitle = favstreamtitles[index]
                            streamtitle = streamtitle.replace("Digitally Imported - ", "")
                            icon = ART_DIR + string.lower(iconreplacement_re.sub("", streamtitle) + ".png")

                            if not self.getStreamicon(icon, False):  # if False is returned, use plugin icon
                                icon = xbmc.translatePath(os.path.join(ADDON.getAddonInfo("path"), "")) + "icon.png"

                            if LABELCOLOR != "FF0000":  # will highlight new channels/is missing channelart
                                self.addItem(streamtitle, favstreamurls[index], streambitrate, icon, LABELCOLOR)
                            else:
                                self.addItem(streamtitle, favstreamurls[index], streambitrate, icon, False)

                            streamtitles.append(streamtitle)  # for caching
                            streamurls.append(favstreamurls[index])
                            streamisnew.append(LABELCOLOR)
                    else:
                        xbmcgui.Dialog().ok(ADDON.getLocalizedString(30120), ADDON.getLocalizedString(30111), item)
                        xbmc.log(
                            "Connection timed out - Could not get the playlist from this url:" + item, xbmc.LOGERROR
                        )

                xbmc.log("Found " + str(len(playlists)) + " streams", xbmc.LOGNOTICE)

                # Write channels to cache
            pickle.dump(streamurls, open(STREAMURLSCACHE, "w"), protocol=0)
            pickle.dump(streamtitles, open(STREAMTITLESCACHE, "w"), protocol=0)
            pickle.dump(streambitrate, open(STREAMBITRATECACHE, "w"), protocol=0)
            pickle.dump(streamisnew, open(STREAMLABELCOLORCACHE, "w"), protocol=0)

            if NEWSTREAMS > 0:  # Yay! New channels found
                xbmc.log(
                    "New channels found - There was found "
                    + str(NEWSTREAMS)
                    + " new piece(s) of channelart - Meaning there could be new channels",
                    xbmc.LOGNOTICE,
                )
                xbmcgui.Dialog().ok(
                    ADDON.getLocalizedString(30130),
                    ADDON.getLocalizedString(30131) + str(NEWSTREAMS) + ADDON.getLocalizedString(30132),
                    ADDON.getLocalizedString(30133),
                    ADDON.getLocalizedString(30134),
                )

                # Resets the 'Force refresh' setting
            ADDON.setSetting(id="forceupdate", value="false")

        else:
            if (
                not os.path.isfile(STREAMTITLESCACHE)
                or not os.path.isfile(STREAMURLSCACHE)
                or not os.path.isfile(STREAMBITRATECACHE)
                or not os.path.isfile(STREAMLABELCOLORCACHE)
            ):
                xbmc.log(
                    'Cachefiles are missing - At least one of the cachefiles is missing please go to the addon settings and select "Force cache refresh"',
                    xbmc.LOGERROR,
                )
                xbmcgui.Dialog().ok(
                    ADDON.getLocalizedString(30140),
                    ADDON.getLocalizedString(30141),
                    ADDON.getLocalizedString(30142),
                    ADDON.getLocalizedString(30143),
                )
                return False

            streamurls = pickle.load(open(STREAMURLSCACHE, "r"))  # load streams from cache
            streamtitles = pickle.load(open(STREAMTITLESCACHE, "r"))  # load streamtitles from cache
            streambitrate = pickle.load(open(STREAMBITRATECACHE, "r"))  # load stream bitrate from cache
            streamisnew = pickle.load(open(STREAMLABELCOLORCACHE, "r"))  # load stream 'is new' from cache

            # Output cache list of streams to XBMC
            for index, item in enumerate(streamurls):
                playlist = item
                streamurl = str(item)
                streamtitle = streamtitles[index]
                icon = ART_DIR + string.lower(iconreplacement_re.sub("", streamtitle) + ".png")

                if not self.getStreamicon(icon, False):  # if False is returned, use plugin icon
                    icon = xbmc.translatePath(os.path.join(ADDON.getAddonInfo("path"), "")) + "icon.png"

                if streamisnew[index] != "FF0000":
                    self.addItem(streamtitle, streamurl, streambitrate, icon, streamisnew[index])
                else:
                    self.addItem(streamtitle, streamurl, streambitrate, icon, False)

            if NEWSTREAMS < 0:  # Missing channelart dialog
                xbmc.log(
                    "Channelart missing - There is "
                    + str(abs(NEWSTREAMS))
                    + " piece(s) of channelart missing - You should refresh your cache - Disable using 'My Favorites' to get new channelart",
                    xbmc.LOGWARNING,
                )
                xbmcgui.Dialog().ok(
                    ADDON.getLocalizedString(30150),
                    ADDON.getLocalizedString(30151) + str(abs(NEWSTREAMS)) + ADDON.getLocalizedString(30152),
                    ADDON.getLocalizedString(30153),
                    ADDON.getLocalizedString(30154),
                )

        return True
Beispiel #9
0
	def getStreams(self) :
		global LABELCOLOR
		global HTTPCOMM

		# will be cached
		streamurls = []
		streamtitles = []
		streamisnew = []
		streambitrate = 40
		channelicons = None

		# Precompiling regexes
		iconreplacement_re = re.compile('[ \'-]', re.I) # generic regex for iconnames
		streamurl_re 	= re.compile('File\d+=([^\n]*)', re.I) # first stream in .pls file
		channeltitle_re = re.compile('Title\d+=([^\n]*)', re.I)
		channelicon_re	= re.compile('="[\d\w\s]+" src="([\d\w:\/\.]+)"', re.I)	
		playlist_re	= None

		HTTPCOMM = HTTPComm() # Init CURL thingy

		# Check if cachefiles has expired
		if ((int( ADDON.getSetting("cacheexpire") ) * 60) != 0 and self.checkFileTime(STREAMURLSCACHE, (int( ADDON.getSetting("cacheexpire") ) * 60)) == True) or ADDON.getSetting("forceupdate") == "true" :
		
			# If username NOT set, get public streams
			if ADDON.getSetting('username') == "" :
				xbmc.log( "Refreshing public streams", xbmc.LOGNOTICE )

				# Get frontpage of di.fm - if it fails, show a dialog in XBMC
				try :
					htmlData     = HTTPCOMM.get( BASEURL )
				except Exception:
					xbmcgui.Dialog().ok( ADDON.getLocalizedString(30100), ADDON.getLocalizedString(30101), ADDON.getLocalizedString(30102) )
					xbmc.log( 'Connection error - Could not connect to di.fm - Check your internet connection', xbmc.LOGERROR )
					return False

				# precompiling regexes
				playlist_re = re.compile('AAC-HE</a>[\s\r\n]*<ul>(?:.+?(?!</ul>))<li><a href="([^"]+(?=(?:\.pls))[^"]+)">40k', re.DOTALL)
				
				playlists = playlist_re.findall(htmlData)
				xbmc.log( 'Found ' + str(len(playlists)) + ' streams', xbmc.LOGNOTICE )

				channelicons  = channelicon_re.findall(htmlData)
				xbmc.log( 'Found ' + str(len(channelicons)) + ' pieces of channelart', xbmc.LOGNOTICE )

				if len(playlists) == 0 :
					xbmcgui.Dialog().ok( ADDON.getLocalizedString(30110), ADDON.getLocalizedString(30111), ADDON.getLocalizedString(30112) )
					return False
				
				# output public streams to XBMC
				for index, item in enumerate(playlists):
					playlist = HTTPCOMM.get(item)
					if (playlist) :
						LABELCOLOR = 'FF0000'
						streamurl = streamurl_re.findall(playlist)
						streamtitle = channeltitle_re.findall(playlist)
						streamtitle = streamtitle[0]
						streamtitle = streamtitle.replace("Digitally Imported - ", "")
						icon = ART_DIR + string.lower(iconreplacement_re.sub('', streamtitle) + ".png")
			
						if(not self.getStreamicon( icon, channelicons[index] )) : # if False is returned, use plugin icon
							icon = xbmc.translatePath( os.path.join( ADDON.getAddonInfo('path'), '' ) ) + 'icon.png'

						# will highlight new channels/has new channelart
						if LABELCOLOR != 'FF0000' :
							self.addItem(streamtitle, streamurl[0], streambitrate, icon, LABELCOLOR)
						else :
							self.addItem(streamtitle, streamurl[0], streambitrate, icon, False)

						streamtitles.append(streamtitle) # for caching
						streamurls.append(streamurl[0])
						streamisnew.append(LABELCOLOR)
					else :
						xbmcgui.Dialog().ok(ADDON.getLocalizedString(30120), ADDON.getLocalizedString(30111), item)
						xbmc.log( 'Connection timed out - Could not get the playlist from this url:' + item, xbmc.LOGERROR )
								
			# Get premium streams
			elif ( ADDON.getSetting('username') != "" ) :
				logindata = urllib.urlencode({ 'member_session[username]':  ADDON.getSetting('username'),
  							       'member_session[password]':  ADDON.getSetting('password') })

				if ADDON.getSetting('bitrate') == '0' :
					streambitrate = 40
				elif ADDON.getSetting('bitrate') == '1' :
					streambitrate = 64
				else :
					streambitrate = 128
				xbmc.log( 'Stream bitrate chosen: ' + str(streambitrate), xbmc.LOGNOTICE )
				
				# Login and get frontpage of di.fm - if it fails, show a dialog in XBMC
				try :
					htmlData     = HTTPCOMM.post( PREMIUMURL, logindata )
				except Exception:
					xbmcgui.Dialog().ok( ADDON.getLocalizedString(30100), ADDON.getLocalizedString(30101), ADDON.getLocalizedString(30102) )
					xbmc.log( 'Connection error - Could not connect to di.fm - Check your internet connection', xbmc.LOGERROR )
					return False
				
				channelicons  = channelicon_re.findall(htmlData)

				playlist_re = re.compile('AAC-HE</a>[\s\r\n]*<ul>(?:.+?(?!</ul>))<li><a href="([^"]+(?=(?:\.pls))[^"]+)">' + str(streambitrate) + 'k', re.DOTALL)
				playlists = playlist_re.findall(htmlData)

				if len(playlists) == 0 :
					xbmcgui.Dialog().ok( ADDON.getLocalizedString(30110), ADDON.getLocalizedString(30111), ADDON.getLocalizedString(30112) )
					return False

				# output premium streams to XBMC
				if ADDON.getSetting("usefavorites") == 'false' :
					xbmc.log( "Refreshing premium streams", xbmc.LOGNOTICE )
					playlists.pop(0) # removes the favorites playlist
					for index, item in enumerate(playlists):
						playlist = HTTPCOMM.get(item)
						if (playlist) :
							LABELCOLOR = 'FF0000'
							streamurl = streamurl_re.findall(playlist)
							streamtitle = channeltitle_re.findall(playlist)
							streamtitle = streamtitle[0]
							streamtitle = streamtitle.replace("Digitally Imported - ", "")
							icon = ART_DIR + string.lower(iconreplacement_re.sub('', streamtitle) + ".png")
			
							if(not self.getStreamicon( icon, channelicons[index] )) : # if False is returned, use plugin icon
								icon = xbmc.translatePath( os.path.join( ADDON.getAddonInfo('path'), '' ) ) + 'icon.png'

							# will highlight new channels/has new channelart
							if LABELCOLOR != 'FF0000' :
								self.addItem(streamtitle, streamurl[0], streambitrate, icon, LABELCOLOR)
							else :
								self.addItem(streamtitle, streamurl[0], streambitrate, icon, False)

							streamtitles.append(streamtitle) # for caching
							streamurls.append(streamurl[0])
							streamisnew.append(LABELCOLOR)
						else :
							xbmcgui.Dialog().ok(ADDON.getLocalizedString(30120), ADDON.getLocalizedString(30111), item)
							xbmc.log( 'Connection timed out - Could not get the playlist from this url:' + item, xbmc.LOGERROR )


				# Output premium favorite streams to XBMC
				elif ADDON.getSetting("usefavorites") == 'true' :
					xbmc.log( "Refreshing premium favorite streams", xbmc.LOGNOTICE )
					playlist = HTTPCOMM.get(playlists[0])
					if (playlist) :
						favstreamurls = streamurl_re.findall(playlist)
						favstreamtitles = channeltitle_re.findall(playlist)
						for index, item in enumerate(favstreamurls):
							LABELCOLOR = 'FF0000'
							streamtitle = favstreamtitles[index]
							streamtitle = streamtitle.replace("Digitally Imported - ", "")
							icon = ART_DIR + string.lower(iconreplacement_re.sub('', streamtitle) + ".png")
			
							if(not self.getStreamicon( icon, False )) : # if False is returned, use plugin icon
								icon = xbmc.translatePath( os.path.join( ADDON.getAddonInfo('path'), '' ) ) + 'icon.png'

							if LABELCOLOR != 'FF0000' : # will highlight new channels/is missing channelart
								self.addItem(streamtitle, favstreamurls[index], streambitrate, icon, LABELCOLOR)
							else :
								self.addItem(streamtitle, favstreamurls[index], streambitrate, icon, False)

							streamtitles.append(streamtitle) # for caching
							streamurls.append(favstreamurls[index])
							streamisnew.append(LABELCOLOR)
					else :
						xbmcgui.Dialog().ok( ADDON.getLocalizedString(30120), ADDON.getLocalizedString(30111), item )
						xbmc.log( 'Connection timed out - Could not get the playlist from this url:' + item, xbmc.LOGERROR )

				xbmc.log( 'Found ' + str(len(playlists)) + ' streams', xbmc.LOGNOTICE )


			# Write channels to cache
			pickle.dump(streamurls, open(STREAMURLSCACHE, "w"), protocol=0)
			pickle.dump(streamtitles,  open(STREAMTITLESCACHE, "w"), protocol=0)
			pickle.dump(streambitrate, open(STREAMBITRATECACHE, "w"), protocol=0)
			pickle.dump(streamisnew, open(STREAMLABELCOLORCACHE, "w"), protocol=0)
		
			if (NEWSTREAMS > 0) : # Yay! New channels found
				xbmc.log( 'New channels found - There was found ' + str(NEWSTREAMS) + ' new piece(s) of channelart - Meaning there could be new channels', xbmc.LOGNOTICE )
				xbmcgui.Dialog().ok( ADDON.getLocalizedString(30130), ADDON.getLocalizedString(30131) + str(NEWSTREAMS) + ADDON.getLocalizedString(30132), ADDON.getLocalizedString(30133),ADDON.getLocalizedString(30134) )
				
			# Resets the 'Force refresh' setting
			ADDON.setSetting(id="forceupdate", value="false")

		else :
			if not os.path.isfile(STREAMTITLESCACHE) or not os.path.isfile(STREAMURLSCACHE) or not os.path.isfile(STREAMBITRATECACHE) or not os.path.isfile(STREAMLABELCOLORCACHE) :
				xbmc.log( 'Cachefiles are missing - At least one of the cachefiles is missing please go to the addon settings and select "Force cache refresh"', xbmc.LOGERROR )
				xbmcgui.Dialog().ok( ADDON.getLocalizedString(30140), ADDON.getLocalizedString(30141), ADDON.getLocalizedString(30142), ADDON.getLocalizedString(30143) )
				return False

			streamurls     = pickle.load(open(STREAMURLSCACHE, "r"))    # load streams from cache
			streamtitles   = pickle.load(open(STREAMTITLESCACHE, "r"))  # load streamtitles from cache
			streambitrate  = pickle.load(open(STREAMBITRATECACHE, "r")) # load stream bitrate from cache
			streamisnew    = pickle.load(open(STREAMLABELCOLORCACHE, "r"))   # load stream 'is new' from cache

			# Output cache list of streams to XBMC
			for index, item in enumerate(streamurls):
				playlist = item
				streamurl = str(item)
				streamtitle = streamtitles[index]
				icon = ART_DIR + string.lower(iconreplacement_re.sub('', streamtitle) + ".png")

				if(not self.getStreamicon( icon, False )) : # if False is returned, use plugin icon
					icon = xbmc.translatePath( os.path.join( ADDON.getAddonInfo('path'), '' ) ) + 'icon.png'

				if streamisnew[index] != 'FF0000' :
					self.addItem(streamtitle, streamurl, streambitrate, icon, streamisnew[index])
				else :
					self.addItem(streamtitle, streamurl, streambitrate, icon, False)

			if (NEWSTREAMS < 0) : # Missing channelart dialog
				xbmc.log( "Channelart missing - There is " + str(abs(NEWSTREAMS)) + " piece(s) of channelart missing - You should refresh your cache - Disable using 'My Favorites' to get new channelart", xbmc.LOGWARNING )
				xbmcgui.Dialog().ok( ADDON.getLocalizedString(30150), ADDON.getLocalizedString(30151) + str(abs(NEWSTREAMS)) + ADDON.getLocalizedString(30152), ADDON.getLocalizedString(30153), ADDON.getLocalizedString(30154))
		
		return True