| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- import time
- from collections import deque
- from queue import Queue
- from threading import Thread, Lock
- import vlc
- from path import Path
- from core.exceptions import NotSupportedFile
- from core.file_utilities import is_media_file_ext, hash_file
- from core.logging_ import Logger
- from core.models import Track
- from core.repositories import MusicFolderRepository, TrackRepository
- logger = Logger.get()
- class CyclicThread(Thread):
- DELAY = 0
- def __init__(self):
- Thread.__init__(self)
- self.interrupted = False
- self.last_exec = 0
- def act(self):
- raise NotImplementedError()
- def run(self):
- t = None
- while 1:
- if self.DELAY:
- t = time.time()
- if not self.DELAY or not self.last_exec or (t - self.last_exec) > self.DELAY:
- self.act()
- self.last_exec = t
- if self.interrupted:
- break
- def trigger(self):
- self.last_exec = 0
- def stop(self):
- self.interrupted = True
- class Discoverer(CyclicThread):
- DELAY = 5
- def __init__(self, indexer):
- CyclicThread.__init__(self)
- self.indexer = indexer
- def act(self):
- music_folder_repo = MusicFolderRepository()
- track_repo = TrackRepository()
- index = {t.path: t for t in track_repo.get_all()}
- for music_folder in music_folder_repo.get_all():
- music_folder_path = Path(music_folder.path)
- for filename in music_folder_path.walkfiles():
- if self.indexer.in_deque(filename):
- continue
- if filename not in index and is_media_file_ext(filename.ext):
- self.indexer.put(filename)
- elif filename in index:
- track = index[filename]
- if track.status == Track.STATUS_UNAVAILABLE:
- self.indexer.put(track.id)
- del index[filename]
- for filename, track in index.items():
- if self.indexer.in_deque(track.id):
- continue
- filename = Path(filename)
- if not filename.exists():
- self.indexer.put(track.id)
- class Indexer(CyclicThread):
- def __init__(self):
- CyclicThread.__init__(self)
- self.deque = deque()
- self.interrupted = False
- self.discoverer = Discoverer(self)
- def start(self):
- logger.info('** indexation thread started **')
- self.discoverer.start()
- super().start()
- def act(self):
- if self.deque:
- try:
- self.index(self.deque.pop())
- except (FileNotFoundError, NotSupportedFile) as e:
- logger.warning("Error during indexation: %s" % e)
- def put(self, filename_or_track_id):
- self.deque.appendleft(filename_or_track_id)
- def in_deque(self, filename_or_track_id):
- return filename_or_track_id in self.deque
- @staticmethod
- def index(filename_or_track_id):
- """ index a media file from the filesystem or a track id """
- track_repo = TrackRepository()
- if type(filename_or_track_id) is int:
- track = track_repo.get_by_id(filename_or_track_id)
- filename = Path(track.path)
- track_hash = track.hash
- if not filename.exists():
- logger.debug('Index - missing: %s' % filename)
- track.status = Track.STATUS_UNAVAILABLE
- track_repo.commit()
- return
- else:
- filename = Path(filename_or_track_id)
- if not filename.exists():
- raise FileNotFoundError(f"File not found: {filename}")
- if not is_media_file_ext(filename.ext):
- raise NotSupportedFile(f"File's extension {filename.ext} is not supported")
- track_hash = hash_file(filename)
- track = track_repo.get_by_hash(track_hash)
- if not track:
- track = Track()
- vlc_media = vlc.Media(filename)
- vlc_media.parse()
- track_infos = vlc_media.get_tracks_info()
- track.title = vlc_media.get_meta(vlc.Meta.Title) or filename.stripext().name
- track.format = filename.ext
- track.artist = vlc_media.get_meta(vlc.Meta.AlbumArtist) or vlc_media.get_meta(vlc.Meta.Artist)
- track.album = vlc_media.get_meta(vlc.Meta.Album)
- track.track_num = vlc_media.get_meta(vlc.Meta.TrackNumber)
- # track.year = vlc_media.get_meta(vlc.Meta.Date)
- # track.duration = vlc_media.get_meta(vlc.Meta.Date)
- # track.size = 0
- track.note = ""
- track.status = Track.STATUS_FOUND
- track.path = filename
- track.hash = track_hash
- if track.id is None:
- track_repo.create(track)
- logger.debug('Index - updated: %s' % filename)
- track_repo.commit()
- def stop(self):
- self.discoverer.stop()
- super().stop()
- logger.info('** indexation thread stopped **')
- if __name__ == '__main__':
- indexer = Indexer()
- indexer.start()
- try:
- indexer.join()
- except KeyboardInterrupt:
- indexer.stop()
|