11package xyz .gianlu .librespot .cache ;
22
3- import com .google .protobuf .ByteString ;
43import org .apache .log4j .Logger ;
54import org .jetbrains .annotations .NotNull ;
65import org .jetbrains .annotations .Nullable ;
76import xyz .gianlu .librespot .common .Utils ;
87import xyz .gianlu .librespot .player .GeneralWritableStream ;
8+ import xyz .gianlu .librespot .player .StreamId ;
99
1010import java .io .Closeable ;
1111import java .io .File ;
@@ -31,7 +31,8 @@ public class CacheManager implements Closeable {
3131 private static final byte HEADER_TIMESTAMP = (byte ) 0b11111111;
3232 private final boolean enabled ;
3333 private final File parent ;
34- private final Map <ByteString , Handler > handlers = new ConcurrentHashMap <>();
34+ private final Map <String , Handler > fileHandlers = new ConcurrentHashMap <>();
35+ private final Map <String , Handler > episodeHandlers = new ConcurrentHashMap <>();
3536 private final Connection table ;
3637
3738 public CacheManager (@ NotNull Configuration conf ) throws IOException {
@@ -59,11 +60,6 @@ public CacheManager(@NotNull Configuration conf) throws IOException {
5960 }
6061 }
6162
62- @ NotNull
63- private static File getCacheFile (@ NotNull File parent , @ NotNull ByteString fileId ) throws IOException {
64- return getCacheFile (parent , Utils .bytesToHex (fileId ));
65- }
66-
6763 @ NotNull
6864 private static File getCacheFile (@ NotNull File parent , @ NotNull String hex ) throws IOException {
6965 String firstLevel = hex .substring (0 , 2 );
@@ -88,88 +84,104 @@ private void deleteCorruptedEntries() throws SQLException, IOException {
8884 if (!enabled ) return ;
8985
9086 List <String > toRemove = new ArrayList <>();
91- try (PreparedStatement statement = table .prepareStatement ("SELECT DISTINCT fileId FROM Headers" )) {
87+ try (PreparedStatement statement = table .prepareStatement ("SELECT DISTINCT streamId FROM Headers" )) {
9288 ResultSet set = statement .executeQuery ();
9389 while (set .next ()) {
94- String fileId = set .getString ("fileId " );
95- if (!exists (parent , fileId ))
96- toRemove .add (fileId );
90+ String streamId = set .getString ("streamId " );
91+ if (!exists (parent , streamId ))
92+ toRemove .add (streamId );
9793 }
9894 }
9995
100- for (String fileId : toRemove )
101- remove (fileId );
96+ for (String streamId : toRemove )
97+ remove (streamId );
10298 }
10399
104100 private void doCleanUp () throws SQLException , IOException {
105101 if (!enabled ) return ;
106102
107- try (PreparedStatement statement = table .prepareStatement ("SELECT fileId , value FROM Headers WHERE id=?" )) {
103+ try (PreparedStatement statement = table .prepareStatement ("SELECT streamId , value FROM Headers WHERE id=?" )) {
108104 statement .setString (1 , Utils .byteToHex (HEADER_TIMESTAMP ));
109105
110106 ResultSet set = statement .executeQuery ();
111107 while (set .next ()) {
112108 long timestamp = Long .parseLong (set .getString ("value" ), 16 ) * 1000 ;
113109 if (System .currentTimeMillis () - timestamp > CLEAN_UP_THRESHOLD )
114- remove (set .getString ("fileId " ));
110+ remove (set .getString ("streamId " ));
115111 }
116112 }
117113 }
118114
119- private void remove (@ NotNull String fileIdHex ) throws SQLException , IOException {
115+ private void remove (@ NotNull String streamId ) throws SQLException , IOException {
120116 if (!enabled ) return ;
121117
122- try (PreparedStatement statement = table .prepareStatement ("DELETE FROM Headers WHERE fileId =?" )) {
123- statement .setString (1 , fileIdHex );
118+ try (PreparedStatement statement = table .prepareStatement ("DELETE FROM Headers WHERE streamId =?" )) {
119+ statement .setString (1 , streamId );
124120 statement .executeUpdate ();
125121 }
126122
127- try (PreparedStatement statement = table .prepareStatement ("DELETE FROM Chunks WHERE fileId =?" )) {
128- statement .setString (1 , fileIdHex );
123+ try (PreparedStatement statement = table .prepareStatement ("DELETE FROM Chunks WHERE streamId =?" )) {
124+ statement .setString (1 , streamId );
129125 statement .executeUpdate ();
130126 }
131127
132- File file = getCacheFile (parent , fileIdHex );
128+ File file = getCacheFile (parent , streamId );
133129 if (file .exists () && !file .delete ())
134130 LOGGER .warn ("Couldn't delete cache file: " + file .getAbsolutePath ());
135131
136- LOGGER .trace (String .format ("Removed %s from cache." , fileIdHex ));
132+ LOGGER .trace (String .format ("Removed %s from cache." , streamId ));
137133 }
138134
139135 private void createTablesIfNeeded () throws SQLException {
140136 if (!enabled ) return ;
141137
142138 try (Statement statement = table .createStatement ()) {
143- statement .execute ("CREATE TABLE IF NOT EXISTS Chunks ( `fileId ` VARCHAR NOT NULL, `chunkIndex` INTEGER NOT NULL, `available` INTEGER NOT NULL, PRIMARY KEY(`fileId `,`chunkIndex`) )" );
139+ statement .execute ("CREATE TABLE IF NOT EXISTS Chunks ( `streamId ` VARCHAR NOT NULL, `chunkIndex` INTEGER NOT NULL, `available` INTEGER NOT NULL, PRIMARY KEY(`streamId `,`chunkIndex`) )" );
144140 }
145141
146142 try (Statement statement = table .createStatement ()) {
147- statement .execute ("CREATE TABLE IF NOT EXISTS Headers ( `fileId ` VARCHAR NOT NULL, `id` VARCHAR NOT NULL, `value` VARCHAR NOT NULL, PRIMARY KEY(`fileId `,`id`) )" );
143+ statement .execute ("CREATE TABLE IF NOT EXISTS Headers ( `streamId ` VARCHAR NOT NULL, `id` VARCHAR NOT NULL, `value` VARCHAR NOT NULL, PRIMARY KEY(`streamId `,`id`) )" );
148144 }
149145 }
150146
151147 @ Override
152148 public void close () throws IOException {
153- for (Handler handler : new ArrayList <>(handlers .values ()))
149+ for (Handler handler : new ArrayList <>(fileHandlers .values ()))
154150 handler .close ();
155151 }
156152
157153 @ Nullable
158- public CacheManager .Handler forFileId (@ NotNull ByteString fileId ) throws IOException {
154+ public Handler forWhatever (@ NotNull StreamId id ) throws IOException {
155+ if (!enabled ) return null ;
156+
157+ if (id .isEpisode ()) return forEpisode (id .getEpisodeGid ());
158+ else return forFileId (id .getFileId ());
159+ }
160+
161+ @ Nullable
162+ public Handler forFileId (@ NotNull String fileId ) throws IOException {
159163 if (!enabled ) return null ;
160164
161- Handler handler = handlers .get (fileId );
165+ Handler handler = fileHandlers .get (fileId );
162166 if (handler == null ) {
163167 handler = new Handler (fileId , getCacheFile (parent , fileId ));
164- handlers .put (fileId , handler );
168+ fileHandlers .put (fileId , handler );
165169 }
166170
167171 return handler ;
168172 }
169173
170174 @ Nullable
171- public CacheManager .Handler forFileId (@ NotNull String fileId ) throws IOException {
172- return forFileId (ByteString .copyFrom (Utils .hexToBytes (fileId )));
175+ public Handler forEpisode (@ NotNull String gid ) throws IOException {
176+ if (!enabled ) return null ;
177+
178+ Handler handler = episodeHandlers .get (gid );
179+ if (handler == null ) {
180+ handler = new Handler (gid , getCacheFile (parent , gid ));
181+ episodeHandlers .put (gid , handler );
182+ }
183+
184+ return handler ;
173185 }
174186
175187 public interface Configuration {
@@ -200,12 +212,12 @@ public static Header find(List<Header> headers, byte id) {
200212 }
201213
202214 public class Handler implements Closeable {
203- private final ByteString fileId ;
215+ private final String streamId ;
204216 private final RandomAccessFile io ;
205217 private boolean updatedTimestamp = false ;
206218
207- private Handler (@ NotNull ByteString fileId , @ NotNull File file ) throws IOException {
208- this .fileId = fileId ;
219+ private Handler (@ NotNull String streamId , @ NotNull File file ) throws IOException {
220+ this .streamId = streamId ;
209221
210222 if (!file .exists () && !file .createNewFile ())
211223 throw new IOException ("Couldn't create cache file!" );
@@ -216,21 +228,21 @@ private Handler(@NotNull ByteString fileId, @NotNull File file) throws IOExcepti
216228 private void updateTimestamp () {
217229 if (updatedTimestamp ) return ;
218230
219- try (PreparedStatement statement = table .prepareStatement ("MERGE INTO Headers (fileId , id, value) VALUES (?, ?, ?)" )) {
220- statement .setString (1 , Utils . bytesToHex ( fileId ) );
231+ try (PreparedStatement statement = table .prepareStatement ("MERGE INTO Headers (streamId , id, value) VALUES (?, ?, ?)" )) {
232+ statement .setString (1 , streamId );
221233 statement .setString (2 , Utils .byteToHex (HEADER_TIMESTAMP ));
222234 statement .setString (3 , Utils .bytesToHex (BigInteger .valueOf (System .currentTimeMillis () / 1000 ).toByteArray ()));
223235
224236 statement .executeUpdate ();
225237 updatedTimestamp = true ;
226238 } catch (SQLException ex ) {
227- LOGGER .warn ("Failed updating timestamp for " + Utils . bytesToHex ( fileId ) , ex );
239+ LOGGER .warn ("Failed updating timestamp for " + streamId , ex );
228240 }
229241 }
230242
231243 public void setHeader (byte id , byte [] value ) throws SQLException {
232- try (PreparedStatement statement = table .prepareStatement ("MERGE INTO Headers (fileId , id, value) VALUES (?, ?, ?)" )) {
233- statement .setString (1 , Utils . bytesToHex ( fileId ) );
244+ try (PreparedStatement statement = table .prepareStatement ("MERGE INTO Headers (streamId , id, value) VALUES (?, ?, ?)" )) {
245+ statement .setString (1 , streamId );
234246 statement .setString (2 , Utils .byteToHex (id ));
235247 statement .setString (3 , Utils .bytesToHex (value ));
236248
@@ -242,8 +254,8 @@ public void setHeader(byte id, byte[] value) throws SQLException {
242254
243255 @ NotNull
244256 public List <Header > getAllHeaders () throws SQLException {
245- try (PreparedStatement statement = table .prepareStatement ("SELECT id, value FROM Headers WHERE fileId =?" )) {
246- statement .setString (1 , Utils . bytesToHex ( fileId ) );
257+ try (PreparedStatement statement = table .prepareStatement ("SELECT id, value FROM Headers WHERE streamId =?" )) {
258+ statement .setString (1 , streamId );
247259
248260 List <Header > headers = new ArrayList <>();
249261 ResultSet set = statement .executeQuery ();
@@ -256,8 +268,8 @@ public List<Header> getAllHeaders() throws SQLException {
256268
257269 @ Nullable
258270 public byte [] getHeader (byte id ) throws SQLException {
259- try (PreparedStatement statement = table .prepareStatement ("SELECT value FROM Headers WHERE fileId =? AND id=? LIMIT 1" )) {
260- statement .setString (1 , Utils . bytesToHex ( fileId ) );
271+ try (PreparedStatement statement = table .prepareStatement ("SELECT value FROM Headers WHERE streamId =? AND id=? LIMIT 1" )) {
272+ statement .setString (1 , streamId );
261273 statement .setString (2 , Utils .byteToHex (id ));
262274
263275 ResultSet set = statement .executeQuery ();
@@ -274,8 +286,8 @@ public boolean hasChunk(int index) throws SQLException, IOException {
274286 if (io .length () < (index + 1 ) * CHUNK_SIZE ) return false ;
275287 }
276288
277- try (PreparedStatement statement = table .prepareStatement ("SELECT available FROM Chunks WHERE fileId =? AND chunkIndex=? LIMIT 1" )) {
278- statement .setString (1 , Utils . bytesToHex ( fileId ) );
289+ try (PreparedStatement statement = table .prepareStatement ("SELECT available FROM Chunks WHERE streamId =? AND chunkIndex=? LIMIT 1" )) {
290+ statement .setString (1 , streamId );
279291 statement .setInt (2 , index );
280292
281293 ResultSet set = statement .executeQuery ();
@@ -310,8 +322,8 @@ public void writeChunk(byte[] buffer, int index) throws IOException, SQLExceptio
310322 io .write (buffer );
311323 }
312324
313- try (PreparedStatement statement = table .prepareStatement ("MERGE INTO Chunks (fileId , chunkIndex, available) VALUES (?, ?, ?)" )) {
314- statement .setString (1 , Utils . bytesToHex ( fileId ) );
325+ try (PreparedStatement statement = table .prepareStatement ("MERGE INTO Chunks (streamId , chunkIndex, available) VALUES (?, ?, ?)" )) {
326+ statement .setString (1 , streamId );
315327 statement .setInt (2 , index );
316328 statement .setInt (3 , 1 );
317329
@@ -323,7 +335,7 @@ public void writeChunk(byte[] buffer, int index) throws IOException, SQLExceptio
323335
324336 @ Override
325337 public void close () throws IOException {
326- handlers .remove (fileId );
338+ fileHandlers .remove (streamId );
327339 synchronized (io ) {
328340 io .close ();
329341 }
0 commit comments