Ejemplo n.º 1
0
def main():
    args, config = init()

    if not os.path.isdir(config['PROG']['DownloadPath']):
        os.mkdir(config['PROG']['DownloadPath'])

    sc_download(
        config['SOUNDCLOUD']['PlaylistUrl'],
        config['PROG']['DownloadPath']
    )

    mc = Mobileclient()
    mc.login(config['GMUSIC']['User'], config['GMUSIC']['Password'], Mobileclient.FROM_MAC_ADDRESS)

    mm = Musicmanager()
    if not (os.path.exists(gmclients.OAUTH_FILEPATH) and mm.login(gmclients.OAUTH_FILEPATH)):
        mm.perform_oauth(gmclients.OAUTH_FILEPATH, open_browser=True)
        if not mm.login(gmclients.OAUTH_FILEPATH):
            sys.stderr.write('Musicmanager could not authenticate')

    if config['GMUSIC']['TargetPlaylist'] not in set([item['name'] for item in mc.get_all_playlists() if not item['deleted']]):
        mc.create_playlist(name=config['GMUSIC']['TargetPlaylist'], description='Tracks synchronized using {}'.format(__prog__), public=False)

    playlist_id, current_members = gm_get_current_pl_member(mc, config['GMUSIC']['TargetPlaylist'])

    for track in os.listdir(config['PROG']['DownloadPath']):
        print('Uploading {}'.format(track))
        uploaded_id = gm_extract_id(mm.upload('{}{}'.format(config['PROG']['DownloadPath'], track)))
        mc.add_songs_to_playlist(playlist_id, uploaded_id)
Ejemplo n.º 2
0
def _process_youtube_upload(youtube_url, ydl_opts, music, metadata_opts,
                            credential, uploader_name):
    manager = Musicmanager()
    manager.login(credential, uploader_name=uploader_name)
    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
        info_dict = ydl.extract_info(youtube_url, download=False)
        if music.title == "":
            music.title = info_dict.get('title', None)
            music.save()
            metadata_opts = {
                i: getattr(music, i)
                for i in [
                    'title', 'album', 'composer', 'genre', 'language',
                    'artist', 'album_artist'
                ]
            }
            logger.debug('New metadata opts: ' + str(metadata_opts))
            ffmpeg_mp3_metadata_pp = FFmpegMP3MetadataPP(ydl, metadata_opts)
            ydl.add_post_processor(ffmpeg_mp3_metadata_pp)
            ydl.download([youtube_url])
            music_filepath = ydl.prepare_filename(info_dict)
            if not music_filepath.endswith('.mp3'):
                music_filepath = music_filepath.replace(
                    music_filepath[music_filepath.rfind('.'):], '.mp3')
                logger.debug("Music filepath: " + music_filepath)
    manager.upload(music_filepath,
                   enable_matching=True,
                   enable_transcoding=False)  # Already transcoding.
    if os.path.isfile(music_filepath):
        os.remove(music_filepath)
Ejemplo n.º 3
0
def download(mode, url, num):
    print(f"Downloading for {mode}")

    #Options
    ydl_opts = {
        'format':
        'bestaudio/best',
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '320',
        }],
        'logger':
        MyLogger(),
        'progress_hooks': [my_hook],
        'outtmpl':
        folders[num][mode][0] + '/%(title)s.%(ext)s'
    }

    #Download the video and extract all the metadata
    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
        info_dict = ydl.extract_info(url, download=True)
        video_title = info_dict.get('title', None)
        video_filename = '.'.join(
            ydl.prepare_filename(info_dict).split('.')[:-1]) + '.mp3'
    print(video_filename)

    #Edit mp3 tag.
    try:
        print(f"Editing artist tag to {mode.capitalize()}...")
        mp3 = MP3File(video_filename)
        mp3.artist = mode.title()
        mp3.save()
        insert_album_art(video_filename, info_dict['id'])
        print("Done!\n")
    except Exception as e:
        print("Error at editing mp3 tag.\n")
        print(e)

    #Backup
    if num != 3:
        try:
            print(f"Making a backup of {video_title}...")
            copy(video_filename, folders[num][mode][1])
            print("Done!\n")
        except:
            print("Error at doing backup.\n")

    #Upload to google
    if num != 3:
        try:
            print(f"Uploading {video_title} to Google Music\n")
            print(f'With url {url}')
            mm = Musicmanager()
            mm.login(uploader_id='D0:50:99:83:B0:0C')
            mm.upload(video_filename)
            print("Done!\n")
        except Exception as e:
            print("Error at uploading the song to google:\n" + e)
Ejemplo n.º 4
0
def init():
    mm = Musicmanager()
    try:
        script_path = os.path.dirname(os.path.abspath(__file__))
    except NameError:
        script_path = os.getcwd()
    mm.login(oauth_credentials=os.path.join(script_path, "oauth.cred"))
    return mm
Ejemplo n.º 5
0
def upload(path):
    mm = Musicmanager()
    mm.login()

    for root, dirs, files in os.walk(path):
        for file_ in files:
            mp3FilePath = os.path.join(root, file_)
            print( "upload : " + file_ )
            mm.upload(mp3FilePath)
            os.remove(mp3FilePath)
Ejemplo n.º 6
0
class GoogleMusicManager:
    def __init__(self):
        self.api = Musicmanager(debug_logging=False)
        with open(path + "oauth.cred", 'w+') as tmp:
            tmp.write(settings['google']['musicmanager'])
            tmp.close()
            self.api.login(tmp.name)
            os.remove(tmp.name)

    def upload_song(self, file):
        self.api.upload(file)
Ejemplo n.º 7
0
class GoogleMusicManager:
    def __init__(self):
        self.api = Musicmanager(debug_logging=False)
        refresh_token = json.loads(
            settings['google']['musicmanager'])['refresh_token']
        credentials = session.credentials_from_refresh_token(
            refresh_token, session.Mobileclient.oauth)
        self.api.login(credentials)

    def upload_song(self, file):
        self.api.upload(file)
Ejemplo n.º 8
0
class GoogleMusic:
    def __init__(self):
        self.api = Musicmanager()
        try:
            print(os.getcwd())
            if not self.api.login(oauth_credentials=config.auth):
                self.api.perform_oauth(storage_filepath=config.auth, open_browser=False)
                self.api.login(oauth_credentials=config.auth)
        except:
            pass

    def upload_audio(self, filepath, transcode_quality='320k'):
        self.api.upload(filepath, enable_matching=False, transcode_quality=transcode_quality)
        print("Upload finished")
Ejemplo n.º 9
0
def authorize_manager(parameters):
    # api = Webclient()
    # api = Mobileclient()
    api = Musicmanager()
    # after running api.perform_oauth() once:
    # api.oauth_login('<a previously-registered device id>')
    # api.login(email=parameters.username, password=parameters.password)
    # => True
    if not os.path.exists(authorize_file + '_manager'):
        api.perform_oauth(authorize_file + '_manager', True)

    api.login(authorize_file + '_manager')
    if not api.is_authenticated():
        return None

    return api
def upload(directory='.',
           oauth=os.environ['HOME'] + '/oauth',
           remove=False,
           uploader_id=__DEFAULT_MAC__):
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)
    logger.info("Init Daemon - Press Ctrl+C to quit")

    api = Musicmanager()
    event_handler = MusicToUpload()
    event_handler.api = api
    event_handler.path = directory
    event_handler.willDelete = remove
    event_handler.logger = logger
    if not api.login(oauth, uploader_id):
        print("Error with oauth credentials")
        sys.exit(1)
    files = [file for file in glob.glob(directory + '/**/*', recursive=True)]
    for file_path in files:
        if os.path.isfile(file_path):
            logger.info("Uploading : " + file_path)
            uploaded, matched, not_uploaded = api.upload(file_path, True)
            if remove and (uploaded or matched):
                os.remove(file_path)
    observer = Observer()
    observer.schedule(event_handler, directory, recursive=True)
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()
Ejemplo n.º 11
0
def main():
    cli = Musicmanager(debug_logging=False)

    if credfile.is_file():
        if cli.login(oauth_credentials=str(credfile)):
            print("Login successful. Don't need to perform oauth.")
            return
        else:
            os.remove(credfile)

    cli.perform_oauth(storage_filepath=str(credfile), open_browser=True)

    if cli.login(oauth_credentials=str(credfile)):
        print("Login successful. Restart the bot!")
    else:
        print("Failed to auth. Try again later.")
Ejemplo n.º 12
0
def index(request):
    args = {}
    if request.user.is_authenticated:
        credential = request.user.profile.google_oauth
        if not credential:
            return HttpResponse('No credentials found. Remake an account.')
        manager = Musicmanager()
        # TODO: Maybe change mac address for each user?
        login_success = manager.login(
            credential,
            uploader_name="GMusicManagerOnline - {}".format(
                request.user.username))
        args.update({'login_success': login_success})
        if login_success:
            quota = manager.get_quota()
            default_fields_form = DefaultFieldsForm(
                request.POST or None, instance=request.user.profile)
            if default_fields_form.is_valid():
                default_fields_form.save()
                return redirect('index')
            args.update({
                'currently_uploaded': quota[0],
                'upload_limit': quota[1],
                'default_fields_form': default_fields_form
            })
        manager.logout()
    return render(request, 'core/index.html', args)
Ejemplo n.º 13
0
	def download_songs(self):
		api = Musicmanager()
		ip = urllib2.urlopen('http://ip.42.pl/raw').read() #Obtain your public IP address
		mac_binary = str(get_mac()) #Obtain binary MAC address
		temp = mac_binary.replace(':', '').replace('-', '').replace('.', '').upper()
		mac_h3x = temp[:2] + ":" + ":".join([temp[i] + temp[i+1] for i in range(2,12,2)]) #Convert MAC from 48bit int to hexadecimal string
		user = pwd.getpwuid(os.getuid())[0] #Get your system's username
		hostname = '<' + ip + '>' + '' + '(gmusicapi-{2.0.0})'
		Musicmanager.perform_oauth(storage_filepath='/home/' + user + '/.config/gmusicapi/oauth.cred', open_browser=False)
		api.login(oauth_credentials='/home/' + user + '/.config/gmusicapi/oauth.cred', uploader_id=mac_h3x, uploader_name=hostname)
		gmusicapi.clients.Musicmanager(debug_logging=True, validate=True)		
		playlist_id = raw_input("insert id: ")
		
		api_ = Mobileclient()
		api_.login(self.email, self.password)
		playlist_method = api_.get_all_playlists()
Ejemplo n.º 14
0
def download(directory=".",
             oauth=os.environ['HOME'] + "/oauth",
             device_id=__DEFAULT_MAC__):
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)
    logger.info("Init Daemon - Press Ctrl+C to quit")
    api = Musicmanager()
    if not api.login(oauth, device_id):
        print("Error with oauth credentials")
        sys.exit(1)

    for song in api.get_uploaded_songs():
        folder_path = os.path.join(directory, song['album_artist'],
                                   song['album'])
        file_path = os.path.join(
            folder_path, '%d - %s.mp3' %
            (song['track_number'], song['title'].replace('/', '_')))
        file_path = file_path.encode('utf8')
        folder_path = folder_path.encode('utf8')
        if not os.path.exists(file_path):
            filename, audio = api.download_song(song['id'])
            if not os.path.exists(folder_path):
                os.makedirs(folder_path)
            with open(file_path, 'wb') as f:
                f.write(audio)
Ejemplo n.º 15
0
class gmObject:
    
    def __init__(self):
        self.mc = Mobileclient()
        self.wc = Webclient()
        self.mm = Musicmanager()
    
    def login(self, username, password):
        error.e = 0
        
        if not self.mc.login(username, password):
            gmtPrintV("gmObject.login: Wrong username or password (or no internet connection)")
            error.e = error.LOGIN_FAILED
            return
        
        if not self.wc.login(username, password):
            gmtPrintV("gmObject.login: Wrong username or password (or no internet connection)")
            error.e = error.LOGIN_FAILED
            return
        
        if not self.mm.login(config.cred_path):
            gmtPrintV("gmObject.login: Wrong credentials (or no internet connection)")
            error.e = error.LOGIN_FAILED
            return
        
    def logout(self):
        error.e = 0
        
        try:
            self.mc.logout()
            self.wc.logout()
            self.mm.logout()
        except:
            gmtPrintV("gmObject.logout: Logout failed")
            error.e = error.LOGOUT_FAILED
Ejemplo n.º 16
0
def initializeClient():
    client = Musicmanager()

    if (client.login()):
        return client
    else:
        client.perform_oauth(open_browser=True)
        initializeClient()
Ejemplo n.º 17
0
def upload(file_path):
    storage = oauth2client.file.Storage(CREDENTIALS_PATH)
    credentials = storage.get()

    if not credentials or credentials.invalid:
        Musicmanager.perform_oauth(CREDENTIALS_PATH, open_browser=False)

    mm = Musicmanager()
    mm.login(CREDENTIALS_PATH)

    result = mm.upload(file_path, enable_matching=True)
    if result[1]:
        raise Exception('{}はアップロード済みです'.format(file_path))
    elif result[2]:
        raise Exception('アップロード失敗 {}'.format(result[2][file_path]))

    os.remove(file_path)
Ejemplo n.º 18
0
def download(base_dir: str = ".",
             creds: str = __DEFAULT_CREDS__,
             device_id: str = __DEFAULT_MAC__) -> None:
    api = Musicmanager()
    if not api.login(creds, device_id):
        logger.error("Error with oauth credentials")
        sys.exit(1)

    Song = namedtuple('Song', ['artist', 'album', 'track', 'title', 'id'])

    def _download(song: Song, downloader: Callable) -> None:
        logger.debug(f"Downloading song '{song.title}'")
        f, audio = downloader(song.id)

        folder = os.path.join(base_dir, song.artist, song.album)
        if not os.path.exists(folder):
            logger.debug(f"Creating folder '{folder}'")
            os.makedirs(folder)
        file = os.path.join(folder, f'{song.track}-{song.title}.mp3')
        with open(file, 'wb') as f:
            logger.debug(f"Writing file '{file}'")
            f.write(audio)

    songs = api.get_uploaded_songs()
    n = len(songs)
    logger.debug(f"Downloading '{n}' to folder '{base_dir}'")
    future_to_song = {}
    with ThreadPoolExecutor() as executor:
        for song in songs:
            artist = song['album_artist']
            album = song['album']
            track = song['track_number']
            title = song['title'].replace('/', '_').replace('?', '_')
            iden = song['id']
            s = Song(artist=artist,
                     album=album,
                     track=track,
                     title=title,
                     id=iden)
            future = executor.submit(_download,
                                     song=s,
                                     downloader=api.download_song)
            future_to_song[future] = s

        succeeded = 0
        failed = 0
        for future in concurrent.futures.as_completed(future_to_song):
            s = future_to_song[future]
            if future.exception():
                logger.warning(
                    f"Failed to download song '{s.title}' because '{future.exception()}'"
                )
                failed += 1
                continue
            succeeded += 1
        logger.debug(
            f"Completed. Total {n} succeded {succeeded} failed {failed}")
Ejemplo n.º 19
0
class GoogleManager():

    def __init__(self, directory):
        self.music_dir = directory

        self.Google = Musicmanager()
        self.Google.login()

    def upload(self):
        files = []
        for dirpath, dirnames, filenames in walk(self.music_dir):
            for name in filenames:
                if name.endswith('.mp3'):
                    files += [join(dirpath, name)]

        for f in files:
            ret = self.Google.upload(f)
            print(ret)
Ejemplo n.º 20
0
def youtube_upload(request):
    # TODO: Async status updates?
    if not request.user.is_authenticated:
        return HttpResponse('log in first')
    credential = request.user.profile.google_oauth
    if not credential:
        return HttpResponse('no creds')
    manager = Musicmanager()
    # TODO: Maybe change mac address for each user?
    login_success = manager.login(
        credential,
        uploader_name="GMusicManagerOnline - {}".format(request.user.username))
    form = YoutubeUploadForm()
    args = {'can_login': login_success, 'form': form, 'success': False}
    if request.method == "POST":
        form = YoutubeUploadForm(request.POST)
        if form.is_valid():
            music = form.save()
            for i in [
                    'title', 'album', 'composer', 'genre', 'language',
                    'artist', 'album_artist'
            ]:
                if getattr(music, i) == "":
                    setattr(music, i,
                            getattr(request.user.profile, "default_" + i))
            music.save()
            youtube_url = request.POST.get('youtube_url')
            metadata_opts = {
                i: getattr(music, i)
                for i in [
                    'title', 'album', 'composer', 'genre', 'language',
                    'artist', 'album_artist'
                ] if getattr(music, i) != ""
            }
            ydl_opts = {
                'format':
                'bestaudio/best',
                'outtmpl':
                settings.MEDIA_ROOT + "/{}{}.%(ext)s".format(
                    request.user.username, int(time.time())),
                'postprocessors': [{
                    'key': 'FFmpegExtractAudio',
                    'preferredcodec': 'mp3',
                    'preferredquality': '320',
                }],
            }
            upload_args = (youtube_url, ydl_opts, music, metadata_opts,
                           credential, "GMusicManagerOnline - {}".format(
                               request.user.username))
            upload_thread = threading.Thread(target=_process_youtube_upload,
                                             args=upload_args)
            upload_thread.start()
            args.update({'success': True})
        args.update({'form': form})
    manager.logout()
    return render(request, 'core/youtube.html', args)
Ejemplo n.º 21
0
def download_all(outdir: str = DEF_OUT_DR,
                 device_id: str = DEF_DEV_ID,
                 mac_addr: str = DEF_MAC_AD):

    mc = Mobileclient()
    mm = Musicmanager()

    mc.oauth_login(DEF_DEV_ID)
    mm.login(uploader_id=DEF_MAC_AD)

    songs = mc.get_all_songs()
    print(f'Downloading {len(songs)}')
    for song in songs:
        filename, audio = mm.download_song(song['id'])
        print(f'Downloading {song["id"]} : {filename}', flush=True)
        with open(f'{outdir}/{filename}', 'wb') as fh:
            fh.write(audio)
        with open(f'{outdir}/{filename}.meta', 'w') as fh:
            json.dump(song, fh, indent=2, sort_keys=True)
Ejemplo n.º 22
0
def main():
    path = sys.argv[1]
    if not os.path.exists(path):
        print("Invalid file path. %s" % path)
        return

    api = Musicmanager()
    api.login()

    if not api.is_authenticated():
        print("Login Error\n")
        return

    print("start upload...\n")
    upload_info = api.upload(path)
    print(upload_info)
    print("upload is completed.\n")

    api.logout()
def download(directory: str = ".",
             oauth: str = __DEFAULT_OAUTH_PATH__,
             device_id: str = __DEFAULT_MAC__,
             down_logger: logging.Logger = logger) -> None:
    api = Musicmanager()
    if not api.login(oauth, device_id):
        if down_logger:
            down_logger.error("Error with oauth credentials")
        sys.exit(1)

    if down_logger:
        down_logger.info("Init Daemon - Press Ctrl+C to quit")

    songs = api.get_uploaded_songs()
    songs_total = len(songs)
    if down_logger:
        logger.debug("Downloading '%d' to folder '%s'" %
                     (songs_total, directory))
    future_to_song = {}
    with ThreadPoolExecutor() as executor:
        for song in songs:
            artist = song['album_artist']
            album = song['album']
            track_number = song['track_number']
            title = song['title'].replace('/', '_').replace('?', '_')
            track_id = song['id']
            song_object = Song(artist=artist,
                               album=album,
                               track_number=track_number,
                               title=title,
                               id=track_id)
            future = executor.submit(_download,
                                     song=song_object,
                                     api=api,
                                     base_dir=directory,
                                     thread_logger=down_logger)
            future_to_song[future] = song

        succeeded = 0
        failed = 0
        for future in concurrent.futures.as_completed(future_to_song):
            song = future_to_song[future]
            if future.exception():
                if down_logger:
                    down_logger.warning(
                        "Failed to download song '%s' because '%s'" %
                        (song.title, future.exception()))
                failed += 1
                continue
            succeeded += 1
        if down_logger:
            down_logger.debug(
                "Completed. Total %d | %d succeeded | %d failed" %
                (songs_total, succeeded, failed))
Ejemplo n.º 24
0
def run():
    global download_dir, notify_plex, mm
    download_dir, notify_plex = parse_args()
    log("Creating music manager")
    mm = Musicmanager()
    log("Attempting login")
    if not mm.login():
        print "OAuth required:"
        mm.perform_oauth()

    get_songs()
Ejemplo n.º 25
0
class GMusicPodcastSyncDestination(PodcastSyncDestination):
    def __init__(self):
        super(GMusicPodcastSyncDestination, self).__init__()
        self.serviceIdentifier = "GOO"
        self.serviceName = "Google Music"
        self.musicManager = Musicmanager()
        self.mobileClient = Mobileclient()
        oAuthFile = "gMusic.oauth"
        if not os.path.isfile(oAuthFile):
            if not self.musicManager.perform_oauth(oAuthFile, True):
                print "Failed to authenticate Music Manager."
                raise PodcastSyncDestinationException("Authentication Failure.")
        else:
            try:
                self.musicManagerauthenticated = self.musicManager.login(oAuthFile)
            except gmusicapi.exceptions.AlreadyLoggedIn:
                pass
        username = raw_input("Enter Google Username: "******"Enter Google Password: "******"Authentication Failure.")
            # perform a push task. should return a PodFastPodcastPushedEpisode instance

    def pushEpisode(self, podcastSyncTaskEpisodePush):
        (uploaded, matched, not_uploaded) = self.musicManager.upload([podcastSyncTaskEpisodePush.localFilename])
        songGoogleMusicID = ""
        if not_uploaded:  # If the track was not uploaded, it may have been uploaded in the past.
            p = re.compile("ALREADY_EXISTS\\((.*)\\)")
            m = p.findall(not_uploaded[podcastSyncTaskEpisodePush.localFilename])
            songGoogleMusicID = m[0]
        else:
            songGoogleMusicID = uploaded[podcastSyncTaskEpisodePush.localFilename]
        print "Track uploaded Successfully. ID:" + songGoogleMusicID
        gmusicPlayLists = self.mobileClient.get_all_playlists()
        playListExists = False
        gmusicPlaylistID = ""
        for gmusicPlayList in gmusicPlayLists:
            if gmusicPlayList["name"] == podcastSyncTaskEpisodePush.playlistName:
                playListExists = True
                gmusicPlaylistID = gmusicPlayList["id"]
                break
        if not playListExists:
            print "Creating playlist..."
            gmusicPlaylistID = self.mobileClient.create_playlist(podcastSyncTaskEpisodePush.playlistName)
        addedEntries = self.mobileClient.add_songs_to_playlist(gmusicPlaylistID, [songGoogleMusicID])
        print "Moved track to playlist."
        return songGoogleMusicID
        # Pull (deletes) an episode from the destination returns true on success, False on faiilure

    def pullEpisode(self, podcastSyncTaskEpisodePull):
        self.mobileClient.delete_songs([podcastSyncTaskEpisodePull.syncDestinationID])
        # TODO: Error check here.
        return True
def main():
    if len(sys.argv) != 2:
        print_help()
        sys.exit(1)
    else:
        username = sys.argv[1]
    password = getpass.getpass()

    mc = Mobileclient()
    mc.login(username, password, Mobileclient.FROM_MAC_ADDRESS)

    mm = Musicmanager()
    mm.perform_oauth()
    mm.login()

    uploaded_songs = mm.get_uploaded_songs()
    uploaded_ids = [track['id'] for track in uploaded_songs]
    for part in chunks(uploaded_ids, 100):
        complete = mc.delete_songs(part)
        if len(complete) != len(part):
            print("Something is wrong")
Ejemplo n.º 27
0
class MyCdList:

    mm = None
    library = None

    def authenticatewithgoogle(self, option):

        self.mm = Musicmanager()
        self.mm.login()  # currently named oauth_login for the Mobileclient

        if option == 0:
            self.library = self.mm.get_purchased_songs()
        elif option == 1:
            self.library = self.mm.get_uploaded_songs()

    def getallartist(self):
        donotaddthis = "The 100 Most Essential Pieces of Classical Music"
        artists = []
        artistsset = set()
        [
            artistsset.add(track['artist']) for track in self.library
            if track['album'] != donotaddthis
        ]
        artists = list(artistsset)
        artists.sort()
        return artists

    def getalbumsforartist(self, artist):

        albums = []
        albumsset = set()
        [
            albumsset.add(track['album']) for track in self.library
            if track['artist'] == artist
        ]
        albums = list(albumsset)
        albums.sort()
        return albums
Ejemplo n.º 28
0
class GoogleClient():
    def __init__(self, username=None, password=None):
        self._username = username
        self._password = password

    # Initiates the oAuth
    def Authenticate(self):
        self.MusicManager = Musicmanager(debug_logging=False)

        attempts = 0
        # Attempt to login. Perform oauth only when necessary.
        while attempts < 3:
                if self.MusicManager.login():
                        break
                self.MusicManager.perform_oauth()
                attempts += 1

        if not self.MusicManager.is_authenticated():
                print("Sorry, login failed.")
                return False

        print("OAuth successfull\n")

        username = self._username
        password = self._password
        if not username or not password:
            cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs')
            if not os.path.isfile(cred_path):
                raise Exception(
                    'No username/password was specified. No config file could '
                    'be found either. Try creating %s and specifying your '
                    'username/password there. Make sure to chmod 600.'
                    % cred_path)
            if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
                raise Exception(
                    'Config file is not protected. Please run: '
                    'chmod 600 %s' % cred_path)
            self.config = ConfigParser.ConfigParser()
            self.config.read(cred_path)
            username = self.config.get('credentials','username')
            password = self.config.get('credentials','password')
            if not username or not password:
                raise Exception(
                    'No username/password could be read from config file'
                    ': %s' % cred_path)
        self.Api = Mobileclient(debug_logging = False)
        if not self.Api.login(username, password, Mobileclient.FROM_MAC_ADDRESS):
           raise Exception('login failed for %s' % username)

        return True
Ejemplo n.º 29
0
	def songs_uploader(self):
		ip = urllib2.urlopen('http://ip.42.pl/raw').read() #Obtain your public IP address
		mac_binary = str(get_mac()) #Obtain binary MAC address
		temp = mac_binary.replace(':', '').replace('-', '').replace('.', '').upper()
		mac_h3x = temp[:2] + ":" + ":".join([temp[i] + temp[i+1] for i in range(2,12,2)]) #Convert MAC from 48bit int to hexadecimal string
		user = pwd.getpwuid(os.getuid())[0] #Get your system's username
		
		api = Musicmanager()
		hostname = '<' + ip + '>' + '' + '(gmusicapi-{2.0.0})'
		Musicmanager.perform_oauth(storage_filepath='/home/' + user + '/.config/gmusicapi/oauth.cred', open_browser=False)
		api.login(oauth_credentials='/home/' + user + '/.config/gmusicapi/oauth.cred', uploader_id=mac_h3x, uploader_name=hostname)
		gmusicapi.clients.Musicmanager(debug_logging=True, validate=True)
		
		#newWorkingDirectory = '../home'
		#os.path.join(os.path.abspath(sys.path[0]), newWorkingDirectory) #Change the working directory
		filepath = '/home/blackram/Scrivania/BRES_/UMM/ciao.mp3'
		uploading = api.upload(filepath, transcode_quality=3, enable_matching=False)
		print 'Uploading...'
		f = open('uploading.txt','w') #log
		f.write(str(uploading))
		f.close()
		
		final = re.search("GetUploadSession error 200: this song is already uploaded", open('uploading.txt','r').read())
		if final is None:
			print '\033[32mTrack uploaded!\033[0m'
		else:
			print '\033[31mTrack already exists in your library!\033[0m'
		
		choice = raw_input("Exit from uploader? [Y/N] ")
		if choice == 'y' or choice == 'Y':
			print 'Return to main menu.'
			Musicmanager.logout(revoke_oauth=False)
			UMM.read_information()
		elif choice == 'n' or choice == 'N':
			print 'Okay.'
			UMM.songs_uploader()
Ejemplo n.º 30
0
def upload(request):
    # TODO: Async status updates?
    if not request.user.is_authenticated:
        return HttpResponse('log in first')
    credential = request.user.profile.google_oauth
    if not credential:
        return HttpResponse('no creds')
    manager = Musicmanager()
    # TODO: Maybe change mac address for each user?
    login_success = manager.login(
        credential,
        uploader_name="GMusicManagerOnline - {}".format(request.user.username))
    form = MusicUploadForm()
    args = {'can_login': login_success, 'form': form, 'success': False}
    if request.method == "POST":
        form = MusicUploadForm(request.POST, request.FILES)
        if form.is_valid():
            music = form.save()
            music_file = request.FILES.get('music_file')
            ext = music_file.name[music_file.name.rfind('.'):]
            fs = FileSystemStorage()
            filename = fs.save("{0}{1}".format(request.user.username, ext),
                               music_file)
            music_filepath = fs.path(filename)
            post_filepath = music_filepath + ".mp3"
            options = {
                i: getattr(music, i)
                for i in [
                    'title', 'album', 'composer', 'genre', 'language',
                    'artist', 'album_artist'
                ] if getattr(music, i) != ""
            }
            logger.info("Transcoding metadata: " + str(options))
            options.update({'quality': '320k'})
            _transcode(music_filepath, options, post_filepath)
            if os.path.isfile(music_filepath):
                os.remove(music_filepath)
            success, _, _ = manager.upload(  # Already transcoding.
                post_filepath,
                enable_matching=True,
                enable_transcoding=False)
            if os.path.isfile(post_filepath):
                os.remove(post_filepath)
            args.update({'success': True})
        args.update({'form': form})
    manager.logout()
    return render(request, 'core/upload.html', args)
Ejemplo n.º 31
0
def api_init():
    mm = Musicmanager()
    e = settings['email']
    creds = os.path.expanduser("~/.local/share/gmusicapi/oauth.cred") # default oauth store location
    if OTHERACCOUNT:
        e = settings['email2']
        creds = os.path.expanduser("~/.local/share/gmusicapi/oauth2.cred")
    if e is not None:
        if settings['first'] == '1' or OTHERACCOUNT and settings['first2'] == '1':
            print "Performing OAUTH for %s" % e
            mm.perform_oauth(storage_filepath=creds)
            update_first(e)
    log("Logging in as %s" % e)
    if mm.login(oauth_credentials=creds):
        return mm
    log("Login failed for second user")
    return False
Ejemplo n.º 32
0
def api_init():
  mm = Musicmanager()
  e = settings['email']
  creds = os.path.expanduser("~/.local/share/gmusicapi/oauth.cred") # default oauth store location
  if OTHERACCOUNT:
    e = settings['email2']
    creds = os.path.expanduser("~/.local/share/gmusicapi/oauth2.cred")
  if e is not None:
    if settings['first'] == '1' or OTHERACCOUNT and settings['first2'] == '1':
      print("Performing OAUTH for %s" % e)
      mm.perform_oauth(storage_filepath=creds)
      update_first(e)
  log("Logging in as %s" % e)
  if mm.login(oauth_credentials=creds, uploader_id=settings['uploader_id']):
    return mm
  log("Login failed for second user")
  return False
Ejemplo n.º 33
0
class GoogleClient():
    # Initiates the oAuth
    def Authenticate(self):
        self.MusicManager = Musicmanager(debug_logging=False)

        attempts = 0
        # Attempt to login. Perform oauth only when necessary.
        while attempts < 3:
                if self.MusicManager.login():
                        break
                self.MusicManager.perform_oauth()
                attempts += 1

        if not self.MusicManager.is_authenticated():
                print "Sorry, login failed."
                return False

        print "Successfully logged in.\n"
        return True
def setup_music_manager_api():
    global music_manager_api
    music_manager_api = Musicmanager()

    if not config.get_is_authenticated():
        print "Follow the instructions to authenticate with Google..."
        credentials = music_manager_api.perform_oauth()
        if credentials is not None:
            config.set_is_authenticated(True)
        else:
            print "Failed to authenticate, try again."
            sys.exit(0)

    music_manager_logged_in = music_manager_api.login()

    if not music_manager_logged_in:
        print "Failed to log in to the music manager API, you will be asked to authenticate again next run."

        sys.exit(0)
Ejemplo n.º 35
0
class GoogleClient():
    # Initiates the oAuth
    def Authenticate(self):
        self.MusicManager = Musicmanager(debug_logging=False)

        attempts = 0
        # Attempt to login. Perform oauth only when necessary.
        while attempts < 3:
            if self.MusicManager.login():
                break
            self.MusicManager.perform_oauth()
            attempts += 1

        if not self.MusicManager.is_authenticated():
            print "Sorry, login failed."
            return False

        print "Successfully logged in.\n"
        return True
Ejemplo n.º 36
0
class Kotone:

    def __init__(self, device_id: str, cred_mc: oauth2client.client.OAuth2Credentials, cred_mm: oauth2client.client.OAuth2Credentials):
        self._mc = Mobileclient()
        if not self._mc.oauth_login(device_id, cred_mc):
            raise RuntimeError('Mobileclient login failed')
        self._mm = Musicmanager()
        if not self._mm.login(cred_mm, _UPLOADER_ID, _UPLOADER_NAME):
            raise RuntimeError('Musicmanager login failed')

    def get_songs(self):
        return self._mc.get_all_songs()

    def download_song(self, song_id: str) -> Tuple[str, bytes]:
        return self._mm.download_song(song_id)

    def stream_url(self, song_id: str) -> str:
        return self._mc.get_stream_url(song_id)

    def upload(self, paths):
        return self._mm.upload(paths)
Ejemplo n.º 37
0
def upload(directory='.',
           oauth=os.environ['HOME'] + '/oauth',
           remove=False,
           uploader_id=__DEFAULT_MAC__,
           oneshot=False):
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)
    logger.info("Init Daemon - Press Ctrl+C to quit")

    api = Musicmanager()
    if not api.login(oauth, uploader_id):
        print("Error with oauth credentials")
        sys.exit(1)
    observer = None
    if not oneshot:
        event_handler = MusicToUpload()
        event_handler.api = api
        event_handler.oauth = oauth
        event_handler.uploader_id = uploader_id
        event_handler.path = directory
        event_handler.remove = remove
        event_handler.logger = logger
        observer = Observer()
        observer.schedule(event_handler, directory, recursive=True)
        observer.start()
    files = [
        file
        for file in glob.glob(glob.escape(directory) + '/**/*', recursive=True)
    ]
    for file_path in files:
        upload_file(api, file_path, logger, remove=remove)
    if oneshot:
        sys.exit(0)
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()
Ejemplo n.º 38
0
	print "Reading config from: " + cfg_file

	with open(cfg_file) as config_file:
		cfg = json.load(config_file)
		assert os.path.isdir(cfg['library'])
except:
	print "Failed to load configuration from settings.json"
	sys.exit();

# Login to GoogleMusic's Mobile API to get library metada
api = Mobileclient()
api.login(cfg["email"], cfg["password"], Mobileclient.FROM_MAC_ADDRESS)

# And now login to the Musicmanager to perform downloads.
mm = Musicmanager()
if (not mm.login()):
	mm.perform_oauth()

# Get the local copy of the track ids (these have been sync'd from remote)
create_path_if_not_exist(APP_DIRS.user_data_dir)
track_ids_file = os.path.join(APP_DIRS.user_data_dir, 'track_ids')
local_track_ids = None
print "Reading local Track Ids from: " + track_ids_file

try:
	with open (track_ids_file, "r") as file_handle:
		local_track_ids = json.loads(file_handle.read())
		print "Loaded {0} Track Id(s)".format(len(local_track_ids))
except IOError as io_error:
	if io_error.errno == errno.ENOENT:
		local_track_ids = []
Ejemplo n.º 39
0
class Gmusic(BeetsPlugin):
    def __init__(self):
        super(Gmusic, self).__init__()
        # Checks for OAuth2 credentials,
        # if they don't exist - performs authorization
        self.m = Musicmanager()
        if os.path.isfile(gmusicapi.clients.OAUTH_FILEPATH):
            self.m.login()
        else:
            self.m.perform_oauth()

    def commands(self):
        gupload = Subcommand('gmusic-upload',
                             help=u'upload your tracks to Google Play Music')
        gupload.func = self.upload

        search = Subcommand('gmusic-songs',
                            help=u'list of songs in Google Play Music library'
                            )
        search.parser.add_option('-t', '--track', dest='track',
                                 action='store_true',
                                 help='Search by track name')
        search.parser.add_option('-a', '--artist', dest='artist',
                                 action='store_true',
                                 help='Search by artist')
        search.func = self.search
        return [gupload, search]

    def upload(self, lib, opts, args):
        items = lib.items(ui.decargs(args))
        files = [x.path.decode('utf-8') for x in items]
        ui.print_(u'Uploading your files...')
        self.m.upload(filepaths=files)
        ui.print_(u'Your files were successfully added to library')

    def search(self, lib, opts, args):
        password = config['gmusic']['password']
        email = config['gmusic']['email']
        password.redact = True
        email.redact = True
        # Since Musicmanager doesn't support library management
        # we need to use mobileclient interface
        mobile = Mobileclient()
        try:
            mobile.login(email.as_str(), password.as_str(),
                         Mobileclient.FROM_MAC_ADDRESS)
            files = mobile.get_all_songs()
        except NotLoggedIn:
            ui.print_(
                u'Authentication error. Please check your email and password.'
            )
            return
        if not args:
            for i, file in enumerate(files, start=1):
                print(i, ui.colorize('blue', file['artist']),
                      file['title'], ui.colorize('red', file['album']))
        else:
            if opts.track:
                self.match(files, args, 'title')
            else:
                self.match(files, args, 'artist')

    @staticmethod
    def match(files, args, search_by):
        for file in files:
            if ' '.join(ui.decargs(args)) in file[search_by]:
                print(file['artist'], file['title'], file['album'])
Ejemplo n.º 40
0
#!/usr/bin/env python3
from gmusicapi import Musicmanager  # pip install gmusicapi
from glob import glob
from argparse import ArgumentParser

m = Musicmanager()
if not m.login():
    m.perform_oauth()
    m.login()


def main():
    parser = ArgumentParser()
    parser.add_argument("files", nargs="+", help="Files to upload")
    args = parser.parse_args()
    for file in args.files:
        if '*' in file:
            for subfile in glob(file):
                print("Starting on {}...".format(subfile), end="\r")
                m.upload(subfile)
                print("Completed {}     ".format(subfile))
        else:
            print("Starting on {}...".format(file), end="\r")
            m.upload(file)
            print("Completed {}     ".format(file))


if __name__ == "__main__":
    main()
Ejemplo n.º 41
0
            # Join the two strings in order to form the full filepath.
            filepath = path.join(root, filename)
            file_paths.append(filepath)
    return file_paths


def uploadfiles(api, files):
    for f in files:
        upload = api.upload(f, transcode_quality="320k", enable_matching=True)
        print(upload)


def get_dir():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-dir', action='store', dest='dir', required=True,
        help='Full directory path from which to upload songs')
    args = parser.parse_args()
    return args.dir

if __name__ == "__main__":
    directory = get_dir()

    client = Musicmanager()
    logged_in = client.login()

    if logged_in:
        print "Successfully logged in. \n" \
              "Attempting upload songs in directory {}".format(directory)
        uploadfiles(client, get_file_paths(directory))
Ejemplo n.º 42
0
from gmusicapi import Musicmanager
from os import listdir
from os.path import isfile, join
import os
import time
import subprocess

api = Musicmanager()
api.login()
mypath = '/home/pi/musics'
while True:
    onlyfiles = [ f for f in listdir(mypath) if isfile(join(mypath,f)) ]
    if len(onlyfiles) > 0:
        time.sleep(5)
        for file in onlyfiles:
            print(file)
            api.upload(mypath + '/' + file)
            os.remove(mypath + '/' + file)
	


Ejemplo n.º 43
0
class Gmusic(BeetsPlugin):
    def __init__(self):
        super(Gmusic, self).__init__()
        self.m = Musicmanager()
        self.config.add({
            u'auto': False,
            u'uploader_id': '',
            u'uploader_name': '',
            u'device_id': '',
            u'oauth_file': gmusicapi.clients.OAUTH_FILEPATH,
        })
        if self.config['auto']:
            self.import_stages = [self.autoupload]

    def commands(self):
        gupload = Subcommand('gmusic-upload',
                             help=u'upload your tracks to Google Play Music')
        gupload.func = self.upload

        search = Subcommand('gmusic-songs',
                            help=u'list of songs in Google Play Music library')
        search.parser.add_option('-t', '--track', dest='track',
                                 action='store_true',
                                 help='Search by track name')
        search.parser.add_option('-a', '--artist', dest='artist',
                                 action='store_true',
                                 help='Search by artist')
        search.func = self.search
        return [gupload, search]

    def authenticate(self):
        if self.m.is_authenticated():
            return
        # Checks for OAuth2 credentials,
        # if they don't exist - performs authorization
        oauth_file = self.config['oauth_file'].as_str()
        if os.path.isfile(oauth_file):
            uploader_id = self.config['uploader_id']
            uploader_name = self.config['uploader_name']
            self.m.login(oauth_credentials=oauth_file,
                         uploader_id=uploader_id.as_str().upper() or None,
                         uploader_name=uploader_name.as_str() or None)
        else:
            self.m.perform_oauth(oauth_file)

    def upload(self, lib, opts, args):
        items = lib.items(ui.decargs(args))
        files = self.getpaths(items)
        self.authenticate()
        ui.print_(u'Uploading your files...')
        self.m.upload(filepaths=files)
        ui.print_(u'Your files were successfully added to library')

    def autoupload(self, session, task):
        items = task.imported_items()
        files = self.getpaths(items)
        self.authenticate()
        self._log.info(u'Uploading files to Google Play Music...', files)
        self.m.upload(filepaths=files)
        self._log.info(u'Your files were successfully added to your '
                       + 'Google Play Music library')

    def getpaths(self, items):
        return [x.path for x in items]

    def search(self, lib, opts, args):
        password = config['gmusic']['password']
        email = config['gmusic']['email']
        uploader_id = config['gmusic']['uploader_id']
        device_id = config['gmusic']['device_id']
        password.redact = True
        email.redact = True
        # Since Musicmanager doesn't support library management
        # we need to use mobileclient interface
        mobile = Mobileclient()
        try:
            new_device_id = (device_id.as_str()
                             or uploader_id.as_str().replace(':', '')
                             or Mobileclient.FROM_MAC_ADDRESS).upper()
            mobile.login(email.as_str(), password.as_str(), new_device_id)
            files = mobile.get_all_songs()
        except NotLoggedIn:
            ui.print_(
                u'Authentication error. Please check your email and password.'
            )
            return
        if not args:
            for i, file in enumerate(files, start=1):
                print(i, ui.colorize('blue', file['artist']),
                      file['title'], ui.colorize('red', file['album']))
        else:
            if opts.track:
                self.match(files, args, 'title')
            else:
                self.match(files, args, 'artist')

    @staticmethod
    def match(files, args, search_by):
        for file in files:
            if ' '.join(ui.decargs(args)) in file[search_by]:
                print(file['artist'], file['title'], file['album'])
Ejemplo n.º 44
0
#! /usr/bin/env python3

from gmusicapi import Musicmanager

mm = Musicmanager()
mm.perform_oauth()
if mm.login():
    print('Authorization successful.')
    mm.logout()
else:
    print('Authorization failed.')
Ejemplo n.º 45
0
class Gmusic(BeetsPlugin):
    def __init__(self):
        super(Gmusic, self).__init__()
        # Checks for OAuth2 credentials,
        # if they don't exist - performs authorization
        self.m = Musicmanager()
        if os.path.isfile(gmusicapi.clients.OAUTH_FILEPATH):
            self.m.login()
        else:
            self.m.perform_oauth()

    def commands(self):
        gupload = Subcommand('gmusic-upload',
                             help=u'upload your tracks to Google Play Music')
        gupload.func = self.upload

        search = Subcommand('gmusic-songs',
                            help=u'list of songs in Google Play Music library')
        search.parser.add_option('-t',
                                 '--track',
                                 dest='track',
                                 action='store_true',
                                 help='Search by track name')
        search.parser.add_option('-a',
                                 '--artist',
                                 dest='artist',
                                 action='store_true',
                                 help='Search by artist')
        search.func = self.search
        return [gupload, search]

    def upload(self, lib, opts, args):
        items = lib.items(ui.decargs(args))
        files = [x.path.decode('utf-8') for x in items]
        ui.print_(u'Uploading your files...')
        self.m.upload(filepaths=files)
        ui.print_(u'Your files were successfully added to library')

    def search(self, lib, opts, args):
        password = config['gmusic']['password']
        email = config['gmusic']['email']
        password.redact = True
        email.redact = True
        # Since Musicmanager doesn't support library management
        # we need to use mobileclient interface
        mobile = Mobileclient()
        try:
            mobile.login(email.as_str(), password.as_str(),
                         Mobileclient.FROM_MAC_ADDRESS)
            files = mobile.get_all_songs()
        except NotLoggedIn:
            ui.print_(
                u'Authentication error. Please check your email and password.')
            return
        if not args:
            for i, file in enumerate(files, start=1):
                print(i, ui.colorize('blue', file['artist']), file['title'],
                      ui.colorize('red', file['album']))
        else:
            if opts.track:
                self.match(files, args, 'title')
            else:
                self.match(files, args, 'artist')

    @staticmethod
    def match(files, args, search_by):
        for file in files:
            if ' '.join(ui.decargs(args)) in file[search_by]:
                print(file['artist'], file['title'], file['album'])
    print(
        "Since this is your first time using the app you will need to allow your google account to authenticate..."
    )
    print(
        "If you would like to change the app settings please modify the config file."
    )
    mm.perform_oauth()
    config = open("yt2gpmCONFIG.txt", "w")
    firstRun = False
    config.write(
        f"firstRun:{firstRun}\nYoutube-DL Args:{ytDlString}\nremoveDownloadedFile (saves storage space):{removeFile}"
    )
    config.close()

print("Attempting to login to GPM.")
mm.login()
print(f"Successfuly logged into GPM, Uploading file: {latestFile}...")

c = mm.upload(latestFile)
mm.logout()

print("File upload complete! Finishing up.")

# remove mp3 file from directory (default)
# if you want to keep the file change config (removeFile to true)
if "True" in removeFile:
    os.remove(latestFile)
    print("Removed downloaded file. Goodbye.")
else:
    print("Goodbye.")
time.sleep(1)
			else:
				print " upload failed !"
				upload_ok = False
		# remove uploaded file
		if upload_ok :
			os.remove(PUSH_DIR + musique)



# init
id_list={}
try : id_list = marshal.load(open(DICT_FILE, "rb"))
except : pass

mm = Musicmanager()
if not mm.login() :
	mm.perform_oauth()
	mm.login()

for arg in sys.argv :
	if arg == 'pull' :
		print 'pulling...'
		pull()
	elif arg == 'push' :
		print 'pushing...'
		push()


# finish
mm.logout()
marshal.dump(id_list, open(DICT_FILE, 'wb'))
Ejemplo n.º 48
0
class MusicSync(object):
    def __init__(self, email=None, password=None):
        self.mm = Musicmanager()
        self.wc = Webclient()
        self.mc = Mobileclient()
        if not email:
            email = raw_input("Email: ")
        if not password:
            password = getpass()

        self.email = email
        self.password = password

        self.logged_in = self.auth()

        print "Fetching playlists from Google..."
        self.playlists = self.wc.get_all_playlist_ids(auto=False)
        print "Got %d playlists." % len(self.playlists["user"])
        print ""

    def auth(self):
        self.logged_in = self.wc.login(self.email, self.password)
        self.logged_in = self.mc.login(self.email, self.password)
        if not self.logged_in:
            print "Login failed..."
            exit()

        print ""
        print "Logged in as %s" % self.email
        print ""

        if not os.path.isfile(OAUTH_FILEPATH):
            print "First time login. Please follow the instructions below:"
            self.mm.perform_oauth()
        self.logged_in = self.mm.login()
        if not self.logged_in:
            print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH
            exit()

        print "Authenticated"
        print ""

    def add_rhapsody_playlist(self, filename, remove_missing=False):
        filename = self.get_platform_path(filename)
        os.chdir(os.path.dirname(filename))
        # playlist_title = os.path.splitext(os.path.basename(filename))[0]
        print "Synching File: %s" % filename

        print "Parsing Songs from %s" % filename
        pc_songs = self.get_songs_from_file(filename)
        # print (pc_songs)
        print "%d songs in local file: %s" % (len(pc_songs), filename)

        # Sanity check max 1000 songs per playlist
        if len(pc_songs) > MAX_SONGS_IN_PLAYLIST:
            print "    Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST
            print "    Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST
            del pc_songs[MAX_SONGS_IN_PLAYLIST:]

        existing_files = 0
        added_files = 0
        failed_files = 0
        removed_files = 0
        fatal_count = 0

        for song in pc_songs:
            playlist_title = song["playlist"]
            if playlist_title not in self.playlists["user"]:
                self.playlists["user"][playlist_title] = [self.mc.create_playlist(playlist_title)]
                time.sleep(0.7)
        print "Starting Playlist Sync with Google music..."
        for song in pc_songs:
            # print song

            plid = ""

            print "--------------------------------"
            print ""
            print "Playlist: %s" % song["playlist"]
            print "Artist: %s" % song["artist"]
            print "Song: %s" % song["title"]
            print "Album: %s" % song["album"]

            playlist_title = song["playlist"]

            plid = self.playlists["user"][playlist_title][0]

            goog_songs = self.wc.get_playlist_songs(plid)

            if self.song_already_in_list(song, goog_songs):
                existing_files += 1
                print "Result: Song Already Added"
                continue
            print "Total %d songs in Google playlist: %s" % (len(goog_songs), playlist_title)
            print "%s - %s,   didn't exist...Will try to add..." % (song["artist"], song["title"])

            print ""
            print "--------------------------------"
            results = self.mc.search_all_access(song["title"], max_results=50)
            nid = self.filter_search_results(results, song)
            print "AA nId: %s " % nid
            if nid:
                song_id = self.mc.add_aa_track(nid)
                added = self.wc.add_songs_to_playlist(plid, song_id)

                print "Playlist UUid: %s" % plid
                print "Song ID: %s" % song_id
                time.sleep(0.3)  # Don't spam the server too fast...
                print "Result: done adding to playlist"
                added_files += 1
                continue
            else:
                query = "%s %s" % (song["artist"], song["title"].split(" ")[0])
                print "Query %s" % query
                results = self.mc.search_all_access(query, max_results=50)
                nid = self.filter_search_results(results, song)
                if nid:
                    song_id = self.mc.add_aa_track(nid)
                    added = self.wc.add_songs_to_playlist(plid, song_id)

                    print "Playlist UUid: %s" % plid
                    print "Song ID: %s" % song_id
                    time.sleep(0.3)  # Don't spam the server too fast...
                    print " -- done adding to playlist"
                    added_files += 1
                    continue
            print "Result: NID Blank, Song not Found in All Access"

        print ""
        print "---"
        print "%d songs unmodified" % existing_files
        print "%d songs added" % added_files
        print "%d songs failed" % failed_files
        print "%d songs removed" % removed_files

    def get_songs_from_file(self, filename):
        songs = []
        f = codecs.open(filename, encoding="utf-8")
        for line in f:
            line = line.rstrip().replace(u"\ufeff", u"")
            if line == "" or line[0] == "#":
                continue
            la = line.split("\\")
            regex_filter = "[^A-Za-z0-9\,\-\.\ \(\)'\!\?\$\/ \& \:]"

            artist = re.sub(regex_filter, "", la[1])
            playlist = re.sub(regex_filter, "", la[0])
            album = re.sub(regex_filter, "", la[2])
            title = re.sub(regex_filter, "", la[3])

            # print "Filtered Strings:"
            # print "Artist: %s" % artist
            # print "Playlist: %s" % playlist
            # print "Song: %s" % title
            # print "Album: %s" % album

            dt = {"playlist": playlist, "artist": artist, "album": album, "title": title}
            # print (dt)

            songs.append(dt)
        f.close()
        return songs

    def get_songs_from_playlist(self, filename):
        songs = []
        f = codecs.open(filename, encoding="utf-8")
        for line in f:
            line = line.rstrip().replace(u"\ufeff", u"")
            if line == "" or line[0] == "#":
                continue
            path = os.path.abspath(self.get_platform_path(line))
            # if not os.path.exists(path):
            #   print "File not found: %s" % line
            #  continue
            songs.append(path)
        f.close()
        return songs

    def get_files_from_playlist(self, filename):
        files = []
        f = codecs.open(filename, encoding="utf-8")
        for line in f:
            line = line.rstrip().replace(u"\ufeff", u"")
            if line == "" or line[0] == "#":
                continue
            path = os.path.abspath(self.get_platform_path(line))
            if not os.path.exists(path):
                print "File not found: %s" % line
                continue
            files.append(path)
        f.close()
        return files

    def song_already_in_list(self, song, goog_songs):
        # tag = self.get_id3_tag(filename)
        i = 0
        while i < len(goog_songs):
            # print goog_songs
            if self.tag_compare(goog_songs[i], song):
                goog_songs.pop(i)
                return True
            i += 1
        return False

    def file_already_in_list(self, filename, goog_songs):
        tag = self.get_id3_tag(filename)
        i = 0
        while i < len(goog_songs):
            if self.tag_compare(goog_songs[i], tag):
                goog_songs.pop(i)
                return True
            i += 1
        return False

    def get_id3_tag(self, filename):
        data = mutagen.File(filename, easy=True)
        r = {}
        if "title" not in data:
            title = os.path.splitext(os.path.basename(filename))[0]
            print "Found song with no ID3 title, setting using filename:"
            print "  %s" % title
            print "  (please note - the id3 format used (v2.4) is invisible to windows)"
            data["title"] = [title]
            data.save()
        r["title"] = data["title"][0]
        r["track"] = int(data["tracknumber"][0].split("/")[0]) if "tracknumber" in data else 0
        # If there is no track, try and get a track number off the front of the file... since thats
        # what google seems to do...
        # Not sure how google expects it to be formatted, for now this is a best guess
        if r["track"] == 0:
            m = re.match("(\d+) ", os.path.basename(filename))
            if m:
                r["track"] = int(m.group(0))
        r["artist"] = data["artist"][0] if "artist" in data else ""
        r["album"] = data["album"][0] if "album" in data else ""
        return r

    def find_song(self, filename, plid):
        tag = self.get_id3_tag(filename)
        print "Song Tag: %s " % tag
        print "Filename: %s" % filename
        ws_plids = []
        ws_plids.append(plid)
        print (ws_plids)
        playlists = self.wc.get_all_playlist_ids()
        print (playlists)
        results = self.wc.get_playlist_songs(ws_plids)
        # NOTE - dianostic print here to check results if you're creating duplicates
        print results
        print "%s ][ %s ][ %s ][ %s" % (tag["title"], tag["artist"], tag["album"], tag["track"])
        for r in results:
            if self.tag_compare(r, tag):
                # TODO: add rough time check to make sure its "close"
                return r
        return None

    def filter_search_results(self, results, song):
        # Try Exact Matching
        for g_song in results["song_hits"]:
            if self.tag_compare(g_song["track"], song):
                return g_song["track"]["nid"]
            elif self.song_compare(g_song["track"], song, "artist"):
                # try just the artist
                return g_song["track"]["nid"]
            elif self.song_compare(g_song["track"], song, "part-song"):
                # try part of song and artist
                return g_song["track"]["nid"]
        return None

    def song_compare(self, g_song, tag, type):
        if "track" not in g_song:
            g_song["track"] = 0
        title_parts = tag["title"].split("(")  # removing shit like (featuring wiz)
        tp = title_parts[0].split(" ")  # First word maybe
        if "artist" in type:
            return g_song["artist"].lower() == tag["artist"].lower()
        if "part-song" in type:
            return g_song["title"].find(tp[0]) and g_song["artist"].lower() == tag["artist"].lower()

        return None

    def tag_compare(self, g_song, tag):
        if "track" not in g_song:
            g_song["track"] = 0

        return (
            g_song["title"].split(" ")[0].lower() == tag["title"].split(" ")[0].lower()
            and g_song["artist"].lower() == tag["artist"].lower()
        )

    def delete_song(self, sid):
        self.wc.delete_songs(sid)
        print "Deleted song by id [%s]" % sid

    def get_platform_path(self, full_path):
        # Try to avoid messing with the path if possible
        if os.sep == "/" and "\\" not in full_path:
            return full_path
        if os.sep == "\\" and "\\" in full_path:
            return full_path
        if "\\" not in full_path:
            return full_path
        return os.path.normpath(full_path.replace("\\", "/"))
class MusicSync(object):
    def __init__(self, email=None, password=None):
        self.mm = Musicmanager()
        self.wc = Webclient()
        if not email:
            email = raw_input("Email: ")
        if not password:
            password = getpass()

        self.email = email
        self.password = password

        self.logged_in = self.auth()

        print "Fetching playlists from Google..."
        self.playlists = self.wc.get_all_playlist_ids(auto=False)
        print "Got %d playlists." % len(self.playlists['user'])
        print ""


    def auth(self):
        self.logged_in = self.wc.login(self.email, self.password)
        if not self.logged_in:
            print "Login failed..."
            exit()

        print ""
        print "Logged in as %s" % self.email
        print ""

        if not os.path.isfile(OAUTH_FILEPATH):
            print "First time login. Please follow the instructions below:"
            self.mm.perform_oauth()
        self.logged_in = self.mm.login()
        if not self.logged_in:
            print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH
            exit()

        print "Authenticated"
        print ""


    def sync_playlist(self, artist_title_array, playlist_title = -99):
        if playlist_title == -99:
            title = "GMusicSync Playlist %3d"%time.time()
        else: title = str(playlist_title)
        print "Synching playlist: %s" % title
        if title not in self.playlists['user']:
            print "   didn't exist... creating..."
            self.playlists['user'][title] = [self.wc.create_playlist(title)]
        print ""

        plid = self.playlists['user'][title][0]
        goog_songs = self.wc.get_playlist_songs(plid)
        print "%d songs already in Google Music playlist" % len(goog_songs)
        pc_songs = artist_title_array
        print "%d songs in local playlist" % len(pc_songs)

        # Sanity check max 1000 songs per playlist
        if len(pc_songs) > MAX_SONGS_IN_PLAYLIST:
            print "    Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST
            print "    Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST
            del pc_songs[MAX_SONGS_IN_PLAYLIST:]

        existing_files = 0
        added_files = 0
        failed_files = 0
        removed_files = 0
        fatal_count = 0

        for fn in pc_songs:
            if self.file_already_in_list(fn, goog_songs):
                existing_files += 1
                continue
            print ""
            try:
                print "Adding: %s - %s"%(fn[0],fn[1])
            except:
                print "Incorrect format for %r, expecting ('artist','title')"%fn
                continue
            online = self.find_song(fn)
            song_id = None
            if online:
                song_id = online['id']
                print "   already uploaded [%s]" % song_id
            else:
                print "   Sorry, can't find song."

            if not song_id:
                failed_files += 1
                continue

            added = self.wc.add_songs_to_playlist(plid, song_id)
            time.sleep(.3) # Don't spam the server too fast...
            print "   done adding to playlist"
            added_files += 1

        print ""
        print "---"
        print "%d songs unmodified" % existing_files
        print "%d songs added" % added_files
        print "%d songs failed" % failed_files
        print "%d songs removed" % removed_files


    def get_files_from_playlist(self, filename):
        files = []
        f = codecs.open(filename, encoding='utf-8')
        for line in f:
            line = line.rstrip().replace(u'\ufeff',u'')
            if line == "" or line[0] == "#":
                continue
            path  = os.path.abspath(self.get_platform_path(line))
            if not os.path.exists(path):
                print "File not found: %s" % line
                continue
            files.append(path)
        f.close()
        return files

    def file_already_in_list(self, artist_title, goog_songs):
        i = 0
        while i < len(goog_songs):
            if self.song_compare(goog_songs[i], artist_title):
                goog_songs.pop(i)
                return True
            i += 1
        return False

    def find_song(self, artist_title):
        try:
            artist = artist_title[0]
            title = artist_title[1]
        except: return None
        results = self.wc.search(title)
        print "\t",results[:2]
        for r in results['song_hits']:
            if self.song_compare(r, artist_title):
                return r
        return None

    def song_compare(self, g_song, artist_title):
        try:
            artist = artist_title[0]
            title = artist_title[1]
        except: return False
        # TODO: add fuzzy matching
        return g_song['title'].lower() == title.lower() and\
               g_song['artist'].lower() == artist.lower()

    def get_platform_path(self, full_path):
        # Try to avoid messing with the path if possible
        if os.sep == '/' and '\\' not in full_path:
            return full_path
        if os.sep == '\\' and '\\' in full_path:
            return full_path
        if '\\' not in full_path:
            return full_path
        return os.path.normpath(full_path.replace('\\', '/'))
Ejemplo n.º 50
0
from gmusicapi import Musicmanager, clients
from node_translator import Translator
import sys, json

translator = Translator()

# Get file paths from node
file_names = translator.get_input()

# Returns path to system stored oauth
oauth_path = clients.OAUTH_FILEPATH

# Init Musicmanager and login
mm = Musicmanager()
is_logged_in = mm.login(oauth_path)

if is_logged_in:
    # Matching set to false due to lack of ffmpeg or avconv
    upload_result = mm.upload(file_names, '320k', False)
    print json.dumps(upload_result)
    # return upload_result

    if upload_result[0] != {}:
        print('Something happened here!')
else:
    sys.exit('Not logged in')




Ejemplo n.º 51
0
class FreeClient(Client):
    """
    Client for free users with limited functionality.
      Free users only have access to songs that they have either purchased
      or uploaded, and they must be downloaded before they can be played.
      Artists and albums cannot be generated, so the expand and radio methods
      have no use.
    """
    def __init__(self):
        """
        Log into Musicmanager and get the library, either by loading an
          existing library file, or by generating a new one.
        """
        self.kind = 'free'
        self.mm = Musicmanager()
        self.mm.login()
        self.songs = []
        self.load_library()
        if not self.songs:
            self.gen_library()

    def load_library(self):
        path = join(common.DATA_DIR, 'library.zip')
        common.w.outbar_msg('Loading library...')
        if not isfile(path):
            common.w.addstr(common.w.infobar, 'Could not find library file.')
            return
        try:
            with zipfile.ZipFile(path) as z:
                try:
                    lib = json.loads(z.read('library.json').decode('utf-8'))
                except json.JSONDecodeError:  # The .json file is invalid.
                    common.w.addstr(
                        common.w.infobar, 'Library file is corrupt.'
                    )
                    return
        except zipfile.BadZipFile:  # The .zip file is invalid.
            common.w.addstr(common.w.infobar, 'Library file is corrupt.')
            return

        for item in lib['songs']:
            try:
                self.songs.append(
                    music_objects.LibrarySong(item, source='json'))
            except KeyError:  # The file has the wrong data.
                common.w.addstr(common.w.infobar, 'Library file is corrupt.')
                return

        l = len(self.songs)
        common.w.outbar_msg('Loaded %s song%s.' % (l, '' if l is 1 else 's'))

    def gen_library(self):
        ids = []  # Avoid duplicates between purchased and uploaded songs.
        common.w.outbar_msg('Generating your library...')

        for song in self.mm.get_uploaded_songs():
            if song['id'] not in ids:
                self.songs.append(music_objects.LibrarySong(song))
                ids.append(song['id'])
        for song in self.mm.get_purchased_songs():
            if song['id'] not in ids:
                self.songs.append(music_objects.LibrarySong(song))
                ids.append(song['id'])
        # Todo: Use something other than json for library storage since it
        # doesn't really make logical sense (songs is a list, not a dict),
        # but for now it's very easy to use.
        with zipfile.ZipFile(join(common.DATA_DIR, 'library.zip'), 'w') as z:
            z.writestr('library.json', json.dumps({'songs': self.songs}))
        l = len(self.songs)
        common.w.outbar_msg(
            'Generated %d song%s.' % (l, '' if l is 1 else 's')
        )
        common.w.now_playing()

    def expand(self, arg=None):
        """
        Artists/albums cannot be generated. so free users cannot expand songs..

        Keyword arguments:
        arg=None: Irrelevant.
        """
        common.q.error_msg('Free users cannot use expand')

    def radio(self, arg=None):
        """
        Artists/albums cannot be generated. so free users cannot create radio
        stations.

        Keyword arguments:
        arg=None: Irrelevant.
        """
        common.q.error_msg('Free users cannot use radio')

    def search(self, query):
        """
        Search the library for some query. and update the
          view with the results.

        Keyword arguments:
        query=None: The search query.
        """
        if query is None:
            common.w.error_msg('Missing search query')
            return

        # Save the current view in case there are no results.
        cache = common.v.copy()

        if common.w.curses:
            limit = common.w.ylimit - 4
        else:
            limit = 10
        common.w.outbar_msg('Searching for \'%s\'...' % query)
        common.v.clear()
        count, query = 0, query.lower()  # Search is case-insensitive.
        for song in self.songs:
            if any(query in song[k].lower()
                   for k in ('name', 'artist', 'album')):
                count += 1
                common.v['songs'].append(song)
                if count == limit:
                    break
        common.w.outbar_msg('Search returned %d results.' % len(common.v))

        if common.v.is_empty():
            common.v.replace(cache)
Ejemplo n.º 52
0
class User:
    def __init__(self, email, app_data_dir):
        self.email = email
        self.app_data_dir = app_data_dir
        self.db_lock = threading.Lock()

    def init(self, oauth_credentials):
        # Initialize the database
        logger.info("%s: Initializing database" % self.email)
        self._data_init()
        # Create the Musicmanager
        logger.info("%s: Logging in to Google music" % self.email)
        self.mm = Musicmanager()
        if not self.mm.login(oauth_credentials):
            logger.info("%s: Error logging in to Google music" % self.email)
            return False
        # Check if we already have any watch paths configured
        config = self._read_config()
        watched_paths = config["watched_paths"] if "watched_paths" in config else []
        logger.info("%s: Found previously watched paths %s" % (self.email, watched_paths))
        # Create the FileWatcher
        logger.info("%s: Creating the FileWatcher" % (self.email))
        self.fw = FileWatcher(self.email, self._finished_writing_callback, watched_paths)
        return True

    def logout(self):
        self.mm.logout()
        self.fw.stop_watching()

    def _read_config(self):
        return util.read_config(os.path.join(self.app_data_dir, self.email, CFG_FILE_NAME))

    def _write_config(self, config):
        util.write_config(config, os.path.join(self.app_data_dir, self.email, CFG_FILE_NAME))

    def get_watched_paths(self):
        logger.debug("reading config from %s" % os.path.join(self.app_data_dir, self.email))
        config = self._read_config()
        logger.debug("read config: %s" % config)
        return config["watched_paths"] if "watched_paths" in config else []

    def add_watch_path(self, path):
        # Add to file watcher
        self.fw.watch(path)
        # Add to the config
        config = self._read_config()
        if "watched_paths" not in config:
            config["watched_paths"] = [path]
        else:
            if path not in config["watched_paths"]:
                config["watched_paths"].append(path)
        self._write_config(config)

    def remove_watch_path(self, path):
        # Remove from the file watcher
        self.fw.remove_watch(path)
        # Remove from the config
        config = self._read_config()
        if "watched_paths" in config:
            if path in config["watched_paths"]:
                config["watched_paths"].remove(path)
        else:
            logger.info("%s trying to remove watch path %s that we weren't watching" % (self.email, path))
        self._write_config(config)

    def set_default_action(self, default_action):
        config = self._read_config()
        config["default_action"] = default_action
        self._write_config(config)

    def get_default_action(self):
        config = self._read_config()
        return config.get("default_action", "scan_only")

    def scan_existing_files(self):
        watched_paths = self.get_watched_paths()
        logger.debug("%s Scanning existing files in these directories: %s" % (self.email, watched_paths))
        for watched_path in watched_paths:
            logger.debug("Scanning existing files in %s" % watched_path)
            for root, subFolders, files in os.walk(watched_path):
                logger.debug("root: %s, subfolders: %s, files: %s" % (root, subFolders, files))
                for file in files:
                    filename, fileExtension = os.path.splitext(file)
                    logger.debug("looking at file %s, filename = %s, file extension = %s" % (file, filename, fileExtension))
                    if fileExtension == ".mp3":
                        logger.debug("Found file %s" % file);
                        self._update_path(os.path.join(root, file), FileStatus.Scanned)
        logger.debug("scanning finished");

    def upload_scanned(self):
        songs = self.get_all_songs() 
        for song_path in songs.keys():
            if songs[song_path]["status"] == FileStatus.Scanned:
                logger.debug("Uploading song %s" % song_path)
                self.upload(song_path)
        return


    def _data_init(self):
        with self.db_lock:
            con = sql.connect(os.path.join(self.app_data_dir, self.email, DB_NAME))
            with con:
                cur = con.cursor()
                cur.execute('''CREATE TABLE IF NOT EXISTS songs(path TEXT PRIMARY KEY, id TEXT, status TEXT)''')

    def _update_path(self, path, status, id=None, override=False):
        logger.info("Updating path %s with id %s and status %s" % (path, id, status))
        info = ((path,
                 "" if not id else id,
                 status)
                )

        with self.db_lock:
            con = sql.connect(os.path.join(self.app_data_dir, self.email, DB_NAME))
            with con:
                cur = con.cursor()
                if not override:
                    # Check if the song is already in the data store and, if so, what its status is
                    cur.execute('''SELECT status FROM songs WHERE path=(?)''', (path,))
                    res = cur.fetchone()
                    if res:
                        res = res[0]
                        if res == FileStatus.Uploaded:
                            # If it's already been uploaded, don't override that status with something else
                            return
                cur.execute('''REPLACE INTO songs VALUES(?, ?, ?)''', info)

    def _finished_writing_callback(self, new_file_path):
        logger.debug("New file %s" % new_file_path)
        filename, file_extension = os.path.splitext(new_file_path)
        if file_extension != ".mp3":
            logger.debug("Skipping non-mp3 file")
            return
        self._update_path(new_file_path, FileStatus.Scanned)
        if self.get_default_action() == "auto_upload":
            logger.info("Uploading new file: %s" % new_file_path)
            self.upload(new_file_path)

    @staticmethod
    def _find_gmusic_song(scanned_song_tags, gmusic_songs):
        try:
            artist = scanned_song_tags.artist.lower()
            album = scanned_song_tags.album.lower()
            title = scanned_song_tags.title.lower()
            #logger.debug("Found scanned song %s - %s - %s" % (artist, album, title))
        except:
            logger.debug("Error grabbing song meta data")
            return
        # Search for an uploaded song that matches
        for gmusic_song in gmusic_songs:
            up_artist = gmusic_song['artist'].lower()
            up_album = gmusic_song['album'].lower()
            up_title = gmusic_song['title'].lower()
            #logger.debug("Looking at song %s - %s - %s" % (up_artist, up_album, up_title))
            if artist == up_artist and album == up_album and title == up_title:
                #logger.debug("Found match!")
                return gmusic_song
        return None

    def sync_library(self):
        logger.debug("Syncing")
        uploaded_songs = self.mm.get_all_songs()
        scanned_songs = self.get_all_songs()
        logger.debug("found %d scanned songs" % len(scanned_songs))
        # Go through all songs marked 'scanned' and search for a matching that's already been uploaded.
        #  If we find one, grab the id and mark the song as uploaded
        for song_path in scanned_songs.keys():
            # Since we only have the path, scan its tags to get the meta data
            audioFile = eyed3.load(song_path)
            if audioFile and audioFile.tag:
                local_song = scanned_songs[song_path]
                gmusic_song = User._find_gmusic_song(audioFile.tag, uploaded_songs)
                # Now make sure our static is in sync, possibilities:
                # 1) We show it as uploaded but google doesn't -> mark it as 'scanned', remove our id
                # 2) Google shows it as uploaded but we don't -> mark it as 'uploaded', add the id
                # 3) We both show it as uploaded and the ids match -> do nothing
                # 4) Neither of us think it was uploaded -> do nothing
                # 5) Google has it but we don't at all -> TODO!! (option for download?) we'll need to detect this another way (currently searching only by scanned songs)
                if gmusic_song:
                    # Google shows this song
                    if local_song['status'] == FileStatus.Scanned:
                        # Google shows it as uploaded but we don't.  Mark it as uploaded and update the id
                        #logger.debug("'%s - %s - %s' was already uploaded, updating its id to %s" % (gmusic_song['artist'], gmusic_song['album'], gmusic_song['title'], gmusic_song['id']))
                        self._update_path(song_path, FileStatus.Uploaded, gmusic_song['id'], override=True)
                    elif local_song['status'] == FileStatus.Uploaded:
                        # We both show it as uploaded, make sure ids match
                        if local_song['id'] != gmusic_song['id']:
                            #logger.debug("Ids differ!  Updating to use google's id")
                            self._update_path(song_path, FileStatus.Uploaded, gmusic_song['id'], override=True)
                        else:
                            pass
                            #logger.debug("Ids match! No update needed")
                else:
                    # No matching song on google found
                    if local_song['status'] == FileStatus.Uploaded:
                        #logger.debug("We show the song as uploaded but google doesn't, changing status to scanned and clearing id")
                        self._update_path(song_path, FileStatus.Scanned, override=True)
                    else:
                        pass
                        #logger.debug("Neither side thinks it's uploaded, no update needed")
            else:
                logger.debug("Error loading metadata for song %s" % song_path)

    def upload(self, file_path):
        uploaded, matched, not_uploaded = self.mm.upload(file_path, enable_matching=False) # async me!
        if uploaded:
            logger.info("Uploaded song %s with ID %s" % (file_path, uploaded[file_path]))
            self._update_path(file_path, FileStatus.Uploaded, uploaded[file_path])
        if matched:
            logger.info("Matched song %s with ID %s" % (file_path, matched[file_path]))
            self._update_path(file_path, FileStatus.Uploaded, uploaded[file_path])
        if not_uploaded:
            reason_string = not_uploaded[file_path]
            if "ALREADY_EXISTS" in reason_string:
                song_id = reason_string[reason_string.find("(") + 1 : reason_string.find(")")]
                logger.info("Song already exists with ID %s, updating database" % song_id)
                # The song ID is located within parentheses in the reason string
                self._update_path(file_path, FileStatus.Uploaded, song_id)
            else:
                logger.info("Unable to upload song %s because %s" % (file_path, reason_string))
                self._update_path(file_path, FileStatus.Error, reason_string)

    def get_all_songs(self):
        songs = {}
        with self.db_lock:
            con = sql.connect(os.path.join(self.app_data_dir, self.email, DB_NAME))
            with con:
                cur = con.cursor()
                for row in cur.execute('''SELECT * FROM songs'''):
                    song_path = row[0]
                    song_id = row[1]
                    song_status = row[2]
                    songs[song_path] = {'id': song_id,
                                        'status': song_status}

        return songs
Ejemplo n.º 53
0
#!/usr/bin/env python2
# see http://unofficial-google-music-api.readthedocs.org/en/latest/usage.html#usage
# arch linux 'pacman -S python2-pip && pip2 install gmusicapi'

from gmusicapi import Musicmanager
from gmusicapi.compat import my_appdirs
import sys
import os.path

mm = Musicmanager()

# TODO use generic path for credentials
OAUTH_FILEPATH = os.path.join(my_appdirs.user_data_dir, 'oauth.cred')
if not os.path.isfile(OAUTH_FILEPATH):
    mm.perform_oauth()

mm.login()
# TODO handle errors (existing tracks/duplicates ...)
# TODO handle errors (existing tracks/duplicates ...)
track = sys.argv[1]
uploaded, matched, not_uploaded = mm.upload(track)
if uploaded[track]:
    sys.exit(0)
sys.exit(1)
Ejemplo n.º 54
0
class MusicLibrary(object):
    'Read information about your Google Music library'
    
    def __init__(self, username=None, password=None,
                 true_file_size=False, scan=True, verbose=0):
        self.verbose = False
	self.manager_id = 0
        if verbose > 1:
            self.verbose = True

        self.__login_and_setup(username, password)
	self.__register_music_manager()
        if scan:
            self.rescan()
        self.true_file_size = true_file_size

    def rescan(self):
        self.__artists = {} # 'artist name' -> {'album name' : Album(), ...}
        self.__albums = [] # [Album(), ...]
        self.__aggregate_albums()

    def __login_and_setup(self, username=None, password=None):
        # If credentials are not specified, get them from $HOME/.gmusicfs
        if not username or not password:
            cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs')
            if not os.path.isfile(cred_path):
                raise NoCredentialException(
                    'No username/password was specified. No config file could '
                    'be found either. Try creating %s and specifying your '
                    'username/password there. Make sure to chmod 600.'
                    % cred_path)
            if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
                raise NoCredentialException(
                    'Config file is not protected. Please run: '
                    'chmod 600 %s' % cred_path)
            self.config = ConfigParser.ConfigParser()
            self.config.read(cred_path)
            username = self.config.get('credentials','username')
            password = self.config.get('credentials','password')
            if not username or not password:
                raise NoCredentialException(
                    'No username/password could be read from config file'
                    ': %s' % cred_path)
                
        self.api = GoogleMusicAPI(debug_logging=self.verbose)
        log.info('Logging in...')
        self.api.login(username, password)
        log.info('Login successful.')

    def __register_music_manager(self):
	self.manager = GoogleMusicManager()
	self.manager_id = ':'.join(re.findall('..', '%012x' % uuid.getnode())).upper()
	log.info('Registering the google music manager...')
        cred_path = os.path.join(os.path.expanduser('~'), '.gmusicfs.ocred')
	if not os.path.isfile(cred_path):
	    log.info('Authorizing GMusicFS application against Google...')
	    self.manager.perform_oauth(storage_filepath=cred_path)
	    os.chmod(cred_path, 0600)
        if not oct(os.stat(cred_path)[os.path.stat.ST_MODE]).endswith('00'):
            raise NoCredentialException(
                'Config file is not protected. Please run: '
                'chmod 600 %s' % cred_path)
	self.manager.login(cred_path, self.manager_id, 'GMusicFS')
	log.info('Successfully registered the google music manager...')
        
    def __aggregate_albums(self):
        'Get all the tracks in the library, parse into artist and album dicts'
        all_artist_albums = {} # 'Artist|||Album' -> Album()
        log.info('Gathering track information...')
        tracks = self.api.get_all_songs()
        for track in tracks:
            # Prefer the album artist over the track artist if there is one:
            artist = normalize(track['artist'])
            # Get the Album object if it already exists:
            key = '%s|||%s' % (formatNames(artist), formatNames(normalize(track['album'])))
            album = all_artist_albums.get(key, None)
            if not album:
                # New Album
                if artist == '':
                    artist = 'unknown'
                album = all_artist_albums[key] = Album(
                    self, formatNames(normalize(track['album'])))
                self.__albums.append(album)
                artist_albums = self.__artists.get(artist, None)
                if artist_albums:
                    artist_albums[formatNames(album.normtitle)] = album
                else:
                    self.__artists[artist] = {album.normtitle: album}
                    artist_albums = self.__artists[artist]
            album.add_track(track)
        log.debug('%d tracks loaded.' % len(tracks))
        log.debug('%d artists loaded.' % len(self.__artists))
        log.debug('%d albums loaded.' % len(self.__albums))

    def get_artists(self):
        return self.__artists

    def get_albums(self):
        return self.__albums

    def get_artist_albums(self, artist):
        log.debug(artist)
        return self.__artists[artist]

    def cleanup(self):
        pass
Ejemplo n.º 55
0
class MusicSync(object):
    def __init__(self, email=None, password=None):
        self.mm = Musicmanager()
        self.wc = Webclient()
        self.mc = Mobileclient()
        if not email:
            email = raw_input("Email: ")
        if not password:
            password = getpass()

        self.email = email
        self.password = password

        self.logged_in = self.auth()

        print "Fetching playlists from Google..."
        self.playlists = self.mc.get_all_user_playlist_contents()
        #self.playlists = self.mc.get_all_playlists()
        #self.playlists = self.wc.get_all_playlist_ids(auto=False)
        self.all_songs = self.mc.get_all_songs()
        #print "Got %d playlists." % len(self.playlists['user'])
        print "Got %d playlists containing %d songs." % (len(self.playlists), len(self.all_songs))
        print ""


    def auth(self):
        self.logged_in = self.mc.login(self.email, self.password)
        #self.logged_in = self.wc.login(self.email, self.password)
        if not self.logged_in:
            print "Login failed..."
            exit()

        print ""
        print "Logged in as %s" % self.email
        print ""

        if not os.path.isfile(OAUTH_FILEPATH):
            print "First time login. Please follow the instructions below:"
            self.mm.perform_oauth()
        self.logged_in = self.mm.login()
        if not self.logged_in:
            print "OAuth failed... try deleting your %s file and trying again." % OAUTH_FILEPATH
            exit()

        print "Authenticated"
        print ""


    def sync_playlist(self, filename, remove_missing):
    #def sync_playlist(self, filename, remove_missing=False):
        filename = self.get_platform_path(filename)
        os.chdir(os.path.dirname(filename))
        title = os.path.splitext(os.path.basename(filename))[0]
        print "Syncing playlist: %s" % filename
        #if title not in self.playlists['user']:
            #print "   didn't exist... creating..."
            #self.playlists['user'][title] = [self.wc.create_playlist(title)]
        print ""

        plid = ""

        for pl in self.playlists:
            if pl['name'] == title:
                plid = pl['id']
                goog_songs = pl['tracks']

        if plid == "":
            print "   didn't exist... creating..."
            plid = self.mc.create_playlist(self, title)

        #plid = self.playlists['user'][title][0]
        #goog_songs = self.wc.get_playlist_songs(plid)
        print "%d songs already in Google Music playlist" % len(goog_songs)
        pc_songs = self.get_files_from_playlist(filename)
        print "%d songs in local playlist" % len(pc_songs)
        print ""

        # Sanity check max 1000 songs per playlist
        if len(pc_songs) > MAX_SONGS_IN_PLAYLIST:
            print "    Google music doesn't allow more than %d songs in a playlist..." % MAX_SONGS_IN_PLAYLIST
            print "    Will only attempt to sync the first %d songs." % MAX_SONGS_IN_PLAYLIST
            del pc_songs[MAX_SONGS_IN_PLAYLIST:]

        existing_files = 0
        added_files = 0
        failed_files = 0
        removed_files = 0
        fatal_count = 0

        for fn in pc_songs:
            if self.file_already_in_list(fn, goog_songs, self.all_songs):
                existing_files += 1
                continue
            print ""
            print "Adding: %s" % os.path.basename(fn).encode('cp1252')
            #print "Adding: %s" % os.path.basename(fn)
            #online = False
            online = self.find_song(fn, goog_songs, self.all_songs)
            #online = self.find_song(fn)
            song_id = None
            if online:
                song_id = online['id']
                print "   already uploaded [%s]" % song_id
            else:
                attempts = 0
                result = []
                while not result and attempts < MAX_UPLOAD_ATTEMPTS_PER_FILE:
                    print "   uploading... (may take a while)"
                    attempts += 1
                    try:
                        result = self.mm.upload(fn)
                    except (BadStatusLine, CannotSendRequest):
                        # Bail out if we're getting too many disconnects
                        if fatal_count >= MAX_CONNECTION_ERRORS_BEFORE_QUIT:
                            print ""
                            print "Too many disconnections - quitting. Please try running the script again."
                            print ""
                            exit()

                        print "Connection Error -- Reattempting login"
                        fatal_count += 1
                        self.wc.logout()
                        self.mc.logout()
                        self.mm.logout()
                        result = []
                        time.sleep(STANDARD_SLEEP)

                    except:
                        result = []
                        time.sleep(STANDARD_SLEEP)

                try:
                    if result[0]:
                        song_id = result[0].itervalues().next()
                    else:
                        song_id = result[1].itervalues().next()
                    print "   upload complete [%s]" % song_id
                except:
                    print "      upload failed - skipping"
                    tag = self.get_id3_tag(fn)
                    print "      failed song:\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252'))

            if not song_id:
                failed_files += 1
                continue

            added = self.mc.add_songs_to_playlist(plid, song_id)
            time.sleep(.3) # Don't spam the server too fast...
            print "   done adding to playlist"
            added_files += 1

        if remove_missing:
            for g in goog_songs:
                for s in self.all_songs:
                    if g['trackId'] == s['id']:
                        print ""
                        print "Removing: %s" % s['title'].encode('cp1252')
                        self.mc.remove_entries_from_playlist(g['id'])
                        #self.wc.remove_songs_from_playlist(plid, s.id)
                        time.sleep(.3) # Don't spam the server too fast...
                        removed_files += 1

        print ""
        print "---"
        print "%d songs unmodified" % existing_files
        print "%d songs added" % added_files
        print "%d songs failed" % failed_files
        print "%d songs removed" % removed_files


    def get_files_from_playlist(self, filename):
        files = []
        f = codecs.open(filename, encoding='cp1252')
        #f = codecs.open(filename, encoding='utf-8')
        for line in f:
            line = line.rstrip().replace(u'\ufeff',u'')
            if line == "" or line[0] == "#":
                continue
            path  = os.path.abspath(self.get_platform_path(line))
            if not os.path.exists(path):
                print "File not found: %s" % line
                continue
            files.append(path)
        f.close()
        return files

    def file_already_in_list(self, filename, goog_songs, all_songs):
        tag = self.get_id3_tag(filename)
        print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252'))
        i = 0
        while i < len(goog_songs):
            for s in all_songs:
                if goog_songs[i]['trackId'] == s['id']:
                    if self.tag_compare(s, tag):
                        print "Found match\t%s\t%s\t%s" % (s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252'))
                        goog_songs.pop(i)
                        return True
            i += 1
        return False

    def get_id3_tag(self, filename):
        data = mutagen.File(filename, easy=True)
        r = {}
        if 'title' not in data:
            title = os.path.splitext(os.path.basename(filename))[0]
            print 'Found song with no ID3 title, setting using filename:'
            print '  %s' % title
            print '  (please note - the id3 format used (v2.4) is invisible to windows)'
            data['title'] = [title]
            data.save()
        r['title'] = data['title'][0]
        r['track'] = int(data['tracknumber'][0].split('/')[0]) if 'tracknumber' in data else 0
        # If there is no track, try and get a track number off the front of the file... since thats
        # what google seems to do...
        # Not sure how google expects it to be formatted, for now this is a best guess
        if r['track'] == 0:
            m = re.match("(\d+) ", os.path.basename(filename))
            if m:
                r['track'] = int(m.group(0))
        r['artist'] = data['artist'][0] if 'artist' in data else ''
        r['album'] = data['album'][0] if 'album' in data else ''
        return r

    def find_song(self, filename, goog_songs, all_songs):
        tag = self.get_id3_tag(filename)
        print "Searching for\t%s\t%s\t%s" % (tag['title'].encode('cp1252'), tag['artist'].encode('cp1252'), tag['album'].encode('cp1252'))
        #results = self.wc.search(tag['title'])
        # NOTE - diagnostic print here to check results if you're creating duplicates
        #print results['song_hits']
        #for r in goog_songs:
        #for r in results['song_hits']:
        for s in all_songs:
            #if r['trackId'] == s['id']:
            if self.tag_compare(s, tag):
                # TODO: add rough time check to make sure its "close"
                print "Found match\t%s\t%s\t%s" % (s['title'].encode('cp1252'), s['artist'].encode('cp1252'), s['album'].encode('cp1252'))
                return s
        return None

    def tag_compare(self, g_song, tag):
        # If a google result has no track, google doesn't return a field for it
        if 'title' not in g_song:
            g_song['title'] = ""
        if 'artist' not in g_song:
            g_song['artist'] = ""
        if 'album' not in g_song:
            g_song['album'] = ""
        if 'track' not in g_song:
            g_song['track'] = 0
        if (g_song['title'].lower() == tag['title'].lower() and g_song['artist'].lower() == tag['artist'].lower()) or\
           (g_song['album'].lower() == tag['album'].lower() and g_song['title'].lower() == tag['title'].lower()) or\
           (g_song['artist'].lower() == tag['artist'].lower() and g_song['album'].lower() == tag['album'].lower() and g_song['track'] == tag['track']):
            print "Partial match\t%s\t%s\t%s" % (g_song['title'].encode('cp1252'), g_song['artist'].encode('cp1252'), g_song['album'].encode('cp1252'))
        return g_song['title'].lower() == tag['title'].lower() and\
               g_song['artist'].lower() == tag['artist'].lower() and\
               g_song['album'].lower() == tag['album'].lower() #and\
               #g_song['track'] == tag['track']

    def delete_song(self, sid):
        self.mc.delete_songs(sid)
        print "Deleted song by id [%s]" % sid

    def get_platform_path(self, full_path):
        # Try to avoid messing with the path if possible
        if os.sep == '/' and '\\' not in full_path:
            return full_path
        if os.sep == '\\' and '\\' in full_path:
            return full_path
        if '\\' not in full_path:
            return full_path
        return os.path.normpath(full_path.replace('\\', '/'))
Ejemplo n.º 56
0
def api_init():
	api = Musicmanager()
	api.login()

	return api
Ejemplo n.º 57
0
class GMusicSync(BeetsPlugin):
    def __init__(self):
        super(GMusicSync, self).__init__()

        self._mm = Musicmanager(debug_logging=False)
        self._library_paths = get_library_paths('default')

        if not os.path.exists(self._library_paths.base):
            os.mkdir(self._library_paths.base);

        self._db = open_db(self._library_paths.db_file)

        if not os.path.exists(self._library_paths.oauth_file):
            self._mm.perform_oauth(self._library_paths.oauth_file)
        else:
            self._mm.login(self._library_paths.oauth_file)

        sync_command = make_command('gmusic-sync', self.sync_library, help='Sync library with Google Play Music')
        sync_command.parser.add_option('-p', '--pretend', dest='pretend', action='store_true', default=False)

        self._commands = [
            sync_command,
        ]

        self.config['password'].redact = True

    def commands(self):
        return self._commands

    def sync_library(self, lib, opts, args):
        total_count = 0
        uploaded_count = 0
        error_count = 0

        for item in lib.items(query=args):
            total_count = total_count + 1
            status = self.sync_track(item, pretend=opts.pretend)
            if status == 'uploaded':
                uploaded_count = uploaded_count + 1
            elif status == 'error':
                error_count = error_count + 1

        print 'Summary:'
        print '  {0} tracks analyzed.'.format(total_count)
        print '  {0} tracks {1}uploaded.'.format(uploaded_count, 'would be ' if opts.pretend else '')
        print '  {0} tracks errored.'.format(error_count)

    def sync_track(self, item, pretend=False):
        item_mtime = arrow.get(item.current_mtime())

        track_row = self._db.get_track(item.id)

        upload_track = track_row is None or \
            track_row.gmusic_sync_time is None or \
            track_row.gmusic_sync_time < item_mtime

        if upload_track:
            try:
                track_id = self.upload_track(item, pretend)

                if not pretend:
                    track_row = TrackRow(id=item.id, gmusic_track_id=track_id, gmusic_sync_time=arrow.utcnow())
                    self._db.update_track(track_row)

                return 'uploaded'
            except Exception as err:
                print '>>> track failed to upload: {0}'.format(err)
                return 'error'

        return 'ok'

    def upload_track(self, item, pretend=False):
        print u'Uploading track: {artist} - {album} - [{track}] {title}'.format(**item)
        track_id = None

        if not pretend:
            uploaded, matched, not_uploaded = self._mm.upload(item.path, enable_matching=True)
            if item.path in uploaded:
                track_id = uploaded[item.path]
                print '>>> track uploaded (gmusic_trackid: {track_id})'.format(track_id=track_id)
            elif item.path in matched:
                track_id = matched[item.path]
                print '>>> track matched (gmusic_trackid: {track_id})'.format(track_id=track_id)
            else:
                reason = not_uploaded[item.path]
                m = re.search('ALREADY_EXISTS\((.*)\)', reason)
                if not m:
                    raise GMusicTrackError(reason)

                track_id = m.group(1)
                print '>>> track already exists (gmusic_trackid: {track_id}'.format(track_id=track_id)
        else:
            track_id = '?'
            print '>>> track would be uploaded'

        return track_id
Ejemplo n.º 58
0
# FORMATTER
formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(message)s')
# HANDLER -> activity.log
file_handler = RotatingFileHandler('logs/activity.log', 'a', 1000000, 1) #Append, 1Mo, 1 backup
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

logger.info('Edgar, reporting for duty ...')

### SETUP: GOOGLE MUSIC API - MUSICMANAGER
requests.packages.urllib3.disable_warnings()
oauth_file = '/root/.oauthfile'
mac_address = 'XXXX'
api = Musicmanager(True,True,True)
musicmanager_login_status = api.login(oauth_file, mac_address)
logger.debug("Musicmanager login status: " + str(musicmanager_login_status))

### SETUP: GOOGLE MUSIC API - WEBCLIENT
google_login = '******'
google_passw = 'XXXX'
webclient = Webclient(True, True, True)
webclient_login_status = webclient.login(google_login, google_passw)
logger.debug("Webclient login status: " + str(webclient_login_status))

### SETUP: SOUNDCLOUD API
soundcloud_userid = 'XXXX'
soundcloud_clientid = 'XXXX'
soundcloud_api_baseurl = 'https://api-v2.soundcloud.com/users/'
soundcloud_api_favoriteparam = '/likes?limit=10&offset=0&client_id='
soundcloud_favorites_url = soundcloud_api_baseurl + soundcloud_userid + soundcloud_api_favoriteparam + soundcloud_clientid