Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
fix conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
Monirzadeh committed Aug 16, 2023
2 parents a03e2b0 + c8df5da commit b8a0c47
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 19 deletions.
47 changes: 47 additions & 0 deletions epub.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ package epub
import (
"fmt"
"io/fs"
"log"
"net/http"
"os"
"path"
"path/filepath"
"regexp"
"strings"
"sync"

Expand Down Expand Up @@ -557,6 +559,51 @@ func (e *Epub) Title() string {
return e.title
}

// EmbedImages download <img> tags in EPUB and modify body to show images
// file inside of EPUB:
// ../ImageFolderName/internalFilename
//
// The image source should either be a URL, a path to a local file, or an embedded data URL; in any
// case, the image file will be retrieved and stored in the EPUB.
//
// The internal filename will be used when storing the image file in the EPUB
// and must be unique among all image files. If the same filename is used more
// than once, FilenameAlreadyUsedError will be returned. The internal filename is
// optional; if no filename is provided, one will be generated.
// if go-epub can't download image it keep it untoch and not return any error just log that

// Just call EmbedImages() after section added
func (e *Epub) EmbedImages() {
imageTagRegex := regexp.MustCompile(`<img.*?src="(.*?)".*?>`)
for i, section := range e.sections {
imageTagMatches := imageTagRegex.FindAllStringSubmatch(section.xhtml.xml.Body.XML, -1)

// Check if imageTagMatches is empty
if len(imageTagMatches) == 0 {
continue // Skip to the next section
}
images := make(map[string]string)

for _, match := range imageTagMatches {
imageURL := match[1]
if !strings.HasPrefix(imageURL, "data:image/") {
images[imageURL] = match[0]
filePath, err := e.AddImage(string(imageURL), "")
if err != nil {
log.Printf("can't add image to the epub: %s", err)
continue
}
e.sections[i].xhtml.xml.Body.XML = strings.ReplaceAll(section.xhtml.xml.Body.XML, match[0], replaceSrcAttribute(match[0], filePath))
}
}
}
}

func replaceSrcAttribute(imgTag string, filePath string) string {
re := regexp.MustCompile(`src="([^"]*)"`)
return re.ReplaceAllString(imgTag, fmt.Sprintf(`src="%s"`, filePath))
}

// Add a media file to the EPUB and return the path relative to the EPUB section
// files
func addMedia(client *http.Client, source string, internalFilename string, mediaFileFormat string, mediaFolderName string, mediaMap map[string]string) (string, error) {
Expand Down
124 changes: 121 additions & 3 deletions epub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -62,13 +63,10 @@ const (
testImageFromFileSource = "testdata/gophercolor16x16.png"
testNumberFilenameStart = "01filenametest.png"
testSpaceInFilename = "filename with space.png"
testImageFromURLSource = "https://golang.org/doc/gopher/gophercolor16x16.png"
testVideoFromFileFilename = "testfromfile.mp4"
testVideoFromFileSource = "testdata/sample_640x360.mp4"
testVideoFromURLSource = "https://filesamples.com/samples/video/mp4/sample_640x360.mp4"
testAudioFromFileFilename = "sample_audio.wav"
testAudioFromFileSource = "testdata/sample_audio.wav"
testAudioFromURLSource = "https://file-examples.com/storage/fe1dbaea7664d369bb6e226/2017/11/file_example_WAV_1MG.wav"
testLangTemplate = `<dc:language>%s</dc:language>`
testDescTemplate = `<dc:description>%s</dc:description>`
testPpdTemplate = `page-progression-direction="%s"`
Expand All @@ -89,6 +87,11 @@ const (
</package>`
testSectionBody = ` <h1>Section 1</h1>
<p>This is a paragraph.</p>`
testSectionBodyWithnotabledownloadImage = ` <h1>Section 1</h1>
<p>This is a paragraph.</p><p><img src="https://example.com/fileNotExist.jpg" loading="lazy"/></p>`
testSectionBodyWithImageEmbed = ` <h1>Section 1</h1>
<p>This is a paragraph.</p>
<p><img src="../images/gophercolor16x16.png" loading="lazy"/></p>`
testSectionContentTemplate = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
Expand Down Expand Up @@ -257,6 +260,13 @@ func TestAddFont(t *testing.T) {
}

func TestAddImage(t *testing.T) {
fs := http.FileServer(http.Dir("./testdata/"))

// start a test server with the file server handler
server := httptest.NewServer(fs)
defer server.Close()

testImageFromURLSource := server.URL + "/gophercolor16x16.png"
e := NewEpub(testEpubTitle)
testImageFromFilePath, err := e.AddImage(testImageFromFileSource, testImageFromFileFilename)
if err != nil {
Expand Down Expand Up @@ -305,6 +315,14 @@ func TestAddImage(t *testing.T) {
}

func TestAddVideo(t *testing.T) {
fs := http.FileServer(http.Dir("./testdata/"))

// start a test server with the file server handler
server := httptest.NewServer(fs)
defer server.Close()

testVideoFromURLSource := server.URL + "/sample_640x360.mp4"

e := NewEpub(testEpubTitle)
testVideoFromFilePath, err := e.AddVideo(testVideoFromFileSource, testVideoFromFileFilename)
if err != nil {
Expand Down Expand Up @@ -362,6 +380,13 @@ func TestAddAudio(t *testing.T) {
}
fmt.Println(testAudioFromFilePath)

fs := http.FileServer(http.Dir("./testdata/"))

// start a test server with the file server handler
server := httptest.NewServer(fs)
defer server.Close()

testAudioFromURLSource := server.URL + "/sample_audio.wav"
testAudioFromURLPath, err := e.AddAudio(testAudioFromURLSource, "")
if err != nil {
t.Errorf("Error adding audio: %s", err)
Expand Down Expand Up @@ -751,6 +776,13 @@ func TestSetCover(t *testing.T) {
}

func TestManifestItems(t *testing.T) {
fs := http.FileServer(http.Dir("./testdata/"))

// start a test server with the file server handler
server := httptest.NewServer(fs)
defer server.Close()

testImageFromURLSource := server.URL + "/gophercolor16x16.png"
testManifestItems := []string{`id="filenamewithspace.png" href="images/filename with space.png" media-type="image/png"></item>`,
`id="gophercolor16x16.png" href="images/gophercolor16x16.png" media-type="image/png"></item>`,
`id="id01filenametest.png" href="images/01filenametest.png" media-type="image/png"></item>`,
Expand Down Expand Up @@ -832,7 +864,93 @@ func TestUnableToCreateEpubError(t *testing.T) {
}
}

func TestEmbedImage(t *testing.T) {
fs := http.FileServer(http.Dir("./testdata/"))

// start a test server with the file server handler
server := httptest.NewServer(fs)
defer server.Close()

testSectionBodyWithImage := ` <h1>Section 1</h1>
<p>This is a paragraph.</p>
<p><img src="` + server.URL + `/gophercolor16x16.png" loading="lazy"/></p>`
testSectionBodyWithImageExpect := ` <h1>Section 1</h1>
<p>This is a paragraph.</p>
<p><img src="../images/gophercolor16x16.png" loading="lazy"/></p>`
e := NewEpub(testEpubTitle)
testSection1Path, err := e.AddSection(testSectionBody, testSectionTitle, testSectionFilename, "")
if err != nil {
t.Errorf("Error adding section: %s", err)
}

testSection2Path, err := e.AddSection(testSectionBodyWithnotabledownloadImage, testSectionTitle, "", "")
if err != nil {
t.Errorf("Error adding section: %s", err)
}
testSection3Path, err := e.AddSection(testSectionBodyWithImage, testSectionTitle, "", "")
if err != nil {
t.Errorf("Error adding section: %s", err)
}
e.EmbedImages()
tempDir := writeAndExtractEpub(t, e, testEpubFilename)

contents, err := storage.ReadFile(filesystem, filepath.Join(tempDir, contentFolderName, xhtmlFolderName, testSection1Path))
if err != nil {
t.Errorf("Unexpected error reading section file: %s", err)
}
// test 1
testSectionContents := fmt.Sprintf(testSectionContentTemplate, testSectionTitle, testSectionBody)
if trimAllSpace(string(contents)) != trimAllSpace(testSectionContents) {
t.Errorf(
"Section file contents don't match\n"+
"Got: %s\n"+
"Expected: %s",
contents,
testSectionContents)
}
// test 2
contents, err = storage.ReadFile(filesystem, filepath.Join(tempDir, contentFolderName, xhtmlFolderName, testSection2Path))
if err != nil {
t.Errorf("Unexpected error reading section file: %s", err)
}

testSection2Contents := fmt.Sprintf(testSectionContentTemplate, testSectionTitle, testSectionBodyWithnotabledownloadImage)
if trimAllSpace(string(contents)) != trimAllSpace(testSection2Contents) {
t.Errorf(
"Section file contents don't match\n"+
"Got: %s\n"+
"Expected: %s",
contents,
testSection2Contents)
}
// test 3
contents, err = storage.ReadFile(filesystem, filepath.Join(tempDir, contentFolderName, xhtmlFolderName, testSection3Path))
if err != nil {
t.Errorf("Unexpected error reading section file: %s", err)
}

testSection3Contents := fmt.Sprintf(testSectionContentTemplate, testSectionTitle, testSectionBodyWithImageExpect)
if trimAllSpace(string(contents)) != trimAllSpace(testSection3Contents) {
t.Errorf(
"Section file contents don't match\n"+
"Got: %s\n"+
"Expected: %s",
contents,
testSection3Contents)
}
cleanup(testEpubFilename, tempDir)
}

func testEpubValidity(t testing.TB) {
fs := http.FileServer(http.Dir("./testdata/"))

// start a test server with the file server handler
server := httptest.NewServer(fs)
defer server.Close()

testAudioFromURLSource := server.URL + "/sample_audio.wav"
testImageFromURLSource := server.URL + "/gophercolor16x16.png"
testVideoFromURLSource := server.URL + "/sample_640x360.mp4"
e := NewEpub(testEpubTitle)
testCoverCSSPath, _ := e.AddCSS(testCoverCSSSource, testCoverCSSFilename)
e.AddCSS(testCoverCSSSource, "")
Expand Down
12 changes: 11 additions & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package epub_test
import (
"fmt"
"log"
"net/http"
"net/http/httptest"

"github.com/bmaupin/go-epub"
)
Expand Down Expand Up @@ -59,6 +61,14 @@ func ExampleEpub_AddFont() {
}

func ExampleEpub_AddImage() {
fs := http.FileServer(http.Dir("./testdata/"))

// start a test server with the file server handler
server := httptest.NewServer(fs)
defer server.Close()

testImageFromURLSource := server.URL + "/gophercolor16x16.png"

e := epub.NewEpub("My title")

// Add an image from a local file
Expand All @@ -68,7 +78,7 @@ func ExampleEpub_AddImage() {
}

// Add an image from a URL. The filename is optional
img2Path, err := e.AddImage("https://golang.org/doc/gopher/gophercolor16x16.png", "")
img2Path, err := e.AddImage(testImageFromURLSource, "")
if err != nil {
log.Fatal(err)
}
Expand Down
47 changes: 32 additions & 15 deletions fetchmedia.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"os"
"path/filepath"
"strings"

"github.com/gabriel-vasile/mimetype"
"github.com/vincent-petithory/dataurl"
Expand All @@ -20,22 +21,38 @@ type grabber struct {
*http.Client
}

func detectMediaType(mediaSource string) string {
if strings.HasPrefix(mediaSource, "http://") || strings.HasPrefix(mediaSource, "https://") {
return "URL"
}

if strings.HasPrefix(mediaSource, "data:") {
return "DataURL"
}

return "File"
}

func (g grabber) checkMedia(mediaSource string) error {
fetchErrors := make([]error, 0)
for _, f := range []func(string, bool) (io.ReadCloser, error){
g.localHandler,
g.httpHandler,
g.dataURLHandler,
} {
var err error
source, err := f(mediaSource, true)
if source != nil {
source.Close()
}
if err == nil {
return nil
}
fetchErrors = append(fetchErrors, err)
var fetchErrors []error // Declare fetchErrors variable
var f func(string, bool) (io.ReadCloser, error)
switch detectMediaType(mediaSource) {
case "URL":
f = g.httpHandler
case "DataURL":
f = g.dataURLHandler
default:
f = g.localHandler
}
source, err := f(mediaSource, true)
if err != nil {
fetchErrors = append(fetchErrors, err) // Capture the error
}
if source != nil {
source.Close()
}
if err == nil {
return nil
}
return &FileRetrievalError{Source: mediaSource, Err: fetchError(fetchErrors)}
}
Expand Down

0 comments on commit b8a0c47

Please sign in to comment.