Fix deletion of Plex music items

- Fixes #336
This commit is contained in:
Croneter 2018-04-12 18:52:37 +02:00
parent 8f30a466ff
commit 0f1e2e7dec
2 changed files with 184 additions and 55 deletions

View file

@ -1719,6 +1719,7 @@ class Music(Items):
# Update album artwork # Update album artwork
artwork.modify_artwork(artworks, albumid, v.KODI_TYPE_ALBUM, kodicursor) artwork.modify_artwork(artworks, albumid, v.KODI_TYPE_ALBUM, kodicursor)
@catch_exceptions(warnuser=True)
def remove(self, plex_id): def remove(self, plex_id):
""" """
Completely remove the item with plex_id from the Kodi and Plex DBs. Completely remove the item with plex_id from the Kodi and Plex DBs.
@ -1728,92 +1729,124 @@ class Music(Items):
try: try:
kodi_id = plex_dbitem[0] kodi_id = plex_dbitem[0]
file_id = plex_dbitem[1] file_id = plex_dbitem[1]
path_id = plex_dbitem[2]
parent_id = plex_dbitem[3] parent_id = plex_dbitem[3]
kodi_type = plex_dbitem[4] kodi_type = plex_dbitem[4]
LOG.info("Removing %s with kodi_id: %s, parent_id: %s, file_id: %s", LOG.info('Removing plex_id %s with kodi_type %s, kodi_id %s, '
kodi_type, kodi_id, parent_id, file_id) 'parent_id %s, file_id %s, pathid %s',
plex_id, kodi_type, kodi_id, parent_id, file_id, path_id)
except TypeError: except TypeError:
LOG.debug('Cannot delete item with plex id %s from Kodi', plex_id) LOG.debug('Cannot delete item with plex id %s from Kodi', plex_id)
return return
# Remove the plex reference # Remove the plex reference
self.plex_db.removeItem(plex_id) self.plex_db.removeItem(plex_id)
##### SONG ##### ##### SONG #####
if kodi_type == v.KODI_TYPE_SONG: if kodi_type == v.KODI_TYPE_SONG:
# Delete song # Delete song and orphaned artists and albums
self.remove_song(kodi_id) self._remove_song(kodi_id, path_id=path_id)
# Album verification # Album verification
album = self.plex_db.getItem_byKodiId(parent_id,
for item in self.plex_db.getItem_byWildId(plex_id): v.KODI_TYPE_ALBUM)
if not self.plex_db.getItem_byParentId(parent_id,
item_kid = item[0] v.KODI_TYPE_SONG):
item_kodi_type = item[1] # No song left for album - so delete the album
self.plex_db.removeItem(album[0])
if item_kodi_type == v.KODI_TYPE_ALBUM: self._remove_album(parent_id)
childs = self.plex_db.getItem_byParentId(item_kid,
v.KODI_TYPE_SONG)
if not childs:
# Delete album
self.remove_album(item_kid)
##### ALBUM ##### ##### ALBUM #####
elif kodi_type == v.KODI_TYPE_ALBUM: elif kodi_type == v.KODI_TYPE_ALBUM:
# Delete songs, album # Delete songs, album
album_songs = self.plex_db.getItem_byParentId(kodi_id, songs = self.plex_db.getItem_byParentId(kodi_id,
v.KODI_TYPE_SONG) v.KODI_TYPE_SONG)
for song in album_songs: for song in songs:
self.remove_song(song[1]) self._remove_song(song[1], path_id=song[2])
# Remove plex songs # Remove songs from Plex table
self.plex_db.removeItems_byParentId(kodi_id, self.plex_db.removeItems_byParentId(kodi_id,
v.KODI_TYPE_SONG) v.KODI_TYPE_SONG)
# Remove the album # Remove the album and associated orphaned entries
self.remove_album(kodi_id) self._remove_album(kodi_id)
##### IF ARTIST ##### ##### IF ARTIST #####
elif kodi_type == v.KODI_TYPE_ARTIST: elif kodi_type == v.KODI_TYPE_ARTIST:
# Delete songs, album, artist # Delete songs, album, artist
albums = self.plex_db.getItem_byParentId(kodi_id, v.KODI_TYPE_ALBUM) albums = self.plex_db.getItem_byParentId(kodi_id, v.KODI_TYPE_ALBUM)
for album in albums: for album in albums:
albumid = album[1] songs = self.plex_db.getItem_byParentId(album[1],
album_songs = self.plex_db.getItem_byParentId(albumid,
v.KODI_TYPE_SONG) v.KODI_TYPE_SONG)
for song in album_songs: for song in songs:
self.remove_song(song[1]) self._remove_song(song[1], path_id=song[2])
# Remove plex song # Remove entries for the songs in the Plex db
self.plex_db.removeItems_byParentId(albumid, v.KODI_TYPE_SONG) self.plex_db.removeItems_byParentId(album[1], v.KODI_TYPE_SONG)
# Remove plex artist
self.plex_db.removeItems_byParentId(albumid, v.KODI_TYPE_ARTIST)
# Remove kodi album # Remove kodi album
self.remove_album(albumid) self._remove_album(album[1])
# Remove plex albums # Remove album entries in the Plex db
self.plex_db.removeItems_byParentId(kodi_id, v.KODI_TYPE_ALBUM) self.plex_db.removeItems_byParentId(kodi_id, v.KODI_TYPE_ALBUM)
# Remove artist # Remove artist
self.remove_artist(kodi_id) self._remove_artist(kodi_id)
LOG.debug("Deleted plex_id %s from kodi database", plex_id) LOG.debug("Deleted plex_id %s from kodi database", plex_id)
def remove_song(self, kodi_id): def _remove_song(self, kodi_id, path_id=None):
""" """
Remove song, and only the song Remove song, orphaned artists and orphaned paths
""" """
if not path_id:
query = 'SELECT idPath FROM song WHERE idSong = ? LIMIT 1'
self.kodicursor.execute(query, (kodi_id, ))
try:
path_id = self.kodicursor.fetchone()[0]
except TypeError:
pass
artist_to_delete = self.kodi_db.delete_song_from_song_artist(kodi_id)
if artist_to_delete:
# Delete the artist reference in the Plex table
artist = self.plex_db.getItem_byKodiId(artist_to_delete,
v.KODI_TYPE_ARTIST)
try:
plex_id = artist[0]
except TypeError:
pass
else:
self.plex_db.removeItem(plex_id)
self._remove_artist(artist_to_delete)
self.kodicursor.execute('DELETE FROM song WHERE idSong = ?',
(kodi_id, ))
# Check whether we have orphaned path entries
query = 'SELECT idPath FROM song WHERE idPath = ? LIMIT 1'
self.kodicursor.execute(query, (path_id, ))
if not self.kodicursor.fetchone():
self.kodicursor.execute('DELETE FROM path WHERE idPath = ?',
(path_id, ))
if v.KODIVERSION < 18:
self.kodi_db.delete_song_from_song_genre(kodi_id)
query = 'DELETE FROM albuminfosong WHERE idAlbumInfoSong = ?'
self.kodicursor.execute(query, (kodi_id, ))
self.artwork.delete_artwork(kodi_id, v.KODI_TYPE_SONG, self.kodicursor) self.artwork.delete_artwork(kodi_id, v.KODI_TYPE_SONG, self.kodicursor)
self.kodicursor.execute("DELETE FROM song WHERE idSong = ?",
(kodi_id,))
def remove_album(self, kodi_id): def _remove_album(self, kodi_id):
""" '''
Remove an album, and only the album Remove an album
""" '''
self.kodi_db.delete_album_from_discography(kodi_id)
if v.KODIVERSION < 18:
self.kodi_db.delete_album_from_album_genre(kodi_id)
query = 'DELETE FROM albuminfosong WHERE idAlbumInfo = ?'
self.kodicursor.execute(query, (kodi_id, ))
self.kodicursor.execute('DELETE FROM album_artist WHERE idAlbum = ?',
(kodi_id, ))
self.kodicursor.execute('DELETE FROM album WHERE idAlbum = ?',
(kodi_id, ))
self.artwork.delete_artwork(kodi_id, v.KODI_TYPE_ALBUM, self.kodicursor) self.artwork.delete_artwork(kodi_id, v.KODI_TYPE_ALBUM, self.kodicursor)
self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?",
(kodi_id,))
def remove_artist(self, kodi_id): def _remove_artist(self, kodi_id):
""" '''
Remove an artist, and only the artist Remove an artist and associated songs and albums
""" '''
self.kodicursor.execute('DELETE FROM album_artist WHERE idArtist = ?',
(kodi_id, ))
self.kodicursor.execute('DELETE FROM artist WHERE idArtist = ?',
(kodi_id, ))
self.kodicursor.execute('DELETE FROM song_artist WHERE idArtist = ?',
(kodi_id, ))
self.kodicursor.execute('DELETE FROM discography WHERE idArtist = ?',
(kodi_id, ))
self.artwork.delete_artwork(kodi_id, self.artwork.delete_artwork(kodi_id,
v.KODI_TYPE_ARTIST, v.KODI_TYPE_ARTIST,
self.kodicursor) self.kodicursor)
self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?",
(kodi_id,))

View file

@ -907,6 +907,102 @@ class KodiDBMethods(object):
self.cursor.execute(query, (name, artistid,)) self.cursor.execute(query, (name, artistid,))
return artistid return artistid
def delete_song_from_song_artist(self, song_id):
"""
Deletes son from song_artist table and possibly orphaned roles
Will returned an orphaned idArtist or None if not orphaned
"""
query = '''
SELECT idArtist, idRole FROM song_artist WHERE idSong = ? LIMIT 1
'''
self.cursor.execute(query, (song_id, ))
artist = self.cursor.fetchone()
if artist is None:
# No entry to begin with
return
# Delete the entry
self.cursor.execute('DELETE FROM song_artist WHERE idSong = ?',
(song_id, ))
# Check whether we need to delete orphaned roles
query = 'SELECT idRole FROM song_artist WHERE idRole = ? LIMIT 1'
self.cursor.execute(query, (artist[1], ))
if not self.cursor.fetchone():
# Delete orphaned role
self.cursor.execute('DELETE FROM role WHERE idRole = ?',
(artist[1], ))
# Check whether we need to delete orphaned artists
query = 'SELECT idArtist FROM song_artist WHERE idArtist = ? LIMIT 1'
self.cursor.execute(query, (artist[0], ))
if self.cursor.fetchone():
return
else:
return artist[0]
def delete_album_from_discography(self, album_id):
"""
Removes the album with id album_id from the table discography
"""
# Need to get the album name as a string first!
query = 'SELECT strAlbum, iYear FROM album WHERE idAlbum = ? LIMIT 1'
self.cursor.execute(query, (album_id, ))
try:
name, year = self.cursor.fetchone()
except TypeError:
return
query = 'SELECT idArtist FROM album_artist WHERE idAlbum = ? LIMIT 1'
self.cursor.execute(query, (album_id, ))
artist = self.cursor.fetchone()
if not artist:
return
query = '''
DELETE FROM discography
WHERE idArtist = ?, strAlbum = ?, strYear = ?
'''
self.cursor.execute(query, (artist[0], name, year))
def delete_song_from_song_genre(self, song_id):
"""
Deletes the one entry with id song_id from the song_genre table.
Will also delete orphaned genres from genre table
"""
query = 'SELECT idGenre FROM song_genre WHERE idSong = ?'
self.cursor.execute(query, (song_id, ))
genres = self.cursor.fetchall()
self.cursor.execute('DELETE FROM song_genre WHERE idSong = ?',
(song_id, ))
# Check for orphaned genres in both song_genre and album_genre tables
query = 'SELECT idGenre FROM song_genre WHERE idGenre = ? LIMIT 1'
query2 = 'SELECT idGenre FROM album_genre WHERE idGenre = ? LIMIT 1'
for genre in genres:
self.cursor.execute(query, (genre[0], ))
if not self.cursor.fetchone():
self.cursor.execute(query2, (genre[0], ))
if not self.cursor.fetchone():
self.cursor.execute('DELETE FROM genre WHERE idGenre = ?',
(genre[0], ))
def delete_album_from_album_genre(self, album_id):
"""
Deletes the one entry with id album_id from the album_genre table.
Will also delete orphaned genres from genre table
"""
query = 'SELECT idGenre FROM album_genre WHERE idAlbum = ?'
self.cursor.execute(query, (album_id, ))
genres = self.cursor.fetchall()
self.cursor.execute('DELETE FROM album_genre WHERE idAlbum = ?',
(album_id, ))
# Check for orphaned genres in both album_genre and song_genre tables
query = 'SELECT idGenre FROM album_genre WHERE idGenre = ? LIMIT 1'
query2 = 'SELECT idGenre FROM song_genre WHERE idGenre = ? LIMIT 1'
for genre in genres:
self.cursor.execute(query, (genre[0], ))
if not self.cursor.fetchone():
self.cursor.execute(query2, (genre[0], ))
if not self.cursor.fetchone():
self.cursor.execute('DELETE FROM genre WHERE idGenre = ?',
(genre[0], ))
def addAlbum(self, name, musicbrainz): def addAlbum(self, name, musicbrainz):
query = 'SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?' query = 'SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?'
self.cursor.execute(query, (musicbrainz,)) self.cursor.execute(query, (musicbrainz,))