Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Currently, it can download manga from the following websites:
| ---------- | ------------------------- |
| Weebcentral (English) | https://weebcentral.com |
| Mangadex (Multilingual) | https://mangadex.org |
| MangaVyvy (English) | https://mangavyvy.com |
| MangaFreak (English)| https://ww3.mangafreak.me |
| Anime-Sama (French only) | https://anime-sama.pw |

Expand Down
1 change: 1 addition & 0 deletions README_FR.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Actuellement, il est possible de télécharger des manga depuis les sites suivan
| ---------- | ------------------------- |
| Weebcentral (Anglais) | https://weebcentral.com |
| Mangadex (Plurilingue) | https://mangadex.org |
| MangaVyvy (Anglais) | https://mangavyvy.com |
| MangaFreak (Anglais) | https://ww3.mangafreak.me |
| Anime-Sama (Français uniquement) | https://anime-sama.pw |

Expand Down
155 changes: 155 additions & 0 deletions internal/source/mangavyvy/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package mangavyvy

import (
"net/url"
"path"
"strings"

"github.com/EliasLd/goweeb/internal/logger"
"github.com/EliasLd/goweeb/internal/source/common"
mangavyvyscraper "github.com/EliasLd/goweeb/internal/source/mangavyvy/scraper"
sourcetypes "github.com/EliasLd/goweeb/internal/source/types"
)

const defaultDomain = "https://mangavyvy.com"

type Provider struct {
domain string
}

func mangaTitleFromURL(
workURL string,
) string {
parsed, err := url.Parse(workURL)
if err != nil {
return "manga"
}

slug := path.Base(
strings.TrimSuffix(parsed.Path, "/"),
)

if slug == "" ||
slug == "." ||
slug == "/" {
return "manga"
}

return strings.ReplaceAll(
slug,
"-",
" ",
)
}

func New(customDomain string) *Provider {
domain := customDomain

if domain == "" {
domain = defaultDomain
}

return &Provider{
domain: strings.TrimSuffix(domain, "/"),
}
}

func (p *Provider) Name() string {
return "mangavyvy"
}

func (p *Provider) Search(
query string,
log *logger.Logger,
) ([]sourcetypes.SearchResult, error) {
results, err := mangavyvyscraper.SearchCatalog(
p.domain,
query,
log,
)
if err != nil {
return nil, err
}

out := make(
[]sourcetypes.SearchResult,
0,
len(results),
)

for _, result := range results {
out = append(
out,
sourcetypes.SearchResult{
Title: result.Title,
URL: result.URL,
},
)
}

return out, nil
}

// Mangavyvy currently exposes a single chapter list per manga.
func (p *Provider) ListScanPaths(
workURL string,
log *logger.Logger,
) ([]common.SelectableItem, error) {
return []common.SelectableItem{
{
Label: "Mangavyvy",
Value: workURL,
},
}, nil
}

//TODO:
// - List Chapters
// - Download Images

func (p *Provider) ListEntries(
workURL string,
scanPath string,
log *logger.Logger,
) (sourcetypes.Work, []sourcetypes.Entry, error) {
chapters, err := mangavyvyscraper.ListChapters(
workURL,
log,
)
if err != nil {
return sourcetypes.Work{}, nil, err
}

entries := make(
[]sourcetypes.Entry,
0,
len(chapters),
)

for _, chapter := range chapters {
entries = append(
entries,
sourcetypes.Entry{
Number: chapter.Number,
Label: chapter.Label,
URL: chapter.URL,
},
)
}

return sourcetypes.Work{
Title: mangaTitleFromURL(workURL),
Kind: sourcetypes.ItemChapter,
}, entries, nil
}

func (p *Provider) GetPageImageURLs(
entryURL string,
log *logger.Logger,
) ([]string, error) {
return mangavyvyscraper.GetPageImageURLs(
entryURL,
p.domain,
log,
)
}
51 changes: 51 additions & 0 deletions internal/source/mangavyvy/scraper/catalog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package mangavyvyscraper

import (
"github.com/EliasLd/goweeb/internal/logger"
"github.com/EliasLd/goweeb/internal/source/common"
)

type MangaResult struct {
Title string
URL string
}

func SearchCatalog(
domain string,
query string,
log *logger.Logger,
) ([]MangaResult, error) {
items, err := common.SearchHTMLCatalog(
common.CatalogSearchConfig{
Domain: domain,
EndpointPath: "/search",
QueryParam: "q",
CardSelector: ".book-list .comic-item",
LinkSelector: `a[href^="/manga/"]`,
TitleSelector: ".comic-title",
},
query,
log,
)
if err != nil {
return nil, err
}

results := make(
[]MangaResult,
0,
len(items),
)

for _, item := range items {
results = append(
results,
MangaResult{
Title: item.Label,
URL: item.Value,
},
)
}

return results, nil
}
Loading
Loading