Skip to content

Commit

Permalink
feat(ebooks): add support for mobi to pdf
Browse files Browse the repository at this point in the history
  • Loading branch information
danvergara committed Sep 5, 2024
1 parent e971581 commit 67fcabc
Showing 1 changed file with 141 additions and 3 deletions.
144 changes: 141 additions & 3 deletions pkg/files/ebooks/mobi.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"path/filepath"
"slices"
"strings"

"github.com/danvergara/morphos/pkg/files/documents"
)

type Mobi struct {
Expand All @@ -25,13 +27,19 @@ func NewMobi(filename string) Mobi {
m := Mobi{
filename: filename,
compatibleFormats: map[string][]string{
"Document": {
documents.PDF,
},
"Ebook": {
EPUB,
},
},
compatibleMIMETypes: map[string][]string{
"Document": {
documents.PDF,
},
"Ebook": {
EPUB,
EpubMimeType,
},
},
}
Expand Down Expand Up @@ -73,20 +81,150 @@ func (m Mobi) ConvertTo(fileType, subtype string, file io.Reader) (io.Reader, er
fileBytes := buf.Bytes()

switch strings.ToLower(fileType) {
case documentType:
switch subtype {
case PDF:
// Create a temporary empty file where the input is gonna be stored.
tmpInputMobi, err := os.CreateTemp("", fmt.Sprintf("*.%s", MOBI))
if err != nil {
return nil, fmt.Errorf("error creating temporary mobi file: %w", err)
}
defer os.Remove(tmpInputMobi.Name())

// Write the content of the input pdf into the temporary file.
if _, err = tmpInputMobi.Write(fileBytes); err != nil {
return nil, fmt.Errorf(
"error writting the input reader to the temporary mobi file",
)
}

if err := tmpInputMobi.Close(); err != nil {
return nil, err
}

pdfFileName := fmt.Sprintf(
"%s.%s",
strings.TrimSuffix(tmpInputMobi.Name(), filepath.Ext(tmpInputMobi.Name())),
PDF,
)

// Parses the file name of the Zip file.
zipFileName := fmt.Sprintf(
"%s.zip",
strings.TrimSuffix(m.filename, filepath.Ext(m.filename)),
)

// Parse the output file name.
outputPdfFilename := fmt.Sprintf(
"%s.%s",
strings.TrimSuffix(m.filename, filepath.Ext(m.filename)),
PDF,
)

cmd := exec.Command("ebook-convert", tmpInputMobi.Name(), pdfFileName)

// Capture stdout.
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}

// Capture stderr.
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, err
}

// Start the command.
if err := cmd.Start(); err != nil {
return nil, err
}
// Create readers to read stdout and stderr.
stdoutScanner := bufio.NewScanner(stdout)
stderrScanner := bufio.NewScanner(stderr)

// Read stdout line by line.
go func() {
for stdoutScanner.Scan() {
log.Println("STDOUT:", stdoutScanner.Text())
}
}()

// Read stderr line by line.
go func() {
for stderrScanner.Scan() {
log.Println("STDERR:", stderrScanner.Text())
}
}()

// Wait for the command to finish.
if err := cmd.Wait(); err != nil {
return nil, err
}

// Open the converted file to get the bytes out of it,
// and then turning them into a io.Reader.
cf, err := os.Open(pdfFileName)
if err != nil {
return nil, err
}
defer os.Remove(cf.Name())

// Creates the zip file that will be returned.
archive, err := os.CreateTemp("", zipFileName)
if err != nil {
return nil, fmt.Errorf(
"error at creating the zip file to store the epub file: %w",
err,
)
}
defer os.Remove(archive.Name())

// Creates a Zip Writer to add files later on.
zipWriter := zip.NewWriter(archive)

// Adds the image to the zip file.
w1, err := zipWriter.Create(outputPdfFilename)
if err != nil {
return nil, fmt.Errorf(
"error creating the zip writer: %w",
err,
)
}

if _, err := io.Copy(w1, cf); err != nil {
return nil, fmt.Errorf(
"error at writing the pdf file content to the zip writer: %w",
err,
)
}

// Closes both zip writer and the zip file after its done with the writing.
zipWriter.Close()
archive.Close()

// Reads the zip file as an slice of bytes.
zipFile, err := os.ReadFile(archive.Name())
if err != nil {
return nil, fmt.Errorf("error reading zip file: %v", err)
}

return bytes.NewReader(zipFile), nil
}
case ebookType:
switch subtype {
case EPUB:
// Create a temporary empty file where the input is gonna be stored.
tmpInputMobi, err := os.CreateTemp("", fmt.Sprintf("*.%s", MOBI))
if err != nil {
return nil, fmt.Errorf("error creating temporary pdf file: %w", err)
return nil, fmt.Errorf("error creating temporary mobi file: %w", err)
}
defer os.Remove(tmpInputMobi.Name())

// Write the content of the input pdf into the temporary file.
if _, err = tmpInputMobi.Write(fileBytes); err != nil {
return nil, fmt.Errorf(
"error writting the input reader to the temporary pdf file",
"error writting the input reader to the temporary mobi file",
)
}

Expand Down

0 comments on commit 67fcabc

Please sign in to comment.