예제 #1
0
파일: ratestats.py 프로젝트: nwrobel/mlYou
def updateRatingTag(audioFilepath):
    '''
    If needed, updates the rating tag value for an audio file by calculating the average of all the existing
    vote values in the file's 'votes' tag. Returns true if an update was needed and performed (rating
    corrected).
    '''
    tagHandler = mlu.tags.io.AudioFileTagIOHandler(audioFilepath)
    currentTags = tagHandler.getTags()

    votesCurrent = mlu.tags.common.formatAudioTagToValuesList(
        currentTags.votes, valuesAs='float')
    ratingCurrent = currentTags.rating
    ratingUpdated = _calculateRatingTagValue(votesCurrent)

    wasUpdated = False
    if (ratingCurrent != ratingUpdated):
        newTags = currentTags
        newTags.rating = ratingUpdated
        tagHandler.setTags(newTags)

        logger.info(
            "Rating tag updated with new value: File={}, OldRating={}, NewRating={}"
            .format(audioFilepath, ratingCurrent, ratingUpdated))
        wasUpdated = True

    else:
        logger.debug(
            "Rating tag not updated, no change needed: File={}".format(
                audioFilepath))

    return UpdateRatingTagResult(audioFilepath=audioFilepath,
                                 wasUpdated=wasUpdated,
                                 oldRating=ratingCurrent,
                                 newRating=ratingUpdated)
예제 #2
0
파일: prefbak.py 프로젝트: nwrobel/prefbak
def performBackup(configData):
    '''
    Reads the given backup config file and performs each backup from the definitions.

    Params:
        configFile: the Json prefbak config file
    '''
    backupRules = configData['backupRules']

    for backupRule in backupRules:
        sourcePath = backupRule['sourcePath']
        destinationPath = backupRule['backupDestDir']

        logger.info("Performing backup step for rule: {} -> {}".format(
            sourcePath, destinationPath))
        performBackupStep(sourcePath, destinationPath)

        # Set the permissions on the destination path and the archive file within so that the user can read the backup
        if (not runningWindowsOS):
            logger.info(
                "Updating file permissions for backup destination directory {}"
                .format(destinationPath))
            backupDataPermissions = configData['backupDataPermissions']
            mypycommons.file.applyPermissionToPath(
                path=destinationPath,
                owner=backupDataPermissions['owner'],
                group=backupDataPermissions['group'],
                mask=backupDataPermissions['mask'],
                recursive=True)
예제 #3
0
파일: ratestats.py 프로젝트: nwrobel/mlYou
def updateRatestatTagsFromVoteData(audioFileVoteData):
    '''
    Updates the ratestat tags for an audio file, given an AudioFileVoteData object containing the
    new votes to be added.
    '''
    logger.debug(
        "Updating ratestat tags with new votes: File={}, NewVotes={}".format(
            audioFileVoteData.filepath, audioFileVoteData.votes))

    tagHandler = mlu.tags.io.AudioFileTagIOHandler(audioFileVoteData.filepath)
    currentTags = tagHandler.getTags()

    votesCurrent = mlu.tags.common.formatAudioTagToValuesList(
        currentTags.votes, valuesAs='float')
    votesUpdated = votesCurrent + audioFileVoteData.votes
    votesUpdatedTagValue = mlu.tags.common.formatValuesListToAudioTag(
        votesUpdated)

    newTags = currentTags
    newTags.votes = votesUpdatedTagValue
    newTags.rating = _calculateRatingTagValue(votesUpdated)
    tagHandler.setTags(newTags)

    logger.info(
        "Updated ratestat tags to the following values: File={}, Votes={}, Rating={}"
        .format(audioFileVoteData.filepath, newTags.votes, newTags.rating))
예제 #4
0
파일: ratestats.py 프로젝트: nwrobel/mlYou
def resetVotePlaylists(votePlaylistsSourceDir, votePlaylistsTempDir):
    '''
    '''
    processedVotePlaylistsFilepaths = _getVotePlaylistFilepaths(
        votePlaylistsTempDir)
    processedVotePlaylistsLineCounts = {}

    for votePlaylist in processedVotePlaylistsFilepaths:
        votePlaylistName = mypycommons.file.GetFilename(votePlaylist)
        lineCount = mypycommons.file.getTextFileLineCount(votePlaylist)
        processedVotePlaylistsLineCounts[votePlaylistName] = lineCount

    sourceVotePlaylistsFilepaths = _getVotePlaylistFilepaths(
        votePlaylistsSourceDir)

    # Remove from the start of each of the original vote playlists the number of lines that were
    # processed in the playlists from the temp dir earlier - essentially we remove the lines that
    # have been processed already, leaving behind any new playlist lines that may have been created
    # in the time between when the playlists were first copied to temp and now
    for votePlaylist in sourceVotePlaylistsFilepaths:
        votePlaylistName = mypycommons.file.GetFilename(votePlaylist)
        removeFirstNLines = processedVotePlaylistsLineCounts[votePlaylistName]
        mypycommons.file.removeFirstNLinesFromTextFile(votePlaylist,
                                                       removeFirstNLines)

    logger.info("Vote playlists reset successfully")
예제 #5
0
파일: ratestats.py 프로젝트: nwrobel/mlYou
def archiveVotePlaylists(playlistsDir, archiveDir):
    '''
    '''
    timeForFilename = (mypycommons.time.getCurrentFormattedTime()).replace(
        ':', '_')
    archiveFilename = "[{}] Archived vote playlists batch.7z".format(
        timeForFilename)

    archiveFilePath = mypycommons.file.JoinPaths(archiveDir, archiveFilename)
    playlistFilepaths = _getVotePlaylistFilepaths(playlistsDir)

    mypycommons.file.create7zArchive(inputFilePath=playlistFilepaths,
                                     archiveOutFilePath=archiveFilePath)
    logger.info(
        "Vote playlists successfully compressed into archive file '{}'".format(
            archiveFilePath))
예제 #6
0
파일: prefbak.py 프로젝트: nwrobel/prefbak
def sourceDataMatchesExistingArchive(sourcePath, archiveFilepath):
    archiveFileInfo = _getContentInfoFor7zArchive(archiveFilepath)
    pathFileInfo = _getContentInfoForPath(sourcePath)

    archiveFileInfoSorted = sorted(archiveFileInfo,
                                   key=lambda k: k['pathName'])
    pathFileInfoSorted = sorted(pathFileInfo, key=lambda k: k['pathName'])

    if (archiveFileInfoSorted == pathFileInfoSorted):
        logger.info("Archive backup data matches all data in the source")
        return True
    else:
        diffContentInfoData = getContentInfoDifferencesBetweenPathAndArchive(
            archiveFileInfoSorted, pathFileInfoSorted)

        outStrGroups = []
        for group in diffContentInfoData['bothWithHashDiff']:
            outStrGroups.append('< File Group > ------------------')
            outStrGroups.append(contentInfoToString(group))
            outStrGroups.append('</ File Group >')

        outStrGroups = '\n'.join(outStrGroups)

        logger.info("""
        Archive backup data is different from data in the source: the following differences are present:\n\n
        These items are in the archive only:\n
        {}\n\n
        These items are in the source path only:\n
        {}\n\n
        These items are in both the source and the archive, but differ in file hash:\n
        {}\n\n
        """.format(contentInfoToString(diffContentInfoData['archiveOnly']),
                   contentInfoToString(diffContentInfoData['pathOnly']),
                   outStrGroups))

        return False
예제 #7
0
파일: ratestats.py 프로젝트: nwrobel/mlYou
def getAudioFileVoteDataFromRatePlaylists(votePlaylistsDir):
    '''
    '''
    audioFileVoteDataList = []
    votePlaylists = _getVotePlaylistFilepaths(votePlaylistsDir)

    for currentVotePlaylistFilepath in votePlaylists:
        currentVoteValue = float(
            mypycommons.file.GetFileBaseName(currentVotePlaylistFilepath))

        logger.info("Reading songs with vote value {} from playlist {}".format(
            currentVoteValue, currentVotePlaylistFilepath))
        playlistSongs = mlu.library.playlist.getAllPlaylistLines(
            currentVotePlaylistFilepath)
        logger.info(
            "Found {} songs in vote value {} playlist: loading them into the data structure"
            .format(len(playlistSongs), currentVoteValue))

        for songFilepath in playlistSongs:
            logger.debug(
                "Adding to data structure: new vote (value {}) for song '{}'".
                format(currentVoteValue, songFilepath))

            # Find the current song in the existing vote data, if it's there, and add the vote
            # to the existing vote data object
            currentSongVoteData = [
                voteData for voteData in audioFileVoteDataList
                if (voteData.filepath == songFilepath)
            ]

            if (currentSongVoteData):
                currentSongVoteData = currentSongVoteData[0]
                currentSongVoteData.votes.append(currentVoteValue)

            # If there's not an object made for this song, create one with the vote data and
            # add it to the vote data list
            else:
                currentSongVoteData = AudioFileVoteData(
                    filepath=songFilepath, votes=[currentVoteValue])
                audioFileVoteDataList.append(currentSongVoteData)

    allVotedSongsCount = len(audioFileVoteDataList)
    logger.info(
        "Vote data loaded from playlists: found {} unique songs that were voted on"
        .format(allVotedSongsCount))

    return audioFileVoteDataList
예제 #8
0
파일: prefbak.py 프로젝트: nwrobel/prefbak
def performBackupStep(sourcePath, destinationPath):
    '''
    Performs a single backup operation. Files can either be mirrored/copied from the source path to 
    the destination path, or an archive file at the destination path can be made from the source
    file.

    Params:
        sourcePath: single filepath (file or directory) to use as the backup source
        destinationPath: single filepath (file or directory) to use as the destination/backup 
            location. Use the name of the archive file if also using the 'compress' param
    '''
    if (not mypycommons.file.directoryExists(destinationPath)):
        logger.info(
            "Backup destination path '{}' does not exist: creating it".format(
                destinationPath))
        mypycommons.file.createDirectory(destinationPath)

    mostRecentArchiveFile = getMostRecentArchiveFile(
        archivePartialFilename=mypycommons.file.GetFilename(sourcePath),
        archiveDir=destinationPath)
    if (mostRecentArchiveFile):
        logger.info(
            "Pre-scan found the latest pre-existing archive file of the source path in this destination dir: {}"
            .format(mostRecentArchiveFile))
    else:
        logger.info(
            "No pre-existing archive file found in this destination dir: it must be empty"
        )

    if (mostRecentArchiveFile and sourceDataMatchesExistingArchive(
            sourcePath, mostRecentArchiveFile)):
        logger.info(
            "An archive with the same data as the source already exists in the destination: no new backup archive will be created"
        )
    else:
        logger.info(
            "Latest archive doesn't exist or doesn't contain the latest source data: a new backup archive will be created"
        )

        archiveName = '[{}] {}{}'.format(
            mypycommons.time.getCurrentTimestampForFilename(),
            mypycommons.file.GetFilename(sourcePath), archiveFileNameSuffix)
        archiveFilepath = mypycommons.file.JoinPaths(destinationPath,
                                                     archiveName)

        logger.info(
            "Creating new backup archive now at {}".format(archiveFilepath))
        create7zArchive(sourcePath, archiveFilepath)
예제 #9
0
파일: prefbak.py 프로젝트: nwrobel/prefbak
    logFilename = 'prefbak.log'
    mypycommons.logger.initSharedLogger(logFilename=logFilename,
                                        logDir=thisProjectLogsDir)
    mypycommons.logger.setSharedLoggerConsoleOutputLogLevel('debug')
    logger = mypycommons.logger.getSharedLogger()

    machineName = getThisMachineName()
    runningWindowsOS = thisMachineIsWindowsOS()

    if (runningWindowsOS):
        sevenZipExeFilepath = "C:\\Program Files\\7-Zip\\7z.exe"
        powershellExeFilepath = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"

        if (mypycommons.file.fileExists(sevenZipExeFilepath)):
            logger.info(
                "Using the 7zip executable program located at {}".format(
                    sevenZipExeFilepath))
        else:
            raise FileNotFoundError(
                "7zip executable program was not found at the default location on this system ({} does not exist)"
                .format(sevenZipExeFilepath))

    backupConfigName = '{}.config.json'.format(machineName)
    backupConfigFilepath = mypycommons.file.JoinPaths(thisProjectConfigDir,
                                                      backupConfigName)

    logger.info(
        "Starting prefbak backup routine script for machine '{}'".format(
            machineName))

    logger.info("Loading this machine's prefbak config file: {}".format(
예제 #10
0
        mypycommons.file.createDirectory(logsDir)

    return logsDir


if __name__ == '__main__':

    mypycommons.logger.initSharedLogger(logFilename='apply-permissions.log',
                                        logDir=getProjectLogsDir())
    mypycommons.logger.setSharedLoggerConsoleOutputLogLevel('info')
    logger = mypycommons.logger.getSharedLogger()

    thisDir = mypycommons.file.getThisScriptCurrentDirectory()
    configFilePath = mypycommons.file.JoinPaths(thisDir, 'permissions.csv')

    logger.info("Starting file permission application script")
    logger.info("Reading permission config file: {}".format(configFilePath))

    permissionRules = mypycommons.file.readCSVFile(configFilePath)
    currentLine = 1

    for rule in permissionRules:
        if (rule['recursive'] == '0'):
            useRecursive = False
        elif (rule['recursive'] == '1'):
            useRecursive = True
        else:
            raise "Invalid value for CSV column 'recursive': should be 0 or 1"

        if (rule['applyToType'] == 'f'):
            applyToType = 'file'
예제 #11
0
        currentTags = tagHandler.getTags()

        tagUpdatesTable.add_row([
            currentTags.title, currentTags.artist, updateResult.oldRating,
            updateResult.newRating
        ])

    mypycommons.file.writeToFile(filepath=summaryFilepath,
                                 content=tagUpdatesTable.get_string())


# ------------------------------- Main script procedure --------------------------------------------
#
if __name__ == "__main__":
    logger.info(
        "Performing full backup (checkpoint) of all music library audio files tags"
    )
    tagsBackupFilepath = mlu.tags.backup.backupMusicLibraryAudioTags()

    logger.info(
        "Searching for all audio under music library root path '{}'".format(
            MLUSettings.musicLibraryRootDir))
    libraryAudioFiles = mlu.library.musiclib.getAllMusicLibraryAudioFilepaths()

    libraryAudioFilesCount = len(libraryAudioFiles)
    logger.info("Found {} audio files in music library root path".format(
        libraryAudioFilesCount))

    logger.info(
        "Checking RATING tags for all audio files and fixing incorrect values")
    updatedAudioFilesResults = []
            [mypycommons.time.formatTimestampForDisplay(playbackInstance.playTimeStart) for playbackInstance in audioFilePlaybackData.playbackInstances],
            currentTags.playCount,
            currentTags.dateLastPlayed,
            currentTags.dateAllPlays
        ])

    mypycommons.file.writeToFile(filepath=summaryFilepath, content=tagUpdatesTable.get_string())

# ------------------------------- Main script procedure --------------------------------------------
#
if __name__ == "__main__":

    #logger.info("Performing full backup (checkpoint) of all music library audio files tags")
    #tagsBackupFilepath = mlu.tags.backup.backupMusicLibraryAudioTags()

    logger.info("Copying MPD log file at '{}' to ~cache temp dir".format(MLUSettings.mpdLogFilepath))
    mypycommons.file.CopyFilesToDirectory(MLUSettings.mpdLogFilepath, MLUSettings.tempDir)
    tempMpdLogFilepath = mypycommons.file.JoinPaths(
        MLUSettings.tempDir, 
        mypycommons.file.GetFilename(MLUSettings.mpdLogFilepath)
    )

    mpdLogLines = mlu.mpd.logs.collectMPDLogLinesFromLogFile(tempMpdLogFilepath)

    collectResults = mlu.mpd.plays.collectAudioFilePlaybackDataFromMPDLogLines(mpdLogLines)
    audioFilePlaybackDataList = collectResults['playbackDataList']
    preserveLastLogLine = collectResults['preserveLastLogLine']

    previewFilepath = _getPlaystatTagUpdatesPreviewFilepath()
    _writePlaystatTagUpdatesPreviewFile(audioFilePlaybackDataList, previewFilepath)
    logger.info("Changes preview file written successfully: File='{}'".format(previewFilepath))
예제 #13
0
import com.nwrobel.mypycommons.time
import com.nwrobel.mypycommons.logger

mypycommons.logger.initSharedLogger(logDir=MLUSettings.logDir)
logger = mypycommons.logger.getSharedLogger()

import mlu.mpd.logs

if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    parser.add_argument("masterLogFilepath", 
        help="Filepath of where the master MPD log containing all MPD log lines from all files, should be saved",
        type=str)

    parser.add_argument('--logs', nargs='+', help='List of MPD log filepaths to merge into a single log file', required=True)
    args = parser.parse_args()

    allMPDLogLines = []
    for logFilepath in args.logs:
        currentMPDLogLines = mlu.mpd.logs.collectMPDLogLinesFromLogFile(logFilepath)
        allMPDLogLines += currentMPDLogLines
        logger.info("Found {} MPDLogLines in log file '{}'".format(len(currentMPDLogLines), logFilepath))

    logger.info("MPDLogLines collected total: {}".format(len(allMPDLogLines)))
    logger.info("Removing duplicate MPDLogLines from total list and sorting them oldest -> newest")
    uniqueSortedMPDLogLines = mlu.mpd.logs.removeDuplicateMPDLogLines(allMPDLogLines)

    logger.info("Unique MPDLogLines total: {} ({} were duplicates and were removed)".format(len(uniqueSortedMPDLogLines), len(allMPDLogLines) - len(uniqueSortedMPDLogLines) ))
    logger.info("Dumping all MPDLogLines to master MPD log file '{}'".format(args.masterLogFilepath))
    mlu.mpd.logs.dumpMPDLogLinesToLogFile(destLogFilepath=args.masterLogFilepath, mpdLogLines=uniqueSortedMPDLogLines)
예제 #14
0
logger = mypycommons.logger.getSharedLogger()

# import project-related modules
import mlu.library.playlist
import mlu.tags.io
import mlu.library.musiclib

def _roundRatingValueForPlaylistMatching(ratingNum):
    value = Decimal(ratingNum).quantize(0, ROUND_HALF_UP)
    return int(value)

# ------------------------------- Main script procedure --------------------------------------------
#
if __name__ == "__main__":

    logger.info("Removing pre-existing (old) rating playlists")
    existingRatingPlaylists = mypycommons.file.GetAllFilesRecursive(MLUSettings.ratePlaylistsPublishedDir)
    for playlistFilepath in existingRatingPlaylists:
        mypycommons.file.DeleteFile(playlistFilepath)

    logger.info("Searching for all audio under music library root path '{}'".format(MLUSettings.musicLibraryRootDir))
    libraryAudioFiles = mlu.library.musiclib.getAllMusicLibraryAudioFilepaths()
    libraryAudioFilesCount = len(libraryAudioFiles)

    logger.info("Found {} audio files in library. Scanning rules".format(libraryAudioFilesCount))
    ratingPlaylistsData = []
    for rule in MLUSettings.ratePlaylistCreateRules:
        if (rule[0] == rule[1]):
            playlistBaseName = rule[0]
        else:
            playlistBaseName = "{}-{}".format(rule[0], rule[1])
예제 #15
0
        tagUpdatesTable.add_row([
            currentTags.title, currentTags.artist, votesAdded,
            currentTags.rating, currentTags.votes
        ])

    mypycommons.file.writeToFile(filepath=summaryFilepath,
                                 content=tagUpdatesTable.get_string())


# ------------------------------- Main script procedure --------------------------------------------
#
if __name__ == "__main__":

    logger.info(
        "Performing full backup (checkpoint) of all music library audio files tags"
    )
    #tagsBackupFilepath = mlu.tags.backup.backupMusicLibraryAudioTags()

    logger.info("Copying vote playlist files to temp location in ~cache")
    mlu.ratestats.copyVotePlaylistsToTemp(
        votePlaylistsSourceDir=MLUSettings.votePlaylistsDir,
        votePlaylistsTempDir=MLUSettings.tempDir)

    logger.info("Loading audio file votes data from all vote playlists")
    audioFileVoteDataList = mlu.ratestats.getAudioFileVoteDataFromRatePlaylists(
        votePlaylistsDir=MLUSettings.tempDir)

    logger.info("Vote playlists data loaded successfully")
    logger.info("Writing new ratestats tag data to audio files")