/
main.py
280 lines (235 loc) · 8.69 KB
/
main.py
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
#! /usr/bin/python
import library
from query import *
import os
import time
import gc
from flask import Flask, request
import json
from flask import render_template
from flask.ext.api import status
app = Flask(__name__)
app.config["DEBUG"] = True
app.config['ALLOWED_EXTENSIONS'] = {'wav'}
music_database = library.Library()
def auto():
"""Tasks to be run automatically each time the program starts up."""
music_database.load()
if music_database.empty():
info = "There is no songs in the library. Please import songs!"
songs = None
else:
num = music_database.size()
info = "Library loaded! Contains " + str(num) + " songs"
songs = music_database.get_songs()
music_database.export()
return info, songs
def cache_library(clear_ans):
"""Caches and optionally clears currently stored library.
:param clear_ans: Clear working directory or not.
"""
if music_database.empty():
info = "Library empty"
else:
info = "Library will be cached."
if clear_ans:
music_database.cache(True)
else:
music_database.cache(False)
music_database.export()
return info
def remove_song(song_id):
"""Removes a song from the database.
:param song_id: fingerprint ID (dir/name) to remove from library:
"""
init_size = music_database.size()
music_database.remove(song_id)
new_size = music_database.size()
if init_size == new_size:
info = "'" + song_id + "' not found."
else:
info = "'" + str(song_id) + "' successfully removed. Library now contains " + str(new_size) + " songs"
music_database.export()
music_database.save()
return info
def remove_all_songs():
"""Removes all songs from library"""
songs = music_database.get_songs()
for song in songs:
music_database.remove(song.get_id())
music_database.export()
music_database.save()
return "Removed All Songs from Library!"
def import_dir(directory):
"""Prompts user to enter location of directory to be imported.
Every file in that directory is then loaded into the library.
:param directory: Enter directory to import to library:"""
if os.path.exists(directory):
start_time = time.time()
info = ""
for filex in os.listdir(directory):
if filex.endswith(".wav"):
filex = directory + "/" + filex
read_start = time.time()
music_database.add(filex)
read_end = time.time()
info += str(filex)
info += " - " + str(round((read_end - read_start), 1)) + " secs"
gc.collect()
end_time = time.time()
music_database.save()
info += "\nDirectory imported in " + str(round((end_time - start_time), 1)) + " seconds"
else:
info = "Invalid directory name!"
music_database.export()
return info
def import_file(audio_file):
"""Prompts user to enter location of directory to be imported.
Every file in that directory is then loaded into the library.
:param audio_file: file to be imported"""
start_time = time.time()
info = ""
read_start = time.time()
music_database.add(audio_file)
read_end = time.time()
info += str(audio_file)
info += " - " + str(round((read_end - read_start), 1)) + " secs"
gc.collect()
end_time = time.time()
music_database.save()
info += "\nFile imported in " + str(round((end_time - start_time), 1)) + " seconds"
music_database.export()
return info
def search_sample(fname):
start_time = time.time()
match = id_sample(fname, mode="record")
end_time = time.time()
return start_time, match, end_time
def id_sample(sample, mode="sample"):
"""Finds any possible matches in the database for the given sample.
:param mode:
:param sample: string file location
:return string"""
quora = QueryClient(music_database.get_hash())
match = quora.query(sample, mode)
return match
def match_file(sample_file_path):
"""Tries to match audio file with song in database.
User is prompted for file location.
:param sample_file_path: enter sample file path to match:"""
if os.path.exists(sample_file_path):
if sample_file_path.endswith(".wav"):
start_time = time.time()
match = id_sample(sample_file_path)
end_time = time.time()
if match[0] == "No match was found":
info = str(match[0])
else:
info = "Your song is:" + match[0]
info += "Search completed in " + str(end_time - start_time) + " seconds"
else:
info = "Query failed. " + "/" + str(sample_file_path) + " is not a WAV file."
else:
info = "/" + str(sample_file_path) + " is not a valid sample filepath. Please re-enter."
return info
def related_songs(match):
"""Return related songs
:param match: song for which to get related songs
"""
info = ""
for name in match[1]:
info += str(name.split("/")[1].strip()) + ", "
return info
def test_helper(f, num):
"""Helper function for test which performs the actual search.
:param num:
:param f: sample file
"""
quora = QueryClient(music_database.get_hash())
if f.endswith(".wav"):
info = "Sample: " + str(f)
for n in range(num):
start_time = time.time()
match = quora.query(f)
end_time = time.time()
if match[0] == "No match was found":
match[0] = "None"
info += "Match " + str((n+1)+match[0]) + " : " + str(round((end_time-start_time), 1)) + " secs"
else:
info = "File is not .wav"
return info
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in app.config['ALLOWED_EXTENSIONS']
@app.route('/')
def index():
return render_template('index.html', title="Hummers - Recognize songs by humming!")
@app.route('/about')
def about():
return render_template('about.html', title="About Us | Hummers")
@app.route('/library')
def library():
info, songs = auto()
return render_template('library.html', title="Library | Hummers", info=info, songs=songs)
@app.route('/remove', methods=['POST'])
def remove():
if request.method == 'POST':
"""remove song with ID <song_id>"""
song_id = str(request.form['song_id'])
remove_song(song_id)
return 'Success', status.HTTP_204_NO_CONTENT
else:
return 'No Song Exist of this ID', status.HTTP_204_NO_CONTENT
@app.route('/search', methods=['POST'])
def search():
if request.method == 'POST':
"""search sample"""
sample = request.files.get('file')
if sample and allowed_file(sample.filename):
filepath = os.path.join(os.path.dirname(__file__), "sample.wav")
sample.save(filepath)
start_time, match, end_time = search_sample(filepath)
if match[0] == "No match was found":
return json.dumps({'song_name': match[0], 'successful': False})
else:
return json.dumps({
'song_name': match[0],
'search_time': "%g secs" % round((end_time - start_time), 1),
'successful': True,
'related': [{'song_name': name} for name in match[1]]
})
return 'Success', status.HTTP_200_OK
else:
return 'No Results Found', status.HTTP_204_NO_CONTENT
@app.route("/upload", methods=["POST"])
def upload():
uploaded_files = request.files.getlist("file[]")
for filex in uploaded_files:
if file and allowed_file(filex.filename):
import_file(filex)
return 'Success', status.HTTP_204_NO_CONTENT
@app.route('/import')
def import_dir():
return render_template('import.html', title="Import Songs | Hummers")
@app.route('/admin', methods=["GET", "POST"])
def admin():
if request.method == 'POST':
action = str(request.form['action'])
if action == 'cache_lib':
info = cache_library(True)
return 'Success', status.HTTP_204_NO_CONTENT
elif action == 'remove_all':
info = remove_all_songs()
return 'Success', status.HTTP_204_NO_CONTENT
elif action == 'force_save':
start_time = time.time()
music_database.save()
end_time = time.time()
info = "Save time: " + str(end_time - start_time)
return 'Success', status.HTTP_204_NO_CONTENT
else:
return 'Error', status.HTTP_404_NOT_FOUND
else:
return render_template('admin.html', title="Administrator Options | Hummers")
if __name__ == '__main__':
app.run()