Use file size and last modification time to compare Kodi playlist files instead of slow MD5 hash of file

This commit is contained in:
croneter 2019-08-01 13:56:50 +02:00
parent 92a7fa7c7a
commit 26fa1ff909
4 changed files with 26 additions and 25 deletions

View file

@ -14,7 +14,8 @@
from __future__ import absolute_import, division, unicode_literals
from logging import getLogger
from .common import Playlist, PlaylistError, PlaylistObserver
from .common import Playlist, PlaylistError, PlaylistObserver, \
kodi_playlist_hash
from . import pms, db, kodi_pl, plex_pl
from ..watchdog import events
@ -221,7 +222,7 @@ def _full_sync():
pass
if not sync_kodi_playlist(path):
continue
kodi_hash = utils.generate_file_md5(path)
kodi_hash = kodi_playlist_hash(path)
playlist = db.get_playlist(path=path)
if playlist and playlist.kodi_hash == kodi_hash:
continue
@ -387,7 +388,7 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
def on_created(self, event):
LOG.debug('on_created: %s', event.src_path)
old_playlist = db.get_playlist(path=event.src_path)
kodi_hash = utils.generate_file_md5(event.src_path)
kodi_hash = kodi_playlist_hash(event.src_path)
if old_playlist and old_playlist.kodi_hash == kodi_hash:
LOG.debug('Playlist already in DB - skipping')
return
@ -406,7 +407,7 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
def on_modified(self, event):
LOG.debug('on_modified: %s', event.src_path)
old_playlist = db.get_playlist(path=event.src_path)
kodi_hash = utils.generate_file_md5(event.src_path)
kodi_hash = kodi_playlist_hash(event.src_path)
if old_playlist and old_playlist.kodi_hash == kodi_hash:
LOG.debug('Nothing modified, playlist already in DB - skipping')
return
@ -425,7 +426,7 @@ class PlaylistEventhandler(events.FileSystemEventHandler):
def on_moved(self, event):
LOG.debug('on_moved: %s to %s', event.src_path, event.dest_path)
kodi_hash = utils.generate_file_md5(event.dest_path)
kodi_hash = kodi_playlist_hash(event.dest_path)
# First check whether we don't already have destination playlist in
# our DB. Just in case....
old_playlist = db.get_playlist(path=event.dest_path)

View file

@ -4,6 +4,8 @@ from __future__ import absolute_import, division, unicode_literals
from logging import getLogger
import Queue
import time
import os
import hashlib
from ..watchdog import events
from ..watchdog.observers import Observer
@ -121,6 +123,22 @@ class Playlist(object):
self._kodi_path = path
def kodi_playlist_hash(path):
"""
Returns a md5 hash [unicode] using os.stat() st_size and st_mtime for the
playlist located at path [unicode]
(size of file in bytes and time of most recent content modification)
There are probably way more efficient ways out there to do this
"""
stat = os.stat(path_ops.encode_path(path))
# stat.st_size is of type long; stat.st_mtime is of type float - hash both
m = hashlib.md5()
m.update(repr(stat.st_size))
m.update(repr(stat.st_mtime))
return m.hexdigest().decode('utf-8')
class PlaylistQueue(OrderedSetQueue):
"""
OrderedSetQueue that drops all directory events immediately

View file

@ -7,7 +7,7 @@ from __future__ import absolute_import, division, unicode_literals
from logging import getLogger
import re
from .common import Playlist, PlaylistError
from .common import Playlist, PlaylistError, kodi_playlist_hash
from . import db, pms
from ..plex_api import API
@ -71,7 +71,7 @@ def create(plex_id):
except Exception:
IGNORE_KODI_PLAYLIST_CHANGE.remove(playlist.kodi_path)
raise
playlist.kodi_hash = utils.generate_file_md5(path)
playlist.kodi_hash = kodi_playlist_hash(path)
db.update_playlist(playlist)
LOG.debug('Created Kodi playlist based on Plex playlist: %s', playlist)

View file

@ -17,7 +17,6 @@ import xml.etree.ElementTree as etree
from . import defused_etree
from xml.etree.ElementTree import ParseError
from functools import wraps
import hashlib
import re
import gc
try:
@ -931,23 +930,6 @@ class XmlKodiSetting(object):
return element
def generate_file_md5(path):
"""
Generates the md5 hash value for the file located at path [unicode].
The hash does not include the path and filename and is thus identical for
a file that was moved/changed name.
Returns a unique unicode containing only hexadecimal digits
"""
m = hashlib.md5()
with open(path_ops.encode_path(path), 'rb') as f:
while True:
piece = f.read(32768)
if not piece:
break
m.update(piece)
return m.hexdigest().decode('utf-8')
def process_method_on_list(method_to_run, items):
"""
helper method that processes a method on each item with pooling if the