diff --git a/docs/manual.md b/docs/manual.md
index 548690d..51caac6 100644
--- a/docs/manual.md
+++ b/docs/manual.md
@@ -722,16 +722,23 @@ video player in your configuration file respectively.
See the [configuration reference page](configuration.md#integration) on how to set up integration with
your media players.
-```
-enbas show --type media --from status --status-id 01J0N11V4V7PWH0DDRAVT7TCFK --attachment-id 01J0N0RQSJ7CFGKHA30F7GBQXT
-```
+- View a specific media attachment from a specific status
+ ```
+ enbas show --type media --from status --status-id 01J0N11V4V7PWH0DDRAVT7TCFK --attachment-id 01J0N0RQSJ7CFGKHA30F7GBQXT
+ ```
+- View all image attachments from a specific status
+ ```
+ enbas show --type media --from status --status-id 01J0N11V4V7PWH0DDRAVT7TCFK --all-images
+ ```
| flag | type | required | description | default |
|------|------|----------|-------------|---------|
| `type` | string | true | The resource you want to view.
Here this should be `media`. | |
| `from` | string | true | The resource you want to view the media from.
Here this should be `status`. | |
| `status-id` | string | true | The ID of the status that you want to view the media from. | |
-| `attachment-id` | string | true | The ID of the media attachment to download and view.
Use this flag multiple times to specify multiple media attachments. | |
+| `attachment-id` | string | false | The ID of the media attachment to download and view.
Use this flag multiple times to specify multiple media attachments. | |
+| `all-images` | boolean | false | Set to `true` to show all images from the status. | false |
+| `all-videos` | boolean | false | Set to `true` to show all videos from the status. | false |
## Bookmarks
diff --git a/internal/executor/errors.go b/internal/executor/errors.go
index c16a2a8..68aa04a 100644
--- a/internal/executor/errors.go
+++ b/internal/executor/errors.go
@@ -116,10 +116,10 @@ func (e NotFollowingError) Error() string {
return "you are not following " + e.Account
}
-type UnknownMediaAttachmentError struct {
- AttachmentID string
-}
-
-func (e UnknownMediaAttachmentError) Error() string {
- return "unknown media attachment '" + e.AttachmentID + "'"
-}
+//type UnknownMediaAttachmentError struct {
+// AttachmentID string
+//}
+//
+//func (e UnknownMediaAttachmentError) Error() string {
+// return "unknown media attachment '" + e.AttachmentID + "'"
+//}
diff --git a/internal/executor/show.go b/internal/executor/show.go
index 6d564d0..7e76119 100644
--- a/internal/executor/show.go
+++ b/internal/executor/show.go
@@ -8,10 +8,10 @@ import (
"flag"
"fmt"
"path/filepath"
- "strings"
"codeflow.dananglin.me.uk/apollo/enbas/internal/client"
"codeflow.dananglin.me.uk/apollo/enbas/internal/config"
+ "codeflow.dananglin.me.uk/apollo/enbas/internal/media"
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
"codeflow.dananglin.me.uk/apollo/enbas/internal/printer"
"codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
@@ -32,6 +32,8 @@ type ShowExecutor struct {
showUserPreferences bool
showStatuses bool
skipAccountRelationship bool
+ getAllImages bool
+ getAllVideos bool
resourceType string
accountName string
statusID string
@@ -62,6 +64,8 @@ func NewShowExecutor(printer *printer.Printer, config *config.Config, name, summ
showExe.BoolVar(&showExe.onlyPinned, flagOnlyPinned, false, "Set to true to show only the account's pinned statuses")
showExe.BoolVar(&showExe.onlyMedia, flagOnlyMedia, false, "Set to true to show only the statuses with media attachments")
showExe.BoolVar(&showExe.onlyPublic, flagOnlyPublic, false, "Set to true to show only the account's public posts")
+ showExe.BoolVar(&showExe.getAllImages, "all-images", false, "Set to true to show all images from a status")
+ showExe.BoolVar(&showExe.getAllVideos, "all-videos", false, "Set to true to show all videos from a status")
showExe.StringVar(&showExe.resourceType, flagType, "", "Specify the type of resource to display")
showExe.StringVar(&showExe.accountName, flagAccountName, "", "Specify the account name in full (username@domain)")
showExe.StringVar(&showExe.statusID, flagStatusID, "", "Specify the ID of the status to display")
@@ -529,10 +533,6 @@ func (s *ShowExecutor) showMedia(gtsClient *client.Client) error {
}
func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
- if len(s.attachmentIDs) == 0 {
- return FlagNotSetError{flagText: flagAttachmentID}
- }
-
if s.statusID == "" {
return FlagNotSetError{flagText: flagStatusID}
}
@@ -551,65 +551,26 @@ func (s *ShowExecutor) showMediaFromStatus(gtsClient *client.Client) error {
return fmt.Errorf("unable to ensure the existence of the directory %q: %w", cacheDir, err)
}
- type media struct {
- url string
- mediaType string
- }
-
- attachmentsHashMap := make(map[string]media)
- imageFiles := make([]string, 0)
- videoFiles := make([]string, 0)
-
- for _, statusAttachment := range status.MediaAttachments {
- attachmentsHashMap[statusAttachment.ID] = media{
- url: statusAttachment.URL,
- mediaType: statusAttachment.Type,
- }
- }
-
- for _, attachmentID := range s.attachmentIDs {
- mediaObj, ok := attachmentsHashMap[attachmentID]
- if !ok {
- return UnknownMediaAttachmentError{AttachmentID: attachmentID}
- }
-
- split := strings.Split(mediaObj.url, "/")
- filename := split[len(split)-1]
- filePath := filepath.Join(cacheDir, filename)
-
- fileExists, err := utilities.FileExists(filePath)
- if err != nil {
- return fmt.Errorf(
- "unable to check if the media file is already downloaded for %s: %w",
- attachmentID,
- err,
- )
- }
-
- if !fileExists {
- if err := gtsClient.DownloadMedia(mediaObj.url, filePath); err != nil {
- return fmt.Errorf(
- "unable to download the media attachment for %s: %w",
- attachmentID,
- err,
- )
- }
- }
-
- switch mediaObj.mediaType {
- case "image":
- imageFiles = append(imageFiles, filePath)
- case "video":
- videoFiles = append(videoFiles, filePath)
- }
+ mediaBundle := media.NewBundle(
+ cacheDir,
+ status.MediaAttachments,
+ s.getAllImages,
+ s.getAllVideos,
+ s.attachmentIDs,
+ )
+
+ if err := mediaBundle.Download(gtsClient); err != nil {
+ return fmt.Errorf("unable to download the media bundle: %w", err)
}
+ imageFiles := mediaBundle.ImageFiles()
if len(imageFiles) > 0 {
if err := utilities.OpenMedia(s.config.Integrations.ImageViewer, imageFiles); err != nil {
return fmt.Errorf("unable to open the image viewer: %w", err)
}
}
+ videoFiles := mediaBundle.VideoFiles()
if len(videoFiles) > 0 {
if err := utilities.OpenMedia(s.config.Integrations.VideoPlayer, videoFiles); err != nil {
return fmt.Errorf("unable to open the video player: %w", err)
diff --git a/internal/media/media.go b/internal/media/media.go
new file mode 100644
index 0000000..41be89f
--- /dev/null
+++ b/internal/media/media.go
@@ -0,0 +1,174 @@
+// SPDX-FileCopyrightText: 2024 Dan Anglin
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package media
+
+import (
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "codeflow.dananglin.me.uk/apollo/enbas/internal/client"
+ "codeflow.dananglin.me.uk/apollo/enbas/internal/model"
+ "codeflow.dananglin.me.uk/apollo/enbas/internal/utilities"
+)
+
+const (
+ mediaTypeImage string = "image"
+ mediaTypeVideo string = "video"
+)
+
+type media struct {
+ source string
+ destination string
+ mediaType string
+}
+
+func (m *media) download(gtsClient *client.Client) error {
+ fileExists, err := utilities.FileExists(m.destination)
+ if err != nil {
+ return fmt.Errorf(
+ "unable to determine if %s exists: %w",
+ m.destination,
+ err,
+ )
+ }
+
+ if fileExists {
+ return nil
+ }
+
+ if err := gtsClient.DownloadMedia(m.source, m.destination); err != nil {
+ return fmt.Errorf(
+ "downloading %s -> %s failed: %w",
+ m.source,
+ m.destination,
+ err,
+ )
+ }
+
+ return nil
+}
+
+func newMediaHashmap(cacheDir string, attachments []model.Attachment) map[string]media {
+ hashmap := make(map[string]media)
+
+ for ind := range attachments {
+ hashmap[attachments[ind].ID] = media{
+ source: attachments[ind].URL,
+ destination: mediaFilepath(cacheDir, attachments[ind].URL),
+ mediaType: attachments[ind].Type,
+ }
+ }
+
+ return hashmap
+}
+
+type Bundle struct {
+ images []media
+ videos []media
+}
+
+func NewBundle(
+ cacheDir string,
+ attachments []model.Attachment,
+ getAllImages bool,
+ getAllVideos bool,
+ attachmentIDs []string,
+) Bundle {
+ mediaHashmap := newMediaHashmap(cacheDir, attachments)
+ images := make([]media, 0)
+ videos := make([]media, 0)
+
+ if !getAllImages && !getAllVideos && len(attachmentIDs) == 0 {
+ return Bundle{
+ images: images,
+ videos: videos,
+ }
+ }
+
+ if getAllImages || getAllVideos {
+ if getAllImages {
+ for _, m := range mediaHashmap {
+ if m.mediaType == mediaTypeImage {
+ images = append(images, m)
+ }
+ }
+ }
+
+ if getAllVideos {
+ for _, m := range mediaHashmap {
+ if m.mediaType == mediaTypeVideo {
+ videos = append(videos, m)
+ }
+ }
+ }
+
+ return Bundle{
+ images: images,
+ videos: videos,
+ }
+ }
+
+ for _, attachmentID := range attachmentIDs {
+ obj, ok := mediaHashmap[attachmentID]
+ if !ok {
+ continue
+ }
+
+ switch obj.mediaType {
+ case mediaTypeImage:
+ images = append(images, obj)
+ case mediaTypeVideo:
+ videos = append(videos, obj)
+ }
+ }
+
+ return Bundle{
+ images: images,
+ videos: videos,
+ }
+}
+
+func (m *Bundle) Download(gtsClient *client.Client) error {
+ for ind := range m.images {
+ if err := m.images[ind].download(gtsClient); err != nil {
+ return fmt.Errorf("received an error trying to download the image files: %w", err)
+ }
+ }
+
+ for ind := range m.videos {
+ if err := m.videos[ind].download(gtsClient); err != nil {
+ return fmt.Errorf("received an error trying to download the video files: %w", err)
+ }
+ }
+
+ return nil
+}
+
+func (m *Bundle) ImageFiles() []string {
+ filepaths := make([]string, len(m.images))
+
+ for ind := range m.images {
+ filepaths[ind] = m.images[ind].destination
+ }
+
+ return filepaths
+}
+
+func (m *Bundle) VideoFiles() []string {
+ filepaths := make([]string, len(m.videos))
+
+ for ind := range m.videos {
+ filepaths[ind] = m.videos[ind].destination
+ }
+
+ return filepaths
+}
+
+func mediaFilepath(cacheDir, mediaURL string) string {
+ split := strings.Split(mediaURL, "/")
+
+ return filepath.Join(cacheDir, split[len(split)-1])
+}