class Validator(ProcessorBase): def __init__(self, config, dbConn, dbSession, readOnly): self.readOnly = readOnly or False self.logger = Logger() self.conn = dbConn self.session = dbSession super().__init__(config, self.logger) def validateArtists(self): for artist in self.session.query(Artist).all(): self.validate(artist) def validate(self, artist, onlyValidateRelease=None): """ Do sanity checks on given Artist :param onlyValidateRelease: Release :param artist: Artist :return: """ if not artist: raise RuntimeError("Invalid Artist") if not self.config: raise RuntimeError("Invalid Configuration") if not self.libraryFolder: raise RuntimeError("Invalid Configuration: Library Folder Not Set") now = arrow.utcnow().datetime self.logger.info("Validating Artist [" + artist.name + "] Release Set [" + str( onlyValidateRelease is None) + "]") try: for release in artist.releases: issuesFound = False if onlyValidateRelease and release.roadieId != onlyValidateRelease.roadieId: continue releaseFolder = self.albumFolder(artist, release.releaseDate.strftime('%Y'), release.title) try: folderExists = os.path.exists(releaseFolder) except: folderExists = False if not folderExists: if not self.readOnly: for media in release.media: for track in media.tracks: locatedTrackInfo = self.tryToFindFileForTrack(artist, track) trackFullPath = track.fullPath() if locatedTrackInfo and trackFullPath and not os.path.exists(trackFullPath): movedFile = self.moveToLibrary(artist, locatedTrackInfo['id3'], locatedTrackInfo['fileName']) if movedFile: self.logger.warn( "! Moved File From [" + locatedTrackInfo[ 'fileName'] + "] To [" + movedFile + "]") folderExists = True else: track.filePath = None track.fileName = None track.fileSize = 0 track.hash = None track.lastUpdated = now if not folderExists: release.libraryStatus = 'Incomplete' self.logger.warn( "X Marking Release Missing [" + str( release) + "] Missing Folder [" + releaseFolder + "] Not Found") continue releaseTrackCount = 0 # If release is not already complete, set to complete unless its found otherwise release.libraryStatus = 'Complete' releaseMediaWithTracks = [] for releaseMedia in release.media: releaseMediaTrackCount = 0 for track in sorted(releaseMedia.tracks, key=lambda tt: tt.trackNumber): try: trackFilename = self.pathToTrack(track) isTrackFilePresent = False if trackFilename: try: isTrackFilePresent = os.path.isfile(trackFilename) except: self.logger.exception() pass if not isTrackFilePresent: # See if track exists in another folder and title was renamed so folder no longer # matches what it is expected to be if not self.readOnly: locatedTrackInfo = self.tryToFindFileForTrack(artist, track) if locatedTrackInfo and not isEqual(trackFilename, locatedTrackInfo['fileName']): movedFile = self.moveToLibrary(artist, locatedTrackInfo['id3'], locatedTrackInfo['fileName']) if movedFile: head, tail = os.path.split(movedFile) headNoLibrary = head.replace(self.config['ROADIE_LIBRARY_FOLDER'], "") trackHash = self.makeTrackHash(artist.roadieId, movedFile) track.fileName = tail track.filePath = headNoLibrary track.hash = trackHash track.fileSize = os.path.getsize(movedFile) track.lastUpdated = now self.logger.warn( "! Located Track [" + str(track.info(includePathInfo=True)) + "]") isTrackFilePresent = True else: track.filePath = None track.fileName = None track.fileSize = 0 track.hash = None track.lastUpdated = now self.logger.warn( "X Missing Track [" + str( track.info(includePathInfo=True)) + "] File [" + str( trackFilename) + "]") issuesFound = True release.libraryStatus = 'Incomplete' if isTrackFilePresent: releaseMediaTrackCount += 1 releaseTrackCount += 1 if not isEqual(track.trackNumber, releaseMediaTrackCount): self.logger.warn("! Track Number Sequence Incorrect Is [" + str(track.trackNumber) + "] Expected [" + str(releaseMediaTrackCount) + "]") release.libraryStatus = 'Incomplete' issuesFound = True except: self.logger.exception() issuesFound = True pass releaseMedia.trackCount = releaseMediaTrackCount if releaseMedia.trackCount > 0: releaseMediaWithTracks.append(releaseMedia) if not self.readOnly: release.media = releaseMediaWithTracks release.mediaCount = len(releaseMediaWithTracks) # Seems not likely that a release only has a single track; more likely missing unknown tracks if releaseTrackCount > 1 and release.trackCount < 2: release.trackCount = releaseTrackCount release.lastUpdated = now self.logger.info("Validated Artist [" + str(artist) + "], " + "Release [" + str(release) + "], " + "IssuesFound [" + str(issuesFound) + "]") if not self.readOnly: self.session.commit() else: self.session.rollback() except: self.logger.exception("Validating Artist, Rolling Back Session Transactions") try: self.session.rollback() except: pass
class CollectionImporter(ProcessorBase): format = None positions = None filename = None collectionId = None collection = None def __init__(self, dbConn, dbSession, readOnly): self.logger = Logger() self.dbConn = dbConn self.dbSession = dbSession self.artistFactory = ArtistFactory(dbConn, dbSession) self.releaseFactory = ReleaseFactory(dbConn, dbSession) self.notFoundEntryInfo = [] self.readOnly = readOnly def _findColumns(self): self.position = -1 self.release = -1 self.artist = -1 for i, position in enumerate(self.positions): if position.lower() == "position": self.position = i elif position.lower() == "release" or position.lower() == "album": self.release = i elif position.lower() == "artist": self.artist = i if self.position < 0 or self.release < 0 or self.artist < 0: self.logger.critical("Unable To Find Required Positions") return False return True def importFile(self, collectionId, fileFormat, filename): self.collectionId = collectionId self.collection = self.dbSession.query(Collection).filter(Collection.id == collectionId).first() self.format = fileFormat self.positions = self.format.split(',') self.filename = filename if not os.path.exists(self.filename): self.logger.critical("Unable to Find CSV File [" + self.filename + "]") else: self.logger.debug("Importing [" + self.filename + "]") return self.importCsvData(open(self.filename)) def importCollection(self, collection): self.collectionId = collection.id self.collection = collection self.positions = collection.listInCSVFormat.split(',') self.importCsvData(io.StringIO(collection.listInCSV)) def importCsvData(self, csvData): try: if not self.collection: self.logger.critical("Unable to Find Collection Id [" + self.collectionId + "]") return False self._findColumns() reader = csv.reader(csvData) self.collection.collectionReleases = [] for row in reader: csvPosition = int(row[self.position].strip()) csvArtist = row[self.artist].strip() csvRelease = row[self.release].strip() artist = self.artistFactory.get(csvArtist, False) if not artist: self.logger.warn(("Artist [" + csvArtist + "] Not Found In Database").encode('utf-8')) self.notFoundEntryInfo.append( {'col': self.collection.name, 'position': csvPosition, 'artist': csvArtist, 'release': csvRelease}); continue release = self.releaseFactory.get(artist, csvRelease, False) if not release: self.logger.warn( ("Not able to find Release [" + csvRelease + "], Artist [" + csvArtist + "]").encode( 'utf-8')) self.notFoundEntryInfo.append( {'col': self.collection.name, 'position': csvPosition, 'artist': csvArtist, 'release': csvRelease}) continue colRelease = CollectionRelease() colRelease.releaseId = release.id colRelease.listNumber = csvPosition colRelease.createdDate = arrow.utcnow().datetime colRelease.roadieId = str(uuid.uuid4()) self.collection.collectionReleases.append(colRelease) self.logger.info( "Added Position [" + str(csvPosition) + "] Release [" + str(release) + "] To Collection") self.collection.lastUpdated = arrow.utcnow().datetime self.dbSession.commit() return True except: self.logger.exception("Error Importing Collection [" + self.collection.name + "]") self.dbSession.rollback() return False