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