Skip to content

Commit

Permalink
Merge pull request #12 from vpoluyaktov/feature_Sort_Result
Browse files Browse the repository at this point in the history
Implemented search result sorting
  • Loading branch information
vpoluyaktov authored Mar 6, 2024
2 parents 44d7d92 + bcc62a6 commit a180daa
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 21 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The Internet Archive site offers a vast collection of free "old-time radio" show
To make this process easier, I developed Audiobook Builder. With this app, all you need is the name of a show or book, or a direct link on archive.org. It will download the .mp3 files for the book, re-encode them with the same bit rate, generate a list of chapters (which can be edited during the process), and ultimately create an audiobook in .m4b format.


![Audiobook Builder in action](https://github.com/vpoluyaktov/abb_ia/blob/master/assets/abb_ia.gif)
![Audiobook Builder in action](https://github.com/vpoluyaktov/abb_ia/blob/master/assets/abb_ia_v2.gif)

## Features
- TUI interface. It allows you to run this application either on your own computer or on a remote server using ssh with tmux, screen, or byobu. This can be helpful when creating an audiobook that takes a long time.
Expand Down Expand Up @@ -145,4 +145,6 @@ Since the copyrights for the majority of old-time radio shows have expired and m
## Todo
- The Text to Speech (**TTS**) version of Audiobook Builder is coming soon. It will allow you to create audiobooks from .epub, fb2, and other formats of electronic books.

## Join us on Discord
https://discord.gg/ntYyJ7xfzX

Binary file removed assets/abb_ia.gif
Binary file not shown.
Binary file added assets/abb_ia_v2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions internal/controller/search_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (c *SearchController) search(cmd *dto.SearchCommand) {
c.mq.SendMessage(mq.SearchController, mq.Footer, &dto.SetBusyIndicator{Busy: true}, false)
c.totalItemsFetched = 0
c.ia = ia_client.New(config.Instance().GetRowsPerPage(), config.Instance().IsUseMock(), config.Instance().IsSaveMock())
resp := c.ia.Search(cmd.Condition.Author, cmd.Condition.Title, "audio")
resp := c.ia.Search(cmd.Condition.Author, cmd.Condition.Title, "audio", cmd.Condition.SortBy, cmd.Condition.SortOrder)
if resp == nil {
logger.Error(mq.SearchController + ": Failed to perform IA search with condition: " + cmd.Condition.Author + " - " + cmd.Condition.Title)
}
Expand All @@ -83,7 +83,7 @@ func (c *SearchController) search(cmd *dto.SearchCommand) {
func (c *SearchController) getGetNextPage(cmd *dto.GetNextPageCommand) {
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")
resp := c.ia.GetNextPage(cmd.Condition.Author, cmd.Condition.Title, "audio", cmd.Condition.SortBy, cmd.Condition.SortOrder)
if resp == nil {
logger.Error(mq.SearchController + ": Failed to perform IA search with condition: " + cmd.Condition.Author + " - " + cmd.Condition.Title)
}
Expand Down
6 changes: 4 additions & 2 deletions internal/dto/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package dto
import "fmt"

type SearchCondition struct {
Author string
Title string
Author string
Title string
SortBy string
SortOrder string
}

type SearchCommand struct {
Expand Down
14 changes: 7 additions & 7 deletions internal/ia/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,27 @@ func New(maxSearchRows int, useMock bool, saveMock bool) *IAClient {
return client
}

func (client *IAClient) Search(author string, title string, mediaType string) *SearchResponse {
func (client *IAClient) Search(author string, title string, mediaType string, sortBy string, sortOrder string) *SearchResponse {
if strings.Contains(title, IA_BASE_URL+"/details/") {
item_id := strings.Split(title, "/")[4]
return client.searchByID(item_id, mediaType)
} else {
client.page = 1
return client.searchByTitle(author, title, mediaType)
return client.searchByTitle(author, title, mediaType, sortBy, sortOrder)
}
}

func (client *IAClient) GetNextPage(author string, title string, mediaType string) *SearchResponse {
func (client *IAClient) GetNextPage(author string, title string, mediaType string, sortBy string, sortOrder string) *SearchResponse {
if strings.Contains(title, IA_BASE_URL+"/details/") {
return &SearchResponse{}
} else {
client.page += 1
resp := client.searchByTitle(author, title, mediaType)
resp := client.searchByTitle(author, title, mediaType, sortBy, sortOrder)
return resp
}
}

func (client *IAClient) searchByTitle(author string, title string, mediaType string) *SearchResponse {
func (client *IAClient) searchByTitle(author string, title string, mediaType string, sortBy string, sortOrder string) *SearchResponse {
mockFile := MOCK_DIR + "/SearchByAuthorAndTitle.json"
result := &SearchResponse{}
if client.loadMockResult {
Expand All @@ -80,8 +80,8 @@ func (client *IAClient) searchByTitle(author string, title string, mediaType str
} else if title != "" {
searchCondition = fmt.Sprintf("title:(%s)", url.QueryEscape(title))
}
var searchURL = fmt.Sprintf(IA_BASE_URL+"/advancedsearch.php?q=%s+AND+mediatype:(%s)&output=json&rows=%d&page=%d",
searchCondition, mediaType, client.maxSearchRows, client.page)
var searchURL = fmt.Sprintf(IA_BASE_URL+"/advancedsearch.php?q=%s+AND+mediatype:(%s)&sort=%s+%s&output=json&rows=%d&page=%d",
searchCondition, mediaType, sortBy, sortOrder, client.maxSearchRows, client.page)
logger.Debug("IA request: " + searchURL)
_, err := client.restyClient.R().SetResult(result).Get(searchURL)
if err != nil {
Expand Down
8 changes: 4 additions & 4 deletions internal/ia/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ func TestMain(m *testing.M) {
func TestSearch(t *testing.T) {
ia := ia_client.New(5, false, false)

res := ia.Search("Old Time Radio Researchers", "Single Episodes", "audio") // search by author and title
res := ia.Search("Old Time Radio Researchers", "Single Episodes", "audio", "date", "asc") // search by author and title
assert.NotNil(t, res)
assert.Equal(t, 5, len(res.Response.Docs))

res = ia.Search("Old Time Radio Researchers", "", "audio") // search by author only
res = ia.Search("Old Time Radio Researchers", "", "audio", "date", "asc") // search by author only
assert.NotNil(t, res)
assert.Equal(t, 5, len(res.Response.Docs))

res = ia.Search("", "Single Episodes", "audio") // search by title only
res = ia.Search("", "Single Episodes", "audio", "date", "asc") // search by title only
assert.NotNil(t, res)
assert.Equal(t, 5, len(res.Response.Docs))

res = ia.Search("", "https://archive.org/details/OTRR_Frank_Race_Singles", "audio") // search by item ID
res = ia.Search("", "https://archive.org/details/OTRR_Frank_Race_Singles", "audio", "date", "asc") // search by item ID
assert.NotNil(t, res)
assert.Equal(t, 1, len(res.Response.Docs))
}
Expand Down
46 changes: 41 additions & 5 deletions internal/ui/search_page.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ui
import (
"fmt"
"strconv"
"strings"

"abb_ia/internal/config"
"abb_ia/internal/dto"
Expand All @@ -23,6 +24,8 @@ type SearchPage struct {
searchSection *grid
author *tview.InputField
title *tview.InputField
SortBy *tview.DropDown
sortOrder *tview.DropDown
searchButton *tview.Button
clearButton *tview.Button
createAudioBookButton *tview.Button
Expand Down Expand Up @@ -50,18 +53,23 @@ func newSearchPage(dispatcher *mq.Dispatcher) *SearchPage {

// search section
p.searchSection = newGrid()
p.searchSection.SetColumns(50, -1)
p.searchSection.SetColumns(50, -1, -1)
p.searchSection.SetBorder(true)
p.searchSection.SetTitle(" Internet Archive Search ")
p.searchSection.SetTitleAlign(tview.AlignLeft)
f := newForm()
f.SetHorizontal(false)
p.author = f.AddInputField("Creator", config.Instance().GetDefaultAuthor(), 40, nil, func(t string) { p.searchCondition.Author = t })
p.title = f.AddInputField("Title", config.Instance().GetDefaultTitle(), 40, nil, func(t string) { p.searchCondition.Title = t })

p.searchButton = f.AddButton("Search", p.runSearch)
p.clearButton = f.AddButton("Clear", p.clearEverything)
f.SetButtonsAlign(tview.AlignRight)
p.searchSection.AddItem(f, 0, 0, 1, 1, 0, 0, true)
f = newForm()
p.SortBy = f.AddDropdown("Sort by:", utils.AddSpaces([]string{"Creator", "Title", "Date", "Size "}), 1, func(o string, i int) { p.searchCondition.SortBy = p.mapSortBy(o) })
p.sortOrder = f.AddDropdown("Sort order:", utils.AddSpaces([]string{"Ascending", "Descending"}), 1, func(o string, i int) { p.searchCondition.SortOrder = p.mapSortOrder(o) })
p.searchSection.AddItem(f, 0, 1, 1, 1, 0, 0, true)
g := newGrid()
g.SetRows(-1, -1)
g.SetColumns(0)
Expand All @@ -75,7 +83,7 @@ func newSearchPage(dispatcher *mq.Dispatcher) *SearchPage {
f.SetButtonsAlign(tview.AlignRight)
g.AddItem(f, 1, 0, 1, 1, 1, 1, true)
p.SettingsButton = f.AddButton("Settings", p.updateConfig)
p.searchSection.AddItem(g, 0, 1, 1, 1, 0, 0, true)
p.searchSection.AddItem(g, 0, 2, 1, 1, 0, 0, true)

p.mainGrid.AddItem(p.searchSection.Grid, 0, 0, 1, 1, 0, 0, true)

Expand All @@ -87,7 +95,7 @@ func newSearchPage(dispatcher *mq.Dispatcher) *SearchPage {
p.resultSection.SetBorder(true)

p.resultTable = newTable()
p.resultTable.setHeaders(" # ", "Author", "Title", "Files", "Duration", "Size")
p.resultTable.setHeaders(" # ", "Creator", "Title", "Files", "Duration", "Size")
p.resultTable.setWeights(1, 3, 6, 1, 2, 2)
p.resultTable.setAlign(tview.AlignRight, tview.AlignLeft, tview.AlignLeft, tview.AlignRight, tview.AlignRight, tview.AlignRight)
p.resultTable.SetSelectionChangedFunc(p.updateDetails)
Expand Down Expand Up @@ -134,6 +142,8 @@ func newSearchPage(dispatcher *mq.Dispatcher) *SearchPage {
p.title,
p.searchButton,
p.clearButton,
p.SortBy,
p.sortOrder,
p.createAudioBookButton,
p.SettingsButton,
p.resultTable.Table,
Expand Down Expand Up @@ -291,15 +301,15 @@ func (p *SearchPage) updateConfig() {
func (p *SearchPage) showNothingFoundError(dto *dto.NothingFoundError) {
newMessageDialog(p.mq, "Error",
"\nNo results were found for your search term:\n"+
"Creator: [darkblue]'"+dto.Condition.Author+"'[black] Title: [darkblue]'"+dto.Condition.Title+"'[black].\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 your search term: \n"+
"Creator: [darkblue]'"+dto.Condition.Author+"'[black] Title: [darkblue]'"+dto.Condition.Title+"'[black].\n"+
"Creator: [darkblue]'"+dto.Condition.Author+"'[black] Title: [darkblue]'"+dto.Condition.Title+"'[black].\n"+
"This is the last page.\n",
p.resultSection.Grid, func() {})
}
Expand All @@ -319,3 +329,29 @@ func (p *SearchPage) showNewVersionMessage(dto *dto.NewAppVersionFound) {
"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() {})
}

func (p *SearchPage) mapSortBy(source string) string {
switch s := strings.TrimSpace(source); s {
case "Creator":
return "creator"
case "Title":
return "title"
case "Date":
return "date"
case "Size":
return "item_size"
default:
return source
}
}

func (p *SearchPage) mapSortOrder(source string) string {
switch s := strings.TrimSpace(source); s {
case "Ascending":
return "asc"
case "Descending":
return "desc"
default:
return source
}
}

0 comments on commit a180daa

Please sign in to comment.