Skip to content

Instantly share code, notes, and snippets.

@simon-weber
Created August 28, 2020 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simon-weber/333753fc295983cf40fba5eb6ec5e643 to your computer and use it in GitHub Desktop.
Save simon-weber/333753fc295983cf40fba5eb6ec5e643 to your computer and use it in GitHub Desktop.
Import Google Music playcount and last played to MediaMonkey

This Python 3 script imports some Google Music metadata to MediaMonkey. Matches are found by a complete match of the song name, album, and artist.

To use it:

  • shut down MediaMonkey
  • make a copy of your MM.DB MediaMonkey database and put it in the same directory as this script
  • use the Autoplaylists for Google Music debug interface to generate a csv of your library, then place it in the same directory as this script and name it google_music_library.csv
  • run python import_gm.py and investigate the logs; repeat on a fresh copy of MM.DB each time until satisfied
  • back up your existing MM.DB and then overwrite it with the modified one
import csv
import sqlite3
from datetime import datetime, timedelta
# A delphi datetime value is the (fractional) number of days since the epoch
# e.g. 42 minutes past the the UNIX epoch is 25569.029166666667 in Delphi terms.
DELPHI_EPOCH = datetime(1899, 12, 30)
def datetime_fromdelphi(dvalue):
return DELPHI_EPOCH + timedelta(days=dvalue)
def datetime_todelphi(dt):
try:
return (dt - DELPHI_EPOCH) / timedelta(days=1)
except TypeError:
# Python 2.7 / Python 3.1 or older don't support division
delta = dt - DELPHI_EPOCH
return delta.days + (delta.seconds + delta.microseconds / 1000000.0) / 24 / 3600
def cmp(x, y):
return (x > y) - (x < y)
def make_connection(db_path):
def iUnicodeCollate(s1, s2):
return cmp(s1.lower(), s2.lower())
conn = sqlite3.connect(
db_path, timeout=60
)
conn.row_factory = sqlite3.Row
conn.create_collation("IUNICODE", iUnicodeCollate)
return conn
def get_mm_row(c, song):
c.execute(
f"""select ID, LastTimePlayed, Artist, Album, SongTitle from Songs
where Artist = ?
and SongTitle = ?
and Album = ?
""",
[song["artist"], song["title"], song["album"]],
)
r = c.fetchall()
if len(r) > 1:
raise ValueError("multiple matches", r)
if not r:
return None
return r[0]
def update_songs(c, songs):
for song in songs:
print(f"{song['artist']}:{song['title']}: {song['play count']}", end="")
playcount = int(song["play count"])
if playcount < 1:
print(f" -> skipping: no plays")
continue
mm_row = get_mm_row(c, song)
if not mm_row:
print("f -> skipping: no match")
continue
mm_id, mm_last_played = mm_row[:2]
updated_both = False
last_played = datetime.strptime(song["last played"], "%m/%d/%Y, %I:%M:%S %p")
last_played_delphi = datetime_todelphi(last_played)
if last_played.timestamp() > 0 and last_played_delphi > mm_last_played:
c.execute(
f"""update Songs
set LastTimePlayed = ?
where ID = ?
""",
[last_played_delphi, mm_id],
)
updated_both = True
c.execute(
f"""update Songs
set PlayCounter = PlayCounter + {playcount}
where ID = ?
""",
[mm_id],
)
print(f" -> updated", updated_both)
if __name__ == "__main__":
try:
conn = make_connection("MM.DB")
with open("google_music_library.csv") as f:
songs = csv.DictReader(f)
c = conn.cursor()
update_songs(c, songs)
finally:
conn.commit()
conn.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment