forked from joribom/musicjerk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
reader.py
179 lines (160 loc) · 6.24 KB
/
reader.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
import gspread, os
from oauth2client.service_account import ServiceAccountCredentials
from datetime import datetime, timedelta
from dateutil.parser import parse as parse_time
from dateutil.tz import tzlocal
from collections import OrderedDict
from person import Person
from album import Album, make_url
from copy import copy
from threading import Thread, Lock
def start_in_thread(func, args=()):
thread = Thread(target=func, args=args)
thread.daemon = True
thread.start()
# Decorator for functions that use data from google sheets,
# to automatically check for new updates.
def check_updates(func):
def wrapper(reader, *args):
try:
if reader.update_required():
start_in_thread(reader.update_values)
except Exception as e:
print ("Caught an exception! '%s'" % str(e))
reader.reconnect()
return func(reader, *args)
return wrapper
def avg(lst):
return sum(lst) / len(lst)
class Reader:
# use creds to create a client to interact with the Google Drive API
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
def __init__(self, debug = False):
self.reconnect()
# Find a workbook by name and open the first sheet
# Make sure you use the right name here.
self.latest_update_check = datetime.now(tzlocal())
self._people = OrderedDict()
self._albums = []
self._album_dict = {}
self.latest_update = None
self.mutex = Lock()
self.updating = Lock()
self.debug = debug
self.update_values()
def user_exists(self, username):
return username.lower() in self.people
def reconnect(self):
creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', Reader.scope)
client = gspread.authorize(creds)
self.sheet = client.open("Musicjerk's big album sheet").sheet1
@property
@check_updates
def albums(self):
self.mutex.acquire()
returnval = self._albums
self.mutex.release()
return returnval
@property
@check_updates
def album_dict(self):
self.mutex.acquire()
returnval = self._album_dict
self.mutex.release()
return returnval
@property
@check_updates
def people(self):
self.mutex.acquire()
returnval = self._people
self.mutex.release()
return returnval
def update_required(self):
if datetime.now(tzlocal()) - self.latest_update_check < timedelta(seconds = 5):
return False
latest_change_time = parse_time(self.sheet.cell(1, 1).value)
self.latest_update_check = datetime.now(tzlocal())
if self.latest_update < latest_change_time:
print("Update required...")
return self.latest_update < latest_change_time
def update_values(self):
if self.updating.locked():
return
self.updating.acquire()
print("Updating values from google sheets...")
self.latest_update = datetime.now(tzlocal())
all_values = self.sheet.get_all_values()
top_row = all_values[0]
col_headers = all_values[1]
new_people = OrderedDict()
for cell in top_row[5:]:
name = cell.lower()
if name and new_people.get(name) is None:
new_people[name] = Person(name)
self.general_data = {}
self.user_data = {}
new_albums = []
new_album_dict = {}
for row in all_values[2:]:
album = row[0].replace(" (Optional)", '')
if not album:
break # Break since no more albums present
artist = row[1]
chosen_by = row[2]
average = row[3]
best_tracks = row[4]
worst_tracks = row[5]
url = make_url(album, artist)
if url in self._album_dict:
new_albums.append(self._album_dict[url])
new_albums[-1].update_values(chosen_by, average, best_tracks, worst_tracks)
else:
new_albums.append(Album(album, artist, chosen_by, average, best_tracks, worst_tracks, self.debug))
new_album_dict[url] = new_albums[-1]
name = ""
for col, value in enumerate(row[7:]):
col = col + 7
name = top_row[col].lower() if top_row[col] else name
header = col_headers[col]
new_people[name].add_value(album, header, value)
if name not in self.user_data:
self.user_data[name] = {}
if album not in self.user_data.get(name):
self.user_data[name][album] = {}
self.user_data[name][album][header] = value
for person in new_people.values():
person.generate_likeness(new_people.values())
self.mutex.acquire()
self._albums = copy(new_albums)
self._album_dict = copy(new_album_dict)
self._people = copy(new_people)
self.mutex.release()
self.updating.release()
start_in_thread(self.update_album_api_values)
start_in_thread(self.update_slow_album_api_values)
print("All values have been updated!")
def update_album_api_values(self):
print("Updating all albums from API calls...")
for album in self._albums[::-1]:
album.update_api_values()
def update_slow_album_api_values(self):
print("Updating all albums from API calls...")
for album in self._albums[::-1]:
album.update_slow_api_values()
def file_updated(self, filepath):
return os.path.exists(filepath) and datetime.fromtimestamp(os.path.getctime(filepath), tzlocal()) > self.latest_update
@property
@check_updates
def names(self):
return list(self.user_data.keys())
@check_updates
def get_likeness(self, person):
if person not in self.people:
return []
return self.people.get(person).likeness_list
@check_updates
def get_ratings(self, person):
if person not in self.people:
return []
return self.people.get(person).get_ratings()