A music player that connects to your cloud/distributed storage.
at main 214 lines 4.7 kB view raw
1module Sources.Services.WebDav exposing (defaults, initialData, makeTrackUrl, makeTree, parseErrorResponse, parsePreparationResponse, parseTreeResponse, postProcessTree, prepare, properties) 2 3{-| IPFS Service. 4 5Resources: 6 7 - <https://ipfs.io/docs/api/> 8 9-} 10 11import Base64 12import Common 13import Dict 14import Dict.Ext as Dict 15import Http 16import Sources exposing (Property, SourceData) 17import Sources.Pick exposing (selectMusicFiles) 18import Sources.Processing exposing (..) 19import Sources.Services.Common exposing (noPrep) 20import Sources.Services.WebDav.Marker as Marker 21import Sources.Services.WebDav.Parser as Parser 22import String.Ext as String 23import Time 24import Url 25 26 27 28-- PROPERTIES 29-- 📟 30 31 32defaults = 33 { name = "Music from WebDAV" 34 } 35 36 37{-| The list of properties we need from the user. 38 39Tuple: (property, label, placeholder, isPassword) 40Will be used for the forms. 41 42-} 43properties : List Property 44properties = 45 [ { key = "url" 46 , label = "Host URL" 47 , placeholder = "https://demo.nextcloud.com" 48 , password = False 49 } 50 , { key = "directoryPath" 51 , label = "Directory (Optional)" 52 , placeholder = "/icidasset/remote.php/webdav/" 53 , password = False 54 } 55 , { key = "username" 56 , label = "Username (Optional)" 57 , placeholder = "" 58 , password = False 59 } 60 , { key = "password" 61 , label = "Password (Optional)" 62 , placeholder = "" 63 , password = True 64 } 65 ] 66 67 68{-| Initial data set. 69-} 70initialData : SourceData 71initialData = 72 Dict.fromList 73 [ ( "directoryPath", "" ) 74 , ( "url", "" ) 75 , ( "username", "" ) 76 , ( "password", "" ) 77 , ( "name", defaults.name ) 78 ] 79 80 81 82-- PREPARATION 83 84 85prepare : String -> SourceData -> Marker -> (Result Http.Error String -> msg) -> Maybe (Cmd msg) 86prepare _ _ _ _ = 87 Nothing 88 89 90 91-- TREE 92 93 94{-| Create a directory tree. 95-} 96makeTree : SourceData -> Marker -> Time.Posix -> (Result Http.Error String -> msg) -> Cmd msg 97makeTree srcData marker _ resultMsg = 98 let 99 directory = 100 case marker of 101 InProgress _ -> 102 marker 103 |> Marker.takeOne 104 |> Maybe.withDefault "" 105 106 _ -> 107 srcData 108 |> Dict.get "directoryPath" 109 |> Maybe.withDefault "" 110 111 username = 112 Dict.fetch "username" "" srcData 113 114 password = 115 Dict.fetch "password" "" srcData 116 117 auth = 118 "Basic " ++ Base64.encode (username ++ ":" ++ password) 119 in 120 Http.request 121 { method = "PROPFIND" 122 , headers = [ Http.header "Authorization" auth, Http.header "Depth" "1" ] 123 , url = url { addAuth = False } srcData directory 124 , body = Http.emptyBody 125 , expect = Http.expectStringResponse resultMsg Common.translateHttpResponse 126 , timeout = Nothing 127 , tracker = Nothing 128 } 129 130 131{-| Re-export parser functions. 132-} 133parsePreparationResponse : String -> Time.Posix -> SourceData -> Marker -> PrepationAnswer Marker 134parsePreparationResponse = 135 noPrep 136 137 138parseTreeResponse : String -> Marker -> TreeAnswer Marker 139parseTreeResponse = 140 Parser.parseTreeResponse 141 142 143parseErrorResponse : String -> Maybe String 144parseErrorResponse = 145 Parser.parseErrorResponse 146 147 148 149-- POST 150 151 152{-| Post process the tree results. 153 154!!! Make sure we only use music files that we can use. 155 156-} 157postProcessTree : List String -> List String 158postProcessTree = 159 selectMusicFiles 160 161 162 163-- TRACK URL 164 165 166{-| Create a public url for a file. 167 168We need this to play the track. 169 170-} 171makeTrackUrl : Time.Posix -> String -> SourceData -> HttpMethod -> String -> String 172makeTrackUrl _ _ srcData _ filePath = 173 url { addAuth = True } srcData filePath 174 175 176 177-- COMMON 178 179 180url : { addAuth : Bool } -> SourceData -> String -> String 181url { addAuth } srcData path = 182 let 183 host = 184 String.chopEnd "/" (Dict.fetch "url" "" srcData) 185 186 username = 187 Dict.fetch "username" "" srcData 188 189 password = 190 Dict.fetch "password" "" srcData 191 192 authPrefix = 193 case ( username, password ) of 194 ( "", "" ) -> 195 "" 196 197 ( u, p ) -> 198 u ++ ":" ++ p 199 200 authBit = 201 if addAuth && String.length authPrefix > 0 then 202 "?basic_auth=" ++ Url.percentEncode (Base64.encode authPrefix) 203 204 else 205 "" 206 207 encodedPath = 208 path 209 |> String.chopStart "/" 210 |> String.split "/" 211 |> List.map Url.percentEncode 212 |> String.join "/" 213 in 214 host ++ "/" ++ encodedPath ++ authBit