diff --git a/.bbl.mybible b/.bbl.mybible deleted file mode 100644 index 8e2abf3..0000000 Binary files a/.bbl.mybible and /dev/null differ diff --git a/.data.go.swp b/.data.go.swp deleted file mode 100644 index 5488f78..0000000 Binary files a/.data.go.swp and /dev/null differ diff --git a/.display_linux.go.swp b/.display_linux.go.swp deleted file mode 100644 index 2a55130..0000000 Binary files a/.display_linux.go.swp and /dev/null differ diff --git a/.display_windows.go.swp b/.display_windows.go.swp deleted file mode 100644 index 58932ee..0000000 Binary files a/.display_windows.go.swp and /dev/null differ diff --git a/.main.go.swp b/.main.go.swp deleted file mode 100644 index 4a0a5ca..0000000 Binary files a/.main.go.swp and /dev/null differ diff --git a/.parse.go.swp b/.parse.go.swp deleted file mode 100644 index a707bb4..0000000 Binary files a/.parse.go.swp and /dev/null differ diff --git a/data.go b/data.go index d25edab..4328e3d 100644 --- a/data.go +++ b/data.go @@ -2,10 +2,11 @@ package main import ( "database/sql" - _ "github.com/mattn/go-sqlite3" "log" "os" "time" + + _ "github.com/mattn/go-sqlite3" //"github.com/PuerkitoBio/goquery" //"github.com/fatih/color" ) @@ -18,6 +19,7 @@ type BibleArchive struct { var ( logger *log.Logger + logFile *os.File db *sql.DB tx *sql.Tx sqlStmtInsBible string = `insert into Bible values(?,?,?,?)` @@ -91,28 +93,33 @@ var ( } ) -func GenLog() (logFile *os.File) { +func GenLog() { var err error - fileName := "bgmysword.log" - if _, err = os.Stat(fileName); err == nil { - os.Remove(fileName) - printRemovedFile(fileName) + logFileName := "bgmysword.log" + + if _, err = os.Stat(logFileName); err == nil { + os.Remove(logFileName) + printRemovedFile(logFileName) } - logFile, err = os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) + + logFile, err = os.OpenFile(logFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { return } + logger = log.New(logFile, "logger: ", log.Lshortfile) return } -func CloseLog(logFile *os.File) { - logFile.Close() +func CloseLog() { + if logMe { + logFile.Close() + } } func Log(s ...interface{}) { if logMe { - logger.Print(s...) + logger.Print(s) } } @@ -149,6 +156,11 @@ func GenModule() { sqlInsDetails() } +func CloseModule() { + tx.Commit() + db.Close() +} + func sqlCrt(sqlStmt string) { _, err := db.Exec(sqlStmt) if err != nil { diff --git a/display_linux.go b/display_linux.go index 4604d03..661222b 100644 --- a/display_linux.go +++ b/display_linux.go @@ -3,9 +3,10 @@ package main import ( "bufio" "fmt" - "github.com/fatih/color" "os" "strings" + + "github.com/fatih/color" //"github.com/PuerkitoBio/goquery" //"github.com/mattn/go-sqlite3" ) @@ -172,9 +173,23 @@ func progressTranslation() { BWhite.Println(transName) } -func progressBook(title, titleSpacing, numSpacing string, currNum, totalNum int) { +func progressBook(index int) { + var spacingNumber string = "" + + book := Bible[index].Book + bookTitle := strings.Replace(book, "+", " ", -1) + + numberOfSpaces := 30 - len(bookTitle) + spacingTitle := strings.Repeat(" ", numberOfSpaces) + + bookNumber := index + 1 + + if bookNumber < 10 { + spacingNumber = " " + } + BGreen.Printf("\r=>%v%v%v%d/%d\n", - title, titleSpacing, numSpacing, currNum, totalNum) + bookTitle, spacingTitle, spacingNumber, bookNumber, 66) } func progressChapter(current, total int) { diff --git a/display_windows.go b/display_windows.go index 2031698..115a754 100644 --- a/display_windows.go +++ b/display_windows.go @@ -99,7 +99,7 @@ func PrintCenter(t string) { } func printRemovedFile(fileName string) { - Black.Println("Removed", fileName) + fmt.Println("Removed", fileName) } func Break(s string) { @@ -119,9 +119,23 @@ func progressTranslation() { fmt.Println(transName) } -func progressBook(title, titleSpacing, numSpacing string, currNum, totalNum int) { +func progressBook(index int) { + var spacingNumber string = "" + + book := Bible[index].Book + bookTitle := strings.Replace(book, "+", " ", -1) + + numberOfSpaces := 30 - len(bookTitle) + spacingTitle := strings.Repeat(" ", numberOfSpaces) + + bookNumber := index + 1 + + if bookNumber < 10 { + spacingNumber = " " + } + fmt.Printf("\r=>%v%v%v%d/%d\n", - title, titleSpacing, numSpacing, currNum, totalNum) + bookTitle, spacingTitle, spacingNumber, bookNumber, 66) } func progressChapter(current, total int) { diff --git a/linux/bgmysword b/linux/bgmysword new file mode 100755 index 0000000..85f29d0 Binary files /dev/null and b/linux/bgmysword differ diff --git a/main.go b/main.go index 33c10d9..9d9fa35 100644 --- a/main.go +++ b/main.go @@ -2,12 +2,9 @@ package main import ( "fmt" - //"github.com/PuerkitoBio/goquery" - //"log" "os" "strconv" - "strings" - //"unicode" + //"github.com/PuerkitoBio/goquery" //"github.com/mattn/go-sqlite3" //"github.com/fatih/color" ) @@ -17,7 +14,6 @@ var ( transName string BibleGatewayUrl string logMe bool - //doc *goquery.Document //db *sql.DB //tx *sql.Tx ) @@ -25,26 +21,32 @@ var ( func init() { defer ColorUnset() ImgINRI() + AnalyseArgs() + GenBibleGatewayUrl() + CopyrightFetch() +} + +func AnalyseArgs() { numArgs := len(os.Args) if numArgs > 1 { - firstArg := os.Args[1] - switch firstArg { + switch os.Args[1] { case "h", "-h", "help", "-help": printHelp() default: translation = os.Args[1] } + } if numArgs > 2 { logMe = true + GenLog() } - GenBibleGatewayUrl() - CopyrightFetch() } func GenBibleGatewayUrl() { preUrl := "https://www.biblegateway.com/passage/?version=" midUrl := "&search=" + BibleGatewayUrl = concat(preUrl, translation, midUrl) } @@ -54,56 +56,43 @@ func GenFullUrl(book, chap string) (url string) { } func main() { + defer CloseLog() defer ColorUnset() - if logMe { - logFile := GenLog() - defer CloseLog(logFile) - } ImgSword() GenModule() + defer CloseModule() progressTranslation() - defer db.Close() - defer tx.Commit() - bookLoop(Bible) + BookLoop(Bible) } -func bookLoop(Bible []BibleArchive) { - var bRange int - bRange = len(Bible) - for i := 0; i < bRange; i++ { - b := i + 1 - title := strings.Replace(Bible[i].Book, "+", " ", -1) - titleSpaces := 30 - len(title) - titleSpacing := strings.Repeat(" ", titleSpaces) - var numSpacing string - if b < 10 { - numSpacing = " " - } else { - numSpacing = "" - } - progressBook(title, titleSpacing, numSpacing, b, bRange) - chapterLoop(Bible[i]) +func BookLoop(Bible []BibleArchive) { + for i := 0; i < 66; i++ { + progressBook(i) + ChapterLoop(Bible[i]) fmt.Println() } } -func chapterLoop(data BibleArchive) { +func ChapterLoop(data BibleArchive) { currentBook := strconv.Itoa(data.Index) - var cRange int = data.ChapterRange + cRange := data.ChapterRange for c := 1; c <= cRange; c++ { progressChapter(c, cRange) + currentChapter := strconv.Itoa(c) url := GenFullUrl(data.Book, currentChapter) + chapterText := Chapter.Parse(url) - Log(chapterText) - saveChapter(currentBook, currentChapter, chapterText) + + SaveChapter(currentBook, currentChapter, chapterText) } } -func saveChapter(currentBook string, currentChapter string, chapterText []string) { +func SaveChapter(currentBook string, currentChapter string, chapterText []string) { for i, s := range chapterText { verseNumber := i + 1 verseText := s + sqlInsBible(currentBook, currentChapter, verseNumber, verseText) } } diff --git a/parse.go b/parse.go index 1eb22f5..1d9f312 100644 --- a/parse.go +++ b/parse.go @@ -1,13 +1,11 @@ package main import ( - //"fmt" - "github.com/PuerkitoBio/goquery" "log" - //"os" "strconv" "strings" - //"unicode" + + "github.com/PuerkitoBio/goquery" //"github.com/mattn/go-sqlite3" //"github.com/fatih/color" ) @@ -48,18 +46,9 @@ const ( ) var ( - //translation string - //transName string - //baseUrl string - //ChapterText []string Chapter ChapterData Verse VerseData Text TextContent - //Chapter.Doc *goquery.Document - //footnoteMap = make(map[string]string) - //containsPoetry bool - //db *sql.DB - //tx *sql.Tx ) func GenDoc(url string) (doc *goquery.Document) { @@ -82,26 +71,39 @@ func CopyrightFetch() { var copyrightInfo, publisherInfo string url := GenFullUrl("Genesis", "1") copyrightDoc := GenDoc(url) + copyrightInfo = copyrightDoc.Find(".publisher-info-bottom p").Text() publisherInfo = copyrightDoc.Find(".publisher-info-bottom p a").Text() transName = copyrightDoc.Find(".publisher-info-bottom strong").Text() + copyrightAccept(copyrightInfo, publisherInfo) } func (Chapter *ChapterData) Parse(url string) (chapterText []string) { + // After formatting the current chapter, + // and returning its formatted text to function 'ChapterLoop', + // remove the chapter's data from memory defer Chapter.Clear() - // Fetch webpage for current chapter. + + // Fetch the webpage for the current chapter. Chapter.GenDoc(url) - // Filter out unneeded text. + + // Filter out unneeded content. Chapter.CleanDoc() + // Find the number of verses and the html class for the current chapter. Chapter.GenHtmlClass() - // Find footnotes and for each, mark text with + + // Find the chapter's footnotes, + // and match each footnote's letter with its expanded text. Chapter.GenFootnotes() + // Mark titles and paragraphs. Chapter.TagDoc() + // Parse the webpage. Chapter.AddVerses() + chapterText = Chapter.Verses return } @@ -118,6 +120,7 @@ func (Chapter *ChapterData) CleanDoc() { // Remove chapter numbers, verse numbers, and cross references // (because MySword formats them differently/automatically). rejects := []string{".chapternum", ".versenum", ".crossreference"} + for _, reject := range rejects { Chapter.Doc.Find(reject).Remove() } @@ -126,8 +129,10 @@ func (Chapter *ChapterData) CleanDoc() { func (Chapter *ChapterData) GenHtmlClass() { // Note the number of verses and the html class which denotes passage text. lastClass, _ := Chapter.Doc.Find("p .text").Last().Attr("class") + doubleClass := prefixHyphenSecond(lastClass) chapterClass := suffixSpace(doubleClass) + lastVerse := suffixHyphenSecond(lastClass) totalVerses, _ := strconv.Atoi(lastVerse) @@ -136,17 +141,22 @@ func (Chapter *ChapterData) GenHtmlClass() { } func (Chapter *ChapterData) GenFootnotes() { + // Make a map of the chapter's footnotes + // with their letters as keys and their expanded text as values. Chapter.Footnotes = make(map[string]string) - // Make a map of the footnotes together with their expanded text. + footnoteTags := Chapter.Doc.Find("ol") containsFootnotes := IsNotEmpty(footnoteTags.Text()) + if containsFootnotes { footnoteTags.Contents().Each(func(i int, s *goquery.Selection) { id, _ := s.Attr("id") - if strings.Contains(id, "fen") { + isFootnote := strings.Contains(id, "fen") + + if isFootnote { footnoteLetter := lastLetter(id) footnoteText := s.Find(".footnote-text").Text() - //footnoteMap[fnLet] = fnText + Chapter.Footnotes[footnoteLetter] = footnoteText } }) @@ -161,39 +171,55 @@ func (Chapter *ChapterData) TagDoc() { Chapter.Doc.Find("h4 .text").Each(func(i int, s *goquery.Selection) { s.SetAttr("id", "title") }) + // Mark the opening line of each paragraph. Chapter.Doc.Find("p").Each(func(i int, s *goquery.Selection) { class, _ := s.Contents().Attr("class") isPassageContent := strings.Contains(class, Chapter.HtmlClass) + if isPassageContent { s.Contents().First().SetAttr("id", "paragraph") } + }) } func (Chapter *ChapterData) AddVerses() { lastVerse := Chapter.VerseIndex + for verse := 1; verse <= lastVerse; verse++ { Chapter.AddVerse(verse) } } func (Chapter *ChapterData) AddVerse(verseNumber int) { + // After formatting the current verse, + // and adding its text to the chapter's data, + // remove the verse's data from memory. defer Verse.Clear() + + // Generate the html class for the current verse. Verse.GenHtmlClass(verseNumber) + + // Parse and format the text of the current verse. Verse.GenContent() - Verse.CleanTags() - Chapter.Append(Verse.String()) -} -func (Verse *VerseData) Clear() { - *Verse = VerseData{} + // Clean the indentation for poetry lines. + Verse.CleanIndent() + + // Add the newly formatted text for the current verse + // to the chapter's list of formatted verses. + Chapter.Append(Verse.String()) } func (Chapter *ChapterData) Append(verseText string) { Chapter.Verses = append(Chapter.Verses, verseText) } +func (Verse *VerseData) Clear() { + *Verse = VerseData{} +} + func (Verse *VerseData) String() string { return str(Verse.Content) } @@ -203,17 +229,21 @@ func (Verse *VerseData) Append(args ...string) { } func (Verse *VerseData) GenHtmlClass(verseNumber int) { - verseNumberString := strconv.Itoa(verseNumber) - Verse.HtmlClass = concat("text ", Chapter.HtmlClass, verseNumberString) + verseNumAsString := strconv.Itoa(verseNumber) + + Verse.HtmlClass = concat("text ", Chapter.HtmlClass, verseNumAsString) + } func (Verse *VerseData) GenContent() { Chapter.Doc.Find(".text").Each(func(i int, s *goquery.Selection) { currClass, _ := s.Attr("class") + if currClass == Verse.HtmlClass { // If text belongs in the current verse: Verse.AnalyseGenre(s) } + }) } @@ -221,10 +251,13 @@ func (Verse *VerseData) AnalyseGenre(s *goquery.Selection) { var classParents string parents := s.Parents() classParents, _ = parents.Attr("class") + + // Workaround for the first verse in the chapter. if strings.Contains(classParents, "chapter") { parents := s.Parents().Parents() classParents, _ = parents.Attr("class") } + switch classParents { case POETRY_LINE_NORMAL: // If first-line poetry: @@ -232,7 +265,7 @@ func (Verse *VerseData) AnalyseGenre(s *goquery.Selection) { Verse.ParsePoetryLine(s) return case POETRY_LINE_INDENTED: - // If second-line poetry: + // If second-line/indented poetry: Verse.ParsePoetryIndent(s) return default: @@ -244,6 +277,7 @@ func (Verse *VerseData) AnalyseGenre(s *goquery.Selection) { func (Verse *VerseData) ParseProse(s *goquery.Selection) { id, _ := s.Attr("id") + switch id { case "title": // If this html id tag was labeled "title" earlier: @@ -262,6 +296,7 @@ func (Verse *VerseData) ParseProse(s *goquery.Selection) { func (Verse *VerseData) ParsePoetryLine(s *goquery.Selection) { id, _ := s.Attr("id") + switch id { // If this html id tag was labeled "title" earlier: case "title": @@ -282,6 +317,7 @@ func (Verse *VerseData) ParsePoetryLine(s *goquery.Selection) { func (Verse *VerseData) ParsePoetryIndent(s *goquery.Selection) { id, _ := s.Contents().Attr("id") + switch id { // If this html id tag was labeled "title" earlier: case "title": @@ -309,31 +345,37 @@ func (Verse *VerseData) Title(s *goquery.Selection) { func (Verse *VerseData) Paragraph() { contentLength := len(Verse.Content) + switch contentLength { case 0: // If the new paragraph starts at the begininning of the verse: - //Verse.Append(PARAGRAPH_BREAK) Chapter.AddParagraph() + return default: // If the new paragraph starts in the middle of the verse: Verse.AddParagraph() + return } } func (Chapter *ChapterData) AddParagraph() { var versesAdded int versesAdded = len(Chapter.Verses) - // If the verse begins with a paragraph break, - // move the paragraph tag to the very end of the previous verse. + switch versesAdded { case 0: + // If this is the first verse in the chapter, + // do nothing. return default: - last := versesAdded - 1 - lastVerse := Chapter.Verses[last] - prevVerses := Chapter.Verses[:last] + // Otherwise, + // move the paragraph tag to the very end of the previous verse. + lastIndex := versesAdded - 1 + lastVerse := Chapter.Verses[lastIndex] + prevVerses := Chapter.Verses[:lastIndex] lastVerseNew := concat(lastVerse, PARAGRAPH_BREAK) temp := append(prevVerses, lastVerseNew) + Chapter.Verses = nil Chapter.Verses = temp return @@ -341,13 +383,11 @@ func (Chapter *ChapterData) AddParagraph() { } func (Verse *VerseData) AddParagraph() { - var last int - var endContent string contentLength := len(Verse.Content) - last = contentLength - 1 - endContent = Verse.Content[last] + lastIndex := contentLength - 1 + prevContent := Verse.Content[lastIndex] - switch endContent { + switch prevContent { case TITLE_CLOSE: // If the new paragraph DOES begin after a title, // the paragraph tag is NOT unneeded. @@ -355,10 +395,7 @@ func (Verse *VerseData) AddParagraph() { default: // If the new paragraph does NOT begin after a title, // a paragraph tag IS needed. - prevContent := Verse.Content[:last] - temp := append(prevContent, PARAGRAPH_BREAK, endContent) - Verse.Content = nil - Verse.Content = temp + Verse.Append(PARAGRAPH_BREAK) return } } @@ -370,6 +407,7 @@ func (Verse *VerseData) ParseContents(sel *goquery.Selection) { s := sel.Eq(i) Text.Analyse(s) } + Verse.Append(Text.String()) } @@ -382,6 +420,7 @@ func (Text *TextContent) Analyse(s *goquery.Selection) { woj := strings.Contains(class, "woj") // Words of Jesus footnote := strings.Contains(class, "footnote") // Footnote smallCaps := strings.Contains(class, "small-caps") // Small-caps (e.g., "LORD") + switch { case woj: Text.WoJ(s.Contents()) @@ -403,18 +442,24 @@ func (Text *TextContent) Append(args ...string) { } func (Text *TextContent) WoJ(sel *goquery.Selection) { - Text.Append(WOJ_OPEN) // Opening tag for words of Jesus + // Opening tag for words of Jesus + Text.Append(WOJ_OPEN) + + // Passage text for words of Jesus for i := range sel.Nodes { // For each html segment of Jesus's words: s := sel.Eq(i) - Text.Analyse(s) // Words of Jesus + Text.Analyse(s) } - Text.Append(WOJ_CLOSE) // Closing tag for words of Jesus + + // Closing tag for words of Jesus + Text.Append(WOJ_CLOSE) } func (Text *TextContent) Footnote(s *goquery.Selection) { fnLetter := s.Find("a").Text() fnText := Chapter.Footnotes[fnLetter] // Footnote text that was marked earlier. + Text.Append(FOOTNOTE_OPEN, fnText, FOOTNOTE_CLOSE) } @@ -422,47 +467,40 @@ func (Text *TextContent) SmallCaps(s *goquery.Selection) { Text.Append(strings.ToUpper(s.Text())) } -func (Verse *VerseData) CleanTags() { - //Verse.CleanParagraphTags() +func (Verse *VerseData) CleanIndent() { if Verse.ContainsPoetry { Verse.CleanIndentTags() } } -func (Verse *VerseData) CleanParagraphTags() { - if Verse.Content[0] == PARAGRAPH_BREAK { - Chapter.AddParagraph() - Verse.RemoveParagraph() - } -} - -func (Verse *VerseData) RemoveParagraph() { - temp := Verse.Content[1:] - Verse.Content = temp -} - func (Verse *VerseData) CleanIndentTags() { var temp TextContent - var foundFirst bool + var isFirstInVerse bool = true for _, s := range Verse.Content { - poetryLine := strings.Contains(s, INDENT_1) - switch poetryLine { + isPoetryLine := strings.Contains(s, INDENT_1) + + switch isPoetryLine { case true: - switch foundFirst { - case false: + + switch isFirstInVerse { + case true: //If line IS the first one in the verse, // keep it single-indented. - foundFirst = true + isFirstInVerse = false temp.Append(s) - case true: + case false: //If line is NOT the first one in the verse, // double its indentation. newLine := strings.Replace(s, INDENT_1, INDENT_2, -1) temp.Append(newLine) } + default: temp.Append(s) } + } + + Verse.Content = nil Verse.Content = temp } diff --git a/bgmysword b/windows/bgmysword similarity index 100% rename from bgmysword rename to windows/bgmysword