Kodi Community Forum

Full Version: TIDAL music (former WiMP)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Wow cool, you are once again the knight in shining armor. I've been playing around for quite a while now and no more errors have occurred. I was a bit irritated at first because the artist slideshow always crashed immediately after I entered your changes until I found out that I had to activate the fade to black option in the settings, and then the following errors disappeared again:

error <general>: EXCEPTION Thrown (PythonToCppException) : -->Python callback/script returned the following error<--
- NOTE: IGNORING THIS CAN LEAD TO MEMORY LEAKS!
Error Type: <class 'AttributeError'>
Error Contents: 'Main' object has no attribute 'SLIDESHOW'
Traceback (most recent call last):
File "/home/cod/.var/app/tv.kodi.Kodi/data/addons/script.artistslideshow/default.py", line 8, in <module>
slideshow.Start()
File "/home/cod/.var/app/tv.kodi.Kodi/data/addons/script.artistslideshow/resources/lib/artistslideshow.py", line 271, in Start
self._use_correct_artwork()
File "/home/cod/.var/app/tv.kodi.Kodi/data/addons/script.artistslideshow/resources/lib/artistslideshow.py", line 1216, in _use_correct_artwork
self.IMAGESFOUND = self.IMAGESFOUND or self.SLIDESHOW.AddImage(
^^^^^^^^^^^^^^
AttributeError: 'Main' object has no attribute 'SLIDESHOW'

Maybe you can have another look at what's going on, but I can live with it for now.
Since I've also posted the problem in the artist slideshow forum (but have not yet received an answer) the question is whether it would be useful to post your suggested solution there too?

Anyway, thank you very much for now!
The SLIDESHOW attribute is the thread which should be started. The Main thread wants to access this attribute before the slideshow is started the first time.
I think, that's the real problem. And for the fadetoblack problem I made a small change to my patches, see below:

python artistslideshow.py:

    def Start(self):
        self._upgrade()
        self._get_plugins()
        sleeping = False
        change_slideshow = True
        if self._is_playing():
            LW.log(['music playing'], xbmc.LOGINFO)
            self._set_property('ArtistSlideshowRunning', 'True')
        else:
            LW.log(['no music playing'], xbmc.LOGINFO)
            if self.DAEMON:
                self._set_property('ArtistSlideshowRunning', 'True')
        if self.MONITOR.waitForAbort(1):
            return
        while not self.MONITOR.abortRequested() and self._get_infolabel(self.ARTISTSLIDESHOWRUNNING) == 'True':
            if self.MONITOR.SettingsChanged():
                self._get_settings()
                self._get_plugins()
                self.MONITOR.UpdatedSettings()
            if self._is_playing():
                sleeping = False
                if change_slideshow:
                    self._clear_properties(fadetoblack=self.FADETOBLACK)
                    self._use_correct_artwork()
                    self._trim_cache()
                    change_slideshow = False
                change_slideshow = self._playback_stopped_or_changed(
                    wait_time=self.MAINSLEEP)
            elif self.DAEMON:
                if not sleeping:
                    self._clear_properties(clearartists=True)
                    sleeping = True
                    change_slideshow = True
                if self._waitForAbort(wait_time=self.MAINIDLESLEEP):
                    break
            elif not self.DAEMON:
                break
        self._clear_properties(slideshowstopping=True)   # This tells the method that it should not start a new slideshow thread
        self._set_property('ArtistSlideshowRunning')
        self._set_property('ArtistSlideshow.CleanupComplete', 'True')
        LW.log(['script version %s stopped' % ADDONVERSION], xbmc.LOGINFO)

The _clear_properties method gets a new parameter "slideshowstopping" and only starts a new slideshow thread if the addon shouldn't stop.
The Start method above calls the _clear_properties method with slideshowstopping=True if the Main thread is going to stop (see above).

python artistslideshow.py:

    def _clear_properties(self, fadetoblack=False, clearartists=False, slideshowstopping=False):
        LW.log(['main thread is cleaning all the properties'])
        self.MBID = ''
        self.FANARTNUMBER = False
        if clearartists:
            self.ALLARTISTS = []
        if self._get_infolabel('ArtistSlideshow.Image'):
            self.SLIDESHOW.ClearImages(fadetoblack=fadetoblack)
        self._slideshow_thread_stop()
        if self._is_playing() and not slideshowstopping:  # Only start a new slideshow thread if the addon shouldn't stop
            self._slideshow_thread_start()
        if self._get_infolabel('ArtistSlideshow.ArtistBiography'):
            self._set_property('ArtistSlideshow.ArtistBiography')
        similar_count = self._get_infolabel('ArtistSlideshow.SimilarCount')
        if similar_count:
            for count in range(int(similar_count)):
                self._set_property(
                    'ArtistSlideshow.%d.SimilarName' % (count + 1))
                self._set_property(
                    'ArtistSlideshow.%d.SimilarThumb' % (count + 1))
            self._set_property('ArtistSlideshow.SimilarCount')
        album_count = self._get_infolabel('ArtistSlideshow.AlbumCount')
        if album_count:
            for count in range(int(album_count)):
                self._set_property(
                    'ArtistSlideshow.%d.AlbumName' % (count + 1))
                self._set_property(
                    'ArtistSlideshow.%d.AlbumThumb' % (count + 1))
            self._set_property('ArtistSlideshow.AlbumCount')

Initialize the SLIDESHOW attribute in the method _init_vars with a not running dummy thread (last line):

python artistslideshow.py:

    def _init_vars(self):
        self.MONITOR = SlideshowMonitor()
        self.FANARTNUMBER = False
        self.CACHEDIR = ''
        self.ARTISTS_INFO = []
        self.IMGDB = '_imgdb.nfo'
        self._set_property('ArtistSlideshow.CleanupComplete')
        self._set_property('ArtistSlideshow', os.path.join(
            ADDONPATH, 'resources', 'images', 'update-slide', ''))
        self.SKININFO = {}
        for item in self.FIELDLIST:
            if self.PASSEDFIELDS[item]:
                self.SKININFO[item[0:-5]] = self.PASSEDFIELDS[item]
            else:
                self.SKININFO[item[0:-5]] = ''
        self.EXTERNALCALLSTATUS = self._get_infolabel(self.EXTERNALCALL)
        LW.log(['external call is set to ' +
               self._get_infolabel(self.EXTERNALCALL)])
        self.NAME = ''
        self.ALLARTISTS = []
        self.MBID = ''
        self.VARIOUSARTISTSMBID = '89ad4ac3-39f7-470e-963a-56509c546377'
        self.LASTPLAYINGFILE = ''
        self.LASTPLAYINGSONG = ''
        self.LASTJSONRESPONSE = ''
        self.LASTARTISTREFRESH = 0
        self.LASTCACHETRIM = 0
        self.PARAMS = {}
        self.SLIDESHOW = Slideshow(self.WINDOW, self.SLIDEDELAY) # Initialize with a not running dummy thread

The method _slideshow_thread_stop should wait for the stopping slideshow thread with a timeout. I used the the sleep time from he addon settings plus 2 seconds (the last two lines):

python artistslideshow.py:

    def _slideshow_thread_stop(self):
        try:
            self.SLIDESHOW.StopSlideshow()
        except AttributeError:
            return
        if self.SLIDESHOW.is_alive():
            self.SLIDESHOW.join(self.SLIDESHOW.SLIDESHOWSLEEP + 2)

Now the ArtistSlideshow addon works with and without the fadetoblack setting and without any crash.

I like the ArtistSlideshow addon but it's too bad that it doesn't work with the Confluence skin.
Does anyone know how to activate it there ?
For those who are interested: https://github.com/pkscout/script.artistslideshow  describes how to insert the ArtistSlideshow into the MusicVisualisation.xml of skins which have no support for the slideshow.
I interted a few lines into the MusicVisualisation.xml of the Confluence skin to activate the ArtistSlideshow there.

- line 5: Start the script in daemon mode
- line 25: added a condition to the "visible" flag of the default fanart image to hide it when the ArtistSlideshow image is loaded
- lines 29 to 36: This is the image control of the ArtistSlideshow addon

xml MusicVisualisation.xml:

<?xml version="1.0" encoding="UTF-8"?>
<window>
    <!-- Start ArtistSlideshow addon as daemon -->
    <onload>RunScript(script.artistslideshow, daemon=True)</onload>
    <defaultcontrol />
    <controls>
        <control type="visualisation" id="2">
            <!-- FIX ME Music Visualization needs to have an id of 2 in this window to be able to lock or change preset -->
            <description>visualisation</description>
            <left>0</left>
            <top>0</top>
            <width>1920</width>
            <height>1080</height>
        </control>
        <control type="image">
            <description>Fanart Image for Artist</description>
            <left>0</left>
            <top>0</top>
            <width>1920</width>
            <height>1080</height>
            <aspectratio>scale</aspectratio>
            <texture background="true">$INFO[Player.Art(fanart)]</texture>
            <colordiffuse>AAFFFFFF</colordiffuse>
            <visible>!String.IsEmpty(Player.Art(fanart)) + !Skin.HasSetting(HideVisualizationFanart) + String.IsEmpty(Window(Visualisation).Property(ArtistSlideshow.Image))</visible>
            <fadetime>600</fadetime>
        </control>
        <!-- The image for the ArtistSlideshow addon -->
         <control type="image">
             <aspectratio>scale</aspectratio>
             <fadetime>400</fadetime>
             <animation effect="fade" start="0" end="100" time="400">WindowOpen</animation>
             <animation effect="fade" start="100" end="0" time="300">WindowClose</animation>
             <texture background="true">$INFO[Window(Visualisation).Property(ArtistSlideshow.Image)]</texture>
             <visible>!String.IsEmpty(Window(Visualisation).Property(ArtistSlideshow.Image))</visible>
         </control>
        
        <!-- media infos -->
        <control type="group">
        ....
Absolutely love this! Thanks so much for all of the hard work. I also compiled the imputstream.ffmpegdirect add-on as per suggestion, and got everything working properly on Kodi 20. Again, thanks for the work - Tidal is amazing, and being able to play Hi-Res files via Kodi is a joy.
Hey @arneson, I would say it works perfectly now as I have no more problems at all, not a single freeze or crash.
So thanks again for that and best regards

By the way, i tried to compile imputstream.ffmpegdirect on Manjaro/Arch and it just wasn't possible for me. I don't get a fraction of the dependencies installed and to my knowledge there are no explicit instructions for compiling on arch. Your ubuntu version seems to work fine on manjaro as well, i don't know if it could work any better?