1module Sources.Services.WebDav.Parser exposing (..)
2
3import Maybe.Extra as Maybe
4import Sources.Pick exposing (isMusicFile)
5import Sources.Processing exposing (Marker, TreeAnswer)
6import Sources.Services.Ipfs.Marker as Marker
7import String.Ext as String
8import Url
9import Xml.Decode exposing (..)
10import XmlParser
11
12
13
14-- TREE
15
16
17parseTreeResponse : String -> Marker -> TreeAnswer Marker
18parseTreeResponse response previousMarker =
19 let
20 currentDir =
21 Maybe.withDefault "//" (Marker.takeOne previousMarker)
22
23 parseResult =
24 XmlParser.parse response
25
26 namespace =
27 parseResult
28 |> Result.map
29 (\xml ->
30 case xml.root of
31 XmlParser.Element nodeName _ _ ->
32 nodeName
33 |> String.split ":"
34 |> List.head
35
36 _ ->
37 Nothing
38 )
39 |> Result.withDefault Nothing
40 |> (\maybe ->
41 case maybe of
42 Just n ->
43 n ++ ":"
44
45 Nothing ->
46 if String.contains "<d:" response then
47 "d:"
48
49 else
50 "D:"
51 )
52
53 entries =
54 response
55 |> decodeString (treeDecoder namespace)
56 |> Result.withDefault []
57 |> List.map Url.percentDecode
58 |> Maybe.values
59 |> List.filter ((/=) currentDir)
60
61 ( dirs, files ) =
62 List.partition (String.endsWith "/") entries
63 in
64 { filePaths =
65 List.map (String.chopStart "/") files
66 , marker =
67 previousMarker
68 |> Marker.removeOne
69 |> Marker.concat dirs
70 }
71
72
73treeDecoder : String -> Decoder (List String)
74treeDecoder namespace =
75 path
76 [ namespace ++ "response" ]
77 (leakyList <| treeItemDecoder namespace)
78
79
80treeItemDecoder : String -> Decoder String
81treeItemDecoder namespace =
82 let
83 withNamespace =
84 String.append namespace
85 in
86 string
87 |> single
88 |> path [ withNamespace "href" ]
89 |> andThen
90 (\href ->
91 oneOf
92 [ -- Audio
93 --------
94 string
95 |> single
96 |> path [ withNamespace "propstat", withNamespace "prop", withNamespace "getcontenttype" ]
97 |> andThen (mustBeAudio href)
98 |> map (\_ -> href)
99
100 -- Directory
101 ------------
102 , string
103 |> single
104 |> path [ withNamespace "propstat", withNamespace "prop", withNamespace "resourcetype", withNamespace "collection" ]
105 |> andThen
106 (\_ ->
107 if String.endsWith "/@eaDir/" href then
108 fail "Ignore Synology metadata"
109
110 else
111 succeed href
112 )
113 ]
114 )
115
116
117mustBeAudio : String -> String -> Decoder String
118mustBeAudio href contentType =
119 if isMusicFile href then
120 succeed contentType
121
122 else if String.startsWith "audio/" contentType then
123 succeed contentType
124
125 else
126 fail "Ignore this, not an audio file"
127
128
129
130-- ERROR
131
132
133parseErrorResponse : String -> Maybe String
134parseErrorResponse =
135 Just