-
Notifications
You must be signed in to change notification settings - Fork 0
/
storageadapter.py
177 lines (139 loc) · 5.82 KB
/
storageadapter.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
"""
TXFMTrackService
(C) 2015
David Rieger
"""
import redis
import re
from pymongo import MongoClient
from collections import OrderedDict
from time import strptime, strftime
class Cache:
def __init__(self, host="redis", port="6379", db="0"):
self.storage = redis.StrictRedis(host=host, port=port, db=db)
self.TIMES_KEY = "times"
def add_song(self, song, time):
"""
Adds [song] to the DB as hash with key [time]
"""
# First remove the song that has been the "playing_song"
# from the storage if it was a TXFM Show rather than an actual song
# i.e. if there's no artist
last_song = self.get_latest_songs(1)
if not last_song["artist"].strip():
self.storage.delete(self.storage.lpop(self.TIMES_KEY))
self.storage.lpush(self.TIMES_KEY, time)
self.storage.hmset(time, song)
def get_times(self, amount=None):
"""
Returns the latest [amount] stored times
All if [amount] is ::None::
Format is String
"""
if amount is None:
end_idx = -1
else:
end_idx = min(amount-1, self.get_amount_songs()-1)
return [t.decode("UTF-8") for t in self.storage.lrange(self.TIMES_KEY, start=0, end=end_idx)]
def get_amount_songs(self):
"""
Returns the number of songs stored in the cache
"""
return self.storage.llen(self.TIMES_KEY)
def get_latest_songs(self, amount=50):
"""
Returns the latest [amount] songs
All if [amount] is ::None::
if [amount] is ::1:: only the value of the hash
for the latest song is returned i.e. no time
"""
if amount is 1:
try:
return self.get_song_for_key(self.get_times(amount=1)[0])
except IndexError:
return {"artist": "None", "title": "None"}
_times = self.get_times(amount)
_all_songs = OrderedDict()
for t in self.get_times(amount):
_all_songs[t] = self.get_song_for_key(t)
return _all_songs
def get_song_for_key(self, time):
"""
Returns a song for the given [time]
whereas time has to be an actual existing hash key
"""
return {k.decode("UTF-8"): v.decode("UTF-8") for (k, v) in self.storage.hgetall(time).items()}
def get_songs_by_time(self, req_time, scope=30):
"""
Returns [scope] songs stored around the given [req_time]
[req_time] must be in the correct format _times %d.%m.%Y %H:%M:%S
but does not have to be an existing key
"""
for t in self.get_times():
# Go through the list from HEAD to TAIL and get the [scope] times arounc the
# time that closestly matches [req_time] but is definitly smaller than [req_time]
if strptime(t, "%d.%m.%Y %H:%M:%S") > strptime(str(req_time), "%d.%m.%Y %H:%M:%S"):
continue
# index of this time in the list
_idx = self.get_times().index(t)
_start_idx = max(_idx-int((scope/2)), 0)
_end_idx = min(_idx+int((scope/2)), self.get_amount_songs()-1)
# Get the songs for all scope times and add to dict
_songs = OrderedDict()
for _timekey in self.get_times()[_start_idx:_end_idx]:
_songs[_timekey] = self.get_song_for_key(_timekey)
return _songs
def get_songs_by_text(self, text, scope=None):
"""
returns all songs that match [text] within the latest [scope] songs
"""
_result = OrderedDict()
for k, v in self.get_latest_songs(amount=self.get_amount_songs()).items():
if (v["title"] + v["artist"]).replace(" ", "").lower().find(text.replace(" ", "").lower()) != -1:
_result[k] = v
return _result
def remove_song(self, time):
"""
removes [time] from the list of times and the accoring song from the cache
"""
self.storage.lrem(self.TIMES_KEY, count=1, value=time)
self.storage.delete(time)
class Persistence:
def __init__(self, host="mongo", port=27017, dbname="txfmstore"):
self.db = MongoClient(host, port)[dbname]
self.col_songs = self.db.songs
def add_song(self, song, time):
song["_id"] = time
self.col_songs.insert_one(song)
def is_stored(self, time):
_res = self.col_songs.find_one({"_id": time})
if _res is None:
return False
return True
def get_songs_by_text(self, text, scope=None):
_songs = OrderedDict()
for t in self.get_all_times():
s = self.col_songs.find_one({"_id": t}, {"_id": False})
if (s["title"] + s["artist"]).replace(" ", "").lower().find(text.replace(" ", "").lower()) != -1:
_songs[t] = s
return _songs
def get_songs_by_time(self, req_time, scope=30):
for t in self.get_all_times():
if strptime(t, "%d.%m.%Y %H:%M:%S") > strptime(str(req_time), "%d.%m.%Y %H:%M:%S"):
continue
# index of this time in the list
_idx = self.get_all_times().index(t)
_start_idx = max(_idx-int((scope/2)), 0)
_end_idx = min(_idx+int((scope/2)), len(self.get_all_times())-1)
_songs = OrderedDict()
for _timekey in self.get_all_times()[_start_idx:_end_idx]:
_songs[_timekey] = self.col_songs.find_one({"_id": _timekey}, {"_id": False})
return _songs
def get_all_times(self):
"""
Returns all times for which a song is stored
Format is a time-object
"""
_times = sorted([strptime(t["_id"], "%d.%m.%Y %H:%M:%S")
for t in self.col_songs.find({}, {"_id": True})], reverse=True)
return [strftime("%d.%m.%Y %H:%M:%S", t) for t in _times]