1module Brain exposing (main)
2
3import Alien
4import Brain.Common.State as Common
5import Brain.Other.State as Other
6import Brain.Ports as Ports
7import Brain.Sources.Processing.State as Processing
8import Brain.Sources.Processing.Types as Processing
9import Brain.Tracks.State as Tracks
10import Brain.Types exposing (..)
11import Brain.User.State as User
12import Brain.User.Types as User
13import Debouncer.Basic as Debouncer
14import Json.Decode as Json
15import Return
16import Return.Ext as Return
17import Sources.Processing as Processing
18import Task
19import Time
20import Time.Ext as Time
21import Url
22import User.Layer as User
23
24
25
26-- 🧠
27
28
29main : Program Flags Model Msg
30main =
31 Platform.worker
32 { init = init
33 , update = update
34 , subscriptions = subscriptions
35 }
36
37
38
39-- 🌳
40
41
42init : Flags -> ( Model, Cmd Msg )
43init flags =
44 let
45 hypDebouncer =
46 2.5
47 |> Debouncer.fromSeconds
48 |> Debouncer.debounce
49 |> Debouncer.accumulateWith Debouncer.allInputs
50 |> Debouncer.toDebouncer
51
52 initialUrl =
53 flags.initialUrl
54 |> Url.fromString
55 |> Maybe.withDefault
56 { protocol = Url.Http
57 , host = ""
58 , port_ = Nothing
59 , path = ""
60 , query = Nothing
61 , fragment = Nothing
62 }
63 in
64 ( -----------------------------------------
65 -- Initial model
66 -----------------------------------------
67 { currentTime = Time.default
68 , hypaethralDebouncer = hypDebouncer
69 , hypaethralRetrieval = Nothing
70 , hypaethralStorage = []
71 , hypaethralUserData = User.emptyHypaethralData
72 , origin = "ORIGIN_UNKNOWN"
73 , processingStatus = Processing.NotProcessing
74 , userSyncMethod = Nothing
75 }
76 -----------------------------------------
77 -- Initial command
78 -----------------------------------------
79 , Cmd.batch
80 [ Task.perform SetCurrentTime Time.now
81 , User.initialCommand initialUrl
82 ]
83 )
84
85
86
87-- 📣
88
89
90update : Msg -> Manager
91update msg =
92 case msg of
93 Bypass ->
94 Return.singleton
95
96 Cmd a ->
97 Return.communicate a
98
99 -----------------------------------------
100 -- Tracks
101 -----------------------------------------
102 DownloadTracks a ->
103 Tracks.download a
104
105 GotSearchResults a ->
106 Tracks.gotSearchResults a
107
108 MakeArtworkTrackUrls a ->
109 Tracks.makeArtworkTrackUrls a
110
111 RemoveTracksBySourceId a ->
112 Tracks.removeBySourceId a
113
114 RemoveTracksFromCache a ->
115 Tracks.removeFromCache a
116
117 ReplaceTrackTags a ->
118 Tracks.replaceTags a
119
120 Search a ->
121 Tracks.search a
122
123 StoreTracksInCache a ->
124 Tracks.storeInCache a
125
126 SyncTrackTags a ->
127 Tracks.syncTrackTags a
128
129 UpdateSearchIndex a ->
130 Tracks.updateSearchIndex a
131
132 -----------------------------------------
133 -- 🦉 Nested
134 -----------------------------------------
135 ProcessingMsg a ->
136 Processing.update a
137
138 UserMsg a ->
139 User.update a
140
141 -----------------------------------------
142 -- 📭 Other
143 -----------------------------------------
144 RefreshedAccessToken a ->
145 Other.refreshedAccessToken a
146
147 SetCurrentTime a ->
148 Other.setCurrentTime a
149
150 ToCache a ->
151 Other.toCache a
152
153
154
155-- 📰
156
157
158subscriptions : Model -> Sub Msg
159subscriptions _ =
160 Sub.batch
161 [ Ports.fromAlien alien
162 , Ports.makeArtworkTrackUrls MakeArtworkTrackUrls
163 , Ports.refreshedAccessToken RefreshedAccessToken
164 , Ports.receiveSearchResults GotSearchResults
165 , Ports.receiveTags (ProcessingMsg << Processing.TagsStep)
166 , Ports.replaceTags ReplaceTrackTags
167
168 --
169 , Time.every (60 * 1000) SetCurrentTime
170 ]
171
172
173
174-- 👽
175
176
177alien : Alien.Event -> Msg
178alien event =
179 case ( event.error, Alien.tagFromString event.tag ) of
180 ( Nothing, Just tag ) ->
181 translateAlienData tag event.data
182
183 ( Just err, Just tag ) ->
184 translateAlienError tag event.data err
185
186 _ ->
187 Bypass
188
189
190translateAlienData : Alien.Tag -> Json.Value -> Msg
191translateAlienData tag data =
192 case tag of
193 Alien.EnclosedData ->
194 UserMsg (User.EnclosedDataRetrieved data)
195
196 Alien.SearchTracks ->
197 Search data
198
199 -----------------------------------------
200 -- From UI
201 -----------------------------------------
202 Alien.DownloadTracks ->
203 DownloadTracks data
204
205 Alien.ProcessSources ->
206 ProcessingMsg (Processing.Process data)
207
208 Alien.RefreshedAccessToken ->
209 RefreshedAccessToken data
210
211 Alien.RemoveEncryptionKey ->
212 UserMsg User.RemoveEncryptionKey
213
214 Alien.RemoveTracksBySourceId ->
215 RemoveTracksBySourceId data
216
217 Alien.RemoveTracksFromCache ->
218 RemoveTracksFromCache data
219
220 Alien.SaveEnclosedUserData ->
221 UserMsg (User.SaveEnclosedData data)
222
223 Alien.SaveFavourites ->
224 UserMsg (User.SaveFavourites data)
225
226 Alien.SavePlaylists ->
227 UserMsg (User.SavePlaylists data)
228
229 Alien.SaveProgress ->
230 UserMsg (User.SaveProgress data)
231
232 Alien.SaveSettings ->
233 UserMsg (User.SaveSettings data)
234
235 Alien.SaveSources ->
236 UserMsg (User.SaveSources data)
237
238 Alien.SaveTracks ->
239 UserMsg (User.SaveTracks data)
240
241 Alien.SetSyncMethod ->
242 UserMsg (User.SetSyncMethod data)
243
244 Alien.StopProcessing ->
245 ProcessingMsg Processing.StopProcessing
246
247 Alien.StoreTracksInCache ->
248 StoreTracksInCache data
249
250 Alien.SyncTrackTags ->
251 SyncTrackTags data
252
253 Alien.ToCache ->
254 ToCache data
255
256 Alien.UnsetSyncMethod ->
257 UserMsg User.UnsetSyncMethod
258
259 Alien.UpdateEncryptionKey ->
260 UserMsg (User.UpdateEncryptionKey data)
261
262 _ ->
263 Bypass
264
265
266translateAlienError : Alien.Tag -> Json.Value -> String -> Msg
267translateAlienError tag _ err =
268 case err of
269 "db is undefined" ->
270 Common.reportUICmdMsg tag "Can't connect to the browser's IndexedDB. FYI, this is __not supported in Firefox's private mode__."
271
272 _ ->
273 Common.reportUICmdMsg tag err