package Ġio . case y . mus ik cube . remote . ui . shared . model . album art Ċ Ċ import Ġandroid . content . Context Ċ import Ġandroid . util . L ru Cache Ċ import Ġio . case y . mus ik cube . remote . Application Ċ import Ġio . case y . mus ik cube . remote . service . websocket . model . I Album Ċ import Ġio . case y . mus ik cube . remote . service . websocket . model . IT rack Ċ import Ġio . case y . mus ik cube . remote . ui . settings . constants . Prefs Ċ import Ġio . case y . mus ik cube . remote . util . Strings Ċ import Ġokhttp 3 . Ok HttpClient Ċ import Ġokhttp 3 . Request Ċ import Ġokhttp 3 . Response Ċ import Ġorg . json . JSONException Ċ import Ġorg . json . JSONObject Ċ import Ġjava . io . IOException Ċ import Ġjava . net . URL Encoder Ċ import Ġjava . util . concurrent . Count DownLatch Ċ import Ġjava . util . regex . Pattern Ċ Ċ enum Ġclass ĠSize Ġconstructor ( internal Ġval Ġkey : ĠString , Ġinternal Ġval Ġorder : ĠInt ) Ġ{ ĊĠĠĠ ĠSmall (" small ", Ġ 0 ), ĊĠĠĠ ĠMedium (" medium ", Ġ 1 ), ĊĠĠĠ ĠLarge (" large ", Ġ 2 ), ĊĠĠĠ ĠExtra Large (" extr al arge ", Ġ 3 ), ĊĠĠĠ ĠMe ga (" mega ", Ġ 4 ); ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġinternal Ġfun Ġfrom ( value : ĠString ?): ĠSize Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġvalues (). find Ġ{ Ġit . key Ġ== Ġvalue Ġ} Ġ?: ĠMedium ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ /* Ġused Ġto Ġstrip Ġextr aneous Ġtags Ġ*/ Ċ private Ġval Ġbad Patterns Ġ= ĠarrayOf ( ĊĠĠĠ ĠPattern . compile (" (? i )^ " Ġ+ ĠPattern . quote ("[ ") Ġ+ Ġ" CD " Ġ+ ĠPattern . quote (" ] ")), ĊĠĠĠ ĠPattern . compile (" (? i )" Ġ+ ĠPattern . quote (" (" ) Ġ+ Ġ" disc Ġ\\ d *" Ġ+ ĠPattern . quote (" )") Ġ+ Ġ"$ "), ĊĠĠĠ ĠPattern . compile (" (? i )" Ġ+ ĠPattern . quote ("[ ") Ġ+ Ġ" disc Ġ\\ d *" Ġ+ ĠPattern . quote (" ]") Ġ+ Ġ"$ "), ĊĠĠĠ ĠPattern . compile (" (? i )" Ġ+ ĠPattern . quote ("( +") Ġ+ Ġ" video " Ġ+ ĠPattern . quote (" )") Ġ+ Ġ"$ "), ĊĠĠĠ ĠPattern . compile (" (? i )" Ġ+ ĠPattern . quote ("[ +") Ġ+ Ġ" video " Ġ+ ĠPattern . quote (" ]") Ġ+ Ġ"$ "), ĊĠĠĠ ĠPattern . compile (" (? i )" Ġ+ ĠPattern . quote (" (" ) Ġ+ Ġ" explicit " Ġ+ ĠPattern . quote (" )") Ġ+ Ġ"$ "), ĊĠĠĠ ĠPattern . compile (" (? i )" Ġ+ ĠPattern . quote ("[ ") Ġ+ Ġ" explicit " Ġ+ ĠPattern . quote (" ]") Ġ+ Ġ"$ "), ĊĠĠĠ ĠPattern . compile (" (? i )" Ġ+ ĠPattern . quote ("[ +") Ġ+ Ġ" digital Ġbook let " Ġ+ ĠPattern . quote (" ]") Ġ+ Ġ"$ ")) Ċ Ċ /* Ġhttp :// www . last . fm / group / Last . fm + Web + Services / forum / 2 1 6 0 4 /_ / 5 2 2 9 0 0 Ġ-- Ġit 's Ġok Ġto Ċ put Ġour Ġkey Ġin Ġthe Ġcode Ġ*/ Ċ private Ġval Ġlast Fm Format Url Ġ= ĊĠĠĠ Ġ" http :// ws . aud ios cro bb ler . com / 2 . 0 /? method = album . get info & api _ key =" Ġ+ ĊĠĠĠ Ġ" 5 0 2 c 6 9 bd 3 f 9 9 4 6 e 8 e 0 beee 4 fcb 2 8 c 4 cd & artist =% s & album =% s & format = json & size =% s " Ċ Ċ private Ġval Ġurl Cache Ġ= ĠL ru Cache < String , ĠString >( 5 0 0 ) Ċ private Ġval Ġbad Url Cache Ġ= ĠL ru Cache < String , ĠBoolean >( 1 0 0 ) Ċ private Ġval Ġin Flight Ġ= Ġmutable Map Of < String , ĠCount DownLatch >() Ċ Ċ private Ġval Ġprefs Ġby Ġlazy Ġ{ ĊĠĠĠ ĠApplication . instance !!. get SharedPreferences ( Prefs . NAME , ĠContext . MODE _ PRIVATE ) Ċ } Ċ Ċ fun ĠgetUrl ( album : ĠI Album , Ġsize : ĠSize Ġ= ĠSize . Small ): ĠString ? Ġ{ ĊĠĠĠ Ġreturn Ġget Thumbnail Url ( album . thumbnail Id ) ĊĠĠĠĠĠĠĠ Ġ?: ĠgetUrl ( album . album Artist , Ġalbum . name , Ġsize ) Ċ } Ċ Ċ fun ĠgetUrl ( track : ĠI Track , Ġsize : ĠSize Ġ= ĠSize . Small ): ĠString ? Ġ{ ĊĠĠĠ Ġreturn Ġget Thumbnail Url ( track . thumbnail Id ) ĊĠĠĠĠĠĠĠ Ġ?: ĠgetUrl ( track . artist , Ġtrack . album , Ġsize ) Ċ } Ċ Ċ fun ĠgetUrl ( artist : ĠString Ġ= Ġ"", Ġalbum : ĠString Ġ= Ġ"", Ġsize : ĠSize Ġ= ĠSize . Small ): ĠString ? Ġ{ ĊĠĠĠ Ġif Ġ(! prefs . getBoolean ( Prefs . Key . LAST FM _ ENABLED , ĠP refs . Default . LAST FM _ ENABLED )) Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġif Ġ( artist . isBlank () Ġ|| Ġalbum . isBlank ()) Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġreturn ĠString . format ( last Fm Format Url , Ġde j unk ( artist ), Ġde j unk ( album ), Ġsize . key ) Ċ } Ċ Ċ fun Ġcan Intercept ( request : ĠRequest ): ĠBoolean Ġ{ ĊĠĠĠ Ġreturn Ġrequest . url (). host () Ġ== Ġ" ws . aud ios cro bb ler . com " Ġ&& ĊĠĠĠĠĠĠĠ Ġrequest . url (). query Parameter (" method ") Ġ== Ġ" album . get info " Ċ } Ċ Ċ private Ġval ĠhttpClient Ġ= ĠOk HttpClient . Builder (). build () Ċ Ċ private Ġfun Ġexecute With Retries ( req : ĠRequest ): ĠResponse ? Ġ{ ĊĠĠĠ Ġvar Ġcount Ġ= Ġ 0 ĊĠĠĠ Ġvar Ġresult : ĠResponse ? Ġ= Ġnull ĊĠĠĠ Ġwhile Ġ( count ++ Ġ< Ġ 3 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= ĠhttpClient . new Call ( req ). execute () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( response . is Successful ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresult Ġ= Ġresponse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġcatch Ġ( ex : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ/* Ġom Ġnom Ġnom Ġ*/ ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn Ġresult Ċ } Ċ Ċ fun Ġintercept ( req : ĠRequest ): ĠRequest ? Ġ{ ĊĠĠĠ Ġval Ġurl Ġ= Ġreq . url () ĊĊĠĠĠ Ġvar ĠimageUrl Ġ= Ġurl Cache [ url . toString ()] Ġ?: Ġ"" ĊĠĠĠ Ġval Ġdesired Size Ġ= ĠSize . from ( url . query Parameter (" size ")) ĊĠĠĠ Ġvar Ġbad Url Ġ= Ġfalse ĊĠĠĠ Ġvar Ġpending : ĠCount DownLatch ? Ġ= Ġnull ĊĊĠĠĠ Ġsynchronized ( url Cache ) Ġ{ ĊĠĠĠĠĠĠĠ Ġbad Url Ġ= Ġbad Url Cache . get ( url . toString ()) Ġ?: Ġfalse ĊĠĠĠĠĠĠĠ Ġpending Ġ= Ġin Flight [ url . toString ()] ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/* Ġlet 's Ġsee Ġif Ġthere 's Ġalready Ġanother Ġrequest Ġfor Ġthis ĠURL Ġin Ġflight . Ġif Ġthere Ġis , ĊĠĠĠ Ġlet Ġit Ġfinish , Ġas Ġit 'll Ġwind Ġup Ġin Ġthe Ġcache Ġand Ġwe Ġwon 't Ġhave Ġto Ġmake Ġmultiple ĊĠĠĠ Ġrequests Ġagainst Ġthe Ġbackend Ġ*/ ĊĠĠĠ Ġif Ġ( pending Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠ Ġpending ?. await () ĊĠĠĠĠĠĠĠ Ġpending Ġ= Ġnull ĊĊĠĠĠĠĠĠĠ Ġsynchronized ( url Cache ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠimageUrl Ġ= Ġurl Cache [ url . toString ()] Ġ?: Ġ"" ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/* Ġdepending Ġon Ġthe Ġabove , Ġwe Ġmay Ġhave Ġan ĠimageUrl ! Ġif Ġwe Ġdo , Ġwe 're Ġgood . Ġotherwise , ĊĠĠĠ Ġlet 's Ġsetup Ġthe Ġcount down Ġl atch Ġso Ġsubsequent Ġrequests Ġwait ... Ġ*/ ĊĠĠĠ Ġif Ġ( imageUrl . isBlank () Ġ&& Ġ! bad Url ) Ġ{ ĊĠĠĠĠĠĠĠ Ġsynchronized ( url Cache ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpending Ġ= ĠCount DownLatch ( 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġin Flight . put ( url . toString (), Ġpending !! ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġif Ġ( imageUrl . isBlank () Ġ&& Ġ! bad Url ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= Ġexecute With Retries ( req ) ĊĊĠĠĠĠĠĠĠ Ġif Ġ( response Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġimages Ġ= Ġmutable ListOf < Pair < Size , ĠString >>() ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġjson Ġ= ĠJSONObject ( response . body ()?. string ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġimages Json Ġ= Ġjson . getJSONObject (" album "). get JSONArray (" image ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( i Ġin Ġ 0 Ġuntil Ġimages Json . length ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġimage Json Ġ= Ġimages Json . getJSONObject ( i ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsize Ġ= ĠSize . from ( image Json . opt String (" size ", Ġ"")) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġresolved Url Ġ= Ġimage Json . opt String ("# text ", Ġ"") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( Strings . not Empty ( resolved Url )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġimages . add ( Pair < Size , ĠString >( size , Ġresolved Url )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcatch Ġ( ex : ĠJSON Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbad Url Cache . put ( url . toString (), Ġtrue ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( images . size Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ/* Ġfind Ġthe Ġimage Ġwith Ġthe Ġclosest Ġto Ġthe Ġrequested Ġsize . ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexact Ġmatch Ġpreferred . Ġ*/ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġclosest Ġ= Ġimages [ 0 ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġlast Delta Ġ= ĠInteger . MAX _ VALUE ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( check Ġin Ġimages ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( check . first Ġ== Ġdesired Size ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclosest Ġ= Ġcheck ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdelta Ġ= ĠMath . abs ( desired Size . order Ġ- Ġcheck . first . order ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( last Delta Ġ> Ġdelta ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclosest Ġ= Ġcheck ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlast Delta Ġ= Ġdelta ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠimageUrl Ġ= Ġclosest . second ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġvar Ġresult : ĠRequest ? Ġ= Ġnull ĊĊĠĠĠ Ġif Ġ( imageUrl . isNotBlank ()) Ġ{ ĊĠĠĠĠĠĠĠ Ġsynchronized ( url Cache ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġurl Cache . put ( url . toString (), ĠimageUrl ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġif Ġ( desired Size Ġ== ĠSize . Me ga ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠimageUrl Ġ= ĠimageUrl . replace ("/ i / u / 3 0 0 x 3 0 0 ", Ġ"/ i / u / 6 0 0 x 6 0 0 ") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġresult Ġ= ĠRequest . Builder (). url ( imageUrl ). build () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsynchronized ( url Cache ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( pending Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpending ?. count Down () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġin Flight . remove ( url . toString ()) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġreturn Ġresult Ċ } Ċ Ċ private Ġfun Ġget Thumbnail Url ( id : ĠLong ): ĠString ? Ġ{ ĊĠĠĠ Ġif Ġ( id Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġhost Ġ= Ġprefs . getString ( Prefs . Key . ADDRESS , ĠP refs . Default . ADDRESS ) ĊĠĠĠĠĠĠĠ Ġval Ġport Ġ= Ġprefs . getInt ( Prefs . Key . AUDIO _ PORT , ĠP refs . Default . MAIN _ PORT ) ĊĠĠĠĠĠĠĠ Ġval Ġssl Ġ= Ġprefs . getBoolean ( Prefs . Key . SSL _ ENABLED , ĠP refs . Default . SSL _ ENABLED ) ĊĠĠĠĠĠĠĠ Ġval Ġscheme Ġ= Ġif Ġ( ssl ) Ġ" https " Ġelse Ġ" http " ĊĠĠĠĠĠĠĠ Ġreturn Ġ"$ scheme :// $ host :$ port / thumbnail /$ id " ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn Ġnull Ċ } Ċ Ċ private Ġfun Ġde j unk ( album : ĠString ): ĠString Ġ{ ĊĠĠĠ Ġvar Ġresult Ġ= Ġalbum ĊĠĠĠ Ġfor Ġ( pattern Ġin Ġbad Patterns ) Ġ{ ĊĠĠĠĠĠĠĠ Ġresult Ġ= Ġpattern . matcher ( result ). replaceAll ("") ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn ĠURL Encoder . encode ( result . trim Ġ{ Ġit . is Whitespace () Ġ}) Ċ }