import math
from i3pystatus import formatp
from i3pystatus import IntervalModule
from gi.repository import Playerctl


class Spotify(IntervalModule):
    """
    Gets Spotify info using playerctl

    .. rubric:: Available formatters

    * `{status}` — current status icon (paused/playing)
    * `{length}` — total song duration (mm:ss format)
    * `{artist}` — artist
    * `{title}` — title
    * `{album}` — album
    """

    settings = (
        ('format', 'formatp string'),
        ('format_not_running', 'Text to show if cmus is not running'),
        ('color', 'The color of the text'),
        ('color_not_running', 'The color of the text, when cmus is not running'),
        ('status', 'Dictionary mapping status to output'),
    )

    # default settings
    color = '#ffffff'
    color_not_running = '#ffffff'
    format = '{status} {length} {artist} - {title}'
    format_not_running = 'Not running'
    interval = 1
    status = {
        'paused': '▷',
        'playing': '▶',
    }

    on_leftclick = 'playpause'
    on_rightclick = 'next_song'
    on_upscroll = 'next_song'
    on_downscroll = 'previous_song'

    def get_info(self, player):
        """gets spotify track info from playerctl"""

        artist = player.get_artist()
        title = player.get_title()
        album = player.get_album()
        status = player.props.status

        # gets the length of spotify through the metadata command
        length = ""

        # stores the metadata and checks if it is valid
        metadata = player.props.metadata
        if metadata is not None:
            # math to convert the number stored in mpris:length to a human readable format
            time = dict(metadata)["mpris:length"] / 60.0e6
            minutes = math.floor(time)
            seconds = round(time % 1 * 60)
            if seconds < 10:
                seconds = "0" + str(seconds)
            length = "{}:{}".format(minutes, seconds)

        # sets length to an empty string if it does not exist for whatever reason. This should usually not happen
        else:
            length = ""

        # returns a dictionary of all spotify data
        return {"artist": artist, "title": title, "album": album, "status": status, "length": length}

    def run(self):
        """Main statement, executes all code every interval"""

        # tries to create player object and get data from player
        try:
            self.player = Playerctl.Player(player_name="spotify")

            response = self.get_info(self.player)

            # creates a dictionary of the spotify data captured
            fdict = {
                'status': self.status[response['status'].lower()],
                'title': response["title"],
                'album': response.get('album', ''),
                'artist': response.get('artist', ''),
                'length': response.get('length', 0),
            }
            self.data = fdict
            self.output = {"full_text": formatp(self.format, **fdict),
                           "color": self.color}

        # outputs the not running string if spotify is closed
        except:
            self.output = {"full_text": self.format_not_running,
                           "color": self.color_not_running}
            if hasattr(self, "data"):
                del self.data

    def playpause(self):
        """Pauses and plays spotify"""
        self.player.play_pause()

    def next_song(self):
        """skips to the next song"""
        self.player.next()

    def previous_song(self):
        """Plays the previous song"""
        self.player.previous()

@@ -73,16 +73,66 @@
 alModule
+%0A%0Aimport gi%0Agi.require_version('Playerctl', '1.0')
 %0Afrom gi
@@ -159,16 +159,22 @@
 layerctl
+, GLib
 %0A%0A%0Aclass
@@ -1416,95 +1416,8 @@
 us%0A%0A
-        # gets the length of spotify through the metadata command%0A        length = %22%22%0A%0A
     
@@ -1521,123 +1521,12 @@
     
-if metadata is not None:%0A            # math to convert the number stored in mpris:length to a human readable format
+try:
 %0A   
@@ -1791,25 +1791,24 @@
 econds)%0A
-%0A
         
 # sets l
@@ -1803,287 +1803,351 @@
     
-# sets length to an empty string if it does not exist for whatever reason. This should usually not happen%0A        else:%0A            length = %22%22%0A%0A        # returns a dictionary of all spotify data%0A        return %7B%22artist%22: artist, %22title%22: title, %22album%22: album, %22status%22: status,
+except (KeyError, TypeError):%0A            length = %22%22%0A%0A        # returns a dictionary of all spotify data%0A        return %7B%0A            %22status%22: self.status%5Bstatus.lower()%5D if status else None,%0A            %22title%22: title if title else %22%22,%0A            %22album%22: album if album else %22%22,%0A            %22artist%22: artist if artist else %22%22,%0A           
  %22le
@@ -2159,16 +2159,26 @@
 : length
+,%0A        
 %7D%0A%0A    d
@@ -2259,73 +2259,8 @@
 %22%22%0A%0A
-        # tries to create player object and get data from player%0A
     
@@ -2347,24 +2347,21 @@
         
-response
+fdict
  = self.
@@ -2382,17 +2382,16 @@
 player)%0A
-%0A
         
@@ -2398,395 +2398,8 @@
     
-# creates a dictionary of the spotify data captured%0A            fdict = %7B%0A                'status': self.status%5Bresponse%5B'status'%5D.lower()%5D,%0A                'title': response%5B%22title%22%5D,%0A                'album': response.get('album', ''),%0A                'artist': response.get('artist', ''),%0A                'length': response.get('length', 0),%0A            %7D%0A            self.data = fdict
 %0A   
@@ -2514,25 +2514,24 @@
 .color%7D%0A
-%0A
         
 # output
@@ -2526,76 +2526,25 @@
     
-# outputs the not running string if spotify is closed%0A        except
+except GLib.Error
 :%0A  
@@ -2669,76 +2669,8 @@
 ing%7D
-%0A            if hasattr(self, %22data%22):%0A                del self.data
 %0A%0A  

Refactor Spotify module