Skip to content

Commit

Permalink
Merge pull request #93 from metafates/dev
Browse files Browse the repository at this point in the history
v3.8.0
  • Loading branch information
metafates authored Sep 14, 2022
2 parents 357f60d + 7294627 commit ee0c6ed
Show file tree
Hide file tree
Showing 81 changed files with 1,957 additions and 824 deletions.
6 changes: 6 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ builds:
- arm64
flags:
- -trimpath
ldflags:
- -X 'github.com/metafates/mangal/constant.BuiltAt={{ .Date }}'
- -X 'github.com/metafates/mangal/constant.BuiltBy={{ .Env.USER }}'
- -X 'github.com/metafates/mangal/constant.Revision={{ .ShortCommit }}'
- -s
- -w

archives:
- replacements:
Expand Down
9 changes: 9 additions & 0 deletions .idea/IntelliLang.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to
[Semantic Versioning](https://semver.org).

## 3.8.0

- Support for more manga metadata fields such as summary, genres, tags, and more.
- Fetch manga metadata from anilist.
`metadata.fetch_anilist` (default: `true`)
- Generate `series.json` file.
`metadata.series_json` (default: `false`)
- Generate `ComicInfo.xml` file (for CBZ only)
`metadata.comic_info_xml` (default: `true`)
- Support for downloading manga covers.
`downloader.download_cover` (default: `false`)
- Better progress message while downloading in TUI mode
- Set option `downloader.create_volume_dir` to `false` by default
- Version command now shows more information (such as build date, commit hash, etc.)
- New flag for inline mode: `--output/-o` to redirect output to file (will use STDOUT if not set)
- New `mangal config set` command to set config values. See `mangal help config set` for more info.
- New `mangal config get` command to get config values. See `mangal help config get` for more info
- New `mangal config info` command to list all available config fields with description for each.
- Improve `mangal clear` command. It's more accurate and faster now.
- Better cache & temp files handling
- Fix `mangal update` command when it was not able to update using script.
- Expose every config field as ENV variable (see `mangal env` to show all of them)

## 3.7.0

- Add support for volumes - now you can select chapters by volume (in TUI mode only). #90
Expand Down
34 changes: 34 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
MAKEFLAGS += --silent

ldflags := -X 'github.com/metafates/mangal/constant.BuiltAt=$(shell date -u)'
ldflags += -X 'github.com/metafates/mangal/constant.BuiltBy=$(shell whoami)@$(shell hostname)'
ldflags += -X 'github.com/metafates/mangal/constant.Revision=$(shell git rev-parse --short HEAD)'
ldflags += -s
ldlags += -w

build_flags := -ldflags=${ldflags}

all: help

help:
@echo "Usage: make [target]"
@echo ""
@echo "Targets:"
@echo " build Build the mangal binary"
@echo " install Install the mangal binary"
@echo " test Run the tests"
@echo " help Show this help message"
@echo ""

install:
@go install "$(build_flags)"


build:
@go build "$(build_flags)"

test:
@go test ./...

uninstall:
@rm -f $(shell which mangal)
130 changes: 6 additions & 124 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,130 +205,12 @@ For example, on __Linux__ it would be `~/.config/mangal/mangal.toml`.
Use env variable `MANGAL_CONFIG_PATH` to set custom config path.
> See `mangal env` to show all available env variables.
Run `mangal where` to show expected config paths

Run `mangal config init` to generate a default config file

<details>
<summary><strong>Default config example (click to show)</strong></summary>

```toml
# mangal.toml

[downloader]
# Default source to use
# Will prompt to choose if empty
# Type `mangal sources` for available sources
default_source = ''
# Name template of the downloaded chapters
# Path forbidden symbols will be replaced with _
# Available variables:
# {index} - index of the chapters
# {padded-index} - same as index but padded with leading zeros
# {chapters-count} - total number of chapters
# {chapter} - name of the chapter
# {manga} - name of the manga
# {volume} - volume of the chapter
# {source} - name of the source
chapter_name_template = '[{padded-index}] {chapter}'
# Where to download manga
# Absolute or relative.
#
# You can also use home variable
# path = "~/..." or "$HOME/..."
path = '.'
# Use asynchronous downloader (faster)
# Do no turn it off unless you have some issues
async = true
# Create a subdirectory for each manga
create_manga_dir = true
# Create a subdirectory for each volume (if available)
careate_volume_dir = true
# Stop downloading other chapters on error
stop_on_error = false




[formats]
# Default format to export chapters
# Available options are: pdf, zip, cbz, plain
use = 'pdf'
# Will skip images that can't be converted to the specified format
# Example: if you want to export to pdf, but some images are gifs, they will be skipped
skip_unsupported_images = true



[history]
# Save chapters to history when downloaded
save_on_download = false
# Save chapters to history on read
save_on_read = true



[icons]
# Icons variant.
# Available options are: emoji, kaomoji, plain, squares, nerd (nerd-font)
variant = 'plain'



[mangadex]
# Preferred language
language = 'en'
# Show nsfw manga/chapters
nsfw = false
# Show chapters that cannot be read (because they are hosted on a different site)
show_unavailable_chapters = false



[mini]
# Limit number of search page entries
search_limit = 20



[reader]
# Name of the app to use as a reader for each format.
# Will use default OS app if empty
pdf = '' # e.g. pdf = 'zathura'
cbz = ''
zip = ''
plain = ''
# Will open chapter in the browser instead of downloading it
read_in_browser = false



[installer]
# Custom scrapers repository (github only)
repo = 'mangal-scrapers'
# Custom scrapers repository owner
user = 'metafates'
# Custom scrapers repository branch
branch = 'main'


[gen]
# Name of author for gen command.
# Will use OS username if empty
author = ''


[logs]
# write logs?
write = false
# Available options are: (from less to most verbose)
# panic, fatal, error, warn, info, debug, trace
level = "info"
# Use json format for logs
json = false
```

</details>
| Command | Description |
|----------------------|--------------------------------------------------|
| `mangal config get` | Get config value for specific key |
| `mangal config set` | Set config value for specific key |
| `mangal config info` | List all config fields with description for each |
| `mangal config init` | Write current config to a file |

## Custom scrapers

Expand Down
91 changes: 91 additions & 0 deletions anilist/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package anilist

import (
"encoding/json"
"github.com/metafates/mangal/filesystem"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/where"
"github.com/spf13/afero"
"io"
"os"
"path/filepath"
"strings"
)

var cache = anilistCache{
Mem: make(map[string]*Manga),
}

type anilistCache struct {
Mem map[string]*Manga `json:"mangas"`
file afero.File
}

func (a *anilistCache) Init() error {
if a.file != nil {
return nil
}

log.Debug("Initializing anilist cacher")

var err error
path := filepath.Join(where.Cache(), "anilist_cache.json")
log.Debugf("Opening anilist cache file at %s", path)
a.file, err = filesystem.Api().OpenFile(path, os.O_RDWR|os.O_CREATE, os.ModePerm)

if err != nil {
log.Warn(err)
return err
}

contents, err := io.ReadAll(a.file)
if err != nil {
log.Warn(err)
return err
}

if len(contents) == 0 {
log.Debug("Anilist cache file is empty, skipping unmarshal")
return nil
}

var temp anilistCache
err = json.Unmarshal(contents, &temp)
if err != nil {
log.Warn(err)
return err
}

log.Debugf("Anilist cache file unmarshalled successfully, len is %d", len(temp.Mem))
a.Mem = temp.Mem
return nil
}

func (a *anilistCache) Get(name string) (*Manga, bool) {
if a.file == nil {
_ = a.Init()
}
mangas, ok := a.Mem[a.formatName(name)]
return mangas, ok
}

func (a *anilistCache) Set(name string, manga *Manga) error {
log.Debug("Setting anilist cacher entry")
a.Mem[a.formatName(name)] = manga
marshalled, err := json.Marshal(a)
if err != nil {
log.Warn(err)
return err
}

_, _ = a.file.Seek(0, 0)
_, err = a.file.Write(marshalled)
if err != nil {
log.Warn(err)
}
return err
}

func (a *anilistCache) formatName(name string) string {
return strings.TrimSpace(strings.ToLower(name))
}
61 changes: 61 additions & 0 deletions anilist/find.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package anilist

import (
"fmt"
levenshtein "github.com/ka-weihe/fast-levenshtein"
"github.com/metafates/mangal/log"
"github.com/metafates/mangal/util"
"github.com/samber/lo"
"strings"
)

var (
retries uint8
limit uint8 = 3
)

func FindClosest(name string) (*Manga, error) {
if retries >= limit {
retries = 0
err := fmt.Errorf("no results found on Anilist for manga %s", name)
log.Error(err)
return nil, err
}

if manga, ok := cache.Get(name); ok {
return manga, nil
}

// search for manga on anilist
urls, err := Search(name)
if err != nil {
log.Error(err)
return nil, err
}

if len(urls) == 0 {
// try again with a different name
retries++
words := strings.Split(name, " ")
if len(words) == 1 {
// trigger limit
retries = limit
return FindClosest("")
}

// one word less
alternateName := strings.Join(words[:util.Max(len(words)-1, 1)], " ")
log.Infof(`No results found on Anilist for manga "%s", trying "%s"`, name, alternateName)
return FindClosest(alternateName)
}

// find the closest match
closest := lo.MinBy(urls, func(a, b *Manga) bool {
return levenshtein.Distance(name, a.Name()) < levenshtein.Distance(name, b.Name())
})

log.Info("Found closest match: " + closest.Name())
retries = 0
_ = cache.Set(name, closest)
return closest, nil
}
Loading

0 comments on commit ee0c6ed

Please sign in to comment.