A music player that connects to your cloud/distributed storage.
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

More work for the Blockstack integration, still blocked though

+194 -54
+3 -2
Makefile
··· 71 71 72 72 73 73 install: 74 - @echo "> Downloading & minifying dependencies" 74 + @echo "> Downloading dependencies" 75 75 @mkdir -p $(VENDOR_DIR) 76 - @curl https://unpkg.com/blockstack@19.2.1/dist/blockstack.js -o $(VENDOR_DIR)/blockstack.min.js 76 + @curl https://unpkg.com/blockstack@19.2.2-beta.1/dist/blockstack.js -o $(VENDOR_DIR)/blockstack.min.js 77 77 @curl https://unpkg.com/lunr@2.3.6/lunr.js -o $(VENDOR_DIR)/lunr.js 78 78 @curl https://unpkg.com/remotestoragejs@1.2.2/release/remotestorage.js -o $(VENDOR_DIR)/remotestorage.min.js 79 79 @curl https://unpkg.com/fast-text-encoding@1.0.0/text.min.js -o $(VENDOR_DIR)/text-encoding-polyfill.min.js ··· 86 86 @curl https://raw.githubusercontent.com/dmihal/Subworkers/6c3a57953615b26cd82fd39894b947f2b954fcfd/subworkers.js -o $(VENDOR_DIR)/subworkers-polyfill.js 87 87 88 88 @# Minify non-minified dependencies 89 + @echo "> Minifying dependencies" 89 90 @closure-compiler --js=$(VENDOR_DIR)/subworkers-polyfill.js --js_output_file=$(VENDOR_DIR)/subworkers-polyfill.min.js 90 91 @closure-compiler --js=$(VENDOR_DIR)/lunr.js --js_output_file=$(VENDOR_DIR)/lunr.min.js 91 92 @closure-compiler --js=$(VENDOR_DIR)/pep.js --js_output_file=$(VENDOR_DIR)/pep.min.js
+27 -11
src/Applications/Brain.elm
··· 12 12 import Debouncer.Basic as Debouncer 13 13 import Json.Decode as Json 14 14 import Json.Encode 15 + import Maybe.Extra as Maybe 15 16 import Playlists.Encoding as Playlists 16 17 import Return2 exposing (..) 17 18 import Return3 ··· 19 20 import Sources.Processing.Encoding as Processing 20 21 import Tracks 21 22 import Tracks.Encoding as Tracks 23 + import Url 22 24 23 25 24 26 ··· 39 41 40 42 41 43 init : Flags -> ( Model, Cmd Msg ) 42 - init flags = 44 + init _ = 43 45 ( ----------------------------------------- 44 46 -- Initial model 45 47 ----------------------------------------- ··· 58 60 ----------------------------------------- 59 61 -- Initial command 60 62 ----------------------------------------- 61 - , Cmd.batch 62 - [ Cmd.map AuthenticationMsg Authentication.initialCommand 63 - , Cmd.map ProcessingMsg Processing.initialCommand 64 - ] 63 + , Cmd.none 65 64 ) 66 65 67 66 ··· 75 74 Bypass -> 76 75 return model 77 76 77 + Initialize href -> 78 + let 79 + initialUrl = 80 + Maybe.withDefault 81 + { protocol = Url.Http 82 + , host = "" 83 + , port_ = Nothing 84 + , path = "" 85 + , query = Nothing 86 + , fragment = Nothing 87 + } 88 + (Url.fromString href) 89 + in 90 + [ Cmd.map AuthenticationMsg (Authentication.initialCommand initialUrl) 91 + , Cmd.map ProcessingMsg Processing.initialCommand 92 + ] 93 + |> Cmd.batch 94 + |> returnWithModel model 95 + 78 96 NotifyUI alienEvent -> 79 97 [ Brain.Ports.toUI alienEvent 80 98 ··· 109 127 ----------------------------------------- 110 128 -- Authentication 111 129 ----------------------------------------- 112 - RedirectToBlockstackSignIn origin -> 113 - origin 130 + RedirectToBlockstackSignIn -> 131 + () 114 132 |> Brain.Ports.redirectToBlockstackSignIn 115 133 |> returnWithModel model 116 134 ··· 356 374 subscriptions model = 357 375 Sub.batch 358 376 [ Brain.Ports.fromAlien alien 377 + , Brain.Ports.initialize Initialize 359 378 360 379 ----------------------------------------- 361 380 -- Children ··· 425 444 report Alien.ProcessSources (Json.errorToString err) 426 445 427 446 Alien.RedirectToBlockstackSignIn -> 428 - data 429 - |> Json.decodeValue (Json.field "origin" Json.string) 430 - |> Result.withDefault "" 431 - |> RedirectToBlockstackSignIn 447 + RedirectToBlockstackSignIn 432 448 433 449 Alien.RemoveTracksBySourceId -> 434 450 data
+24 -6
src/Applications/Brain/Authentication.elm
··· 28 28 import Json.Encode as Json 29 29 import Return3 as Return exposing (..) 30 30 import Task.Extra exposing (do) 31 + import Url exposing (Url) 32 + import Url.Extra as Url 31 33 32 34 33 35 ··· 47 49 } 48 50 49 51 50 - initialCommand : Cmd Msg 51 - initialCommand = 52 - Cmd.batch 53 - [ do RetrieveMethod 54 - , do RetrieveEnclosedData 55 - ] 52 + initialCommand : Url -> Cmd Msg 53 + initialCommand initialUrl = 54 + case Url.action initialUrl of 55 + [ "authenticate", "blockstack" ] -> 56 + case Url.extractQueryParam "authResponse" initialUrl of 57 + Just authResponse -> 58 + Cmd.batch 59 + [ do RetrieveEnclosedData 60 + , Ports.handlePendingBlockstackSignIn authResponse 61 + ] 62 + 63 + Nothing -> 64 + Cmd.batch 65 + [ do RetrieveMethod 66 + , do RetrieveEnclosedData 67 + ] 68 + 69 + _ -> 70 + Cmd.batch 71 + [ do RetrieveMethod 72 + , do RetrieveEnclosedData 73 + ] 56 74 57 75 58 76
+2 -1
src/Applications/Brain/Core.elm
··· 36 36 37 37 type Msg 38 38 = Bypass 39 + | Initialize String 39 40 | NotifyUI Alien.Event 40 41 | NotSoFast (Debouncer.Msg Msg) 41 42 | ToCache Alien.Event 42 43 ----------------------------------------- 43 44 -- Authentication 44 45 ----------------------------------------- 45 - | RedirectToBlockstackSignIn String 46 + | RedirectToBlockstackSignIn 46 47 ----------------------------------------- 47 48 -- Children 48 49 -----------------------------------------
+8 -2
src/Applications/Brain/Ports.elm
··· 1 - port module Brain.Ports exposing (fabricateSecretKey, fromAlien, receiveSearchResults, receiveTags, redirectToBlockstackSignIn, removeCache, requestBlockstack, requestCache, requestIpfs, requestRemoteStorage, requestSearch, requestTags, requestTextile, toBlockstack, toCache, toIpfs, toRemoteStorage, toTextile, toUI, updateSearchIndex) 1 + port module Brain.Ports exposing (fabricateSecretKey, fromAlien, handlePendingBlockstackSignIn, initialize, receiveSearchResults, receiveTags, redirectToBlockstackSignIn, removeCache, requestBlockstack, requestCache, requestIpfs, requestRemoteStorage, requestSearch, requestTags, requestTextile, toBlockstack, toCache, toIpfs, toRemoteStorage, toTextile, toUI, updateSearchIndex) 2 2 3 3 import Alien 4 4 import Json.Encode as Json ··· 12 12 port fabricateSecretKey : Alien.Event -> Cmd msg 13 13 14 14 15 - port redirectToBlockstackSignIn : String -> Cmd msg 15 + port handlePendingBlockstackSignIn : String -> Cmd msg 16 + 17 + 18 + port redirectToBlockstackSignIn : () -> Cmd msg 16 19 17 20 18 21 port removeCache : Alien.Event -> Cmd msg ··· 65 68 66 69 67 70 port fromAlien : (Alien.Event -> msg) -> Sub msg 71 + 72 + 73 + port initialize : (String -> msg) -> Sub msg 68 74 69 75 70 76 port receiveSearchResults : (List String -> msg) -> Sub msg
+10 -8
src/Applications/UI.elm
··· 106 106 init : Flags -> Url -> Nav.Key -> ( Model, Cmd Msg ) 107 107 init flags url key = 108 108 let 109 + rewrittenUrl = 110 + Page.rewriteUrl url 111 + 109 112 maybePage = 110 - Page.fromUrl url 113 + Page.fromUrl rewrittenUrl 111 114 112 115 page = 113 116 Maybe.withDefault Page.Index maybePage ··· 667 670 LinkClicked (Browser.External href) -> 668 671 returnWithModel model (Nav.load href) 669 672 670 - UrlChanged ({ fragment, query } as urlWithQuery) -> 673 + UrlChanged url -> 671 674 let 672 - url = 673 - { urlWithQuery | query = Nothing } 675 + rewrittenUrl = 676 + Page.rewriteUrl { url | query = Nothing } 674 677 in 675 - case ( query, Page.fromUrl url ) of 678 + case ( url.query, Page.fromUrl rewrittenUrl ) of 676 679 ( Nothing, Just page ) -> 677 680 { model | page = page, url = url } 678 681 |> return ··· 717 720 -- Authentication 718 721 ----------------------------------------- 719 722 ExternalAuth Authentication.Blockstack _ -> 720 - [ ( "origin", Json.Encode.string (Common.urlOrigin model.url) ) ] 721 - |> Json.Encode.object 722 - |> Alien.broadcast Alien.RedirectToBlockstackSignIn 723 + Alien.RedirectToBlockstackSignIn 724 + |> Alien.trigger 723 725 |> Ports.toBrain 724 726 |> returnWithModel model 725 727
+5 -3
src/Applications/UI/Authentication.elm
··· 23 23 import Material.Icons.Av as Icons 24 24 import Material.Icons.Content as Icons 25 25 import Material.Icons.Navigation as Icons 26 + import Maybe.Extra as Maybe 26 27 import Return3 as Return exposing (..) 27 28 import SHA 28 29 import String.Ext as String ··· 33 34 import UI.Reply exposing (Reply(..)) 34 35 import UI.Svg.Elements 35 36 import Url exposing (Url) 37 + import Url.Extra as Url 36 38 37 39 38 40 ··· 69 71 70 72 initialModel : Url -> Model 71 73 initialModel url = 72 - case String.split "/" (String.dropLeft 1 url.path) of 74 + case Url.action url of 73 75 [ "authenticate", "remotestorage", encodedUserAddress ] -> 74 76 let 75 77 userAddress = ··· 642 644 , outOfOrder = False 643 645 } 644 646 , choiceButton 645 - { action = Bypass -- TriggerExternalAuth Blockstack "" 647 + { action = TriggerExternalAuth Blockstack "" 646 648 , icon = \_ _ -> Svg.map never UI.Svg.Elements.blockstackLogo 647 649 , infoLink = Just "https://blockstack.org" 648 650 , isLast = False 649 651 , label = "Blockstack" 650 - , outOfOrder = True 652 + , outOfOrder = False 651 653 } 652 654 , choiceButton 653 655 { action =
+12 -7
src/Applications/UI/Page.elm
··· 1 - module UI.Page exposing (Page(..), fromUrl, sameBase, sources, toString) 1 + module UI.Page exposing (Page(..), fromUrl, rewriteUrl, sameBase, sources, toString) 2 2 3 3 import Maybe.Extra as Maybe 4 4 import Sources exposing (Service(..)) ··· 29 29 30 30 31 31 fromUrl : Url -> Maybe Page 32 - fromUrl url = 33 - if Maybe.unwrap False (String.contains "path=") url.query == True then 32 + fromUrl = 33 + parse route 34 + 35 + 36 + rewriteUrl : Url -> Url 37 + rewriteUrl url = 38 + if Maybe.unwrap False (String.contains "path=") url.query then 34 39 -- Sometimes we have to use this kind of routing when doing redirections 35 40 let 36 41 maybePath = ··· 41 46 path = 42 47 Maybe.withDefault "" maybePath 43 48 in 44 - if Maybe.unwrap False (String.contains "token=") url.fragment == True then 49 + if Maybe.unwrap False (String.contains "token=") url.fragment then 45 50 -- For some oauth stuff, replace the query with the fragment 46 - parse route { url | path = path, query = url.fragment } 51 + { url | path = path, query = url.fragment } 47 52 48 53 else 49 - parse route { url | path = path } 54 + { url | path = path } 50 55 51 56 else 52 57 -- Otherwise do hash-based routing and replace the path with the fragment 53 - parse route { url | path = Maybe.withDefault "" url.fragment } 58 + { url | path = Maybe.withDefault "" url.fragment } 54 59 55 60 56 61 toString : Page -> String
+44 -12
src/Javascript/Workers/brain.js
··· 17 17 const app = Elm.Brain.init() 18 18 19 19 20 + function initialize(initialUrl) { 21 + app.ports.initialize.send(initialUrl) 22 + } 23 + 24 + 20 25 21 26 // UI 22 27 // == 23 28 24 29 self.onmessage = event => { 25 - if (event.data.tag) app.ports.fromAlien.send(event.data) 30 + if (event.data.action) return handleAction(event.data.action, event.data.data) 31 + if (event.data.tag) return app.ports.fromAlien.send(event.data) 26 32 } 33 + 27 34 28 35 app.ports.toUI.subscribe(event => { 29 36 self.postMessage(event) 30 37 }) 38 + 39 + 40 + function handleAction(action, data) { switch (action) { 41 + case "INITIALIZE": return initialize(data) 42 + }} 31 43 32 44 33 45 ··· 92 104 let bl 93 105 94 106 95 - function bl0ckst4ck(appDomain) { 107 + function bl0ckst4ck() { 96 108 if (!bl) { 97 109 importScripts("/vendor/blockstack.min.js") 98 110 99 111 bl = new blockstack.UserSession({ 100 - options: { 101 - appConfig: new blockstack.AppConfig({ 102 - appDomain: appDomain 103 - }), 104 - sessionStore: BLOCKSTACK_SESSION_STORE 105 - } 112 + appConfig: new blockstack.AppConfig({ 113 + appDomain: location.origin 114 + }), 115 + sessionStore: BLOCKSTACK_SESSION_STORE 106 116 }) 107 117 } 108 118 ··· 118 128 } 119 129 120 130 121 - app.ports.redirectToBlockstackSignIn.subscribe(event => { 122 - const session = bl0ckst4ck(event.data) 131 + app.ports.handlePendingBlockstackSignIn.subscribe(authResponse => { 132 + const session = bl0ckst4ck() 133 + 134 + console.log("TODO", authResponse) 135 + 123 136 // TODO 137 + session.handlePendingSignIn(authResponse).then(userData => { 138 + console.log(userData) 139 + }) 140 + }) 141 + 142 + 143 + app.ports.redirectToBlockstackSignIn.subscribe(event => { 144 + const session = bl0ckst4ck() 145 + const authRequest = session.makeAuthRequest( 146 + session.generateAndStoreTransitKey(), 147 + location.origin + "?action=authenticate/blockstack", 148 + location.origin + "/manifest.json", 149 + [ "store_write" ] 150 + ) 151 + 152 + self.postMessage({ 153 + action: "REDIRECT_TO_BLOCKSTACK", 154 + data: authRequest 155 + }) 124 156 }) 125 157 126 158 127 159 app.ports.requestBlockstack.subscribe(event => { 128 - const session = bl0ckst4ck(event.data.appDomain) 160 + const session = bl0ckst4ck() 129 161 // TODO 130 162 }) 131 163 132 164 133 165 app.ports.toBlockstack.subscribe(event => { 134 166 const json = JSON.stringify(event.data.data) 135 - const session = bl0ckst4ck(event.data.appDomain) 167 + const session = bl0ckst4ck() 136 168 // TODO 137 169 }) 138 170
+33 -1
src/Javascript/index.js
··· 28 28 29 29 const brain = new Worker("workers/brain.js") 30 30 31 + 31 32 app.ports.toBrain.subscribe(thing => { 32 33 brain.postMessage(thing) 33 34 }) 34 35 36 + 35 37 brain.onmessage = event => { 36 - if (event.data.tag) app.ports.fromAlien.send(event.data) 38 + if (event.data.action) return handleAction(event.data.action, event.data.data) 39 + if (event.data.tag) return app.ports.fromAlien.send(event.data) 37 40 } 41 + 42 + 43 + brain.postMessage({ 44 + action: "INITIALIZE", 45 + data: window.location.href 46 + }) 47 + 48 + 49 + function handleAction(action, data) { switch (action) { 50 + case "REDIRECT_TO_BLOCKSTACK": return redirectToBlockstack(data) 51 + }} 38 52 39 53 40 54 ··· 122 136 123 137 124 138 139 + // Authentication 140 + // -------------- 141 + 142 + function redirectToBlockstack(authRequest) { 143 + switch (location.hostname) { 144 + case "0.0.0.0": 145 + case "127.0.0.1": 146 + case "localhost": 147 + return window.location.href = `http://localhost:8888/auth?authRequest=${authRequest}` 148 + 149 + default: 150 + return window.location.href = `https://browser.blockstack.org/auth?authRequest=${authRequest}` 151 + } 152 + } 153 + 154 + 155 + 125 156 // Backdrop 126 157 // -------- 127 158 ··· 186 217 187 218 window.addEventListener("online", onlineStatusChanged) 188 219 window.addEventListener("offline", onlineStatusChanged) 220 + 189 221 190 222 function onlineStatusChanged() { 191 223 app.ports.setIsOnline.send(navigator.onLine)
+1 -1
src/Library/Authentication/RemoteStorage.elm
··· 48 48 in 49 49 String.concat 50 50 [ oauthOrigin 51 - , "?redirect_uri=" ++ Url.percentEncode (origin ++ "/authenticate/remotestorage/" ++ ua) 51 + , "?redirect_uri=" ++ Url.percentEncode (origin ++ "?action=authenticate/remotestorage/" ++ ua) 52 52 , "&client_id=" ++ Url.percentEncode origin 53 53 , "&scope=" ++ Url.percentEncode "diffuse:rw" 54 54 , "&response_type=token"
+25
src/Library/Url/Extra.elm
··· 1 + module Url.Extra exposing (action, extractQueryParam) 2 + 3 + import Maybe.Extra as Maybe 4 + import Url exposing (Url) 5 + import Url.Parser as Url 6 + import Url.Parser.Query as Query 7 + 8 + 9 + 10 + -- 🔱 11 + 12 + 13 + action : Url -> List String 14 + action url = 15 + url 16 + |> extractQueryParam "action" 17 + |> Maybe.map (String.split "/") 18 + |> Maybe.withDefault [] 19 + 20 + 21 + extractQueryParam : String -> Url -> Maybe String 22 + extractQueryParam key url = 23 + url 24 + |> Url.parse (Url.query (Query.string key)) 25 + |> Maybe.join