indexer.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import time
  2. import vlc
  3. from path import Path
  4. from core.exceptions import NotSupportedFile
  5. from core.file_utilities import is_media_file_ext, hash_file
  6. from core.logging_ import Logger
  7. from core.models import Track
  8. from core.repositories import MusicFolderRepository, TrackRepository
  9. logger = Logger.get()
  10. class Indexation:
  11. def __init__(self):
  12. self.started = False
  13. self.music_folder_repo = MusicFolderRepository()
  14. self.track_repo = TrackRepository()
  15. self.music_folders = []
  16. self.index = {}
  17. self.processed = set()
  18. self.t0 = time.time()
  19. def index_file(self, music_folder, filename, force_update=False):
  20. filename = Path(filename)
  21. if not filename.exists():
  22. raise FileNotFoundError(f"File not found: {filename}")
  23. if not is_media_file_ext(filename.ext):
  24. raise NotSupportedFile(f"File's extension {filename.ext} is not supported")
  25. vlc_media = vlc.Media(filename)
  26. vlc_media.parse()
  27. track_infos = vlc_media.get_tracks_info()
  28. track_hash = hash_file(filename)
  29. if track_hash in self.processed:
  30. print(" ... file already indexed, ignore: ", filename)
  31. return
  32. if self.index and track_hash in self.index:
  33. track = self.index[track_hash]
  34. else:
  35. track = next(iter(self.track_repo.get_by('hash', track_hash)), None) or Track()
  36. if track.id and not force_update:
  37. return track
  38. track.profile_id = 0
  39. track.music_folder_id = music_folder.id
  40. track.title = vlc_media.get_meta(vlc.Meta.Title) or filename.stripext().name
  41. track.format = filename.ext
  42. track.artist = vlc_media.get_meta(vlc.Meta.AlbumArtist) or vlc_media.get_meta(vlc.Meta.Artist)
  43. track.album = vlc_media.get_meta(vlc.Meta.Album)
  44. track.track_num = vlc_media.get_meta(vlc.Meta.TrackNumber)
  45. # track.year = vlc_media.get_meta(vlc.Meta.Date)
  46. # track.duration = vlc_media.get_meta(vlc.Meta.Date)
  47. # track.size = 0
  48. track.note = ""
  49. track.status = Track.STATUS_FOUND
  50. track.path = filename
  51. track.hash = track_hash
  52. if track.id is not None:
  53. logger.debug('Index - update: %s' % filename)
  54. else:
  55. self.track_repo.create(track)
  56. logger.debug('Index - create: %s' % filename)
  57. self.track_repo.commit()
  58. return track
  59. def index_all(self, filter_music_folder_id=None, force_update=False):
  60. self.index = {t.hash: t for t in self.track_repo.get_all()}
  61. self.processed = set()
  62. self.t0 = time.time()
  63. self.started = True
  64. if filter_music_folder_id:
  65. music_folders = [self.music_folder_repo.get_by_id(filter_music_folder_id)]
  66. else:
  67. music_folders = self.music_folder_repo.get_all()
  68. # add and update tracks
  69. for music_folder in music_folders:
  70. music_folder_path = Path(music_folder.path)
  71. for filename in music_folder_path.walkfiles():
  72. if not is_media_file_ext(filename.ext):
  73. continue
  74. track = self.index_file(music_folder, filename, force_update=force_update)
  75. self.processed.add(track.hash)
  76. # mark missings
  77. for hash_, track in self.index.items():
  78. if hash_ in self.processed:
  79. continue
  80. track.status = Track.STATUS_UNAVAILABLE
  81. self.track_repo.commit()
  82. logger.debug('Index - marked as unavailable: %s' % track.path)
  83. class Indexer:
  84. @staticmethod
  85. def index_file(music_folder, path, force_update=False):
  86. indexation = Indexation()
  87. indexation.index_file(music_folder, path, force_update=force_update)
  88. @staticmethod
  89. def index_folder(music_folder, force_update=False):
  90. logger.debug('** Start indexation on folder %s' % music_folder.id)
  91. indexation = Indexation()
  92. indexation.index_all(filter_music_folder_id=music_folder.id, force_update=force_update)
  93. @staticmethod
  94. def index_all(force_update=False, started_call=None, ended_call=None):
  95. if started_call is not None:
  96. started_call()
  97. logger.debug('** Start complete indexation')
  98. indexation = Indexation()
  99. indexation.index_all(force_update=force_update)
  100. logger.debug('** Complete indexation ended')
  101. if ended_call is not None:
  102. ended_call()
  103. if __name__ == '__main__':
  104. Indexer.index_all()