From 4464790fd0cf36a6bc0a8304c59aa9b069d4e0be Mon Sep 17 00:00:00 2001 From: vpoluyaktov Date: Fri, 19 Jan 2024 18:18:12 -0800 Subject: [PATCH] Github repo url fixed. Few UI improvements. --- README.md | 7 +++- internal/audiobookshelf/utils.go | 24 +++++++++++ internal/config/config.go | 1 + internal/controller/boot_controller.go | 7 +++- internal/controller/build_controller.go | 5 ++- internal/controller/cleanup_controller.go | 2 +- internal/controller/copy_controller.go | 26 +++++------- internal/controller/download_controller.go | 4 +- internal/controller/encoding_controller.go | 3 +- internal/controller/search_controller.go | 9 ++++- internal/controller/upload_controller.go | 7 +++- internal/dto/audiobook.go | 2 +- internal/github/client.go | 46 ++++++++++++++++------ internal/github/utils.go | 28 ------------- internal/ia/model.go | 4 +- internal/ui/build_page.go | 10 ++++- internal/ui/chapters_page.go | 10 ++--- internal/ui/colors.go | 2 + internal/ui/download_page.go | 2 +- internal/ui/encoding_page.go | 2 +- internal/ui/footer.go | 32 ++++++++++----- internal/ui/search_page.go | 15 +++---- 22 files changed, 152 insertions(+), 96 deletions(-) create mode 100644 internal/audiobookshelf/utils.go diff --git a/README.md b/README.md index fd2e434..2863b04 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,13 @@ To install Audiobook Builder (`abb_ia`) on your system, follow these steps: 4. Run the binary file by executing the command `./abb_ia`. The TUI interface will appear. 5. Follow the instructions on the application interface to do a search, create an audiobook, and upload it to the [Audiobookshelf server](https://www.audiobookshelf.org) if necessary. You can try searching for: -- **Old Time Radio Researches Group: Single Episodes** +- **Old Time Radio Researchers Group: Single Episodes** + - **BBC Radio 4: Radio Drama** (make sure to check if the show is copyrighted). +- **Boxcars711:*** +- **Greg Lauer:*** +- **Relic Radio:*** +- **Radio Memories Network:*** - **CBC: Radio Mystery Theater** 6. Enjoy listening to an audiobook on your favorite device. diff --git a/internal/audiobookshelf/utils.go b/internal/audiobookshelf/utils.go new file mode 100644 index 0000000..89464e4 --- /dev/null +++ b/internal/audiobookshelf/utils.go @@ -0,0 +1,24 @@ +package audiobookshelf + +import "path/filepath" + +// Calculate Audiobookshelf directory structure (see: https://www.audiobookshelf.org/docs#book-directory-structure) +func GetDestignationPath(outputDir string, series string, author string) string { + destPath := filepath.Join(outputDir, author) + if series != "" { + destPath = filepath.Join(destPath, author+" - "+series) + } + return destPath +} + +func GetDestignationDir(series string, seriesNo string, title string, narrator string) string { + abTitle := "" + if series != "" && seriesNo != "" { + abTitle = seriesNo + ". " + } + abTitle += title + if narrator != "" { + abTitle += " {" + narrator + "}" + } + return abTitle +} diff --git a/internal/config/config.go b/internal/config/config.go index b2e1a80..ebce678 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -104,6 +104,7 @@ func Load() { "History", "Podcast", "Nonfiction", + "Education", "News", "Speech", } diff --git a/internal/controller/boot_controller.go b/internal/controller/boot_controller.go index 84dfd68..b8e842e 100644 --- a/internal/controller/boot_controller.go +++ b/internal/controller/boot_controller.go @@ -71,7 +71,12 @@ func (c *BootController) checkFFmpeg() bool { func (c *BootController) checkNewVersion() { - latestVersion, err := github.GetLatestVersion(config.Instance().GetRepoOwner(), config.Instance().GetRepoName()) + if config.Instance().AppVersion() == "0.0.0" { + // this is local dev version. Don't check new version + return + } + git := github.NewClient(config.Instance().GetRepoOwner(), config.Instance().GetRepoName()) + latestVersion, err := git.GetLatestVersion() if err != nil { logger.Error("Can't check new version: " + err.Error()) return diff --git a/internal/controller/build_controller.go b/internal/controller/build_controller.go index 34e2ba0..e19eda7 100644 --- a/internal/controller/build_controller.go +++ b/internal/controller/build_controller.go @@ -67,11 +67,10 @@ func (c *BuildController) dispatchMessage(m *mq.Message) { func (c *BuildController) stopBuild(cmd *dto.StopCommand) { c.stopFlag = true - logger.Debug(mq.BuildController + ": Received StopBuild command") + logger.Info(fmt.Sprintf("Building the audiobook: %s - %s...", c.ab.Author, c.ab.Title)) } func (c *BuildController) startBuild(cmd *dto.BuildCommand) { - logger.Info(mq.BuildController + " received " + cmd.String()) c.stopFlag = false c.startTime = time.Now() c.ab = cmd.Audiobook @@ -94,6 +93,8 @@ func (c *BuildController) startBuild(cmd *dto.BuildCommand) { c.mq.SendMessage(mq.BuildController, mq.Footer, &dto.UpdateStatus{Message: "Building audiobook..."}, false) c.mq.SendMessage(mq.BuildController, mq.Footer, &dto.SetBusyIndicator{Busy: true}, false) + logger.Info(fmt.Sprintf("Building the audiobook: %s - %s...", c.ab.Author, c.ab.Title)) + // prepare .mp3 file list c.createFilesLists(c.ab) // prepare metadata diff --git a/internal/controller/cleanup_controller.go b/internal/controller/cleanup_controller.go index 46a9d45..03f1b93 100644 --- a/internal/controller/cleanup_controller.go +++ b/internal/controller/cleanup_controller.go @@ -37,7 +37,7 @@ func (c *CleanupController) dispatchMessage(m *mq.Message) { } func (c *CleanupController) cleanUp(cmd *dto.CleanupCommand, requestor string) { - logger.Info(mq.CleanupController + " received " + cmd.String()) + logger.Debug(mq.CleanupController + " received " + cmd.String()) c.ab = cmd.Audiobook if !(c.ab.Config.IsSaveMock() || c.ab.Config.IsUseMock()) { diff --git a/internal/controller/copy_controller.go b/internal/controller/copy_controller.go index de894ff..8858201 100644 --- a/internal/controller/copy_controller.go +++ b/internal/controller/copy_controller.go @@ -8,6 +8,7 @@ import ( "path/filepath" "time" + "abb_ia/internal/audiobookshelf" "abb_ia/internal/dto" "abb_ia/internal/utils" @@ -85,7 +86,6 @@ func (c *CopyController) dispatchMessage(m *mq.Message) { func (c *CopyController) startCopy(cmd *dto.CopyCommand) { c.startTime = time.Now() - logger.Info(mq.CopyController + " received " + cmd.String()) c.ab = cmd.Audiobook // update part size and whole audiobook size after re-encoding @@ -106,6 +106,8 @@ func (c *CopyController) startCopy(cmd *dto.CopyCommand) { c.mq.SendMessage(mq.CopyController, mq.Footer, &dto.UpdateStatus{Message: "Copying audiobook files to Audiobookshelf..."}, false) c.mq.SendMessage(mq.CopyController, mq.Footer, &dto.SetBusyIndicator{Busy: true}, false) + logger.Info(fmt.Sprintf("Copying the audiobook: %s - %s to %s/...", c.ab.Author, c.ab.Title, c.ab.Config.OutputDir)) + c.stopFlag = false c.filesCopy = make([]fileCopy, len(c.ab.Parts)) jd := utils.NewJobDispatcher(c.ab.Config.GetConcurrentDownloaders()) @@ -141,27 +143,17 @@ func (c *CopyController) copyAudiobookPart(ab *dto.Audiobook, partId int) { defer file.Close() // Calculate Audiobookshelf directory structure (see: https://www.audiobookshelf.org/docs#book-directory-structure) - destPath := filepath.Join(ab.Config.GetOutputDir(), ab.Author) - if ab.Series != "" { - destPath = filepath.Join(destPath, ab.Author+" - "+ab.Series) - } - abTitle := "" - if ab.Series != "" && ab.SeriesNo != "" { - abTitle = ab.SeriesNo + ". " - } - abTitle += ab.Title - if ab.Narator != "" { - abTitle += " {" + ab.Narator + "}" - } + destPath := audiobookshelf.GetDestignationPath(ab.Config.GetOutputDir(), ab.Series, ab.Author) + destDir := audiobookshelf.GetDestignationDir(ab.Series, ab.SeriesNo, ab.Title, ab.Narrator) - destPath = filepath.Clean(filepath.Join(destPath, abTitle, filepath.Base(part.M4BFile))) - destDir := filepath.Dir(destPath) + filePath := filepath.Clean(filepath.Join(destPath, destDir, filepath.Base(part.M4BFile))) + fullPath := filepath.Dir(filePath) - if err := os.MkdirAll(destDir, 0750); err != nil { + if err := os.MkdirAll(fullPath, 0750); err != nil { logger.Error("Can't create output directory: " + err.Error()) return } - f, err := os.OpenFile(destPath, os.O_CREATE|os.O_WRONLY, 0644) + f, err := os.OpenFile(filePath, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { logger.Fatal("Can't create Audiobookshelf .m4b file: " + err.Error()) return diff --git a/internal/controller/download_controller.go b/internal/controller/download_controller.go index 07fad43..57bcc5b 100644 --- a/internal/controller/download_controller.go +++ b/internal/controller/download_controller.go @@ -59,7 +59,7 @@ func (c *DownloadController) stopDownload(cmd *dto.StopCommand) { func (c *DownloadController) startDownload(cmd *dto.DownloadCommand) { c.startTime = time.Now() - logger.Info(mq.DownloadController + " received " + cmd.String()) + c.mq.SendMessage(mq.DownloadController, mq.Footer, &dto.UpdateStatus{Message: "Downloading mp3 files..."}, false) c.mq.SendMessage(mq.DownloadController, mq.Footer, &dto.SetBusyIndicator{Busy: true}, false) @@ -75,6 +75,8 @@ func (c *DownloadController) startDownload(cmd *dto.DownloadCommand) { c.ab.TotalSize = item.TotalSize c.ab.TotalDuration = item.TotalLength + logger.Info(fmt.Sprintf("Downloading IA item: %s - %s...", c.ab.Author, c.ab.Title)) + // update Book info on UI c.mq.SendMessage(mq.DownloadController, mq.DownloadPage, &dto.DisplayBookInfoCommand{Audiobook: c.ab}, true) diff --git a/internal/controller/encoding_controller.go b/internal/controller/encoding_controller.go index 6baee02..993d5b9 100644 --- a/internal/controller/encoding_controller.go +++ b/internal/controller/encoding_controller.go @@ -69,7 +69,6 @@ func (c *EncodingController) stopEncoding(cmd *dto.StopCommand) { func (c *EncodingController) startEncoding(cmd *dto.EncodeCommand) { c.startTime = time.Now() - logger.Info(mq.EncodingController + " received " + cmd.String()) c.ab = cmd.Audiobook c.stopFlag = false @@ -79,6 +78,8 @@ func (c *EncodingController) startEncoding(cmd *dto.EncodeCommand) { c.mq.SendMessage(mq.EncodingController, mq.Footer, &dto.UpdateStatus{Message: "Re-encoding mp3 files..."}, false) c.mq.SendMessage(mq.EncodingController, mq.Footer, &dto.SetBusyIndicator{Busy: true}, false) + logger.Info(fmt.Sprintf("Re-encoding mp3 files: %s - %s...", c.ab.Author, c.ab.Title)) + // re-encode files jd := utils.NewJobDispatcher(c.ab.Config.GetConcurrentEncoders()) for i, f := range c.ab.Mp3Files { diff --git a/internal/controller/search_controller.go b/internal/controller/search_controller.go index 1bced27..e1fe341 100644 --- a/internal/controller/search_controller.go +++ b/internal/controller/search_controller.go @@ -56,7 +56,7 @@ func (c *SearchController) dispatchMessage(m *mq.Message) { } func (c *SearchController) search(cmd *dto.SearchCommand) { - logger.Info(mq.SearchController + " received " + cmd.String()) + logger.Info(fmt.Sprintf("Searching for: %s - %s", cmd.Condition.Author, cmd.Condition.Title)) c.mq.SendMessage(mq.SearchController, mq.Footer, &dto.UpdateStatus{Message: "Fetching Internet Archive items..."}, false) c.mq.SendMessage(mq.SearchController, mq.Footer, &dto.SetBusyIndicator{Busy: true}, false) c.totalItemsFetched = 0 @@ -73,12 +73,14 @@ func (c *SearchController) search(cmd *dto.SearchCommand) { c.mq.SendMessage(mq.SearchController, mq.Footer, &dto.UpdateStatus{Message: ""}, false) c.mq.SendMessage(mq.SearchController, mq.SearchPage, &dto.SearchComplete{Condition: cmd.Condition}, false) if itemsFetched == 0 { + logger.Info("Nothing found") c.mq.SendMessage(mq.SearchController, mq.SearchPage, &dto.NothingFoundError{Condition: cmd.Condition}, false) + } else { + logger.Info(fmt.Sprintf("Items fetched: %d", c.totalItemsFetched)) } } func (c *SearchController) getGetNextPage(cmd *dto.GetNextPageCommand) { - logger.Info(mq.SearchController + " received " + cmd.String()) c.mq.SendMessage(mq.SearchController, mq.Footer, &dto.UpdateStatus{Message: "Fetching Internet Archive items..."}, false) c.mq.SendMessage(mq.SearchController, mq.Footer, &dto.SetBusyIndicator{Busy: true}, false) resp := c.ia.GetNextPage(cmd.Condition.Author, cmd.Condition.Title, "audio") @@ -93,7 +95,10 @@ func (c *SearchController) getGetNextPage(cmd *dto.GetNextPageCommand) { c.mq.SendMessage(mq.SearchController, mq.Footer, &dto.UpdateStatus{Message: ""}, false) c.mq.SendMessage(mq.SearchController, mq.SearchPage, &dto.SearchComplete{Condition: cmd.Condition}, false) if itemsFetched == 0 { + logger.Info("Last page reached") c.mq.SendMessage(mq.SearchController, mq.SearchPage, &dto.LastPageMessage{Condition: cmd.Condition}, false) + } else { + logger.Info(fmt.Sprintf("Items fetched: %d", c.totalItemsFetched)) } } diff --git a/internal/controller/upload_controller.go b/internal/controller/upload_controller.go index 7a803b3..97ba426 100644 --- a/internal/controller/upload_controller.go +++ b/internal/controller/upload_controller.go @@ -54,13 +54,14 @@ func (c *UploadController) dispatchMessage(m *mq.Message) { } func (c *UploadController) absScan(cmd *dto.AbsScanCommand) { - logger.Info(mq.UploadController + " received " + cmd.String()) + ab := cmd.Audiobook url := ab.Config.GetAudiobookshelfUrl() username := ab.Config.GetAudiobookshelfUser() password := ab.Config.GetAudiobookshelfPassword() libraryName := ab.Config.GetAudiobookshelfLibrary() + if url != "" && username != "" && password != "" && libraryName != "" { absClient := audiobookshelf.NewClient(url) err := absClient.Login(username, password) @@ -94,13 +95,15 @@ func (c *UploadController) absScan(cmd *dto.AbsScanCommand) { func (c *UploadController) absUpload(cmd *dto.AbsUploadCommand) { c.startTime = time.Now() - logger.Info(mq.UploadController + " received " + cmd.String()) + c.ab = cmd.Audiobook url := c.ab.Config.GetAudiobookshelfUrl() username := c.ab.Config.GetAudiobookshelfUser() password := c.ab.Config.GetAudiobookshelfPassword() libraryName := c.ab.Config.GetAudiobookshelfLibrary() + logger.Info(fmt.Sprintf("Uploading the audiobook: %s - %s to %s...", c.ab.Author, c.ab.Title, c.ab.Config.AudiobookshelfUrl)) + if url != "" && username != "" && password != "" && libraryName != "" { absClient := audiobookshelf.NewClient(url) err := absClient.Login(username, password) diff --git a/internal/dto/audiobook.go b/internal/dto/audiobook.go index 82d775e..2d8cadd 100644 --- a/internal/dto/audiobook.go +++ b/internal/dto/audiobook.go @@ -14,7 +14,7 @@ type Audiobook struct { Genre string Series string SeriesNo string - Narator string + Narrator string Year string CoverURL string CoverFile string diff --git a/internal/github/client.go b/internal/github/client.go index 88b6b9f..f99e583 100644 --- a/internal/github/client.go +++ b/internal/github/client.go @@ -1,22 +1,44 @@ package github +import ( + "encoding/json" + "fmt" + "net/http" +) + type GithubClient struct { - token string + repoOwner string + repoName string +} + +func NewClient(repoOwner string, repoName string) (*GithubClient) { + c := &GithubClient{repoOwner: repoOwner, repoName: repoName} + return c } -func NewClient(token string) (*GithubClient, error) { - c := &GithubClient{token: token} - return c, nil +type Release struct { + TagName string `json:"tag_name"` } -func (c *GithubClient) GetLatestVer(owner string, repo string) (string, error) { - ver := "" +func (c *GithubClient) GetLatestVersion() (string, error) { + url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", c.repoOwner, c.repoName) - // curl -L \ - // -H "Accept: application/vnd.github+json" \ - // -H "Authorization: Bearer " \ - // -H "X-GitHub-Api-Version: 2022-11-28" \ - // https://api.github.com/repos/vpoluyaktov/abb_ia/releases/latest + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() - return ver, nil + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("failed to fetch latest release: %s", resp.Status) + } + + var release Release + err = json.NewDecoder(resp.Body).Decode(&release) + if err != nil { + return "", err + } + + return release.TagName, nil } + diff --git a/internal/github/utils.go b/internal/github/utils.go index e35eb13..8cebb26 100644 --- a/internal/github/utils.go +++ b/internal/github/utils.go @@ -1,39 +1,11 @@ package github import ( - "encoding/json" "fmt" - "net/http" "github.com/hashicorp/go-version" ) -type Release struct { - TagName string `json:"tag_name"` -} - -func GetLatestVersion(owner string, repo string) (string, error) { - url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo) - - resp, err := http.Get(url) - if err != nil { - return "", err - } - defer resp.Body.Close() - - if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("failed to fetch latest release: %s", resp.Status) - } - - var release Release - err = json.NewDecoder(resp.Body).Decode(&release) - if err != nil { - return "", err - } - - return release.TagName, nil -} - func CompareVersions(version1 string, version2 string) (int, error) { v1, err := version.NewVersion(version1) if err != nil { diff --git a/internal/ia/model.go b/internal/ia/model.go index b242a71..2036340 100644 --- a/internal/ia/model.go +++ b/internal/ia/model.go @@ -44,7 +44,7 @@ type SearchResponse struct { BackupLocation string `json:"backup_location,omitempty"` ExternalIdentifier strArray `json:"external-identifier,omitempty"` Genre strArray `json:"genre,omitempty"` - Language string `json:"language,omitempty"` + Language strArray `json:"language,omitempty"` Licenseurl string `json:"licenseurl,omitempty"` StrippedTags strArray `json:"stripped_tags,omitempty"` } `json:"docs"` @@ -92,7 +92,7 @@ type ItemDetails struct { Files map[string]struct { Source string `json:"source"` Format string `json:"format"` - Original string `json:"original"` + Original strArray `json:"original"` Length string `json:"length"` Mtime string `json:"mtime"` Size string `json:"size"` diff --git a/internal/ui/build_page.go b/internal/ui/build_page.go index 544b7bb..6215d9c 100644 --- a/internal/ui/build_page.go +++ b/internal/ui/build_page.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "abb_ia/internal/audiobookshelf" "abb_ia/internal/dto" "abb_ia/internal/mq" "abb_ia/internal/utils" @@ -69,7 +70,7 @@ func newBuildPage(dispatcher *mq.Dispatcher) *BuildPage { // copy section p.copySection = newGrid() p.copySection.SetColumns(-1) - p.copySection.SetTitle(" Copy to the output directory: ") + p.copySection.SetTitle(" Output directory: ") p.copySection.SetTitleAlign(tview.AlignLeft) p.copySection.SetBorder(true) p.copyTable = newTable() @@ -82,7 +83,7 @@ func newBuildPage(dispatcher *mq.Dispatcher) *BuildPage { // upload section p.uploadSection = newGrid() p.uploadSection.SetColumns(-1) - p.uploadSection.SetTitle(" Upload to Audiobookshelf server: ") + p.uploadSection.SetTitle(" Audiobookshelf server: ") p.uploadSection.SetTitleAlign(tview.AlignLeft) p.uploadSection.SetBorder(true) p.uploadTable = newTable() @@ -196,6 +197,10 @@ func (p *BuildPage) displayBookInfo(ab *dto.Audiobook) { } p.buildTable.ScrollToBeginning() + destPath := audiobookshelf.GetDestignationPath(ab.Config.GetOutputDir(), ab.Series, ab.Author) + destDir := audiobookshelf.GetDestignationDir(ab.Series, ab.SeriesNo, ab.Title, ab.Narrator) + filePath := filepath.Clean(filepath.Join(destPath, destDir)) + p.copySection.SetTitle(" Output directory " + filePath + "/: ") p.copyTable.Clear() p.copyTable.showHeader() for i, part := range ab.Parts { @@ -203,6 +208,7 @@ func (p *BuildPage) displayBookInfo(ab *dto.Audiobook) { } p.copyTable.ScrollToBeginning() + p.uploadSection.SetTitle(" Audiobookshelf server " + ab.Config.AudiobookshelfUrl + ": ") p.uploadTable.Clear() p.uploadTable.showHeader() for i, part := range ab.Parts { diff --git a/internal/ui/chapters_page.go b/internal/ui/chapters_page.go index 612eeff..182b931 100644 --- a/internal/ui/chapters_page.go +++ b/internal/ui/chapters_page.go @@ -24,7 +24,7 @@ type ChaptersPage struct { inputSeries *tview.InputField inputSeriesNo *tview.InputField inputGenre *tview.DropDown - inputNarator *tview.InputField + inputNarrator *tview.InputField inputCover *tview.InputField buttonCreateBook *tview.Button buttonCancel *tview.Button @@ -100,9 +100,9 @@ func newChaptersPage(dispatcher *mq.Dispatcher) *ChaptersPage { p.ab.Genre = strings.TrimSpace(s) } }) - p.inputNarator = f2.AddInputField("Narator:", "", 20, nil, func(s string) { + p.inputNarrator = f2.AddInputField("Narrator:", "", 20, nil, func(s string) { if p.ab != nil { - p.ab.Narator = s + p.ab.Narrator = s } }) infoSection.AddItem(f2.Form, 0, 2, 1, 1, 0, 0, true) @@ -196,7 +196,7 @@ func newChaptersPage(dispatcher *mq.Dispatcher) *ChaptersPage { p.inputSeries, p.inputSeriesNo, p.inputGenre, - p.inputNarator, + p.inputNarrator, p.inputCover, p.buttonCreateBook, p.buttonCancel, @@ -409,7 +409,7 @@ func (p *ChaptersPage) buildBook() { p.ab.Title = p.inputTitle.GetText() p.ab.Series = p.inputSeries.GetText() p.ab.SeriesNo = p.inputSeriesNo.GetText() - p.ab.Narator = p.inputNarator.GetText() + p.ab.Narrator = p.inputNarrator.GetText() _, p.ab.Genre = p.inputGenre.GetCurrentOption() p.mq.SendMessage(mq.ChaptersPage, mq.BuildController, &dto.BuildCommand{Audiobook: p.ab}, true) diff --git a/internal/ui/colors.go b/internal/ui/colors.go index 69a9b10..bbbd7a6 100644 --- a/internal/ui/colors.go +++ b/internal/ui/colors.go @@ -7,6 +7,7 @@ import ( var ( white = tcell.NewRGBColor(255, 255, 255) + darkWhite = tcell.NewRGBColor(235, 235, 235) gray = tcell.NewRGBColor(202, 202, 202) blue = tcell.NewRGBColor(12, 34, 184) lightBlue = tcell.ColorBlue @@ -15,6 +16,7 @@ var ( black = tcell.NewRGBColor(0, 0, 0) cyan = tcell.NewRGBColor(80, 176, 189) red = tcell.ColorRed + darkRed = tcell.ColorDarkRed labelsColor = yellow valuesColor = white diff --git a/internal/ui/download_page.go b/internal/ui/download_page.go index b272ba5..f5f692d 100644 --- a/internal/ui/download_page.go +++ b/internal/ui/download_page.go @@ -66,7 +66,7 @@ func newDownloadPage(dispatcher *mq.Dispatcher) *DownloadPage { p.progressSection = newGrid() p.progressSection.SetColumns(-1) p.progressSection.SetBorder(true) - p.progressSection.SetTitle(" Download progress: ") + p.progressSection.SetTitle(" Total download progress: ") p.progressSection.SetTitleAlign(tview.AlignLeft) p.progressTable = newTable() p.progressTable.setWeights(1) diff --git a/internal/ui/encoding_page.go b/internal/ui/encoding_page.go index f87a3fd..8e1a86f 100644 --- a/internal/ui/encoding_page.go +++ b/internal/ui/encoding_page.go @@ -66,7 +66,7 @@ func newEncodingPage(dispatcher *mq.Dispatcher) *EncodingPage { p.progressSection = newGrid() p.progressSection.SetColumns(-1) p.progressSection.SetBorder(true) - p.progressSection.SetTitle(" Encoding progress: ") + p.progressSection.SetTitle(" Total encoding progress: ") p.progressSection.SetTitleAlign(tview.AlignLeft) p.progressTable = newTable() p.progressTable.setWeights(1) diff --git a/internal/ui/footer.go b/internal/ui/footer.go index e55f3f7..80b25e4 100644 --- a/internal/ui/footer.go +++ b/internal/ui/footer.go @@ -8,6 +8,12 @@ import ( "github.com/vpoluyaktov/tview" ) +const ( + idleMessage = " IDLE " + busyMessage = " BUSY " + defaultStatusMessage = " [black]Keys and shortcuts: [yellow]Arrows, Tab, Shift+Tab[darkblue]: navigation, [yellow]Enter[darkblue]: action, [yellow]Ctrl+U[darkblue]: clear a field, [yellow]Ctrl+C[darkblue]: exit" +) + type footer struct { mq *mq.Dispatcher grid *tview.Grid @@ -23,18 +29,20 @@ func newFooter(dispatcher *mq.Dispatcher) *footer { f.mq.RegisterListener(mq.Footer, f.dispatchMessage) f.busyIndicator = tview.NewTextView() - f.busyIndicator.SetText("") + f.busyIndicator.SetText(idleMessage) f.busyIndicator.SetTextAlign(tview.AlignCenter) f.busyIndicator.SetBorder(false) - f.busyIndicator.SetTextColor(busyIndicatorFgColor) + f.busyIndicator.SetTextColor(footerFgColor) f.busyIndicator.SetBackgroundColor(busyIndicatorBgColor) + f.busyIndicator.SetDynamicColors(true) f.statusMessage = tview.NewTextView() - f.statusMessage.SetText("") + f.statusMessage.SetText(defaultStatusMessage) f.statusMessage.SetTextAlign(tview.AlignLeft) f.statusMessage.SetBorder(false) f.statusMessage.SetTextColor(footerFgColor) f.statusMessage.SetBackgroundColor(footerBgColor) + f.statusMessage.SetDynamicColors(true) f.version = tview.NewTextView() f.version.SetText("v" + config.Instance().AppVersion() + " (" + config.Instance().GetBuildDate() + ") ") @@ -44,7 +52,7 @@ func newFooter(dispatcher *mq.Dispatcher) *footer { f.version.SetBackgroundColor(footerBgColor) f.grid = tview.NewGrid() - f.grid.SetColumns(8, -1) + f.grid.SetColumns(8, -1, 12) f.grid.AddItem(f.busyIndicator, 0, 0, 1, 1, 0, 0, false) f.grid.AddItem(f.statusMessage, 0, 1, 1, 1, 0, 0, false) f.grid.AddItem(f.version, 0, 2, 1, 1, 0, 0, false) @@ -71,20 +79,26 @@ func (f *footer) dispatchMessage(m *mq.Message) { } func (f *footer) updateStatus(s *dto.UpdateStatus) { - f.statusMessage.SetText(s.Message) + if s.Message != "" { + f.statusMessage.SetTextColor(black) + f.statusMessage.SetText(" " + s.Message) + } else { + f.statusMessage.SetTextColor(footerFgColor) + f.statusMessage.SetText(defaultStatusMessage) + } ui.Draw() } func (f *footer) toggleBusyIndicator(c *dto.SetBusyIndicator) { if c.Busy { f.busyFlag = true - f.busyIndicator.SetTextColor(busyIndicatorFgColor) - f.busyIndicator.SetBackgroundColor(busyIndicatorBgColor) - f.busyIndicator.SetText(" Busy> ") + f.busyIndicator.SetTextColor(yellow) + f.busyIndicator.SetBackgroundColor(darkRed) + f.busyIndicator.SetText(busyMessage) go f.updateBusyIndicator() } else { f.busyFlag = false - f.busyIndicator.SetText("") + f.busyIndicator.SetText(idleMessage) f.busyIndicator.SetTextColor(footerFgColor) f.busyIndicator.SetBackgroundColor(footerBgColor) ui.Draw() diff --git a/internal/ui/search_page.go b/internal/ui/search_page.go index 63b1acf..cc2d8d7 100644 --- a/internal/ui/search_page.go +++ b/internal/ui/search_page.go @@ -245,7 +245,7 @@ func (p *SearchPage) createBook() { // get selectet row from the results table row, _ := p.resultTable.GetSelection() if row <= 0 || len(p.searchResult) <= 0 || len(p.searchResult) < row { - newMessageDialog(p.mq, "Error", "Please perform a search first", p.searchSection.Grid, func() {}) + newMessageDialog(p.mq, "Error", "\nPlease conduct a search beforehand.", p.searchSection.Grid, func() {}) } else if !(utils.CommandExists("ffmpeg") && utils.CommandExists("ffprobe")) { p.showFFMPEGNotFoundError(&dto.FFMPEGNotFoundError{}) } else { @@ -290,15 +290,16 @@ func (p *SearchPage) updateConfig() { func (p *SearchPage) showNothingFoundError(dto *dto.NothingFoundError) { newMessageDialog(p.mq, "Error", - "No results were found for your search term: [darkblue]'"+dto.Condition.Author+" - "+dto.Condition.Title+"'[black].\n"+ + "\nNo results were found for your search term:\n"+ + "Creator: [darkblue]'"+dto.Condition.Author+"'[black] Title: [darkblue]'"+dto.Condition.Title+"'[black].\n"+ "Please revise your search criteria.", p.searchSection.Grid, func() {}) } func (p *SearchPage) showLastPageMessage(dto *dto.LastPageMessage) { newMessageDialog(p.mq, "Notification", - "No more items were found for \n"+ - "your search term: [darkblue]'"+dto.Condition.Author+" - "+dto.Condition.Title+"'[black]\n"+ + "No more items were found for your search term: \n"+ + "Creator: [darkblue]'"+dto.Condition.Author+"'[black] Title: [darkblue]'"+dto.Condition.Title+"'[black].\n"+ "This is the last page.\n", p.resultSection.Grid, func() {}) } @@ -313,8 +314,8 @@ func (p *SearchPage) showFFMPEGNotFoundError(dto *dto.FFMPEGNotFoundError) { func (p *SearchPage) showNewVersionMessage(dto *dto.NewAppVersionFound) { newMessageDialog(p.mq, "Notification", - "New version of the application has been released: [darkblue]"+dto.NewVersion+"[black]\n"+ - "Your current version is [darkblue]"+dto.CurrentVersion+"[black]\n"+ - "You can download the new version of the application from:\n[darkblue]https://abb_ia/releases", + "New version of the Audiobook Builder has been released: [darkblue]"+dto.NewVersion+"[black]\n"+ + "Your current version is [darkblue]v"+dto.CurrentVersion+"[black]\n"+ + "You can download the new version of the application from:\n[darkblue]https://github.com/"+config.Instance().GetRepoOwner()+"/"+config.Instance().GetRepoName()+"/releases", p.searchSection.Grid, func() {}) }