Esempio n. 1
0
class GMusic(object):
    def __init__(self):
        self.webclient = Webclient(debug_logging=False)
        self.email = None
        self.password = None
        self.authenticated = False
        self.all_songs = list()
        self.playlists = list()

    def authenticate(self, email=None, password=None):
        if email:
            self.email = email
        if password:
            self.password = password

        try:
            Log("AUTHENTICATING!!!!111")
            self.authenticated = self.webclient.login(self.email, self.password)
        except AlreadyLoggedIn:
            self.authenticated = True


        return self.authenticated

    def get_all_songs(self):
        try:
            self.all_songs = self.webclient.get_all_songs()
        except NotLoggedIn:
            if self.authenticate():
                self.all_songs = self.webclient.get_all_songs()
            else:
                Log("LOGIN FAILURE")
                return

        return self.all_songs

    def get_all_playlists(self):
        try:
            self.playlists = self.webclient.get_all_playlist_ids()
        except NotLoggedIn:
            if self.authenticate():
                self.playlists = self.webclient.get_all_playlist_ids()
            else:
                Log("LOGIN FAILURE")
                return

        return self.playlists

    def get_stream_url(self, song_id):
        try:
            stream_url = self.webclient.get_stream_url(song_id)
        except NotLoggedIn:
            if self.authenticate():
                stream_url = self.webclient.get_stream_url(song_id)
            else:
                Log("LOGIN FAILURE")
                return

        return stream_url
Esempio n. 2
0
class gMusicClient(object):
	logged_in = False
	api = None
	playlists = dict()
	library = dict()

	def __init__(self, email, password):
		self.api = Webclient()
		logged_in = False
		attempts = 0
		if len(password) is 0:
			password = getpass("Google password:"******"title"]
			if song["artist"] == "":
				song_artist = "Unknown Artist"
			else:
				song_artist = song["artist"]
			if song["album"] == "":
				song_album = "Unknown Album"
			else:
				song_album = song["album"]
			if not (song_artist in self.library):
				albums_dict = dict()
				self.library[song_artist] = albums_dict
			if not (song_album in self.library[song_artist]):
				song_list = list()
				self.library[song_artist][song_album] = song_list
			self.library[song_artist][song_album].append(song)
		plists = self.api.get_all_playlist_ids(auto=True, user=True)
		for u_playlist, u_playlist_id in plists["user"].iteritems():
			self.playlists[u_playlist] = self.api.get_playlist_songs(u_playlist_id[0])
		self.playlists["Thumbs Up"] = [song for song in songs if song['rating'] == 5]

	def getSongStream(self, song):
		return self.api.get_stream_urls(song["id"])

	def getStreamAudio(self, song):
		return self.api.get_stream_audio(song["id"])

	def thumbsUp(self, song):
		try:
			song["rating"] = 5
			song_list = [song]
			self.api.change_song_metadata(song_list)
			print "Gave a Thumbs Up to {0} by {1} on Google Play.".format(song["title"].encode("utf-8"), song["artist"].encode("utf-8"))
		except:
			print "Error giving a Thumbs Up on Google Play."
Esempio n. 3
0
class GMusicSession(object):
    def __init__(self):
        super(GMusicSession, self).__init__()
        logger.info('Mopidy uses Google Music')
        self.api = Webclient()

    def login(self, username, password):
        if self.api.is_authenticated():
            self.api.logout()
        try:
            self.api.login(username, password)
        except CallFailure as error:
            logger.error(u'Failed to login as "%s": %s', username, error)
        return self.api.is_authenticated()

    def logout(self):
        if self.api.is_authenticated():
            return self.api.logout()
        else:
            return True

    def get_all_songs(self):
        if self.api.is_authenticated():
            return self.api.get_all_songs()
        else:
            return {}

    def get_stream_url(self, song_id):
        if self.api.is_authenticated():
            try:
                return self.api.get_stream_urls(song_id)[0]
            except CallFailure as error:
                logger.error(u'Failed to lookup "%s": %s', song_id, error)

    def get_all_playlist_ids(self):
        if self.api.is_authenticated():
            return self.api.get_all_playlist_ids()
        else:
            return {}

    def get_playlist_songs(self, playlist_id):
        if self.api.is_authenticated():
            return self.api.get_playlist_songs(playlist_id)
        else:
            return {}
Esempio n. 4
0
def list():
	mm = Webclient()
	token = request.form['token']
	mm.setToken(token)
	playlists = mm.get_all_playlist_ids()
	output = "["

	songs = mm.get_all_songs(incremental=False)
	output += "{'title': 'Full library', 'songs' : "
	output += json.dumps(songs)
	output += "},"

	for (key,values) in playlists['user'].items():
		for playlistid in values:
			output += "{ 'title':'"+key+"', 'songs' :"
			songs=mm.get_playlist_songs(playlistid)
			output += json.dumps(songs)
			output += "},"

	output += "]"

	return output
Esempio n. 5
0
def main():
    api = Webclient()
    login(api)
    playlists = api.get_all_playlist_ids().pop('user')
    indexed_playlist_names = index_playlists(playlists)
    curlist = choose_playlist(api, indexed_playlist_names, playlists)[0]
    songs = api.get_playlist_songs(curlist)
    print songs

    curpos = 0
    cursongid = songs[curpos]['id']
    cursongurl = api.get_stream_url(cursongid)
    print cursongurl
    #cursong = play(cursongurl)

    while 1:
        if cursong.poll() is not None:
            curpos += 1
            cursongid = songs[curpos]['id']
            cursong = play(get_stream_url(cursongid))
        c = getch()
        if (c == 'q'):
            api.logout()
            break
Esempio n. 6
0
def main():
  api = Webclient()
  login(api)
  playlists = api.get_all_playlist_ids().pop('user')
  indexed_playlist_names = index_playlists(playlists)
  curlist = choose_playlist(api, indexed_playlist_names, playlists)[0]
  songs = api.get_playlist_songs(curlist)
  print songs

  curpos = 0;
  cursongid = songs[curpos]['id']
  cursongurl = api.get_stream_url(cursongid)
  print cursongurl
  #cursong = play(cursongurl)

  while 1:
    if cursong.poll() is not None:
      curpos += 1
      cursongid = songs[curpos]['id']
      cursong = play(get_stream_url(cursongid))
    c = getch() 
    if (c == 'q'):
      api.logout() 
      break
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('\\', '/'))
class Music(Command):
    def __init__(self, credentials):
        self.keywords = ['music']
        self.gmusic = Webclient()
        self.gmusic.login(credentials['u'], credentials['pass'])
        self.currentPlaylist = list()
        self.currentSong = dict()
        self.isPlaying = False
        self.playlistIndex = 0
        self.updateSongs()
        self.player = PCM()

    def updateSongs(self):
        self.playlists = self.gmusic.get_all_playlist_ids()["user"]
        if len(self.currentPlaylist) == 0:
            self.currentPlaylist= self.gmusic.get_playlist_songs(self.playlists['Megalist'][0])
            random.shuffle(self.currentPlaylist)

        if not self.currentSong:
            self.currentSong = self.currentPlaylist[self.playlistIndex]

        self.library = self.gmusic.get_all_songs()
            
    def play(self, cs = None):
        if cs == None:
            cs = self.currentPlaylist[self.playlistIndex]
        self.currentSong = cs
        self.isPlaying = True
#       self.player.write(self.gmusic.get_stream_audio(self.currentSong[u'id']))
        print 'play' + self.currentSong['title']

    def pause(self):
        self.isPlaying = False
        print 'pausing'

    def nextSong(self):
        self.playlistIndex += 1
        if self.playlistIndex >= len(self.currentPlaylist):
            self.playlistIndex = 0
            self.pause()
        else:
            self.play()

    def previousSong(self):
        self.playlistIndex -= 1
        if self.playlistIndex < 0:
            self.playlistIndex = 0
        self.play()

    def rickRoll(self):
        self.playlist = list()
        for song in self.library:
            if song['titleNorm'] == 'never gonna give you up':
                self.currentPlaylist = [song]
                self.playlistIndex = 0
                self.play()

    def playSong(self, songname):
        for song in self.library:
            if songname in song['titleNorm']:
                self.play(cs = song)
                self.currentPlaylist = [song]
#               tempplaylist = self.gmusic.get_playlist_songs(self.playlists['Megalist'][0])
#               random.shuffle(tempplaylist)
#               self.currentPlaylist += tempplaylist
                break
    def playAlbum(self, albumname):
        tempplaylist = list()
        for song in self.library:
            if albumname in song["albumNorm"] or albumname in song["album"]:
                tempplaylist += [song]
        if len(tempplaylist) > 0:
            self.currentPlaylist = sorted(tempplaylist, key=lambda k: k['track'])
            self.play()

    def playArtist(self, artistname):
        tempplaylist = list()
        for song in self.library:
            if artistname in song["artistNorm"] or artistname in song["artist"]:
                tempplaylist += [song]    
        if len(templaylist) > 0:
            self.currentPlaylist = tempplaylist
            random.shuffle(self.currentPlaylist)
            self.playlistIndex = 0
            self.play()

    def playPlaylist(self, playlistname):
        self.currentPlaylist = self.gmusic.get_playlist_songs(self.playlists[playlistname][0])
        random.shuffle(self.currentPlaylist)
        self.playlistIndex = 0
        self.play()

    def run(self, commandlist):
        if len(commandlist) == 0:
            if self.isPlaying == True:
                self.pause()
            else:
                self.play()
            print "music toggle"

        elif commandlist[0] == "play":
            if len(commandlist) == 1:
                if self.isPlaying == False:
                    self.play()
                    print "play music"

            elif commandlist [1] == "playlist":
                self.playPlaylist(" ".join(commandlist[2:]))

            elif commandlist [1] == "song":
                self.playSong(" ".join(commandlist[2:]))

            elif commandlist [1] == "artist":
                self.playArtist(" ".join(commandlist[2:]))

            elif commandlist[1] == "album":
                self.playAlbum(" ".join(commandlist[2:]))
            
            
        elif commandlist[0] == "pause":
            if self.isPlaying == True:
                self.pause()

        elif commandlist[0] == "next":
            self.nextSong()

        elif commandlist[0] == "previous":
            self.previousSong()

        else:
            print "m err"
Esempio n. 10
0
    def handle(self, *args, **options):
        if GPLAY_PASS == "" or GPLAY_USER == "":
            self.stdout.write('Credentials not set up. Please edit settings.py')
            return

        api = Webclient()
        if not api.login(GPLAY_USER,GPLAY_PASS):
            self.stdout.write('Incorrect credentials, login failed')
            return

        self.stdout.write('Connected to Google Music, downloading data...')
        library = api.get_all_songs()
        self.stdout.write('Data downloaded!')
        self.stdout.write('Clearing DB...')
        cursor = connection.cursor()
        # This can take a long time using ORM commands on the Pi, so lets Truncate
        cursor.execute('DELETE FROM ' + Track._meta.db_table)
        cursor.execute('DELETE FROM ' + Album._meta.db_table)
        cursor.execute('DELETE FROM ' + Artist._meta.db_table)
        cursor.execute('DELETE FROM ' + Playlist._meta.db_table)
        cursor.execute('DELETE FROM ' + PlaylistConnection._meta.db_table)
        self.stdout.write('Parsing new data...')

        # Easier to keep track of who we've seen like this...
        artists = []
        albums = []

        for song in library:
            track = Track()

            if song['albumArtist'] == "":
                if song['artist'] == "":
                    a = "Unknown Artist"
                else:
                    a = song['artist']
            else:
                a = song['albumArtist']

            if a not in artists:
                artist = Artist()
                artist.name = a
                try:
                    artist.art_url = song['artistImageBaseUrl']
                except:
                    artist.art_url = ""
                artist.save()
                artists.append(a)
                self.stdout.write('Added artist: '+ a)
            else:
                artist = Artist.objects.get(name=a)
            track.artist = artist

            if song['album'] not in albums:
                album = Album()
                album.name = song['album']
                album.artist = artist
                try:
                    album.art_url = song['albumArtUrl']
                except:
                    album.art_url = ""
                album.save()
                albums.append(song['album'])
            else:
                album = Album.objects.get(name=song['album'])
            track.album = album

            track.name = song['title']
            track.stream_id = song['id']
            try:
                track.track_no = song['track']
            except:
                track.track_no = 0
            track.save()

        self.stdout.write('All tracks saved!')
        self.stdout.write('Getting Playlists...')
        playlists = api.get_all_playlist_ids(auto=False, user=True)
        self.stdout.write('Saving playlists...')
        for name in playlists['user']:
            for pid in playlists['user'][name]:
                p = Playlist()
                p.pid = pid
                p.name = name
                p.save()

        for playlist in Playlist.objects.all():
            self.stdout.write('Getting playlist contents for ' + playlist.name)
            songs = api.get_playlist_songs(playlist.pid)
            for song in songs:
                track = Track.objects.get(stream_id=song['id'])
                pc = PlaylistConnection()
                pc.playlist = playlist
                pc.track = track
                pc.save()

        self.stdout.write('Library saved!')
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('\\', '/'))
Esempio n. 12
0
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 "Fetching songs from Google..."
        self.songs = self.wc.get_all_songs()
        print "Got %d songs." % len(self.songs)        

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

        print "Logged in as %s" % self.email
        
        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"
        
    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 in self.playlists['user']:
            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)
            
            # 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
            # print "Google songs: %s" % goog_songs
            for fn in pc_songs:
                if self.file_already_in_list(fn, goog_songs):
                    existing_files += 1
                    continue
                print "  adding: %s" % os.path.basename(fn)
                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 "Too many disconnections - quitting. Please try running the script again."
                               exit()
    
                            print "Connection Error -- Reattempting login"
                            fatal_count += 1
                            self.wc.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"
    
                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
    
            if remove_missing:
                for s in goog_songs:
                    print "  removing: %s" % s['title']
                    self.wc.remove_songs_from_playlist(plid, s.id)
                    time.sleep(.3) # Don't spam the server too fast...
                    removed_files += 1
                
            print "%d songs unmodified" % existing_files
            print "%d songs added" % added_files
            print "%d songs failed" % failed_files
            print "%d songs removed" % removed_files
            print "Ended: %s" % filename
        else:
            print "  playlist %s didn't exist - skipping" % filename

    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, filename, goog_songs):
        tag = self.get_id3_tag(filename)
        i = 0
        while i < len(goog_songs):
            # print "checking: %s" % tag
            # print "against: %s" % goog_songs[i]
            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):
        tag = self.get_id3_tag(filename)
        
        # NOTE - diagnostic print here to check results if you're creating duplicates
        print "  [%s][%s][%s][%s]" % (tag['title'], tag['artist'], tag['album'], tag['track'])
        for s in self.songs:
            if self.tag_compare(s, tag):
                print "  %s matches %s" % (s['title'], tag['title']) 
                return s
        print "  No matches for %s" % tag['title']
        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 'track' not in g_song:
            g_song['track'] = 0
        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.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('\\', '/'))
from gmusicapi import Webclient
import os
import getpass

api = Webclient()

api.__init__()

while (api.login(raw_input('Email: '), getpass.getpass()) == False):
	print 'Error, try again'

i = 1
for playlist in api.get_all_playlist_ids()['user']:
	print str(i) + '. ' + playlist
	i += 1

while True:
	chosen_number = int(raw_input('Choose a playlist to export (enter the number): '))
	if chosen_number < i and chosen_number >= 0:
		break
	else:
		print 'Error, try again'

i = 1
for playlist in api.get_all_playlist_ids()['user']:
	if i == chosen_number:
		chosen_id = api.get_all_playlist_ids()['user'][playlist][0]
		chosen_name = playlist
		break
	else:
		i += 1
Esempio n. 14
0
    def handle(self, *args, **options):
        if GPLAY_PASS == "" or GPLAY_USER == "":
            self.stdout.write(
                'Credentials not set up. Please edit settings.py')
            return

        api = Webclient()
        if not api.login(GPLAY_USER, GPLAY_PASS):
            self.stdout.write('Incorrect credentials, login failed')
            return

        self.stdout.write('Connected to Google Music, downloading data...')
        library = api.get_all_songs()
        self.stdout.write('Data downloaded!')
        self.stdout.write('Clearing DB...')
        cursor = connection.cursor()
        # This can take a long time using ORM commands on the Pi, so lets Truncate
        cursor.execute('DELETE FROM ' + Track._meta.db_table)
        cursor.execute('DELETE FROM ' + Album._meta.db_table)
        cursor.execute('DELETE FROM ' + Artist._meta.db_table)
        cursor.execute('DELETE FROM ' + Playlist._meta.db_table)
        cursor.execute('DELETE FROM ' + PlaylistConnection._meta.db_table)
        self.stdout.write('Parsing new data...')

        # Easier to keep track of who we've seen like this...
        artists = []
        albums = []

        for song in library:
            track = Track()

            if song['albumArtist'] == "":
                if song['artist'] == "":
                    a = "Unknown Artist"
                else:
                    a = song['artist']
            else:
                a = song['albumArtist']

            if a not in artists:
                artist = Artist()
                artist.name = a
                try:
                    artist.art_url = song['artistImageBaseUrl']
                except:
                    artist.art_url = ""
                artist.save()
                artists.append(a)
                self.stdout.write('Added artist: ' + a)
            else:
                artist = Artist.objects.get(name=a)
            track.artist = artist

            if song['album'] not in albums:
                album = Album()
                album.name = song['album']
                album.artist = artist
                try:
                    album.art_url = song['albumArtUrl']
                except:
                    album.art_url = ""
                album.save()
                albums.append(song['album'])
            else:
                album = Album.objects.get(name=song['album'])
            track.album = album

            track.name = song['title']
            track.stream_id = song['id']
            try:
                track.track_no = song['track']
            except:
                track.track_no = 0
            track.save()

        self.stdout.write('All tracks saved!')
        self.stdout.write('Getting Playlists...')
        playlists = api.get_all_playlist_ids(auto=False, user=True)
        self.stdout.write('Saving playlists...')
        for name in playlists['user']:
            for pid in playlists['user'][name]:
                p = Playlist()
                p.pid = pid
                p.name = name
                p.save()

        for playlist in Playlist.objects.all():
            self.stdout.write('Getting playlist contents for ' + playlist.name)
            songs = api.get_playlist_songs(playlist.pid)
            for song in songs:
                track = Track.objects.get(stream_id=song['id'])
                pc = PlaylistConnection()
                pc.playlist = playlist
                pc.track = track
                pc.save()

        self.stdout.write('Library saved!')
Esempio n. 15
0
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, 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 "Synching 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 = 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)

        # 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 ""
            print "Adding: %s" % os.path.basename(fn)
            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.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"

            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

        if remove_missing:
            for s in goog_songs:
                print ""
                print "Removing: %s" % s['title']
                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='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):
        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):
        tag = self.get_id3_tag(filename)
        results = self.wc.search(tag['title'])
        # NOTE - dianostic print here to check results if you're creating duplicates
        #print results['song_hits']
        #print "%s ][ %s ][ %s ][ %s" % (tag['title'], tag['artist'], tag['album'], tag['track'])
        for r in results['song_hits']:
            if self.tag_compare(r, tag):
                # TODO: add rough time check to make sure its "close"
                return r
        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 'track' not in g_song:
            g_song['track'] = 0
        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.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('\\', '/'))