Add ability to download all books

This commit is contained in:
Ryan Hollis 2024-02-15 19:38:11 -05:00
parent cb91edc6c6
commit 377317d443

187
main.go
View file

@ -11,8 +11,10 @@ import (
const ( const (
// These should be set to control the book that is downloaded. // These should be set to control the book that is downloaded.
Language = "Spanish" DesiredLanguage = "Spanish"
BookName = "Complete Spanish Step-by-Step" DesiredBookName = "Complete Spanish Step-by-Step"
DownloadAllBooks = false
) )
const ( const (
@ -20,6 +22,7 @@ const (
GetMenuUrl = "https://mhe-language-lab.azurewebsites.net/api/GetSubMenus?parentID=%d" GetMenuUrl = "https://mhe-language-lab.azurewebsites.net/api/GetSubMenus?parentID=%d"
GetFlashCardsUrl = "https://mhe-language-lab.azurewebsites.net/api/GetFlashCards?menuID=%d" GetFlashCardsUrl = "https://mhe-language-lab.azurewebsites.net/api/GetFlashCards?menuID=%d"
FlashCards = "Flashcards" FlashCards = "Flashcards"
ProgressChecks = "Progress Checks"
FlashCardsStudyMode = "Flashcards: Study Mode" FlashCardsStudyMode = "Flashcards: Study Mode"
FileStart = `#separator:tab FileStart = `#separator:tab
#html:true #html:true
@ -35,44 +38,54 @@ func main() {
} }
func DoEverything() error { func DoEverything() error {
// Get the list of languages and select the desired language. // Get the list of languages and select the desired language.
languageMenu, err := GetMenu(0) languageMenu, err := GetMenuOptions(0)
if err != nil { if err != nil {
return err return err
} }
var languageId int
for _, languageEntry := range languageMenu { for _, languageEntry := range languageMenu {
if languageEntry.MenuTitle == Language { if DownloadAllBooks || languageEntry.MenuTitle == DesiredLanguage {
languageId = languageEntry.MenuID fmt.Printf("Downloading flashcards for language %s\n", languageEntry.MenuTitle)
break err = DownloadFlashCardsForLanguage(languageEntry)
if err != nil {
return err
} }
} }
}
return nil
}
func DownloadFlashCardsForLanguage(language *MenuEntry) error {
// Get the list of books for the selected language and select the desired book. // Get the list of books for the selected language and select the desired book.
bookMenu, err := GetMenu(languageId) bookMenu, err := GetMenuOptions(language.MenuID)
if err != nil { if err != nil {
return err return err
} }
var bookId int
for _, bookEntry := range bookMenu { for _, bookEntry := range bookMenu {
if bookEntry.MenuTitle == BookName { if DownloadAllBooks || bookEntry.MenuTitle == DesiredBookName {
bookId = bookEntry.MenuID fmt.Printf("Downloading flashcards for book %s\n", bookEntry.MenuTitle)
break err = DownloadFlashCardsForBook(language, bookEntry)
if err != nil {
return err
} }
} }
}
return nil
}
func DownloadFlashCardsForBook(language, book *MenuEntry) error {
// Get the chapters of the book and download the flashcards.
// For each book, there are multiple options. Ones called "Flashcards" and "Progress Checks" are compatible with flashcards.
// There are some books that don't have either of those. In that case, the book is not compatible with this program.
flashCardOption, err := GetMenuOptionWithNames(book.MenuID, FlashCards, ProgressChecks)
if err != nil {
return err
}
if flashCardOption == nil {
fmt.Printf("Book %s does not have flashcards or progress checks\n", book.MenuTitle)
return nil
}
// Get the chapters of the book and download the flashcards. // Flash cards will return a list of chapters. Which might have subchapters or may lead directly to flashcards.
bookOptions, err := GetMenu(bookId) chapters, err := GetMenuOptions(flashCardOption.MenuID)
if err != nil {
return err
}
var flashCardId int
for _, options := range bookOptions {
if options.MenuTitle == FlashCards {
flashCardId = options.MenuID
break
}
}
chapters, err := GetMenu(flashCardId)
if err != nil { if err != nil {
return err return err
} }
@ -84,6 +97,11 @@ func DoEverything() error {
fileOutput := strings.Builder{} fileOutput := strings.Builder{}
fileOutput.WriteString(FileStart) fileOutput.WriteString(FileStart)
for _, chapter := range chapters { for _, chapter := range chapters {
// Download the flashcards for the whole chapter, including subchapters.
chapterCards, err := GetChapterCards(chapter)
if err != nil {
return err
}
// Make 1-digit numbers start with zero, so that alphabetical sorting works correctly. // Make 1-digit numbers start with zero, so that alphabetical sorting works correctly.
if chapter.MenuTitle[1] == '.' { if chapter.MenuTitle[1] == '.' {
chapter.MenuTitle = "0" + chapter.MenuTitle chapter.MenuTitle = "0" + chapter.MenuTitle
@ -92,24 +110,56 @@ func DoEverything() error {
chapter.MenuTitle = strings.ReplaceAll(chapter.MenuTitle, "<i>", "") chapter.MenuTitle = strings.ReplaceAll(chapter.MenuTitle, "<i>", "")
chapter.MenuTitle = strings.ReplaceAll(chapter.MenuTitle, "</i>", "") chapter.MenuTitle = strings.ReplaceAll(chapter.MenuTitle, "</i>", "")
fmt.Printf("%+v\n", chapter.MenuTitle) fmt.Printf("Chapter: %v\n", chapter.MenuTitle)
// Get all sections in the chapter and get the study mode flashcards in each section.
sections, err := GetMenu(chapter.MenuID) // Write the flashcards to the file, one for Spanish to English and one for English to Spanish.
for _, card := range chapterCards {
title := chapter.MenuTitle
if chapter.MenuTitle[2:4] == ". " {
title = chapter.MenuTitle[0:4] + "(" + language.MenuTitle[0:1] + "2E) " + chapter.MenuTitle[4:]
}
fileOutput.WriteString(fmt.Sprintf("%s\t%s\t%s %s\n", card.SideA, card.SideB, book.MenuTitle, title))
}
for _, card := range chapterCards {
title := chapter.MenuTitle
if chapter.MenuTitle[2:4] == ". " {
title = chapter.MenuTitle[0:4] + "(E2" + language.MenuTitle[0:1] + ") " + chapter.MenuTitle[4:]
}
fileOutput.WriteString(fmt.Sprintf("%s\t%s\t%s %s\n", card.SideB, card.SideA, book.MenuTitle, title))
}
}
if fileOutput.Len() == len(FileStart) {
fmt.Printf("No flashcards found for book %s\n", book.MenuTitle)
return nil
} else {
fileName := fmt.Sprintf("output/%s.txt", book.MenuTitle)
err = os.WriteFile(fileName, []byte(fileOutput.String()), 0644)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("File written to %s\n", fileName)
}
return nil
}
func GetChapterCards(chapter *MenuEntry) ([]*Card, error) {
fmt.Printf(" %+v\n", chapter.MenuTitle)
var chapterCards []*Card var chapterCards []*Card
for _, section := range sections { if chapter.FlashCardsAndQuiz {
fmt.Printf(" %+v\n", section.MenuTitle) // If this chapter is the bottom of the graph, get the flashcards.
modes, err := GetMenu(section.MenuID) flashCardMode, err := GetMenuOptionWithNames(chapter.MenuID, FlashCardsStudyMode)
if err != nil { if err != nil {
return err return nil, err
} }
for _, mode := range modes { if flashCardMode == nil {
if mode.MenuTitle == FlashCardsStudyMode { fmt.Printf("Chapter %s does not have flashcard mode", chapter.MenuTitle)
cards, err := GetFlashCards(mode.MenuID) return nil, nil
}
cards, err := GetFlashCards(flashCardMode.MenuID)
if err != nil { if err != nil {
return err return nil, err
} }
for _, card := range cards { for _, card := range cards {
if strings.Contains(card.SideA, "\r\n") { if strings.Contains(card.SideA, "\r\n") {
@ -127,41 +177,31 @@ func DoEverything() error {
} }
} }
continue continue
} else {
card.SideA = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(card.SideA, "\t", ""), "\n", ""), "\r", ""), "\n", "")
card.SideB = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(card.SideB, "\t", ""), "\n", ""), "\r", ""), "\n", "")
} }
chapterCards = append(chapterCards, card) chapterCards = append(chapterCards, card)
} }
} } else {
} // If this chapter has subchapters, get the flashcards for each subchapter.
} subChapters, err := GetMenuOptions(chapter.MenuID)
if len(chapterCards) == 0 {
continue
}
for _, card := range chapterCards {
title := chapter.MenuTitle
if chapter.MenuTitle[2:4] == ". " {
title = chapter.MenuTitle[0:4] + "(" + Language[0:1] + "2E) " + chapter.MenuTitle[4:]
}
fileOutput.WriteString(fmt.Sprintf("%s\t%s\t%s %s\n", card.SideA, card.SideB, BookName, title))
}
for _, card := range chapterCards {
title := chapter.MenuTitle
if chapter.MenuTitle[2:4] == ". " {
title = chapter.MenuTitle[0:4] + "(E2" + Language[0:1] + ") " + chapter.MenuTitle[4:]
}
fileOutput.WriteString(fmt.Sprintf("%s\t%s\t%s %s\n", card.SideB, card.SideA, BookName, title))
}
}
fileName := fmt.Sprintf("output/%s.tsv", BookName)
err = os.WriteFile(fileName, []byte(fileOutput.String()), 0644)
if err != nil { if err != nil {
return err return nil, err
} }
for _, subChapter := range subChapters {
fmt.Printf("File written to %s\n", fileName) subChapterCards, err := GetChapterCards(subChapter)
if err != nil {
return nil return nil, err
}
chapterCards = append(chapterCards, subChapterCards...)
}
}
return chapterCards, nil
} }
func GetMenu(parentID int) ([]*MenuEntry, error) {
func GetMenuOptions(parentID int) ([]*MenuEntry, error) {
resp, err := http.Get(fmt.Sprintf(GetMenuUrl, parentID)) resp, err := http.Get(fmt.Sprintf(GetMenuUrl, parentID))
if err != nil { if err != nil {
return nil, err return nil, err
@ -178,6 +218,21 @@ func GetMenu(parentID int) ([]*MenuEntry, error) {
return getMenuResponse, nil return getMenuResponse, nil
} }
func GetMenuOptionWithNames(parentID int, names ...string) (*MenuEntry, error) {
options, err := GetMenuOptions(parentID)
if err != nil {
return nil, err
}
for _, option := range options {
for _, name := range names {
if option.MenuTitle == name {
return option, nil
}
}
}
return nil, nil
}
func GetFlashCards(menuID int) ([]*Card, error) { func GetFlashCards(menuID int) ([]*Card, error) {
resp, err := http.Get(fmt.Sprintf(GetFlashCardsUrl, menuID)) resp, err := http.Get(fmt.Sprintf(GetFlashCardsUrl, menuID))
if err != nil { if err != nil {