Example #1
0
class LibraryItem(object):
    def __init__(self, data):
        self._children = SortedDict()
        self._data = data
        self._parent = None

    def row(self):
        return self.parentItem()._children.index(self._data)

    def childAt(self, row):
        _key, child = self._children.itemAt(row)
        return child

    def parentItem(self):
        return self._parent

    def clear(self):
        self._parent = None
        while self._children:
            _, child = self._children.popitem()
            child.clear()
Example #2
0
class LibraryItem(object):

    def __init__(self, data):
        self._children = SortedDict()
        self._data = data
        self._parent = None

    def row(self):
        return self.parentItem()._children.index(self._data)

    def childAt(self, row):
        _key, child = self._children.itemAt(row)
        return child

    def parentItem(self):
        return self._parent

    def clear(self):
        self._parent = None
        while self._children:
            _, child = self._children.popitem()
            child.clear()
Example #3
0
 def __init__(self, *args, **kwargs):
     QAbstractItemModel.__init__(self, *args, **kwargs)
     self._rootIndex = QModelIndex()
     self._artists = SortedDict()
Example #4
0
class LibraryModel(QAbstractItemModel):

    toggleRow = pyqtSignal(int, QModelIndex, bool)

    def __init__(self, *args, **kwargs):
        QAbstractItemModel.__init__(self, *args, **kwargs)
        self._rootIndex = QModelIndex()
        self._artists = SortedDict()

    def columnCount(self, parent=QModelIndex()):
        return 1

    def rowCount(self, parent=QModelIndex()):
        parentItem = parent.internalPointer()
        if parentItem is None:
            return len(self._artists)

        return len(parentItem._children)

    def data(self, index, role=Qt.DisplayRole):
        if role == Qt.DisplayRole or role == Qt.ToolTipRole:
            item = index.internalPointer()
            return item.data()

        return None

    def mimeData(self, indexes):
        items = [index.internalPointer().mimeDataDict for index in indexes]
        mimeDataDict = {'source': 'library',
                        'items': items}
        return mimeWrapJson(mimeDataDict)

    def flags(self, index):
        item = index.internalPointer()
        if isinstance(item, TrackItem):
            return Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled
        else:
            return Qt.ItemIsSelectable | Qt.ItemIsEnabled

    def parent(self, index):
        item = index.internalPointer()

        parentItem = item.parentItem()

        if parentItem is None:
            return self._rootIndex

        return self.createIndex(parentItem.row(), 0, parentItem)

    def index(self, row, column, parent):
        if not parent.isValid():
            _key,item = self._artists.itemAt(row)
        else:
            parentItem = parent.internalPointer()
            item = parentItem.childAt(row)

        return self.createIndex(row, column, item)

    def headIndex(self):
        return self.index(0, 0, self._rootIndex)

    def getArtist(self, artist):
        albumartistkey = ArtistItem.getKey(artist)

        if albumartistkey in self._artists:
            artistItem = self._artists[albumartistkey]
        else:
            artistItem = ArtistItem(artist)
            artistItem.model = self
            self._artists[albumartistkey] = artistItem

        return albumartistkey, artistItem

    def removeArtist(self, artist):
        artist = ArtistItem.getKey(artist)

        artistItem = self._artists[artist]
        artistItem.model = None
        artistItem.clear()
        del self._artists[artist]

    def loadData(self, libraryData):
        self.beginResetModel()

        # clear library tree
        while self._artists:
            _, artistItem = self._artists.popitem()
            artistItem.clear()

        # fill new
        for hash_, meta in libraryData.iteritems():

            albumartist = meta['albumartist']
            artist = meta['artist']
            album = (meta['year'], meta['album'])
            track = (meta['discnumber'], meta['tracknumber'], meta['trackname'])

            if albumartist != artist:
                track = track + (artist,)
            else:
                track = track + ('',)

            _albumArtistKey, artistItem = self.getArtist(albumartist)

            albumItem = artistItem.getAlbum(album)

            if track not in albumItem._children:
                trackItem = TrackItem(track)
                trackItem.hash = hash_
                trackItem.length = meta['length']
                trackItem._parent = albumItem
                albumItem._children[track] = trackItem

        variousArtist = self._artists.get('')
        if variousArtist is not None:
            # recheck album artists
            for album, albumItem in variousArtist._children.items():
                albumArtists = set(trackItem._data[3]
                                   for track, trackItem in albumItem._children.iteritems())
                if '' in albumArtists:
                    albumArtists.remove('')

                if len(albumArtists) > 1:
                    # album has multiple artists
                    continue

                # album has one artist
                newAlbumArtist = tuple(albumArtists)[0]
                newAlbumItem = self.getArtist(newAlbumArtist)[1].getAlbum(album)

                for track, trackItem in albumItem._children.items():
                    newTrack = track[:-1] + ('',)

                    if newTrack not in newAlbumItem._children:
                        newTrackItem = TrackItem(newTrack)
                        newTrackItem.hash = trackItem.hash
                        newTrackItem.length = trackItem.length
                        newTrackItem._parent = newAlbumItem

                        newAlbumItem._children[newTrack] = newTrackItem

                    albumItem.removeTrack(track)

        # put one-track artists under various
        for artist, artistItem in self._artists.items():
            if artistItem == variousArtist or len(artistItem._children) > 1:
                continue
            album, albumItem = artistItem._children.items()[0]
            if len(albumItem._children) > 1:
                continue

            track, trackItem = albumItem._children.items()[0]
            newTrack = track[:-1] + (artist,)
            newAlbumItem = variousArtist.getAlbum(album)

            if newTrack not in newAlbumItem._children:
                newTrackItem = TrackItem(newTrack)
                newTrackItem.hash = trackItem.hash
                newTrackItem.length = trackItem.length
                newTrackItem._parent = newAlbumItem

                newAlbumItem._children[newTrack] = newTrackItem

            albumItem.removeTrack(track)

        gc.collect()

        self.endResetModel()

    def albumHashes(self, index):
        item = index.internalPointer()
        if not isinstance(item, AlbumItem):
            raise TypeError, 'Suplied index does not point to AlbumItem'

        return item.albumHashes()

    def filter(self, query):
        query = unidecode(query).lower()
        filtered = ((artistKey, albumKey, albumItem, trackItem.row(), trackItem.match(query))
                    for artistKey, artistItem in self._artists.iteritems()
                    for albumKey, albumItem in artistItem._children.iteritems()
                    for trackItem in albumItem._children.itervalues())

        shownArtistKeys, shownAlbumKeys = set(), set()

        parentIndex = None

        for artistKey, albumKey, albumItem, trackRow, isMatch in filtered:
            parentIndex = self.createIndex(albumItem.row(), 0, albumItem)
            self.toggleRow.emit(trackRow, parentIndex, isMatch)

            if isMatch:
                shownArtistKeys.add(artistKey)
                shownAlbumKeys.add(albumKey)
        del parentIndex

        for artistKey, artistItem in self._artists.iteritems():
            if artistKey not in shownArtistKeys:
                # hide artist row
                self.toggleRow.emit(artistItem.row(), self._rootIndex, False)

            else:
                # show artist, filter albums
                self.toggleRow.emit(artistItem.row(), self._rootIndex, True)

                for albumKey, albumItem in artistItem._children.iteritems():
                    parentIndex = self.createIndex(artistItem.row(), 0, artistItem)

                    if albumKey in shownAlbumKeys:
                        self.toggleRow.emit(albumItem.row(), parentIndex, True)
                    else:
                        self.toggleRow.emit(albumItem.row(), parentIndex, False)

    def showAll(self):
        for artistItem in self._artists.itervalues():
            self.toggleRow.emit(artistItem.row(), self._rootIndex, True)
            artistIndex = self.createIndex(artistItem.row(), 0, artistItem)

            for albumItem in artistItem._children.itervalues():
                self.toggleRow.emit(albumItem.row(), artistIndex, True)
                albumIndex = self.createIndex(albumItem.row(), 0, albumItem)

                for trackItem in albumItem._children.itervalues():
                    self.toggleRow.emit(trackItem.row(), albumIndex, True)
Example #5
0
 def __init__(self, data):
     self._children = SortedDict()
     self._data = data
     self._parent = None
Example #6
0
 def __init__(self, *args, **kwargs):
     QAbstractItemModel.__init__(self, *args, **kwargs)
     self._rootIndex = QModelIndex()
     self._artists = SortedDict()
Example #7
0
class LibraryModel(QAbstractItemModel):

    toggleRow = pyqtSignal(int, QModelIndex, bool)

    def __init__(self, *args, **kwargs):
        QAbstractItemModel.__init__(self, *args, **kwargs)
        self._rootIndex = QModelIndex()
        self._artists = SortedDict()

    def columnCount(self, parent=QModelIndex()):
        return 1

    def rowCount(self, parent=QModelIndex()):
        parentItem = parent.internalPointer()
        if parentItem is None:
            return len(self._artists)

        return len(parentItem._children)

    def data(self, index, role=Qt.DisplayRole):
        if role == Qt.DisplayRole or role == Qt.ToolTipRole:
            item = index.internalPointer()
            return item.data()

        return None

    def mimeData(self, indexes):
        mimeDataDicts = [
            index.internalPointer().mimeDataDict() for index in indexes
        ]
        return mimeWrapJson(mimeDataDicts)

    def flags(self, index):
        item = index.internalPointer()
        if isinstance(item, TrackItem):
            return Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled
        else:
            return Qt.ItemIsSelectable | Qt.ItemIsEnabled

    def parent(self, index):
        item = index.internalPointer()

        parentItem = item.parentItem()

        if parentItem is None:
            return self._rootIndex

        return self.createIndex(parentItem.row(), 0, parentItem)

    def index(self, row, column, parent):
        if not parent.isValid():
            _key, item = self._artists.itemAt(row)
        else:
            parentItem = parent.internalPointer()
            item = parentItem.childAt(row)

        return self.createIndex(row, column, item)

    def loadData(self, libraryData):
        self.beginResetModel()

        while self._artists:
            _, artistItem = self._artists.popitem()
            artistItem.clear()

        gc.collect()

        # fill new
        for hash_, meta in libraryData.iteritems():

            albumartist = meta['albumartist']
            album = (meta['year'], meta['album'])
            track = (meta['discnumber'], meta['tracknumber'],
                     meta['trackname'])

            if albumartist != meta['artist']:
                track = track + (meta['artist'], )
            else:
                track = track + ('', )

            albumartistkey = albumartist
            if albumartistkey.lower().startswith('the '):
                albumartistkey = albumartist[4:]

            if albumartistkey in self._artists:
                artistItem = self._artists[albumartistkey]
            else:
                artistItem = ArtistItem(albumartist)
                artistItem.model = self
                self._artists[albumartistkey] = artistItem

            if album in artistItem._children:
                albumItem = artistItem._children[album]
            else:
                albumItem = AlbumItem(album)
                albumItem._parent = artistItem
                artistItem._children[album] = albumItem

            if track not in albumItem._children:
                trackItem = TrackItem(track)
                trackItem.hash = hash_
                trackItem.length = meta['length']
                trackItem._parent = albumItem
                albumItem._children[track] = trackItem

        variousArtist = self._artists.get('')
        if variousArtist is not None:
            # recheck album artists
            for album, albumItem in variousArtist._children.items():
                albumArtists = set(
                    trackItem._data[3]
                    for track, trackItem in albumItem._children.iteritems())
                if '' in albumArtists:
                    albumArtists.remove('')

                if len(albumArtists) == 1:
                    newAlbumArtist = tuple(albumArtists)[0]
                    del variousArtist._children[album]

                    newAlbumArtistKey = newAlbumArtist
                    if newAlbumArtistKey.lower().startswith('the '):
                        newAlbumArtistKey = newAlbumArtistKey[4:]

                    if newAlbumArtistKey in self._artists:
                        artistItem = self._artists[newAlbumArtistKey]
                    else:
                        artistItem = ArtistItem(newAlbumArtist)
                        artistItem.model = self
                        self._artists[newAlbumArtistKey] = artistItem

                    artistItem._children[album] = albumItem
                    albumItem._parent = artistItem

        self.endResetModel()

    def albumHashes(self, index):
        item = index.internalPointer()
        if not isinstance(item, AlbumItem):
            raise TypeError, 'Suplied index does not point to AlbumItem'

        return item.albumHashes()

    def filter(self, query):
        filtered = (
            (artistKey, albumKey, albumItem, trackItem.row(),
             trackItem.match(query))
            for artistKey, artistItem in self._artists.iteritems()
            for albumKey, albumItem in artistItem._children.iteritems()
            for trackItem in albumItem._children.itervalues())

        shownArtistKeys, shownAlbumKeys = set(), set()

        parentIndex = None

        for artistKey, albumKey, albumItem, trackRow, isMatch in filtered:
            parentIndex = self.createIndex(albumItem.row(), 0, albumItem)
            self.toggleRow.emit(trackRow, parentIndex, isMatch)

            if isMatch:
                shownArtistKeys.add(artistKey)
                shownAlbumKeys.add(albumKey)
        del parentIndex

        for artistKey, artistItem in self._artists.iteritems():
            if artistKey not in shownArtistKeys:
                # hide artist row
                self.toggleRow.emit(artistItem.row(), self._rootIndex, False)

            else:
                # show artist, filter albums
                self.toggleRow.emit(artistItem.row(), self._rootIndex, True)

                for albumKey, albumItem in artistItem._children.iteritems():
                    parentIndex = self.createIndex(artistItem.row(), 0,
                                                   artistItem)

                    if albumKey in shownAlbumKeys:
                        self.toggleRow.emit(albumItem.row(), parentIndex, True)
                    else:
                        self.toggleRow.emit(albumItem.row(), parentIndex,
                                            False)

    def showAll(self):
        for artistItem in self._artists.itervalues():
            self.toggleRow.emit(artistItem.row(), self._rootIndex, True)
            artistIndex = self.createIndex(artistItem.row(), 0, artistItem)

            for albumItem in artistItem._children.itervalues():
                self.toggleRow.emit(albumItem.row(), artistIndex, True)
                albumIndex = self.createIndex(albumItem.row(), 0, albumItem)

                for trackItem in albumItem._children.itervalues():
                    self.toggleRow.emit(trackItem.row(), albumIndex, True)
Example #8
0
 def __init__(self, data):
     self._children = SortedDict()
     self._data = data
     self._parent = None