termusiclib/
types.rs

1use std::path::PathBuf;
2use std::sync::Arc;
3
4use crate::config::v2::tui::{keys::KeyBinding, theme::styles::ColorTermusic};
5use crate::ids::{IdConfigEditor, IdKey};
6use crate::invidious::{Instance, YoutubeVideo};
7use crate::library_db::SearchCriteria;
8use crate::podcast::{EpData, PodcastFeed, PodcastNoId};
9use crate::songtag::SongTag;
10use anyhow::{anyhow, Result};
11use image::DynamicImage;
12
13#[derive(Clone, PartialEq, Eq, Debug)]
14pub enum Msg {
15    // AppClose,
16    ConfigEditor(ConfigEditorMsg),
17    DataBase(DBMsg),
18    DeleteConfirmCloseCancel,
19    DeleteConfirmCloseOk,
20    DeleteConfirmShow,
21    Download(DLMsg),
22    ErrorPopupClose,
23    GeneralSearch(GSMsg),
24    HelpPopupShow,
25    HelpPopupClose,
26    Layout(MainLayoutMsg),
27    Library(LIMsg),
28    LyricMessage(LyricMsg),
29    LyricCycle,
30    LyricAdjustDelay(i64),
31    Player(PlayerMsg),
32    Playlist(PLMsg),
33    Podcast(PCMsg),
34    /// Closes the Quit Popup, if it was shown without quitting.
35    QuitPopupCloseCancel,
36    /// Always will directly quit.
37    QuitPopupCloseOk,
38    /// Either shows the Quit Dialog if enabled, or if dialog is disabled, directly quits
39    QuitPopupShow,
40    SavePlaylist(SavePlaylistMsg),
41    TagEditor(TEMsg),
42    UpdatePhoto,
43    YoutubeSearch(YSMsg),
44    Xywh(XYWHMsg),
45
46    /// Force a redraw because of some change.
47    ///
48    /// This is necessary as `Components` do not have access to `Model.redraw`.
49    ///
50    /// For example pushing ARROW DOWN to change the selection in a table.
51    ForceRedraw,
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum MainLayoutMsg {
56    /// Switch to the Music library view
57    TreeView,
58    /// Switch to the Database view
59    DataBase,
60    /// Switch to the Podcast view
61    Podcast,
62}
63
64/// Player relates messages
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum PlayerMsg {
67    ToggleGapless,
68    TogglePause,
69    VolumeUp,
70    VolumeDown,
71    SpeedUp,
72    SpeedDown,
73    SeekForward,
74    SeekBackward,
75}
76
77/// Save Playlist Popup related messages
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub enum SavePlaylistMsg {
80    PopupShow,
81    PopupCloseCancel,
82    PopupUpdate(String),
83    PopupCloseOk(String),
84    ConfirmCloseCancel,
85    ConfirmCloseOk(String),
86}
87
88#[derive(Clone, Copy, PartialEq, Eq, Debug)]
89pub enum XYWHMsg {
90    /// Toggle the hidden / shown status of the displayed image.
91    ToggleHidden,
92    MoveLeft,
93    MoveRight,
94    MoveUp,
95    MoveDown,
96    ZoomIn,
97    ZoomOut,
98}
99
100pub type DLMsgURL = Arc<str>;
101
102#[derive(Clone, PartialEq, Eq, Debug)]
103pub enum DLMsg {
104    /// Indicates a Start of a download.
105    ///
106    /// `(Url, Title)`
107    DownloadRunning(DLMsgURL, String),
108    /// Indicates the Download was a Success, though termusic post-processing is not done yet.
109    ///
110    /// `(Url)`
111    DownloadSuccess(DLMsgURL),
112    /// Indicates the Download thread finished in both Success or Error.
113    ///
114    /// `(Url, Filename)`
115    DownloadCompleted(DLMsgURL, Option<String>),
116    /// Indicates that the Download has Errored and has been aborted.
117    ///
118    /// `(Url, Title, ErrorAsString)`
119    DownloadErrDownload(DLMsgURL, String, String),
120    /// Indicates that the Download was a Success, but termusic post-processing failed.
121    /// Like re-saving tags after editing.
122    ///
123    /// `(Url, Title)`
124    DownloadErrEmbedData(DLMsgURL, String),
125
126    // TODO: The Following 2 things have absolutely nothing to-do with Download
127    /// Show a status message in the TUI.
128    ///
129    /// `((Title, Text))`
130    MessageShow((String, String)),
131    /// Hide a status message in the TUI.
132    ///
133    /// `((Title, Text))`
134    MessageHide((String, String)),
135
136    // TODO: The Following 2 things have absolutely nothing to-do with Download
137    /// Fetching & loading the image was a success, with the image.
138    FetchPhotoSuccess(ImageWrapper),
139    /// Fetching & loading the image has failed, with error message.
140    /// `(ErrorAsString)`
141    FetchPhotoErr(String),
142}
143
144#[derive(Clone, Copy, PartialEq, Eq, Debug)]
145pub enum LyricMsg {
146    LyricTextAreaBlurUp,
147    LyricTextAreaBlurDown,
148}
149
150#[derive(Clone, PartialEq, Eq, Debug)]
151pub enum ConfigEditorMsg {
152    PodcastDirBlurDown,
153    PodcastDirBlurUp,
154    PodcastSimulDownloadBlurDown,
155    PodcastSimulDownloadBlurUp,
156    PodcastMaxRetriesBlurDown,
157    PodcastMaxRetriesBlurUp,
158
159    AlbumPhotoAlignBlurDown,
160    AlbumPhotoAlignBlurUp,
161    ChangeLayout,
162    CloseCancel,
163    CloseOk,
164    ColorChanged(IdConfigEditor, ColorTermusic),
165    SymbolChanged(IdConfigEditor, String),
166    ConfigChanged,
167    ConfigSaveOk,
168    ConfigSaveCancel,
169    ExitConfirmationBlurDown,
170    ExitConfirmationBlurUp,
171    ExtraYtdlpArgsBlurDown,
172    ExtraYtdlpArgsBlurUp,
173    Open,
174    KeyFocus(KFMsg),
175    MusicDirBlurDown,
176    MusicDirBlurUp,
177
178    PlaylistDisplaySymbolBlurDown,
179    PlaylistDisplaySymbolBlurUp,
180    PlaylistRandomTrackBlurDown,
181    PlaylistRandomTrackBlurUp,
182    PlaylistRandomAlbumBlurDown,
183    PlaylistRandomAlbumBlurUp,
184
185    LibraryForegroundBlurDown,
186    LibraryForegroundBlurUp,
187    LibraryBackgroundBlurDown,
188    LibraryBackgroundBlurUp,
189    LibraryBorderBlurDown,
190    LibraryBorderBlurUp,
191    LibraryHighlightBlurDown,
192    LibraryHighlightBlurUp,
193    LibraryHighlightSymbolBlurDown,
194    LibraryHighlightSymbolBlurUp,
195
196    PlaylistForegroundBlurDown,
197    PlaylistForegroundBlurUp,
198    PlaylistBackgroundBlurDown,
199    PlaylistBackgroundBlurUp,
200    PlaylistBorderBlurDown,
201    PlaylistBorderBlurUp,
202    PlaylistHighlightBlurDown,
203    PlaylistHighlightBlurUp,
204    PlaylistHighlightSymbolBlurDown,
205    PlaylistHighlightSymbolBlurUp,
206
207    ProgressForegroundBlurDown,
208    ProgressForegroundBlurUp,
209    ProgressBackgroundBlurDown,
210    ProgressBackgroundBlurUp,
211    ProgressBorderBlurDown,
212    ProgressBorderBlurUp,
213
214    LyricForegroundBlurDown,
215    LyricForegroundBlurUp,
216    LyricBackgroundBlurDown,
217    LyricBackgroundBlurUp,
218    LyricBorderBlurDown,
219    LyricBorderBlurUp,
220
221    ThemeSelectBlurDown,
222    ThemeSelectBlurUp,
223    ThemeSelectLoad(usize),
224
225    KeyChange(IdKey, KeyBinding),
226    SaveLastPositionBlurDown,
227    SaveLastPosotionBlurUp,
228    SeekStepBlurDown,
229    SeekStepBlurUp,
230    KillDaemonBlurDown,
231    KillDaemonBlurUp,
232
233    PlayerUseMprisBlurDown,
234    PlayerUseMprisBlurUp,
235    PlayerUseDiscordBlurDown,
236    PlayerUseDiscordBlurUp,
237    PlayerPortBlurDown,
238    PlayerPortBlurUp,
239
240    CurrentlyPlayingTrackSymbolBlurDown,
241    CurrentlyPlayingTrackSymbolBlurUp,
242
243    ImportantPopupForegroundBlurDown,
244    ImportantPopupForegroundBlurUp,
245    ImportantPopupBackgroundBlurDown,
246    ImportantPopupBackgroundBlurUp,
247    ImportantPopupBorderBlurDown,
248    ImportantPopupBorderBlurUp,
249
250    FallbackForegroundBlurDown,
251    FallbackForegroundBlurUp,
252    FallbackBackgroundBlurDown,
253    FallbackBackgroundBlurUp,
254    FallbackBorderBlurDown,
255    FallbackBorderBlurUp,
256    FallbackHighlightBlurDown,
257    FallbackHighlightBlurUp,
258}
259
260#[derive(Clone, Copy, Debug, PartialEq, Eq)]
261pub enum KFMsg {
262    DatabaseAddAllBlurDown,
263    DatabaseAddAllBlurUp,
264    DatabaseAddSelectedBlurDown,
265    DatabaseAddSelectedBlurUp,
266    GlobalConfigBlurDown,
267    GlobalConfigBlurUp,
268    GlobalDownBlurDown,
269    GlobalDownBlurUp,
270    GlobalGotoBottomBlurDown,
271    GlobalGotoBottomBlurUp,
272    GlobalGotoTopBlurDown,
273    GlobalGotoTopBlurUp,
274    GlobalHelpBlurDown,
275    GlobalHelpBlurUp,
276    GlobalLayoutTreeviewBlurDown,
277    GlobalLayoutTreeviewBlurUp,
278    GlobalLayoutDatabaseBlurDown,
279    GlobalLayoutDatabaseBlurUp,
280    GlobalLeftBlurDown,
281    GlobalLeftBlurUp,
282    GlobalLyricAdjustForwardBlurDown,
283    GlobalLyricAdjustForwardBlurUp,
284    GlobalLyricAdjustBackwardBlurDown,
285    GlobalLyricAdjustBackwardBlurUp,
286    GlobalLyricCycleBlurDown,
287    GlobalLyricCycleBlurUp,
288    GlobalPlayerNextBlurDown,
289    GlobalPlayerNextBlurUp,
290    GlobalPlayerPreviousBlurDown,
291    GlobalPlayerPreviousBlurUp,
292    GlobalPlayerSeekForwardBlurDown,
293    GlobalPlayerSeekForwardBlurUp,
294    GlobalPlayerSeekBackwardBlurDown,
295    GlobalPlayerSeekBackwardBlurUp,
296    GlobalPlayerSpeedUpBlurDown,
297    GlobalPlayerSpeedUpBlurUp,
298    GlobalPlayerSpeedDownBlurDown,
299    GlobalPlayerSpeedDownBlurUp,
300    GlobalPlayerToggleGaplessBlurDown,
301    GlobalPlayerToggleGaplessBlurUp,
302    GlobalPlayerTogglePauseBlurDown,
303    GlobalPlayerTogglePauseBlurUp,
304    GlobalQuitBlurDown,
305    GlobalQuitBlurUp,
306    GlobalRightBlurDown,
307    GlobalRightBlurUp,
308    GlobalUpBlurDown,
309    GlobalUpBlurUp,
310    GlobalVolumeDownBlurDown,
311    GlobalVolumeDownBlurUp,
312    GlobalVolumeUpBlurDown,
313    GlobalVolumeUpBlurUp,
314    GlobalSavePlaylistBlurDown,
315    GlobalSavePlaylistBlurUp,
316    LibraryDeleteBlurDown,
317    LibraryDeleteBlurUp,
318    LibraryLoadDirBlurDown,
319    LibraryLoadDirBlurUp,
320    LibraryPasteBlurDown,
321    LibraryPasteBlurUp,
322    LibrarySearchBlurDown,
323    LibrarySearchBlurUp,
324    LibrarySearchYoutubeBlurDown,
325    LibrarySearchYoutubeBlurUp,
326    LibraryTagEditorBlurDown,
327    LibraryTagEditorBlurUp,
328    LibraryYankBlurDown,
329    LibraryYankBlurUp,
330    PlaylistDeleteBlurDown,
331    PlaylistDeleteBlurUp,
332    PlaylistDeleteAllBlurDown,
333    PlaylistDeleteAllBlurUp,
334    PlaylistShuffleBlurDown,
335    PlaylistShuffleBlurUp,
336    PlaylistModeCycleBlurDown,
337    PlaylistModeCycleBlurUp,
338    PlaylistPlaySelectedBlurDown,
339    PlaylistPlaySelectedBlurUp,
340    PlaylistSearchBlurDown,
341    PlaylistSearchBlurUp,
342    PlaylistSwapDownBlurDown,
343    PlaylistSwapDownBlurUp,
344    PlaylistSwapUpBlurDown,
345    PlaylistSwapUpBlurUp,
346    PlaylistAddRandomAlbumBlurDown,
347    PlaylistAddRandomAlbumBlurUp,
348    PlaylistAddRandomTracksBlurDown,
349    PlaylistAddRandomTracksBlurUp,
350    LibrarySwitchRootBlurDown,
351    LibrarySwitchRootBlurUp,
352    LibraryAddRootBlurDown,
353    LibraryAddRootBlurUp,
354    LibraryRemoveRootBlurDown,
355    LibraryRemoveRootBlurUp,
356    GlobalLayoutPodcastBlurDown,
357    GlobalLayoutPodcastBlurUp,
358    GlobalXywhMoveLeftBlurDown,
359    GlobalXywhMoveLeftBlurUp,
360    GlobalXywhMoveRightBlurDown,
361    GlobalXywhMoveRightBlurUp,
362    GlobalXywhMoveUpBlurDown,
363    GlobalXywhMoveUpBlurUp,
364    GlobalXywhMoveDownBlurDown,
365    GlobalXywhMoveDownBlurUp,
366    GlobalXywhZoomInBlurDown,
367    GlobalXywhZoomInBlurUp,
368    GlobalXywhZoomOutBlurDown,
369    GlobalXywhZoomOutBlurUp,
370    GlobalXywhHideBlurDown,
371    GlobalXywhHideBlurUp,
372    PodcastMarkPlayedBlurDown,
373    PodcastMarkPlayedBlurUp,
374    PodcastMarkAllPlayedBlurDown,
375    PodcastMarkAllPlayedBlurUp,
376    PodcastEpDownloadBlurDown,
377    PodcastEpDownloadBlurUp,
378    PodcastEpDeleteFileBlurDown,
379    PodcastEpDeleteFileBlurUp,
380    PodcastDeleteFeedBlurDown,
381    PodcastDeleteFeedBlurUp,
382    PodcastDeleteAllFeedsBlurDown,
383    PodcastDeleteAllFeedsBlurUp,
384    PodcastSearchAddFeedBlurDown,
385    PodcastSearchAddFeedBlurUp,
386    PodcastRefreshFeedBlurDown,
387    PodcastRefreshFeedBlurUp,
388    PodcastRefreshAllFeedsBlurDown,
389    PodcastRefreshAllFeedsBlurUp,
390}
391
392/// Basically a Tree Node, but without having to include `tui-realm-treeview` as another dependency for lib
393#[derive(Debug, Clone, PartialEq, Eq)]
394pub struct RecVec<T, V> {
395    pub id: T,
396    pub value: V,
397    pub children: Vec<RecVec<T, V>>,
398}
399
400#[derive(Clone, Debug, PartialEq, Eq)]
401pub enum LIMsg {
402    TreeStepInto(String),
403    TreeStepOut,
404    TreeBlur,
405    Yank,
406    Paste,
407    SwitchRoot,
408    AddRoot,
409    RemoveRoot,
410
411    /// A requested node is ready from loading.
412    /// `(Tree, FocusNode)`
413    TreeNodeReady(RecVec<PathBuf, String>, Option<String>),
414}
415
416#[derive(Clone, Copy, Debug, PartialEq, Eq)]
417pub enum DBMsg {
418    /// Add all Track Results (from view `Tracks`) to the playlist
419    AddAllToPlaylist,
420    /// Add a single Track Result (from view `Tracks`) to the playlist
421    AddPlaylist(usize),
422    /// Add all Results (from view `Result`) to the playlist
423    AddAllResultsToPlaylist,
424    /// Add a single result (from view `Result`) to the playlist
425    AddResultToPlaylist(usize),
426    CriteriaBlurDown,
427    CriteriaBlurUp,
428    /// Search Results (for view `Result`) from a `Database`(view) index
429    SearchResult(SearchCriteria),
430    SearchResultBlurDown,
431    SearchResultBlurUp,
432    /// Serarch Tracks (for view `Tracks`) from a `Result`(view) index
433    SearchTrack(usize),
434    SearchTracksBlurDown,
435    SearchTracksBlurUp,
436
437    AddAllResultsConfirmShow,
438    AddAllResultsConfirmCancel,
439}
440
441#[derive(Clone, Debug, PartialEq, Eq)]
442pub enum PCMsg {
443    PodcastBlurDown,
444    PodcastBlurUp,
445    EpisodeBlurDown,
446    EpisodeBlurUp,
447    PodcastAddPopupShow,
448    PodcastAddPopupCloseOk(String),
449    PodcastAddPopupCloseCancel,
450    SyncData((i64, PodcastNoId)),
451    NewData(PodcastNoId),
452    Error(PodcastFeed),
453    PodcastSelected(usize),
454    DescriptionUpdate,
455    EpisodeAdd(usize),
456    EpisodeMarkPlayed(usize),
457    EpisodeMarkAllPlayed,
458    PodcastRefreshOne(usize),
459    PodcastRefreshAll,
460    FetchPodcastStart(String),
461    EpisodeDownload(usize),
462    DLStart(EpData),
463    DLComplete(EpData),
464    DLResponseError(EpData),
465    DLFileCreateError(EpData),
466    DLFileWriteError(EpData),
467    EpisodeDeleteFile(usize),
468    FeedDeleteShow,
469    FeedDeleteCloseOk,
470    FeedDeleteCloseCancel,
471    FeedsDeleteShow,
472    FeedsDeleteCloseOk,
473    FeedsDeleteCloseCancel,
474    SearchItunesCloseCancel,
475    SearchItunesCloseOk(usize),
476    SearchSuccess(Vec<PodcastFeed>),
477    SearchError(String),
478}
479
480/// Playlist Library View messages
481#[derive(Clone, Debug, PartialEq, Eq)]
482pub enum PLMsg {
483    NextSong,
484    PrevSong,
485    /// Change focus to the next view
486    PlaylistTableBlurDown,
487    /// Change focus to the previous view
488    PlaylistTableBlurUp,
489    /// Add a directory / file to the playlist
490    Add(PathBuf),
491    /// Remove INDEX from playlist
492    Delete(usize),
493    /// Clear the Playlist
494    DeleteAll,
495    /// Select the next mode in the list
496    ///
497    /// see `termusicplayback::playlist::Loop` for all modes
498    LoopModeCycle,
499    /// Play a specific index
500    PlaySelected(usize),
501    /// Shuffle the current items in the playlist
502    Shuffle,
503    /// Swap a entry at INDEX with +1 (down)
504    SwapDown(usize),
505    /// Swap a entry at INDEX with -1 (up)
506    SwapUp(usize),
507    /// Start choosing random albums to be added to the playlist
508    AddRandomAlbum,
509    /// Start choosing random tracks to be added to the playlist
510    AddRandomTracks,
511}
512#[derive(Clone, Debug, PartialEq, Eq)]
513pub enum GSMsg {
514    PopupShowDatabase,
515    PopupShowLibrary,
516    PopupShowPlaylist,
517    PopupShowEpisode,
518    PopupShowPodcast,
519    PopupCloseCancel,
520    InputBlur,
521    PopupUpdateDatabase(String),
522    PopupUpdateLibrary(String),
523    PopupUpdatePlaylist(String),
524    PopupUpdateEpisode(String),
525    PopupUpdatePodcast(String),
526    TableBlur,
527    PopupCloseEpisodeAddPlaylist,
528    PopupCloseDatabaseAddPlaylist,
529    PopupCloseLibraryAddPlaylist,
530    PopupCloseOkLibraryLocate,
531    PopupClosePlaylistPlaySelected,
532    PopupCloseOkPlaylistLocate,
533    PopupCloseOkEpisodeLocate,
534    PopupCloseOkPodcastLocate,
535}
536
537#[derive(Clone, Debug, PartialEq, Eq)]
538pub enum YSMsg {
539    InputPopupShow,
540    InputPopupCloseCancel,
541    InputPopupCloseOk(String),
542    TablePopupNext,
543    TablePopupPrevious,
544    TablePopupCloseCancel,
545    TablePopupCloseOk(usize),
546
547    /// The youtube search was a success, with all values.
548    YoutubeSearchSuccess(YoutubeOptions),
549    /// Indicates that the youtube search has failed, with error message.
550    ///
551    /// `(ErrorAsString)`
552    YoutubeSearchFail(String),
553}
554#[derive(Clone, Debug, PartialEq, Eq)]
555pub enum TEMsg {
556    TagEditorRun(String),
557    TagEditorClose,
558    TECounterDeleteOk,
559    TEDownload(usize),
560    TEEmbed(usize),
561    TEFocus(TFMsg),
562    TERename,
563    TESearch,
564    TESelectLyricOk(usize),
565
566    TESearchLyricResult(SongTagRecordingResult),
567}
568
569#[derive(Clone, Copy, Debug, PartialEq, Eq)]
570pub enum TFMsg {
571    CounterDeleteBlurDown,
572    CounterDeleteBlurUp,
573    InputArtistBlurDown,
574    InputArtistBlurUp,
575    InputTitleBlurDown,
576    InputTitleBlurUp,
577    InputAlbumBlurDown,
578    InputAlbumBlurUp,
579    InputGenreBlurDown,
580    InputGenreBlurUp,
581    SelectLyricBlurDown,
582    SelectLyricBlurUp,
583    TableLyricOptionsBlurDown,
584    TableLyricOptionsBlurUp,
585    TextareaLyricBlurDown,
586    TextareaLyricBlurUp,
587}
588
589#[derive(Debug, Clone, PartialEq, Eq)]
590pub enum SongTagRecordingResult {
591    Finish(Vec<SongTag>),
592}
593
594#[derive(Clone, PartialEq, Debug)]
595pub struct ImageWrapper {
596    pub data: DynamicImage,
597}
598impl Eq for ImageWrapper {}
599
600#[derive(Clone, PartialEq, Eq, Debug)]
601pub struct YoutubeOptions {
602    pub items: Vec<YoutubeVideo>,
603    pub page: u32,
604    pub invidious_instance: Instance,
605}
606
607impl Default for YoutubeOptions {
608    fn default() -> Self {
609        Self {
610            items: Vec::new(),
611            page: 1,
612            invidious_instance: crate::invidious::Instance::default(),
613        }
614    }
615}
616
617impl YoutubeOptions {
618    pub fn get_by_index(&self, index: usize) -> Result<&YoutubeVideo> {
619        if let Some(item) = self.items.get(index) {
620            return Ok(item);
621        }
622        Err(anyhow!("index not found"))
623    }
624
625    pub async fn prev_page(&mut self) -> Result<()> {
626        if self.page > 1 {
627            self.page -= 1;
628            self.items = self.invidious_instance.get_search_query(self.page).await?;
629        }
630        Ok(())
631    }
632
633    pub async fn next_page(&mut self) -> Result<()> {
634        self.page += 1;
635        self.items = self.invidious_instance.get_search_query(self.page).await?;
636        Ok(())
637    }
638
639    #[must_use]
640    pub const fn page(&self) -> u32 {
641        self.page
642    }
643}