build close to render standalone app..
14
cmd/build.go
|
@ -3,7 +3,9 @@ package cmd
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
// "accorder/pkg/calibre"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var buildCmd = &cobra.Command{
|
||||
|
@ -19,15 +21,23 @@ the configuration file for the future use (therefore: 'accorder build PROFILE'
|
|||
should be enough for the next successful build).`,
|
||||
Args: OnlyProfileArgument,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println(args)
|
||||
fromFlag := viper.GetString("directory")
|
||||
fromConfig := viper.GetString(fmt.Sprintf("%s.directory", args[0]))
|
||||
if fromFlag != "" && fromFlag != fromConfig {
|
||||
fmt.Printf("Would you like to write the new directory path:\n%s\ninto the configuration file?\n", viper.GetString("directory"))
|
||||
fromConfig = fromFlag
|
||||
}
|
||||
fmt.Println("DIRECTORY:", fromConfig)
|
||||
// calibre.RenderStandaloneApp()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(buildCmd)
|
||||
buildCmd.PersistentFlags().StringP("directory", "d", "", "A local Calibre directory path.")
|
||||
buildCmd.PersistentFlags().StringP("librarian", "l", "", "Librarian's name.")
|
||||
buildCmd.PersistentFlags().StringP("jsonpath", "j", "", "Path where to render all metadata into JSON.")
|
||||
buildCmd.PersistentFlags().StringP("bibtex", "b", "", "Import books from BibTex file into Calibre.")
|
||||
CustomHelpOutput(buildCmd)
|
||||
viper.BindPFlag("directory", buildCmd.PersistentFlags().Lookup("directory"))
|
||||
rootCmd.AddCommand(buildCmd)
|
||||
}
|
||||
|
|
|
@ -19,5 +19,4 @@ func OnlyProfileArgument(cmd *cobra.Command, args []string) error {
|
|||
return fmt.Errorf("You can only have one argument and that should be PROFILE.")
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
|
28
cmd/root.go
|
@ -2,9 +2,10 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
@ -35,26 +36,33 @@ The configuration file will keep information about one or more PROFILE.
|
|||
Under every PROFILE's configuration section there will be information
|
||||
about the directory path of local Calibre's library, librarian's name,
|
||||
credentials needed to upload the files to the destination server etc.`,
|
||||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := initConfig(args); err != nil {
|
||||
fmt.Println("ERROR:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
// Execute adds all child commands to the root command and sets flags appropriately.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println("BYE!", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
// cobra.OnInitialize(initConfig)
|
||||
|
||||
rootCmd.SetHelpTemplate(RootHelpTemplate)
|
||||
rootCmd.SetUsageTemplate(RootUsageTemplate)
|
||||
}
|
||||
|
||||
// initConfig reads in config file and ENV variables if set.
|
||||
func initConfig() {
|
||||
func initConfig(args []string) error {
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
viper.SetConfigFile(cfgFile)
|
||||
|
@ -65,7 +73,6 @@ func initConfig() {
|
|||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Search config in home directory with name ".accorder" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
viper.SetConfigName(".accorder")
|
||||
|
@ -77,4 +84,15 @@ func initConfig() {
|
|||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
|
||||
hasProfile := false
|
||||
for k := range viper.AllSettings() {
|
||||
if k == args[0] {
|
||||
hasProfile = true
|
||||
}
|
||||
}
|
||||
if !hasProfile {
|
||||
return fmt.Errorf("PROFILE %s should be added to the configuration file.\n", args[0])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
3
go.mod
|
@ -3,8 +3,11 @@ module accorder
|
|||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/karrick/godirwalk v1.16.1 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.9.0
|
||||
nullprogram.com/x/uuid v1.2.1 // indirect
|
||||
)
|
||||
|
|
7
go.sum
|
@ -54,6 +54,7 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI
|
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
|
@ -196,6 +197,8 @@ github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
|
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
||||
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
|
@ -685,6 +688,10 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
nullprogram.com/x/isaac64 v1.0.0 h1:60wAUcmF8LI7bqmIR84aCviOFYsZ16uzVVQwEv0KMo0=
|
||||
nullprogram.com/x/isaac64 v1.0.0/go.mod h1:50jMhq3WThwRpM4z6xTHwp94BMqha3WbuKWb2vRxr78=
|
||||
nullprogram.com/x/uuid v1.2.1 h1:dBg/lObcs+vykLutnXWbZp++/mRvyCnZcsq+BRfoJY4=
|
||||
nullprogram.com/x/uuid v1.2.1/go.mod h1:NmzZbQYLdE9DEeN3zar52XwVIehpxzbXHxsbV/08T2I=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
@ -0,0 +1,382 @@
|
|||
package calibre
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/cespare/xxhash"
|
||||
// "github.com/google/uuid"
|
||||
"github.com/karrick/godirwalk"
|
||||
"nullprogram.com/x/uuid"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed embResources
|
||||
embResources embed.FS
|
||||
)
|
||||
|
||||
func c(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type DataJs struct {
|
||||
Portable bool `json:"portable"`
|
||||
Total int `json:"total,omitempty"`
|
||||
Books []*BookJSON `json:"books"`
|
||||
}
|
||||
|
||||
// type BooksJSON struct {
|
||||
// Books []*BookJSON `json:"books"`
|
||||
// }
|
||||
|
||||
type IdentifierJSON struct {
|
||||
Scheme string `json:"scheme"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
type FormatJSON struct {
|
||||
Format string `json:"format"`
|
||||
DirPath string `json:"dir_path"`
|
||||
FileName string `json:"file_name"`
|
||||
Size int64 `json:"size"`
|
||||
XXHash uint64 `json:"xxhash"`
|
||||
}
|
||||
|
||||
type BookJSON struct {
|
||||
Id string `json:"_id"`
|
||||
Librarian string `json:"librarian"`
|
||||
LibraryUUID string `json:"library_uuid"`
|
||||
Title string `json:"title"`
|
||||
TitleSort string `json:"title_sort,omitempty"`
|
||||
Authors []string `json:"authors"`
|
||||
Abstract string `json:"abstract"`
|
||||
Tags []string `json:"tags"`
|
||||
Publisher string `json:"publisher"`
|
||||
Pubdate string `json:"pubdate"`
|
||||
LastModified string `json:"last_modified"`
|
||||
Languages []string `json:"languages"`
|
||||
Identifiers []*IdentifierJSON `json:"identifiers"`
|
||||
Formats []*FormatJSON `json:"formats"`
|
||||
CoverUrl string `json:"cover_url"`
|
||||
}
|
||||
|
||||
type BookOpf struct {
|
||||
XMLName xml.Name `xml:"package"`
|
||||
Version string `xml:"version,attr"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
UniqueIdentifier string `xml:"unique-identifier,attr"`
|
||||
Metadata struct {
|
||||
XMLName xml.Name `xml:"metadata"`
|
||||
DC string `xml:"dc,attr"`
|
||||
OPF string `xml:"opf,attr"`
|
||||
Identifiers []struct {
|
||||
XMLName xml.Name `xml:"identifier"`
|
||||
Scheme string `xml:"scheme,attr"`
|
||||
Id string `xml:"id,attr"` // Calibre has two internal Ids: calibre_id and uuid_id
|
||||
Value string `xml:",chardata"`
|
||||
} `xml:"identifier"`
|
||||
Title string `xml:"title"`
|
||||
Creators []struct {
|
||||
XMLName xml.Name `xml:"creator"`
|
||||
Role string `xml:"role,attr"`
|
||||
Name string `xml:",chardata"`
|
||||
} `xml:"creator"`
|
||||
Published string `xml:"date"`
|
||||
Description string `xml:"description"`
|
||||
Publisher string `xml:"publisher"`
|
||||
Languages []struct {
|
||||
XMLName xml.Name `xml:"language"`
|
||||
Language string `xml:",chardata"`
|
||||
} `xml:"language"`
|
||||
Tags []struct {
|
||||
XMLName xml.Name `xml:"subject"`
|
||||
Tag string `xml:",chardata"`
|
||||
} `xml:"subject"`
|
||||
Meta []struct {
|
||||
XMLName xml.Name `xml:"meta"`
|
||||
Content string `xml:"content,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
} `xml:"meta"`
|
||||
}
|
||||
}
|
||||
|
||||
// TitleSort returns if Calibre processed Title for sorting order
|
||||
func (book BookOpf) TitleSort() string {
|
||||
for _, meta := range book.Metadata.Meta {
|
||||
if meta.Name == "calibre:title_sort" && meta.Content != book.Metadata.Title {
|
||||
return meta.Content
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// LastModified returns when Calibre last time touched the file
|
||||
func (book BookOpf) LastModified() string {
|
||||
lastModified := ""
|
||||
for _, meta := range book.Metadata.Meta {
|
||||
if meta.Name == "calibre:timestamp" {
|
||||
lastModified = meta.Content
|
||||
}
|
||||
}
|
||||
return lastModified
|
||||
}
|
||||
|
||||
// Authors parses creators and give back authors
|
||||
func (book BookOpf) Authors() []string {
|
||||
authors := []string{}
|
||||
if len(book.Metadata.Creators) > 0 {
|
||||
for _, author := range book.Metadata.Creators {
|
||||
if author.Role == "aut" {
|
||||
authors = append(authors, author.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return authors
|
||||
}
|
||||
|
||||
// Tags gets a list of tags from Subject nodes in OPF
|
||||
func (book BookOpf) Tags() []string {
|
||||
tags := []string{}
|
||||
for _, tag := range book.Metadata.Tags {
|
||||
tags = append(tags, tag.Tag)
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// Languages gets a list of languages
|
||||
func (book BookOpf) Languages() []string {
|
||||
languages := []string{}
|
||||
for _, l := range book.Metadata.Languages {
|
||||
languages = append(languages, l.Language)
|
||||
}
|
||||
return languages
|
||||
}
|
||||
|
||||
// Identifiers returns list of identifiers like ISBN, DOI, Google, Amazon...
|
||||
func (book BookOpf) Identifiers() []*IdentifierJSON {
|
||||
identifiers := []*IdentifierJSON{}
|
||||
for _, i := range book.Metadata.Identifiers {
|
||||
if i.Id == "" {
|
||||
identifiers = append(identifiers, &IdentifierJSON{
|
||||
Scheme: strings.ToLower(i.Scheme),
|
||||
Code: i.Value,
|
||||
})
|
||||
}
|
||||
}
|
||||
return identifiers
|
||||
}
|
||||
|
||||
// Formats return list of files and info on them
|
||||
func Formats(path string) []*FormatJSON {
|
||||
formats := []*FormatJSON{}
|
||||
files, err := os.ReadDir(path)
|
||||
c(err)
|
||||
|
||||
for _, f := range files {
|
||||
if f.Name() != "metadata.opf" && f.Name() != "cover.jpg" {
|
||||
fi, err := f.Info()
|
||||
c(err)
|
||||
x, err := os.Open(filepath.Join(path, f.Name()))
|
||||
c(err)
|
||||
defer x.Close()
|
||||
xxHash := xxhash.New()
|
||||
_, err = io.Copy(xxHash, x)
|
||||
c(err)
|
||||
formats = append(formats, &FormatJSON{
|
||||
Format: strings.ReplaceAll(filepath.Ext(f.Name()), ".", ""),
|
||||
DirPath: path,
|
||||
FileName: f.Name(),
|
||||
Size: fi.Size(),
|
||||
XXHash: xxHash.Sum64(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return formats
|
||||
}
|
||||
|
||||
func lsEmbResources() {
|
||||
_ = fs.WalkDir(embResources, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
c(err)
|
||||
// fmt.Println(" ", path)
|
||||
_ = path
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func copyEmbResources(destPath string) {
|
||||
_ = fs.WalkDir(embResources, ".", func(fsPath string, fsEntry fs.DirEntry, err error) error {
|
||||
destFsPath := strings.ReplaceAll(fsPath, "embResources/", "")
|
||||
c(err)
|
||||
if fsPath == "." {
|
||||
return nil
|
||||
} else if fsEntry.IsDir() {
|
||||
err := os.MkdirAll(filepath.Join(destPath, destFsPath), 0755)
|
||||
c(err)
|
||||
} else {
|
||||
newFile, err := os.Create(destFsPath)
|
||||
c(err)
|
||||
defer newFile.Close()
|
||||
|
||||
embFile, err := embResources.Open(fsPath)
|
||||
c(err)
|
||||
_, err = io.Copy(newFile, embFile)
|
||||
c(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func writeDataJs(calibrePath string, books []*BookJSON) {
|
||||
// j, _ := json.MarshalIndent(&BooksJSON{books})
|
||||
dataJsFirst, err := os.Create(filepath.Join(calibrePath, "static", "data1.js"))
|
||||
c(err)
|
||||
defer dataJsFirst.Close()
|
||||
|
||||
j1, _ := json.Marshal(&DataJs{
|
||||
Portable: true,
|
||||
Total: len(books),
|
||||
Books: books[0:24],
|
||||
})
|
||||
calibreBooks1 := []byte("CALIBRE_BOOKS1=")
|
||||
_, _ = dataJsFirst.Write(append(calibreBooks1, j1...))
|
||||
|
||||
// [24:120], [120:216], [216:3288], [3288:6360], [6360:9432], [9432:12504]
|
||||
block := 24
|
||||
counter := 2
|
||||
for i := range [2]int{} {
|
||||
ii := make([]int, int(math.Pow(2, float64(i+1))))
|
||||
for j := range ii {
|
||||
_ = j
|
||||
|
||||
var jsn []byte
|
||||
|
||||
endBlock := block + int(math.Pow(32, float64(i+1)))*3
|
||||
|
||||
if endBlock > len(books) {
|
||||
endBlock = len(books)
|
||||
}
|
||||
|
||||
dataJs, err := os.Create(filepath.Join(calibrePath, "static", fmt.Sprintf("data%d.js", counter)))
|
||||
c(err)
|
||||
defer dataJs.Close()
|
||||
|
||||
if endBlock <= len(books) {
|
||||
jsn, _ = json.Marshal(&DataJs{
|
||||
Portable: true,
|
||||
Books: books[block:endBlock],
|
||||
})
|
||||
} else {
|
||||
jsn, _ = json.Marshal(&DataJs{
|
||||
Portable: true,
|
||||
Books: []*BookJSON{},
|
||||
})
|
||||
}
|
||||
calibreBooks := []byte(fmt.Sprintf("CALIBRE_BOOKS%d=", counter))
|
||||
_, _ = dataJs.Write(append(calibreBooks, jsn...))
|
||||
block = endBlock
|
||||
counter++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PrintExePath() {
|
||||
fmt.Println(os.Executable())
|
||||
}
|
||||
|
||||
func RenderStandaloneApp(calibrePath string) {
|
||||
// exePath, err := os.Executable()
|
||||
// c(err)
|
||||
// calibrePath := fmt.Sprintf("%s/", filepath.Dir(exePath))
|
||||
// calibrePath := "/home/m/CalibreLibraries/MarcellMarsBooks/"
|
||||
// calibrePath := "/media/m/My Book/motw/motw_calibre_libraries/MarcellMarsBooks/"
|
||||
fmt.Println(calibrePath)
|
||||
|
||||
var outputs sync.Map
|
||||
var wg sync.WaitGroup
|
||||
count := 0
|
||||
err := godirwalk.Walk(calibrePath, &godirwalk.Options{
|
||||
Callback: func(path string, info *godirwalk.Dirent) error {
|
||||
if info.Name() == "metadata.opf" {
|
||||
bookOpf := &BookOpf{}
|
||||
count++
|
||||
wg.Add(1)
|
||||
go func(bookOpf *BookOpf) {
|
||||
// randSuffix := uuid.New()
|
||||
randSuffix := uuid.NewGen()
|
||||
relativeDirPath := strings.NewReplacer(calibrePath, "", "metadata.opf", "").Replace(path)
|
||||
f, _ := os.ReadFile(path)
|
||||
_ = xml.Unmarshal([]byte(f), &bookOpf)
|
||||
|
||||
book := &BookJSON{
|
||||
// Id: randSuffix.String(),
|
||||
Id: randSuffix.NewV4().String(),
|
||||
Title: bookOpf.Metadata.Title,
|
||||
Librarian: "Aaron Elbakyan",
|
||||
// LibraryUUID: randSuffix.String(),
|
||||
LibraryUUID: randSuffix.NewV4().String(),
|
||||
TitleSort: bookOpf.TitleSort(),
|
||||
Authors: bookOpf.Authors(),
|
||||
Pubdate: bookOpf.Metadata.Published,
|
||||
LastModified: bookOpf.LastModified(),
|
||||
Tags: bookOpf.Tags(),
|
||||
Publisher: bookOpf.Metadata.Publisher,
|
||||
Abstract: bookOpf.Metadata.Description,
|
||||
Languages: bookOpf.Languages(),
|
||||
Identifiers: bookOpf.Identifiers(),
|
||||
Formats: Formats(filepath.Join(calibrePath, relativeDirPath)),
|
||||
CoverUrl: filepath.Join(relativeDirPath, "cover.jpg"),
|
||||
}
|
||||
// outputs.Store(fmt.Sprintf("%s_%s", book.LastModified, randSuffix.String()), book)
|
||||
outputs.Store(fmt.Sprintf("%s_%s", book.LastModified, randSuffix.NewV4().String()), book)
|
||||
wg.Done()
|
||||
}(bookOpf)
|
||||
}
|
||||
if count > 100 {
|
||||
wg.Wait()
|
||||
count = 0
|
||||
}
|
||||
return nil
|
||||
},
|
||||
ErrorCallback: func(path string, err error) godirwalk.ErrorAction {
|
||||
fmt.Fprintf(os.Stderr, "ERROR: %s\n", err)
|
||||
return godirwalk.SkipNode
|
||||
},
|
||||
Unsorted: true})
|
||||
wg.Wait()
|
||||
|
||||
c(err)
|
||||
|
||||
var keysByDate []string
|
||||
outputs.Range(func(k, v interface{}) bool {
|
||||
keysByDate = append(keysByDate, k.(string))
|
||||
return true
|
||||
})
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(keysByDate)))
|
||||
|
||||
var books []*BookJSON
|
||||
for _, keyByDate := range keysByDate {
|
||||
b, _ := outputs.Load(keyByDate)
|
||||
books = append(books, b.(*BookJSON))
|
||||
}
|
||||
|
||||
// j, _ := json.MarshalIndent(&BooksJSON{books}, "", " ")
|
||||
// fmt.Println(string(j))
|
||||
// _ = j
|
||||
|
||||
lsEmbResources()
|
||||
copyEmbResources(calibrePath)
|
||||
writeDataJs(calibrePath, books)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width'>
|
||||
|
||||
<title>Memory of the World Library</title>
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="static/favicons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="static/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="static/favicons/favicon-16x16.png">
|
||||
<link rel="mask-icon" href="static/favicons/safari-pinned-tab.svg" color="#5bbad5">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link rel='stylesheet' href='static/css/bundle.css'>
|
||||
|
||||
<script rel="prefetch" src="static/data1.js"></script>
|
||||
<script defer src='static/js/bundle.js'></script>
|
||||
</head>
|
||||
|
||||
<body class="pl-2 pr-2 monocle:p-0 phone:p-0">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
CALIBRE_BOOKS1={"portable":false}
|
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 978 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 6.4 KiB |
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="1374.000000pt" height="1374.000000pt" viewBox="0 0 1374.000000 1374.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,1374.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M6869 11514 c-24 -18 -49 -33 -56 -33 -6 -1 -13 -4 -15 -8 -1 -5 -48
|
||||
-37 -103 -73 -55 -36 -102 -68 -105 -71 -3 -3 -9 -8 -15 -10 -20 -8 -280 -184
|
||||
-283 -191 -2 -5 -8 -8 -13 -8 -6 0 -15 -5 -22 -10 -14 -12 -155 -105 -203
|
||||
-135 -19 -11 -42 -28 -53 -37 -11 -9 -22 -14 -25 -11 -3 3 -8 -2 -12 -11 -3
|
||||
-9 -10 -16 -16 -16 -5 0 -35 -17 -66 -39 -31 -21 -61 -39 -66 -39 -5 0 -12 -4
|
||||
-15 -9 -10 -14 -79 -63 -89 -63 -5 0 -17 -9 -27 -20 -10 -11 -22 -20 -26 -20
|
||||
-10 0 -133 -83 -137 -92 -2 -5 -7 -8 -12 -8 -10 0 -134 -82 -138 -92 -2 -4 -8
|
||||
-8 -13 -8 -11 0 -133 -81 -137 -92 -2 -5 -7 -8 -12 -8 -8 0 -374 -239 -397
|
||||
-259 -7 -6 -16 -11 -20 -11 -5 0 -20 -11 -35 -25 -15 -14 -31 -25 -36 -25 -4
|
||||
0 -17 -7 -27 -15 -11 -9 -101 -69 -200 -135 -99 -65 -184 -122 -190 -127 -5
|
||||
-4 -22 -14 -37 -22 -16 -8 -28 -18 -28 -23 0 -4 -5 -8 -10 -8 -6 0 -33 -16
|
||||
-60 -35 -27 -19 -54 -35 -59 -35 -5 0 -11 -3 -13 -7 -3 -8 -174 -124 -193
|
||||
-132 -5 -2 -33 -21 -62 -43 -29 -21 -55 -38 -58 -38 -3 0 -27 -16 -54 -35 -26
|
||||
-19 -53 -35 -59 -35 -6 0 -12 -4 -14 -8 -4 -11 -155 -112 -167 -112 -5 0 -11
|
||||
-3 -13 -7 -5 -12 -95 -73 -107 -73 -6 0 -11 -4 -11 -8 0 -5 -12 -15 -27 -23
|
||||
-16 -8 -30 -16 -33 -20 -6 -6 -389 -261 -405 -269 -5 -3 -51 -33 -102 -67 -51
|
||||
-35 -97 -63 -103 -63 -5 0 -10 -4 -10 -8 0 -4 -22 -21 -50 -37 -27 -17 -50
|
||||
-33 -50 -37 0 -5 -7 -8 -15 -8 -8 0 -15 -4 -15 -10 0 -5 -4 -10 -10 -10 -5 0
|
||||
-32 -16 -59 -35 -26 -19 -53 -35 -59 -35 -6 0 -12 -3 -14 -8 -1 -4 -50 -38
|
||||
-108 -77 -58 -38 -108 -74 -112 -80 -5 -6 -8 -6 -8 0 0 6 -6 3 -13 -6 -7 -9
|
||||
-22 -19 -35 -23 -12 -4 -22 -11 -22 -15 0 -5 -13 -14 -30 -21 -16 -7 -30 -16
|
||||
-30 -20 0 -4 -16 -15 -35 -24 -19 -9 -35 -21 -35 -27 0 -6 -5 -7 -10 -4 -6 3
|
||||
-10 1 -10 -4 0 -6 -4 -11 -9 -11 -6 0 -31 -15 -56 -32 -26 -18 -54 -38 -63
|
||||
-43 -37 -22 -77 -50 -82 -56 -3 -3 -16 -12 -30 -19 -14 -7 -42 -26 -62 -42
|
||||
-21 -16 -38 -27 -38 -23 0 3 -7 0 -15 -7 -33 -30 -45 -38 -54 -38 -5 0 -16 -6
|
||||
-23 -13 -17 -17 -488 -330 -510 -339 -9 -4 -37 -26 -61 -50 -74 -74 -100 -190
|
||||
-98 -438 1 -118 4 -169 16 -285 4 -27 8 -69 10 -93 3 -24 7 -56 11 -70 5 -27
|
||||
11 -64 18 -112 2 -14 7 -41 11 -60 4 -19 9 -45 11 -57 1 -11 5 -30 8 -41 4
|
||||
-11 8 -29 10 -39 10 -48 39 -164 56 -223 11 -36 22 -76 24 -90 3 -14 5 -25 6
|
||||
-25 1 0 3 -7 5 -15 4 -17 62 -187 72 -210 3 -8 7 -17 7 -20 1 -3 7 -15 14 -27
|
||||
7 -13 10 -23 7 -23 -3 0 6 -20 19 -45 14 -25 23 -45 20 -45 -7 0 64 -136 98
|
||||
-187 15 -23 28 -45 28 -49 0 -4 7 -14 15 -23 8 -9 29 -32 47 -52 18 -20 51
|
||||
-49 73 -65 22 -16 49 -37 59 -46 11 -10 26 -18 33 -18 7 0 13 -4 13 -10 0 -5
|
||||
7 -10 15 -10 8 0 15 -4 15 -9 0 -5 20 -21 44 -35 25 -14 51 -32 58 -39 7 -7
|
||||
47 -36 88 -65 41 -28 98 -67 125 -87 28 -20 68 -48 90 -63 22 -15 41 -30 43
|
||||
-34 2 -5 10 -8 18 -8 8 0 14 -3 14 -8 0 -4 18 -18 40 -32 22 -14 40 -28 40
|
||||
-32 0 -5 6 -8 13 -8 8 0 22 -9 32 -20 10 -11 22 -20 27 -20 5 0 14 -5 21 -10
|
||||
7 -6 48 -36 92 -67 44 -32 82 -60 85 -63 3 -3 12 -9 21 -15 10 -5 37 -24 60
|
||||
-41 24 -16 76 -52 114 -79 39 -27 76 -55 83 -61 6 -7 21 -16 32 -19 11 -3 20
|
||||
-10 20 -14 0 -4 18 -17 40 -30 22 -12 40 -26 40 -32 0 -5 5 -9 11 -9 6 0 28
|
||||
-14 49 -30 21 -17 42 -30 48 -30 6 0 12 -3 14 -7 4 -9 174 -133 182 -133 3 0
|
||||
14 -7 24 -16 9 -8 60 -45 112 -82 52 -37 97 -70 98 -74 2 -5 9 -8 15 -8 7 0
|
||||
24 -11 39 -25 15 -14 31 -25 35 -25 4 0 19 -9 33 -20 63 -51 120 -90 129 -90
|
||||
5 0 11 -3 13 -7 5 -11 147 -113 157 -113 5 0 11 -4 13 -8 1 -5 26 -23 53 -42
|
||||
28 -18 52 -36 55 -39 12 -14 70 -51 80 -51 5 0 10 -3 10 -8 0 -4 18 -18 40
|
||||
-32 22 -14 40 -28 40 -32 0 -5 7 -8 15 -8 9 0 18 -7 21 -15 4 -8 10 -15 15
|
||||
-15 8 0 113 -71 144 -98 6 -5 24 -17 40 -27 17 -11 56 -39 87 -62 31 -24 59
|
||||
-43 62 -43 3 0 14 -6 23 -14 39 -31 113 -86 118 -86 4 0 132 -90 180 -127 6
|
||||
-4 33 -24 60 -43 28 -19 52 -38 53 -42 2 -4 8 -8 13 -8 9 0 67 -38 79 -51 3
|
||||
-3 28 -21 55 -39 28 -19 52 -37 53 -42 2 -4 10 -8 18 -8 8 0 14 -4 14 -10 0
|
||||
-5 6 -10 14 -10 8 0 16 -4 18 -8 2 -5 26 -23 53 -42 28 -18 52 -36 55 -39 12
|
||||
-14 70 -51 80 -51 5 0 10 -3 10 -7 0 -5 25 -24 55 -43 30 -19 54 -38 55 -42 0
|
||||
-5 5 -8 11 -8 11 0 92 -60 97 -72 2 -5 10 -8 18 -8 8 0 14 -4 14 -10 0 -5 7
|
||||
-10 15 -10 8 0 15 -4 15 -10 0 -5 7 -10 15 -10 8 0 15 -4 15 -10 0 -5 6 -10
|
||||
14 -10 8 0 16 -3 18 -8 4 -9 202 -150 223 -158 15 -6 52 13 84 44 9 9 31 28
|
||||
49 42 18 14 45 36 61 50 57 52 91 80 96 80 3 0 16 10 28 23 12 12 47 43 77 67
|
||||
67 55 95 79 124 105 12 11 41 35 64 53 22 19 50 41 60 50 11 10 34 28 52 42
|
||||
17 13 47 38 65 55 18 16 50 44 70 60 21 17 47 39 59 50 12 11 45 38 72 60 27
|
||||
22 65 54 84 72 19 18 41 33 48 33 6 0 12 7 12 15 0 8 4 15 8 15 5 0 18 8 30
|
||||
17 41 35 108 91 187 158 26 22 58 50 71 63 13 12 25 22 28 22 6 0 44 33 91 78
|
||||
13 12 27 22 30 22 3 0 13 8 23 17 10 10 40 36 67 58 26 22 59 49 71 60 12 11
|
||||
39 34 60 50 20 17 44 37 53 46 9 8 39 33 66 55 28 21 52 42 55 45 3 3 34 30
|
||||
70 60 36 29 70 58 76 64 6 5 30 26 54 45 25 19 62 51 84 70 23 19 45 38 51 43
|
||||
5 4 21 17 35 30 14 12 45 38 69 57 24 19 56 46 71 60 15 14 43 37 62 52 19 15
|
||||
45 37 59 50 14 13 45 39 69 58 24 19 61 51 83 70 22 19 62 52 89 72 28 21 46
|
||||
38 42 38 -5 1 1 6 12 13 21 12 69 52 162 134 26 24 53 43 60 43 6 0 12 7 12
|
||||
15 0 8 4 15 10 15 10 0 27 14 98 78 21 18 58 49 85 69 26 21 47 41 47 45 0 4
|
||||
5 8 10 8 6 0 18 8 28 17 31 30 85 77 117 101 17 13 50 41 75 62 40 35 154 131
|
||||
219 185 13 11 58 49 101 85 84 71 84 70 215 179 50 41 97 81 106 90 9 9 25 23
|
||||
36 31 26 21 137 113 143 120 5 5 118 99 135 113 6 4 21 17 35 30 14 12 45 38
|
||||
69 57 24 19 48 40 55 45 6 6 38 33 71 60 33 28 67 58 76 67 9 10 19 18 23 18
|
||||
4 0 21 13 39 29 34 32 160 139 242 206 70 57 104 87 131 114 13 13 24 21 24
|
||||
18 0 -4 15 8 33 26 19 18 49 43 67 57 18 14 43 34 55 45 12 11 41 36 66 55 24
|
||||
19 53 44 64 55 11 11 36 32 55 47 19 15 47 37 61 50 15 13 46 39 69 58 132
|
||||
108 133 110 128 165 -5 64 -34 105 -96 136 -26 13 -49 24 -52 24 -3 0 -12 5
|
||||
-20 10 -8 5 -60 32 -115 60 -102 52 -117 60 -170 88 -29 15 -51 57 -61 117 -4
|
||||
29 -8 44 -19 85 -5 16 -9 39 -10 50 -1 11 -5 36 -8 55 -4 19 -10 49 -13 65 -7
|
||||
41 -11 68 -18 150 -4 39 -9 90 -12 115 -6 50 -6 368 0 415 2 17 7 62 11 100 8
|
||||
80 9 87 20 138 4 20 10 37 14 37 4 0 20 12 38 28 40 35 59 51 108 87 22 16 47
|
||||
36 57 45 9 8 31 26 49 40 18 14 58 45 89 70 31 25 69 54 85 65 69 49 85 72 85
|
||||
120 0 65 -34 115 -102 148 -29 14 -93 44 -143 67 -49 23 -112 52 -140 65 -54
|
||||
25 -137 64 -308 144 -59 28 -109 51 -112 51 -2 0 -50 22 -105 49 -55 28 -103
|
||||
50 -105 51 -5 1 -84 37 -230 105 -171 80 -233 109 -295 138 -36 17 -67 31 -70
|
||||
32 -44 15 -70 29 -70 38 0 6 -3 8 -6 4 -4 -3 -27 5 -53 18 -76 39 -146 69
|
||||
-153 67 -5 -1 -8 3 -8 10 0 6 -3 9 -6 6 -3 -4 -31 6 -62 22 -70 34 -202 97
|
||||
-302 142 -41 19 -102 48 -135 64 -33 16 -62 29 -65 29 -3 0 -40 18 -83 38
|
||||
-106 51 -191 91 -197 92 -3 1 -43 19 -90 42 -47 22 -119 57 -161 76 -115 53
|
||||
-173 80 -291 136 -59 28 -109 51 -111 51 -3 0 -65 29 -138 63 -155 74 -171 81
|
||||
-181 79 -5 -1 -8 3 -8 8 0 6 -4 10 -9 10 -5 0 -51 20 -102 44 -157 73 -209 96
|
||||
-219 96 -6 0 -10 5 -10 10 0 6 -5 10 -12 10 -6 0 -49 18 -94 40 -46 22 -88 40
|
||||
-93 40 -6 0 -11 5 -11 12 0 6 -3 9 -6 6 -3 -4 -41 11 -85 33 -43 21 -81 39
|
||||
-83 39 -3 0 -49 20 -103 45 -132 62 -147 69 -153 76 -9 10 -94 30 -121 27 -14
|
||||
-1 -45 -17 -70 -34z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.2 KiB |