Also bump Bliss version
This commit is contained in:
parent
56108cea38
commit
6edc90c287
166
mpd/client.py
166
mpd/client.py
@ -103,60 +103,63 @@ if "XDG_DATA_HOME" in os.environ:
|
||||
else:
|
||||
_BLISSIFY_DATA_HOME = os.path.expanduser("~/.local/share/blissify")
|
||||
|
||||
# Distance between two songs
|
||||
|
||||
def distance(x, y):
|
||||
distance = math.sqrt(
|
||||
"""
|
||||
Compute the distance between two songs.
|
||||
|
||||
Params:
|
||||
- x: First song dict
|
||||
- y: Second song dict
|
||||
Returns: The cartesian distance between the two songs.
|
||||
"""
|
||||
return math.sqrt(
|
||||
(x["tempo"] - y["tempo"])**2 +
|
||||
(x["amplitude"] - y["amplitude"])**2 +
|
||||
(x["frequency"] - y["frequency"])**2 +
|
||||
(x["attack"] - y["attack"])**2)
|
||||
return distance
|
||||
(x["attack"] - y["attack"])**2
|
||||
)
|
||||
|
||||
# Distance between a set and a point
|
||||
def distance_set(X, y):
|
||||
temp_distance = distance(X[0], y);
|
||||
for song in X:
|
||||
a = distance(song, y);
|
||||
temp_distance = a if a < temp_distance else temp_distance;
|
||||
return temp_distance;
|
||||
|
||||
# Hausdorff distance between two sets
|
||||
def hauff_distance_sets(X, Y):
|
||||
temp_distance = distance_set(X, Y[0]);
|
||||
for song in X:
|
||||
a = distance_set(Y, song);
|
||||
temp_distance = a if a > temp_distance else temp_distance;
|
||||
|
||||
for song in Y:
|
||||
a = distance_set(X, song);
|
||||
temp_distance = a if a > temp_distance else temp_distance;
|
||||
return temp_distance
|
||||
|
||||
def mean_song(X):
|
||||
count = 0;
|
||||
result = { 'tempo': 0, 'amplitude': 0, 'frequency':0, 'attack':0 }
|
||||
|
||||
"""
|
||||
Compute a "mean" song for a given iterable of song dicts.
|
||||
|
||||
Params:
|
||||
- X: An iterable of song dicts.
|
||||
Returns: A "mean" song, whose features are the mean features of the songs
|
||||
in the iterable.
|
||||
"""
|
||||
count = 0
|
||||
result = {'tempo': 0, 'amplitude': 0, 'frequency': 0, 'attack': 0}
|
||||
|
||||
for song in X:
|
||||
result["tempo"] += song["tempo"];
|
||||
result["amplitude"] += song["amplitude"];
|
||||
result["frequency"] += song["frequency"];
|
||||
result["attack"] += song["attack"];
|
||||
count = count + 1;
|
||||
result["tempo"] /= count;
|
||||
result["amplitude"] /= count;
|
||||
result["frequency"] /= count;
|
||||
result["attack"] /= count;
|
||||
return result;
|
||||
|
||||
result["tempo"] += song["tempo"]
|
||||
result["amplitude"] += song["amplitude"]
|
||||
result["frequency"] += song["frequency"]
|
||||
result["attack"] += song["attack"]
|
||||
count = count + 1
|
||||
result["tempo"] /= count
|
||||
result["amplitude"] /= count
|
||||
result["frequency"] /= count
|
||||
result["attack"] /= count
|
||||
return result
|
||||
|
||||
|
||||
# Custom distance between two sets
|
||||
def distance_sets(X, Y):
|
||||
a = mean_song(X);
|
||||
b = mean_song(Y);
|
||||
"""
|
||||
Compute the distance between two iterables of song dicts, defined as the
|
||||
distance between the two mean songs of the iterables.
|
||||
|
||||
return distance(a, b);
|
||||
Params:
|
||||
- X: First iterable of song dicts.
|
||||
- Y: First iterable of song dicts.
|
||||
Returns: The distance between the two iterables.
|
||||
"""
|
||||
return distance(mean_song(X), mean_song(Y))
|
||||
|
||||
def main_album(queue_length):
|
||||
|
||||
def _init():
|
||||
# Get MPD connection settings
|
||||
try:
|
||||
mpd_host = os.environ["MPD_HOST"]
|
||||
@ -199,6 +202,7 @@ def main_album(queue_length):
|
||||
all_songs = [x["file"] for x in client.listall() if "file" in x]
|
||||
current_song = random.choice(all_songs)
|
||||
client.add(current_song)
|
||||
|
||||
logging.info("Currently played song is %s." % (current_song,))
|
||||
|
||||
# Get current song coordinates
|
||||
@ -211,17 +215,23 @@ def main_album(queue_length):
|
||||
client.disconnect()
|
||||
sys.exit(1)
|
||||
|
||||
return client, conn, cur, current_song_coords
|
||||
|
||||
|
||||
def main_album(queue_length):
|
||||
client, conn, cur, current_song_coords = _init()
|
||||
|
||||
for i in range(queue_length):
|
||||
# No cache management
|
||||
# Get all songs from the current album
|
||||
album = current_song_coords["album"];
|
||||
album = current_song_coords["album"]
|
||||
cur.execute("SELECT id, tempo, amplitude, frequency, attack, filename, album FROM songs WHERE album=?", (album,))
|
||||
target_album_set = cur.fetchall();
|
||||
target_album_set = cur.fetchall()
|
||||
|
||||
# Get all other songs
|
||||
cur.execute("SELECT id, tempo, amplitude, frequency, attack, filename, album FROM songs ORDER BY album")
|
||||
tmp_song_data = cur.fetchone()
|
||||
shortest_distance = -1
|
||||
shortest_distance = -1
|
||||
|
||||
# Check the best suitable album
|
||||
while tmp_song_data:
|
||||
@ -233,18 +243,18 @@ def main_album(queue_length):
|
||||
# Get all songs from the current temporary album
|
||||
while tmp_song_data:
|
||||
if (current_album_set[i]["album"] == tmp_song_data["album"]):
|
||||
current_album_set.append(tmp_song_data);
|
||||
current_album_set.append(tmp_song_data)
|
||||
else:
|
||||
break;
|
||||
break
|
||||
tmp_song_data = cur.fetchone()
|
||||
i = i + 1
|
||||
# Skip current album and already processed albums
|
||||
if ( (current_album_set[0]["album"] != target_album_set[0]["album"]) and
|
||||
not (("file: %s" % (current_album_set[0]["filename"],)) in client.playlist()) ):
|
||||
# Skip current album and already processed albums
|
||||
if((current_album_set[0]["album"] != target_album_set[0]["album"]) and
|
||||
not (("file: %s" % (current_album_set[0]["filename"],)) in client.playlist())):
|
||||
tmp_distance = distance_sets(current_album_set, target_album_set)
|
||||
if tmp_distance < shortest_distance or shortest_distance == -1:
|
||||
shortest_distance = tmp_distance
|
||||
closest_album = current_album_set;
|
||||
closest_album = current_album_set
|
||||
|
||||
logging.info("Closest album found is \"%s\". Distance is %f." % (closest_album[0]["album"], shortest_distance))
|
||||
for song in closest_album:
|
||||
@ -255,59 +265,9 @@ def main_album(queue_length):
|
||||
client.close()
|
||||
client.disconnect()
|
||||
|
||||
|
||||
def main_single(queue_length):
|
||||
# Get MPD connection settings
|
||||
try:
|
||||
mpd_host = os.environ["MPD_HOST"]
|
||||
try:
|
||||
mpd_password, mpd_host = mpd_host.split("@")
|
||||
except ValueError:
|
||||
mpd_password = None
|
||||
except KeyError:
|
||||
mpd_host = "localhost"
|
||||
mpd_password = None
|
||||
try:
|
||||
mpd_port = os.environ["MPD_PORT"]
|
||||
except KeyError:
|
||||
mpd_port = 6600
|
||||
|
||||
# Connect to MPD
|
||||
client = PersistentMPDClient(host=mpd_host, port=mpd_port)
|
||||
if mpd_password is not None:
|
||||
client.password(mpd_password)
|
||||
# Connect to db
|
||||
db_path = os.path.join(_BLISSIFY_DATA_HOME, "db.sqlite3")
|
||||
logging.debug("Using DB path: %s." % (db_path,))
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute('pragma foreign_keys=ON')
|
||||
cur = conn.cursor()
|
||||
|
||||
# Ensure random is not enabled
|
||||
status = client.status()
|
||||
if int(status["random"]) != 0:
|
||||
logging.warning("Random mode is enabled. Are you sure you want it?")
|
||||
|
||||
# Take the last song from current playlist and iterate from it
|
||||
playlist = client.playlist()
|
||||
if len(playlist) > 0:
|
||||
current_song = playlist[-1].replace("file: ", "").rstrip()
|
||||
# If current playlist is empty
|
||||
else:
|
||||
# Add a random song to start with
|
||||
all_songs = [x["file"] for x in client.listall() if "file" in x]
|
||||
current_song = random.choice(all_songs)
|
||||
client.add(current_song)
|
||||
logging.info("Currently played song is %s." % (current_song,))
|
||||
# Get current song coordinates
|
||||
cur.execute("SELECT id, tempo, amplitude, frequency, attack, filename FROM songs WHERE filename=?", (current_song,))
|
||||
current_song_coords = cur.fetchone()
|
||||
if current_song_coords is None:
|
||||
logging.error("Current song %s is not in db. You should update the db." %
|
||||
(current_song,))
|
||||
client.close()
|
||||
client.disconnect()
|
||||
sys.exit(1)
|
||||
client, conn, cur, current_song_coords = _init()
|
||||
|
||||
for i in range(queue_length):
|
||||
# Get cached distances from db
|
||||
|
Loading…
Reference in New Issue
Block a user