-
Notifications
You must be signed in to change notification settings - Fork 397
/
Copy pathbuild_a_better_playlist.rb
58 lines (47 loc) · 1.45 KB
/
build_a_better_playlist.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
def music_shuffle filenames
songs_and_paths = filenames.map do |s|
[s, s.split('/')] # [song, path]
end
tree = {:root => []}
# put each song into the tree
insert_into_tree = proc do |branch, song, path|
if path.length == 0 # add to current branch
branch[:root] << song
else # delve deeper
sub_branch = path[0]
path.shift # like "pop", but pops off the front
if !branch[sub_branch]
branch[sub_branch] = {:root => []}
end
insert_into_tree[branch[sub_branch], song, path]
end
end
songs_and_paths.each{|sp| insert_into_tree[tree, *sp]}
# recursively:
# - shuffle sub-branches (and root)
# - weight each sub-branch (and root)
# - merge (shuffle) these groups together
shuffle_branch = proc do |branch|
shuffled_subs = []
branch.each do |key, unshuffled|
shuffled_subs << if key == :root
unshuffled # At this level, these are all duplicates.
else
shuffle_branch[unshuffled]
end
end
weighted_songs = []
shuffled_subs.each do |shuffled_songs|
shuffled_songs.each_with_index do |song, idx|
num = shuffled_songs.length.to_f
weight = (idx + rand) / num
weighted_songs << [song, weight]
end
end
weighted_songs.sort_by{|s,v| v}.map{|s,v| s}
end
shuffle_branch[tree]
end
# songs = ['aa/bbb', 'aa/ccc', 'aa/ddd',
# 'AAA/xxxx', 'AAA/yyyy', 'AAA/zzzz', 'foo/bar']
# puts(music_shuffle(songs))