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.

Closes #214

+156 -23
+1 -1
Justfile
··· 77 77 @elm: 78 78 echo "> Compiling Elm application" 79 79 elm make {{SRC_DIR}}/Applications/Brain.elm --output {{BUILD_DIR}}/brain.elm.js 80 - elm make {{SRC_DIR}}/Applications/UI.elm --output {{BUILD_DIR}}/ui.elm.js 80 + elm make {{SRC_DIR}}/Applications/UI.elm --output {{BUILD_DIR}}/ui.elm.js --debug 81 81 82 82 83 83 @elm-prod:
+2 -7
src/Applications/UI/Adjunct.elm
··· 6 6 import Return.Ext as Return 7 7 import UI.Alfred.State as Alfred 8 8 import UI.Audio.State as Audio 9 - import UI.Authentication.Types as Authentication 9 + import UI.Authentication.Common as Authentication 10 10 import UI.Common.State as Common 11 11 import UI.Interface.State exposing (hideOverlay) 12 12 import UI.Page as Page ··· 32 32 Return.singleton m 33 33 34 34 authenticated = 35 - case model.authentication of 36 - Authentication.Authenticated _ -> 37 - True 38 - 39 - _ -> 40 - False 35 + Authentication.isAuthenticated model.authentication 41 36 in 42 37 if not authenticated || (m.focusedOnInput && Maybe.isNothing model.alfred) then 43 38 case m.pressedKeys of
+10
src/Applications/UI/Authentication/Common.elm
··· 8 8 -- 🛠 9 9 10 10 11 + isAuthenticated : State -> Bool 12 + isAuthenticated state = 13 + case state of 14 + Authenticated _ -> 15 + True 16 + 17 + _ -> 18 + False 19 + 20 + 11 21 extractMethod : State -> Maybe Method 12 22 extractMethod state = 13 23 case state of
+22 -14
src/Applications/UI/Authentication/State.elm
··· 29 29 import UI.Backdrop as Backdrop 30 30 import UI.Common.State as Common exposing (showNotification, showNotificationWithModel) 31 31 import UI.Ports as Ports 32 + import UI.Sources.Query 32 33 import UI.Sources.State as Sources 33 34 import UI.Types as UI exposing (..) 34 35 import UI.User.State.Import as User ··· 283 284 notAuthenticated model = 284 285 -- This is the message we get when the app initially 285 286 -- finds out we're not authenticated. 286 - andThen 287 - Backdrop.setDefault 288 - (if model.isUpgrading then 289 - """ 290 - Thank you for using Diffuse V1! 291 - If you want to import your old data, 292 - please pick the storage method you used before and 293 - go to the [import page](#/settings/import-export). 294 - """ 295 - |> Notifications.stickySuccess 296 - |> showNotificationWithModel { model | isUpgrading = False } 287 + (if model.isUpgrading then 288 + """ 289 + Thank you for using Diffuse V1! 290 + If you want to import your old data, 291 + please pick the storage method you used before and 292 + go to the [import page](#/settings/import-export). 293 + """ 294 + |> Notifications.stickySuccess 295 + |> showNotificationWithModel { model | isUpgrading = False } 296 + 297 + else 298 + Return.singleton model 299 + ) 300 + |> andThen Backdrop.setDefault 301 + -- When the user wants to create a source (by passing the info through the url) 302 + -- and the user isn't signed in yet, sign in using the "Local" method. 303 + |> (if UI.Sources.Query.requestedAddition model.url then 304 + andThen (signIn Local) 297 305 298 - else 299 - Return.singleton model 300 - ) 306 + else 307 + identity 308 + ) 301 309 302 310 303 311 remoteStorageWebfinger : RemoteStorage.Attributes -> Result Http.Error String -> Manager
+68
src/Applications/UI/Sources/Query.elm
··· 1 + module UI.Sources.Query exposing (..) 2 + 3 + import Dict 4 + import Json.Decode as Decode 5 + import Sources exposing (Source) 6 + import Url exposing (Url) 7 + import Url.Parser as Url 8 + import Url.Parser.Query as Query 9 + 10 + 11 + requestedAddition : Url -> Bool 12 + requestedAddition url = 13 + case Url.parse (urlParser identity) url of 14 + Nothing -> 15 + False 16 + 17 + Just [] -> 18 + False 19 + 20 + Just (_ :: _) -> 21 + True 22 + 23 + 24 + sourcesFromUrl : Url -> List Source 25 + sourcesFromUrl url = 26 + url 27 + |> Url.parse (urlParser <| List.filterMap fromUrl) 28 + |> Maybe.withDefault [] 29 + 30 + 31 + 32 + -- 🔬 33 + 34 + 35 + fromUrl : String -> Maybe Source 36 + fromUrl json = 37 + json 38 + |> Decode.decodeString sourceParser 39 + |> Result.toMaybe 40 + 41 + 42 + urlParser individualParser = 43 + individualParser 44 + |> Query.custom "source" 45 + |> Url.query 46 + 47 + 48 + sourceParser : Decode.Decoder Source 49 + sourceParser = 50 + Decode.andThen 51 + (\{ service, data } -> 52 + if Dict.member "name" data then 53 + Decode.succeed 54 + { id = "FILL_IN_LATER" 55 + , data = data 56 + , directoryPlaylists = True 57 + , enabled = True 58 + , service = service 59 + } 60 + 61 + else 62 + Decode.fail "Missing `name` in `data` dictionary" 63 + ) 64 + <| 65 + Decode.map2 66 + (\s d -> { service = s, data = d }) 67 + (Decode.field "kind" Sources.serviceDecoder) 68 + (Decode.field "data" <| Decode.dict Decode.string)
+19
src/Applications/UI/Sources/State.elm
··· 26 26 import UI.Sources.ContextMenu as Sources 27 27 import UI.Sources.Form as Form 28 28 import UI.Sources.Page as Sources 29 + import UI.Sources.Query 29 30 import UI.Sources.Types exposing (..) 30 31 import UI.Tracks.State as Tracks 31 32 import UI.Types as UI exposing (Manager, Model) ··· 148 149 149 150 150 151 -- 🔱 152 + 153 + 154 + addSourcesFromUrl : Manager 155 + addSourcesFromUrl model = 156 + case UI.Sources.Query.sourcesFromUrl model.url of 157 + [] -> 158 + Return.singleton model 159 + 160 + sources -> 161 + sources 162 + |> List.foldl 163 + (\s -> andThen <| addToCollection s) 164 + (Return.singleton model) 165 + |> Return.command 166 + (Nav.replaceUrl 167 + model.navKey 168 + (model.url.path ++ Page.toString model.page) 169 + ) 151 170 152 171 153 172 finishedProcessing : Manager
+2
src/Applications/UI/User/State/Import.elm
··· 126 126 Return.singleton m 127 127 ) 128 128 |> andThen 129 + Sources.addSourcesFromUrl 130 + |> andThen 129 131 (\m -> 130 132 if m.processAutomatically then 131 133 Sources.process m
+32 -1
src/Library/Sources.elm
··· 1 - module Sources exposing (Property, Service(..), Source, SourceData, enabledSourceIds, setProperId) 1 + module Sources exposing (..) 2 2 3 3 import Conditional exposing (..) 4 4 import Dict exposing (Dict) 5 + import Json.Decode 5 6 import Time 6 7 7 8 ··· 47 48 | Google 48 49 | Ipfs 49 50 | WebDav 51 + 52 + 53 + serviceDictionary : Dict String Service 54 + serviceDictionary = 55 + Dict.fromList 56 + [ ( "amazons3", AmazonS3 ) 57 + , ( "amazon_s3", AmazonS3 ) 58 + , ( "azureblob", AzureBlob ) 59 + , ( "azure_blob", AzureBlob ) 60 + , ( "azurefile", AzureFile ) 61 + , ( "azure_file", AzureFile ) 62 + , ( "btfs", Btfs ) 63 + , ( "dropbox", Dropbox ) 64 + , ( "google", Google ) 65 + , ( "ipfs", Ipfs ) 66 + , ( "webdav", WebDav ) 67 + , ( "web_dav", WebDav ) 68 + ] 69 + 70 + 71 + serviceDecoder : Json.Decode.Decoder Service 72 + serviceDecoder = 73 + Json.Decode.andThen 74 + (\string -> 75 + serviceDictionary 76 + |> Dict.get string 77 + |> Maybe.map Json.Decode.succeed 78 + |> Maybe.withDefault (Json.Decode.fail "Invalid source kind") 79 + ) 80 + Json.Decode.string 50 81 51 82 52 83