A music player that connects to your cloud/distributed storage.
1module Sources.Services.Ipfs.Parser exposing (Link, linkDecoder, parseDnsLookup, parseErrorResponse, parseTreeResponse, treeDecoder)
2
3import Dict
4import Json.Decode exposing (..)
5import Sources exposing (SourceData)
6import Sources.Pick exposing (isMusicFile)
7import Sources.Processing exposing (Marker(..), PrepationAnswer, TreeAnswer)
8import Sources.Services.Ipfs.Marker as Marker
9import String.Ext as String
10import Time
11
12
13
14-- PREPARATION
15
16
17parseDnsLookup : String -> Time.Posix -> SourceData -> Marker -> PrepationAnswer Marker
18parseDnsLookup response _ srcData _ =
19 case decodeString dnsResultDecoder response of
20 Ok path ->
21 srcData
22 |> Dict.insert "directoryHashFromDnsLink" (String.chopStart "/ipfs/" path)
23 |> (\s -> { sourceData = s, marker = TheEnd })
24
25 Err _ ->
26 { sourceData = srcData, marker = TheEnd }
27
28
29dnsResultDecoder : Decoder String
30dnsResultDecoder =
31 oneOf
32 [ at [ "Path" ] string
33 , cloudflareDnsResultDecoder
34 ]
35
36
37cloudflareDnsResultDecoder : Decoder String
38cloudflareDnsResultDecoder =
39 string
40 |> at [ "Answer", "0", "data" ]
41 |> map
42 (\txt ->
43 txt
44 |> String.chopEnd "\""
45 |> String.chopStart "\""
46 |> String.chopStart "dnslink=/ipfs/"
47 )
48
49
50
51-- TREE
52
53
54parseTreeResponse : String -> Marker -> TreeAnswer Marker
55parseTreeResponse response previousMarker =
56 let
57 prefix =
58 case previousMarker of
59 TheBeginning ->
60 ""
61
62 _ ->
63 response
64 |> decodeString prefixDecoder
65 |> Result.map
66 (String.chopStart "/ipfs/"
67 >> String.split "/"
68 >> List.drop 1
69 >> String.join "/"
70 )
71 |> Result.map
72 (\s ->
73 if String.isEmpty s then
74 ""
75
76 else
77 s ++ "/"
78 )
79 |> Result.withDefault ""
80
81 links =
82 case decodeString treeDecoder response of
83 Ok l ->
84 l
85
86 Err _ ->
87 []
88
89 dirs =
90 links
91 |> List.filter (.typ >> (==) 1)
92 |> List.map (\l -> prefix ++ l.name)
93
94 files =
95 links
96 |> List.filter (.typ >> (==) 2)
97 |> List.filter (.name >> isMusicFile)
98 |> List.map (\l -> prefix ++ l.name)
99 in
100 { filePaths =
101 files
102 , marker =
103 previousMarker
104 |> Marker.removeOne
105 |> Marker.concat dirs
106 }
107
108
109prefixDecoder : Decoder String
110prefixDecoder =
111 field "Objects" <| index 0 <| field "Hash" <| string
112
113
114treeDecoder : Decoder (List Link)
115treeDecoder =
116 field "Objects" <| index 0 <| field "Links" <| list linkDecoder
117
118
119
120-- LINKS
121
122
123type alias Link =
124 { hash : String
125 , name : String
126 , typ : Int
127 }
128
129
130linkDecoder : Decoder Link
131linkDecoder =
132 map3 Link
133 (field "Hash" string)
134 (field "Name" string)
135 (field "Type" int)
136
137
138
139-- ERRORS
140
141
142parseErrorResponse : String -> Maybe String
143parseErrorResponse response =
144 response
145 |> decodeString (field "Message" string)
146 |> Result.toMaybe