2017-04-27 10:34:27 -04:00
|
|
|
module Mastodon.Decoder
|
|
|
|
exposing
|
|
|
|
( appRegistrationDecoder
|
|
|
|
, accessTokenDecoder
|
|
|
|
, accountDecoder
|
|
|
|
, attachmentDecoder
|
2017-04-27 12:39:14 -04:00
|
|
|
, contextDecoder
|
2017-04-27 10:34:27 -04:00
|
|
|
, decodeWebSocketMessage
|
2017-11-29 08:06:08 -05:00
|
|
|
, decodeClients
|
2017-04-27 10:34:27 -04:00
|
|
|
, mastodonErrorDecoder
|
|
|
|
, mentionDecoder
|
|
|
|
, notificationDecoder
|
|
|
|
, tagDecoder
|
|
|
|
, reblogDecoder
|
2017-04-29 16:48:55 -04:00
|
|
|
, relationshipDecoder
|
2017-05-30 18:27:30 -04:00
|
|
|
, searchResultsDecoder
|
2017-04-27 10:34:27 -04:00
|
|
|
, statusDecoder
|
|
|
|
, webSocketEventDecoder
|
|
|
|
)
|
|
|
|
|
|
|
|
import Json.Decode as Decode
|
|
|
|
import Json.Decode.Pipeline as Pipe
|
|
|
|
import Mastodon.Model exposing (..)
|
|
|
|
import Mastodon.WebSocket exposing (..)
|
|
|
|
|
|
|
|
|
|
|
|
appRegistrationDecoder : String -> String -> Decode.Decoder AppRegistration
|
|
|
|
appRegistrationDecoder server scope =
|
|
|
|
Pipe.decode AppRegistration
|
|
|
|
|> Pipe.hardcoded server
|
|
|
|
|> Pipe.hardcoded scope
|
|
|
|
|> Pipe.required "client_id" Decode.string
|
|
|
|
|> Pipe.required "client_secret" Decode.string
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "id" idDecoder
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "redirect_uri" Decode.string
|
|
|
|
|
|
|
|
|
|
|
|
accessTokenDecoder : AppRegistration -> Decode.Decoder AccessTokenResult
|
|
|
|
accessTokenDecoder registration =
|
|
|
|
Pipe.decode AccessTokenResult
|
|
|
|
|> Pipe.hardcoded registration.server
|
|
|
|
|> Pipe.required "access_token" Decode.string
|
|
|
|
|
2021-01-10 16:25:03 -05:00
|
|
|
sourceDecoder : Decode.Decoder Source
|
|
|
|
sourceDecoder =
|
|
|
|
Pipe.decode Source
|
|
|
|
|> Pipe.optional "privacy" Decode.string "public"
|
|
|
|
|> Pipe.optional "sensitive" Decode.bool False
|
|
|
|
|> Pipe.optional "language" Decode.string ""
|
2017-04-27 10:34:27 -04:00
|
|
|
|
|
|
|
accountDecoder : Decode.Decoder Account
|
|
|
|
accountDecoder =
|
|
|
|
Pipe.decode Account
|
|
|
|
|> Pipe.required "acct" Decode.string
|
|
|
|
|> Pipe.required "avatar" Decode.string
|
|
|
|
|> Pipe.required "created_at" Decode.string
|
|
|
|
|> Pipe.required "display_name" Decode.string
|
|
|
|
|> Pipe.required "followers_count" Decode.int
|
|
|
|
|> Pipe.required "following_count" Decode.int
|
|
|
|
|> Pipe.required "header" Decode.string
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "id" idDecoder
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "locked" Decode.bool
|
|
|
|
|> Pipe.required "note" Decode.string
|
|
|
|
|> Pipe.required "statuses_count" Decode.int
|
|
|
|
|> Pipe.required "url" Decode.string
|
|
|
|
|> Pipe.required "username" Decode.string
|
2021-01-10 16:25:03 -05:00
|
|
|
|> Pipe.optional "source" sourceDecoder
|
|
|
|
{ privacy = "public"
|
|
|
|
, sensitive = False
|
|
|
|
, language = ""
|
|
|
|
}
|
2017-04-27 10:34:27 -04:00
|
|
|
|
|
|
|
|
2017-05-22 18:25:28 -04:00
|
|
|
applicationDecoder : Decode.Decoder Application
|
|
|
|
applicationDecoder =
|
|
|
|
Pipe.decode Application
|
|
|
|
|> Pipe.required "name" Decode.string
|
|
|
|
|> Pipe.required "website" (Decode.nullable Decode.string)
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
attachmentDecoder : Decode.Decoder Attachment
|
|
|
|
attachmentDecoder =
|
|
|
|
Pipe.decode Attachment
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "id" idDecoder
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "type" Decode.string
|
|
|
|
|> Pipe.required "url" Decode.string
|
2017-05-11 04:55:15 -04:00
|
|
|
|> Pipe.optional "remote_url" Decode.string ""
|
2021-01-10 16:44:48 -05:00
|
|
|
|> Pipe.optional "preview_url" Decode.string ""
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "text_url" (Decode.nullable Decode.string)
|
|
|
|
|
|
|
|
|
2017-04-27 12:39:14 -04:00
|
|
|
contextDecoder : Decode.Decoder Context
|
|
|
|
contextDecoder =
|
|
|
|
Pipe.decode Context
|
|
|
|
|> Pipe.required "ancestors" (Decode.list statusDecoder)
|
|
|
|
|> Pipe.required "descendants" (Decode.list statusDecoder)
|
|
|
|
|
|
|
|
|
2017-11-29 08:06:08 -05:00
|
|
|
clientDecoder : Decode.Decoder Client
|
|
|
|
clientDecoder =
|
|
|
|
Pipe.decode Client
|
|
|
|
|> Pipe.required "server" Decode.string
|
|
|
|
|> Pipe.required "token" Decode.string
|
|
|
|
|> Pipe.required "account" (Decode.maybe accountDecoder)
|
|
|
|
|
|
|
|
|
|
|
|
decodeClients : String -> Result String (List Client)
|
|
|
|
decodeClients json =
|
|
|
|
Decode.decodeString (Decode.list clientDecoder) json
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
mastodonErrorDecoder : Decode.Decoder String
|
|
|
|
mastodonErrorDecoder =
|
|
|
|
Decode.field "error" Decode.string
|
|
|
|
|
|
|
|
|
|
|
|
mentionDecoder : Decode.Decoder Mention
|
|
|
|
mentionDecoder =
|
|
|
|
Pipe.decode Mention
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "id" idDecoder
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "url" Decode.string
|
|
|
|
|> Pipe.required "username" Decode.string
|
|
|
|
|> Pipe.required "acct" Decode.string
|
|
|
|
|
|
|
|
|
|
|
|
notificationDecoder : Decode.Decoder Notification
|
|
|
|
notificationDecoder =
|
|
|
|
Pipe.decode Notification
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "id" idDecoder
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "type" Decode.string
|
|
|
|
|> Pipe.required "created_at" Decode.string
|
|
|
|
|> Pipe.required "account" accountDecoder
|
|
|
|
|> Pipe.optional "status" (Decode.nullable statusDecoder) Nothing
|
|
|
|
|
|
|
|
|
2017-04-29 16:48:55 -04:00
|
|
|
relationshipDecoder : Decode.Decoder Relationship
|
|
|
|
relationshipDecoder =
|
|
|
|
Pipe.decode Relationship
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "id" idDecoder
|
2017-04-29 16:48:55 -04:00
|
|
|
|> Pipe.required "blocking" Decode.bool
|
|
|
|
|> Pipe.required "followed_by" Decode.bool
|
|
|
|
|> Pipe.required "following" Decode.bool
|
|
|
|
|> Pipe.required "muting" Decode.bool
|
|
|
|
|> Pipe.required "requested" Decode.bool
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
tagDecoder : Decode.Decoder Tag
|
|
|
|
tagDecoder =
|
|
|
|
Pipe.decode Tag
|
|
|
|
|> Pipe.required "name" Decode.string
|
|
|
|
|> Pipe.required "url" Decode.string
|
|
|
|
|
|
|
|
|
|
|
|
reblogDecoder : Decode.Decoder Reblog
|
|
|
|
reblogDecoder =
|
|
|
|
Decode.map Reblog (Decode.lazy (\_ -> statusDecoder))
|
|
|
|
|
|
|
|
|
2017-05-30 18:27:30 -04:00
|
|
|
searchResultsDecoder : Decode.Decoder SearchResults
|
|
|
|
searchResultsDecoder =
|
|
|
|
Pipe.decode SearchResults
|
|
|
|
|> Pipe.required "accounts" (Decode.list accountDecoder)
|
|
|
|
|> Pipe.required "statuses" (Decode.list statusDecoder)
|
|
|
|
|> Pipe.required "hashtags" (Decode.list Decode.string)
|
|
|
|
|
|
|
|
|
2017-11-29 08:06:08 -05:00
|
|
|
idDecoder : Decode.Decoder String
|
|
|
|
idDecoder =
|
|
|
|
-- Note: since v2.0.0 of the Mastodon API, ids are treated as strings, so we
|
|
|
|
-- treat all ids as strings.
|
|
|
|
Decode.oneOf
|
|
|
|
[ Decode.string
|
|
|
|
, Decode.int |> Decode.map toString
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
statusIdDecoder : Decode.Decoder StatusId
|
|
|
|
statusIdDecoder =
|
|
|
|
idDecoder |> Decode.map StatusId
|
|
|
|
|
|
|
|
|
2017-04-27 10:34:27 -04:00
|
|
|
statusDecoder : Decode.Decoder Status
|
|
|
|
statusDecoder =
|
|
|
|
Pipe.decode Status
|
|
|
|
|> Pipe.required "account" accountDecoder
|
2019-05-15 16:13:06 -04:00
|
|
|
|> Pipe.optional "application" (Decode.nullable applicationDecoder) Nothing
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "content" Decode.string
|
|
|
|
|> Pipe.required "created_at" Decode.string
|
|
|
|
|> Pipe.optional "favourited" (Decode.nullable Decode.bool) Nothing
|
|
|
|
|> Pipe.required "favourites_count" Decode.int
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "id" statusIdDecoder
|
|
|
|
|> Pipe.required "in_reply_to_account_id" (Decode.nullable idDecoder)
|
|
|
|
|> Pipe.required "in_reply_to_id" (Decode.nullable statusIdDecoder)
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "media_attachments" (Decode.list attachmentDecoder)
|
|
|
|
|> Pipe.required "mentions" (Decode.list mentionDecoder)
|
|
|
|
|> Pipe.optional "reblog" (Decode.lazy (\_ -> Decode.nullable reblogDecoder)) Nothing
|
|
|
|
|> Pipe.optional "reblogged" (Decode.nullable Decode.bool) Nothing
|
|
|
|
|> Pipe.required "reblogs_count" Decode.int
|
|
|
|
|> Pipe.required "sensitive" (Decode.nullable Decode.bool)
|
|
|
|
|> Pipe.required "spoiler_text" Decode.string
|
|
|
|
|> Pipe.required "tags" (Decode.list tagDecoder)
|
|
|
|
|> Pipe.required "uri" Decode.string
|
2017-05-14 09:12:04 -04:00
|
|
|
|> Pipe.required "url" (Decode.nullable Decode.string)
|
2017-04-27 10:34:27 -04:00
|
|
|
|> Pipe.required "visibility" Decode.string
|
|
|
|
|
|
|
|
|
|
|
|
webSocketEventDecoder : Decode.Decoder WebSocketMessage
|
|
|
|
webSocketEventDecoder =
|
|
|
|
Pipe.decode WebSocketMessage
|
|
|
|
|> Pipe.required "event" Decode.string
|
2017-11-29 08:06:08 -05:00
|
|
|
|> Pipe.required "payload"
|
|
|
|
-- NOTE: as of the Mastodon API v2.0.0, ids may be either ints or
|
|
|
|
-- strings. If we receive an int (most likely for the delete event),
|
|
|
|
-- we cast it to a string.
|
|
|
|
(Decode.oneOf
|
|
|
|
[ Decode.string
|
|
|
|
, Decode.int |> Decode.map toString
|
|
|
|
]
|
|
|
|
)
|
2017-04-27 10:34:27 -04:00
|
|
|
|
|
|
|
|
|
|
|
decodeWebSocketMessage : String -> WebSocketEvent
|
|
|
|
decodeWebSocketMessage message =
|
|
|
|
case (Decode.decodeString webSocketEventDecoder message) of
|
2017-11-29 08:06:08 -05:00
|
|
|
Ok { event, payload } ->
|
|
|
|
case event of
|
2017-04-27 10:34:27 -04:00
|
|
|
"update" ->
|
2017-11-29 08:06:08 -05:00
|
|
|
StatusUpdateEvent (Decode.decodeString statusDecoder payload)
|
2017-04-27 10:34:27 -04:00
|
|
|
|
|
|
|
"delete" ->
|
2017-11-29 08:06:08 -05:00
|
|
|
StatusDeleteEvent (StatusId payload)
|
2017-04-27 10:34:27 -04:00
|
|
|
|
|
|
|
"notification" ->
|
2017-11-29 08:06:08 -05:00
|
|
|
NotificationEvent (Decode.decodeString notificationDecoder payload)
|
2017-04-27 10:34:27 -04:00
|
|
|
|
|
|
|
event ->
|
|
|
|
ErrorEvent <| "Unknown WS event " ++ event
|
|
|
|
|
|
|
|
Err error ->
|
|
|
|
ErrorEvent error
|