2024-06-02 07:53:13 +01:00
// SPDX-FileCopyrightText: 2024 Dan Anglin <d.n.i.anglin@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-or-later
2024-02-23 09:44:57 +00:00
package model
2024-02-23 14:19:12 +00:00
import (
2024-06-11 14:17:47 +01:00
"io"
"math"
2024-06-11 01:26:25 +01:00
"strconv"
2024-06-03 03:54:27 +01:00
"strings"
2024-02-23 14:19:12 +00:00
"time"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
)
2024-02-23 09:44:57 +00:00
type Status struct {
2024-05-27 01:05:31 +01:00
Account Account ` json:"account" `
Application Application ` json:"application" `
Bookmarked bool ` json:"bookmarked" `
Card Card ` json:"card" `
Content string ` json:"content" `
CreatedAt time . Time ` json:"created_at" `
Emojis [ ] Emoji ` json:"emojis" `
Favourited bool ` json:"favourited" `
FavouritesCount int ` json:"favourites_count" `
ID string ` json:"id" `
InReplyToAccountID string ` json:"in_reply_to_account_id" `
InReplyToID string ` json:"in_reply_to_id" `
Language string ` json:"language" `
MediaAttachments [ ] Attachment ` json:"media_attachments" `
Mentions [ ] Mention ` json:"mentions" `
Muted bool ` json:"muted" `
Pinned bool ` json:"pinned" `
2024-06-11 01:26:25 +01:00
Poll * Poll ` json:"poll" `
2024-05-27 01:05:31 +01:00
Reblog * StatusReblogged ` json:"reblog" `
Reblogged bool ` json:"reblogged" `
ReblogsCount int ` json:"reblogs_count" `
RepliesCount int ` json:"replies_count" `
Sensitive bool ` json:"sensitive" `
SpolierText string ` json:"spoiler_text" `
Tags [ ] Tag ` json:"tags" `
Text string ` json:"text" `
URI string ` json:"uri" `
URL string ` json:"url" `
2024-05-30 18:46:33 +01:00
Visibility StatusVisibility ` json:"visibility" `
2024-02-23 09:44:57 +00:00
}
type Card struct {
AuthorName string ` json:"author_name" `
AuthorURL string ` json:"author_url" `
Blurhash string ` json:"blurhash" `
Description string ` json:"description" `
EmbedURL string ` json:"embed_url" `
HTML string ` json:"html" `
Image string ` json:"image" `
ProviderName string ` json:"provider_name" `
ProviderURL string ` json:"provider_url" `
Title string ` json:"title" `
Type string ` json:"type" `
URL string ` json:"url" `
Height int ` json:"height" `
Width int ` json:"width" `
}
type Mention struct {
Acct string ` json:"acct" `
ID string ` json:"id" `
URL string ` json:"url" `
Username string ` json:"username" `
}
type Poll struct {
Emojis [ ] Emoji ` json:"emojis" `
Expired bool ` json:"expired" `
Voted bool ` json:"voted" `
Multiple bool ` json:"multiple" `
ExpiredAt time . Time ` json:"expires_at" `
ID string ` json:"id" `
OwnVotes [ ] int ` json:"own_votes" `
VotersCount int ` json:"voters_count" `
VotesCount int ` json:"votes_count" `
Options [ ] PollOption ` json:"options" `
}
type PollOption struct {
Title string ` json:"title" `
2024-06-04 09:54:40 +01:00
VotesCount int ` json:"votes_count" `
2024-02-23 09:44:57 +00:00
}
type StatusReblogged struct {
2024-05-30 18:46:33 +01:00
Account Account ` json:"account" `
Application Application ` json:"application" `
Bookmarked bool ` json:"bookmarked" `
Card Card ` json:"card" `
Content string ` json:"content" `
CreatedAt time . Time ` json:"created_at" `
Emojis [ ] Emoji ` json:"emojis" `
Favourited bool ` json:"favourited" `
FavouritesCount int ` json:"favourites_count" `
ID string ` json:"id" `
InReplyToAccountID string ` json:"in_reply_to_account_id" `
InReplyToID string ` json:"in_reply_to_id" `
Language string ` json:"language" `
MediaAttachments [ ] Attachment ` json:"media_attachments" `
Mentions [ ] Mention ` json:"mentions" `
Muted bool ` json:"muted" `
Pinned bool ` json:"pinned" `
Poll Poll ` json:"poll" `
Reblogged bool ` json:"reblogged" `
RebloggsCount int ` json:"reblogs_count" `
RepliesCount int ` json:"replies_count" `
Sensitive bool ` json:"sensitive" `
SpolierText string ` json:"spoiler_text" `
Tags [ ] Tag ` json:"tags" `
Text string ` json:"text" `
URI string ` json:"uri" `
URL string ` json:"url" `
Visibility StatusVisibility ` json:"visibility" `
2024-02-23 09:44:57 +00:00
}
type Tag struct {
History [ ] any ` json:"history" `
Name string ` json:"name" `
URL string ` json:"url" `
}
type Attachment struct {
Meta MediaMeta ` json:"meta" `
Blurhash string ` json:"blurhash" `
Description string ` json:"description" `
ID string ` json:"id" `
PreviewRemoteURL string ` json:"preview_remote_url" `
PreviewURL string ` json:"preview_url" `
RemoteURL string ` json:"remote_url" `
TextURL string ` json:"text_url" `
Type string ` json:"type" `
URL string ` json:"url" `
}
type MediaMeta struct {
Focus MediaFocus ` json:"focus" `
Original MediaDimensions ` json:"original" `
Small MediaDimensions ` json:"small" `
}
type MediaFocus struct {
X float64 ` json:"x" `
Y float64 ` json:"y" `
}
type MediaDimensions struct {
Aspect float64 ` json:"aspect" `
Bitrate int ` json:"bitrate" `
Duration float64 ` json:"duration" `
FrameRate string ` json:"frame_rate" `
Size string ` json:"size" `
Height int ` json:"height" `
Width int ` json:"width" `
}
2024-02-23 14:19:12 +00:00
2024-05-31 21:18:11 +01:00
func ( s Status ) Display ( noColor bool ) string {
2024-06-11 14:17:47 +01:00
indent := " "
2024-06-11 01:26:25 +01:00
var builder strings . Builder
// The account information
builder . WriteString ( utilities . FullDisplayNameFormat ( noColor , s . Account . DisplayName , s . Account . Acct ) + "\n\n" )
// The content of the status.
builder . WriteString ( utilities . HeaderFormat ( noColor , "CONTENT:" ) )
builder . WriteString ( utilities . WrapLines ( utilities . ConvertHTMLToText ( s . Content ) , "\n " , 80 ) )
// If a poll exists in a status, write the contents to the builder.
if s . Poll != nil {
2024-06-11 14:17:47 +01:00
displayPollContent ( & builder , * s . Poll , noColor , indent )
2024-06-11 01:26:25 +01:00
}
// The ID of the status
2024-06-11 14:17:47 +01:00
builder . WriteString ( "\n\n" + utilities . HeaderFormat ( noColor , "STATUS ID:" ) + "\n" + indent + s . ID )
2024-06-11 01:26:25 +01:00
// The ID of the poll if it exists
if s . Poll != nil {
2024-06-11 14:17:47 +01:00
builder . WriteString ( "\n\n" + utilities . HeaderFormat ( noColor , "POLL ID:" ) + "\n" + indent + s . Poll . ID )
2024-06-11 01:26:25 +01:00
}
// Status creation time
2024-06-11 14:17:47 +01:00
builder . WriteString ( "\n\n" + utilities . HeaderFormat ( noColor , "CREATED AT:" ) + "\n" + indent + utilities . FormatTime ( s . CreatedAt ) )
2024-06-11 01:26:25 +01:00
// Status stats
builder . WriteString (
"\n\n" +
utilities . HeaderFormat ( noColor , "STATS:" ) +
2024-06-11 14:17:47 +01:00
"\n" + indent + utilities . FieldFormat ( noColor , "Boosts: " ) + strconv . Itoa ( s . ReblogsCount ) +
"\n" + indent + utilities . FieldFormat ( noColor , "Likes: " ) + strconv . Itoa ( s . FavouritesCount ) +
"\n" + indent + utilities . FieldFormat ( noColor , "Replies: " ) + strconv . Itoa ( s . RepliesCount ) ,
2024-02-23 14:19:12 +00:00
)
2024-06-11 01:26:25 +01:00
// Status visibility
2024-06-11 14:17:47 +01:00
builder . WriteString ( "\n\n" + utilities . HeaderFormat ( noColor , "VISIBILITY:" ) + "\n" + indent + s . Visibility . String ( ) )
2024-06-11 01:26:25 +01:00
// Status URL
2024-06-11 14:17:47 +01:00
builder . WriteString ( "\n\n" + utilities . HeaderFormat ( noColor , "URL:" ) + "\n" + indent + s . URL )
2024-06-11 01:26:25 +01:00
return builder . String ( )
2024-02-23 14:19:12 +00:00
}
2024-06-03 03:54:27 +01:00
type StatusList struct {
Name string
Statuses [ ] Status
}
func ( s StatusList ) Display ( noColor bool ) string {
var builder strings . Builder
2024-06-09 15:58:10 +01:00
separator := strings . Repeat ( "─" , 80 )
2024-06-03 03:54:27 +01:00
2024-06-04 17:01:33 +01:00
builder . WriteString ( utilities . HeaderFormat ( noColor , s . Name ) + "\n" )
2024-06-03 03:54:27 +01:00
for _ , status := range s . Statuses {
2024-06-04 20:29:19 +01:00
builder . WriteString ( "\n" + utilities . FullDisplayNameFormat ( noColor , status . Account . DisplayName , status . Account . Acct ) + "\n" )
2024-06-03 03:54:27 +01:00
statusID := status . ID
createdAt := status . CreatedAt
if status . Reblog != nil {
2024-06-04 20:29:19 +01:00
builder . WriteString ( "reposted this status from " + utilities . FullDisplayNameFormat ( noColor , status . Reblog . Account . DisplayName , status . Reblog . Account . Acct ) + "\n" )
2024-06-03 03:54:27 +01:00
statusID = status . Reblog . ID
createdAt = status . Reblog . CreatedAt
}
2024-06-11 14:17:47 +01:00
builder . WriteString ( utilities . WrapLines ( utilities . ConvertHTMLToText ( status . Content ) , "\n" , 80 ) )
if status . Poll != nil {
displayPollContent ( & builder , * status . Poll , noColor , "" )
}
builder . WriteString (
"\n\n" +
utilities . FieldFormat ( noColor , "ID:" ) + " " + statusID + "\t" +
utilities . FieldFormat ( noColor , "Created at:" ) + " " + utilities . FormatTime ( createdAt ) +
"\n" ,
)
2024-06-03 03:54:27 +01:00
builder . WriteString ( separator + "\n" )
}
return builder . String ( )
}
2024-06-11 14:17:47 +01:00
func displayPollContent ( writer io . StringWriter , poll Poll , noColor bool , indent string ) {
for ind , option := range poll . Options {
var percentage int
if poll . VotesCount == 0 {
percentage = 0
} else {
calculate := math . Floor ( 100 * ( float64 ( option . VotesCount ) / float64 ( poll . VotesCount ) ) )
percentage = int ( calculate )
}
writer . WriteString (
"\n\n" + indent + "[" + strconv . Itoa ( ind ) + "] " + option . Title +
"\n" + indent + strings . Repeat ( "\u2584" , 80 ) +
"\n" + indent + strconv . Itoa ( option . VotesCount ) + " votes " +
"(" + strconv . Itoa ( percentage ) + "%)" ,
)
}
writer . WriteString ( "\n\n" + indent + utilities . FieldFormat ( noColor , "Total votes:" ) + " " + strconv . Itoa ( poll . VotesCount ) )
writer . WriteString ( "\n" + indent + utilities . FieldFormat ( noColor , "Poll open until:" ) + " " + utilities . FormatTime ( poll . ExpiredAt ) )
}