def build_transaction(cls, songs):
            """:param songs: a list of dictionary representations of songs."""

            #Warn about metadata changes that may cause problems.
            #If you change the interface in api, you can warn about changing bad categories, too.
            #Something like safelychange(song, entries) where entries are only those you want to change.

            for song in songs:
                for key in song:
                    allowed_values = MetadataExpectations.get_expectation(key).allowed_values
                    if allowed_values and song[key] not in allowed_values:
                        LogController.get_logger("modifyentries").warning(
                            "setting key %s to unallowed value %s for id "
                            "%s. Check metadata expectations in "
                            "protocol.py" % (key, song[key], song["id"]))


            req = {"entries": songs}

            res = {"type": "object",
                   "properties":{
                       "success": {"type":"boolean"},
                       "songs":WC_Protocol.song_array
                       },
                   "additionalProperties":False
                   }
            return (req, res)
    def get_expectation(cls, key, warn_on_unknown=True):
        """Get the Expectation associated with the given key name.
        If no Expectation exists for that name, an immutable Expectation of any type is returned."""

        try:
            expt = getattr(cls, key)
            if not issubclass(expt, _MetadataExpectation):
                raise TypeError
            return expt
        except (AttributeError, TypeError):
            if warn_on_unknown:
                LogController.get_logger("get_expectation").warning("unknown metadata type '%s'", key)

            return UnknownExpectation
    def make_metadata_request(self, filenames):
        """Returns (Metadata protobuff, dictionary mapping ClientId to filename) for the given mp3s."""

        filemap = {} #map clientid -> filename

        metadata = self.make_pb("metadata_request")

        for filename in filenames:

            if not filename.split(".")[-1].lower() == "mp3":
                LogController.get_logger("make_metadata_request").error(
                        "cannot upload '%s' because it is not an mp3.", filename)
                continue

            track = metadata.tracks.add()

            #Eventually pull this to supported_filetypes
            audio = MP3(filename, ID3 = EasyID3)


            #The id is a 22 char hash of the file. It is found by:
            # stripping tags
            # getting an md5 sum
            # converting sum to base64
            # removing trailing ===

            #My implementation is _not_ the same hash the music manager will send;
            # they strip tags first. But files are differentiated across accounts,
            # so this shouldn't cause problems.

            #This will reupload files if their tags change.
            
            with open(filename, mode="rb") as f:
                file_contents = f.read()
            
            h = hashlib.md5(file_contents).digest()
            h = base64.encodestring(h)[:-3]
            id = h

            filemap[id] = filename
            track.id = id

            filesize = os.path.getsize(filename)

            track.fileSize = filesize

            track.bitrate = audio.info.bitrate / 1000
            track.duration = int(audio.info.length * 1000)

            #GM requires at least a title.
            if "title" in audio:
                track.title = audio["title"][0] 
            else:
                #attempt to handle unicode filenames.
                enc = utils.guess_str_encoding(filename)[0]
                track.title = filename.decode(enc).split(r'/')[-1]


            #TODO refactor
            if "album" in audio: track.album = audio["album"][0]
            if "artist" in audio: track.artist = audio["artist"][0]
            if "composer" in audio: track.composer = audio["composer"][0]

            #albumartist is 'performer' according to this guy: 
            # https://github.com/plexinc-plugins/Scanners.bundle/commit/95cc0b9eeb7fa8fa77c36ffcf0ec51644a927700

            if "performer" in audio: track.albumArtist = audio["performer"][0]
            if "genre" in audio: track.genre = audio["genre"][0]
            if "date" in audio: track.year = int(audio["date"][0].split("-")[0]) #this looks like an assumption
            if "bpm" in audio: track.beatsPerMinute = int(audio["bpm"][0])

            #think these are assumptions:
            if "tracknumber" in audio: 
                tracknumber = audio["tracknumber"][0].split("/")
                track.track = int(tracknumber[0])
                if len(tracknumber) == 2 and tracknumber[1]:
                    track.totalTracks = int(tracknumber[1])

            if "discnumber" in audio:
                discnumber = audio["discnumber"][0].split("/")
                track.disc = int(discnumber[0])
                if len(discnumber) == 2 and discnumber[1]:
                    track.totalDiscs = int(discnumber[1])

        return (metadata, filemap)
Пример #4
0
# -*- coding: utf-8 -*-
"""Utilities used in testing."""

import numbers
import unittest
import random
import inspect
from getpass import getpass
import re

from gmusicapi.api import Api
from gmusicapi.exceptions import CallFailure, NotLoggedIn
from gmusicapi.protocol.metadata import md_expectations
from gmusicapi.utils.apilogging import LogController

log = LogController.get_logger("utils")

#A regex for the gm id format, eg:
#c293dd5a-9aa9-33c4-8b09-0c865b56ce46
hex_set = "[0-9a-f]"
gm_id_regex = re.compile(
    ("{h}{{8}}-" + ("{h}{{4}}-" * 3) + "{h}{{12}}").format(h=hex_set))


def init():
    """Makes an instance of the unit-tested api and attempts to login with it.
    Returns the authenticated api.
    """

    api = UnitTestedApi()
"""Utilities used in testing."""

import numbers
import unittest
import random
import inspect
from getpass import getpass
import re

from gmusicapi.api import Api
from gmusicapi.exceptions import CallFailure, NotLoggedIn
from gmusicapi.protocol.metadata import md_expectations
from gmusicapi.utils.apilogging import LogController

log = LogController.get_logger("utils")

#A regex for the gm id format, eg:
#c293dd5a-9aa9-33c4-8b09-0c865b56ce46
hex_set = "[0-9a-f]"
gm_id_regex = re.compile(("{h}{{8}}-" +
                         ("{h}{{4}}-" * 3) +
                         "{h}{{12}}").format(h=hex_set))


def init():
    """Makes an instance of the unit-tested api and attempts to login with it.
    Returns the authenticated api.
    """

    api = UnitTestedApi()