Exemplo n.º 1
0
class TreeWidgetItemData:
    def __init__(self, item_type, songs=None, **kwargs):

        # metadata values
        self.metadata = None

        # application values
        # always strings
        self.dict = {}
        app_fields = (InputField.SONG_FIELDS if item_type
                      == TreeWidgetType.SONG else InputField.ALBUM_FIELDS)
        for field in set(kwargs.keys()) | app_fields:
            # set all mandatory settings to their defaults if not
            # specified in the parameters
            # and any extra settings specified in the parameters
            if field in kwargs:
                self.dict[field] = kwargs[field]
            else:
                # set to default setting
                self.dict[field] = get_setting(field)

            if field == "coverArt" and self.dict[field] in APPLICATION_IMAGES:
                # convert resource path to real file path for ffmpeg
                self.dict[field] = APPLICATION_IMAGES[get_setting(field)]

        # add song metadata
        if item_type == TreeWidgetType.SONG:
            try:
                self.metadata = Metadata(self.dict["song_path"])

                cover_exts = {".jpg", ".jpeg", ".bmp", ".gif", ".png"}
                cover_names = {
                    "cover",
                    "folder",
                    "front",
                    os.path.splitext(self.dict["song_file"])[0],
                }
                cover_file = None
                for file in os.listdir(self.dict["song_dir"]):
                    path = posixpath.join(self.dict["song_dir"], file)
                    name, ext = os.path.splitext(file)
                    if (os.path.isfile(path) and name.lower() in cover_names
                            and ext.lower() in cover_exts):
                        logger.info(f"Found cover file {path}")
                        cover_file = path
                        break

                if (get_setting("preferCoverArtFile")
                        == SETTINGS_VALUES.CheckBox.CHECKED and cover_file):
                    self.set_value("coverArt", cover_file)
                elif get_setting(
                        "extractCoverArt") == SETTINGS_VALUES.CheckBox.CHECKED:
                    if (cover_path :=
                            self.metadata.get_cover_art()) is not None:
                        self.set_value("coverArt", cover_path)
                    elif cover_file:
                        self.set_value("coverArt", cover_file)

            except Exception as e:
                logger.warning("Error while getting cover art")
                logger.warning(e)
                logger.warning(self.dict["song_path"])
        else:
            # album gets metadata from children
            # song metadata is stored as song.<key>
            # e.g. song.album would be the album name
            #
            # we will only get metadata from one song
            # because the album shouldn't care about
            # the varying metadata values for the songs
            # such as title or track number
            for song in songs:
                for key, value in song.to_dict().items():
                    key = "song.{}".format(key)
                    self.dict[key] = value
                break

        self.update_fields()

    def update_fields(self):
        for field, value in self.dict.items():
            self.set_value(field, value)

    def to_dict(self):
        dict = {
            **self.dict,
            **(self.metadata.get_tags() if self.metadata is not None else {}),
        }
        return dict

    def get_value(self, field):
        return self.dict[field]

    def get_metadata_value(self, key):
        if key in self.metadata.get_tags():
            return self.metadata.get_tags()[key]
        return None

    def set_value(self, field, value):
        # replace {variable} with value from metadata
        value = SettingTemplate(value).safe_substitute(**self.to_dict())
        self.dict[field] = value

    def get_duration_ms(self):
        if "length" in self.metadata.get_tags():
            return float(self.metadata.get_tags()["length"]) * 1000
        else:
            logger.error("Could not find duration of file {}".format(
                self.dict["song_path"]))
            logger.debug(self.metadata.get_tags())
            return 999999999

    def get_track_number(self):
        if "tracknumber" in self.metadata.get_tags():
            try:
                tracknumber = self.metadata.get_tags()["tracknumber"]
                if "/" in tracknumber:
                    # sometimes track number is represented as a fraction
                    tracknumber = tracknumber[:tracknumber.index("/")]
                return int(tracknumber)
            except:
                logger.warning("Could not convert {} to int".format(
                    self.metadata.get_tags()["tracknumber"]))
                return 0
        return 0

    def __str__(self):
        return str(self.dict)