Naming refactor. Added comments.
This commit is contained in:
parent
a3cf924918
commit
fc0e662409
18
cache.go
18
cache.go
|
@ -11,15 +11,18 @@ import (
|
||||||
|
|
||||||
var cacheEnabled bool = true
|
var cacheEnabled bool = true
|
||||||
|
|
||||||
|
// EnableCache enables request caching for reads
|
||||||
func EnableCache() {
|
func EnableCache() {
|
||||||
cacheEnabled = true
|
cacheEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisableCache disables cache reads
|
||||||
func DisableCache() {
|
func DisableCache() {
|
||||||
cacheEnabled = false
|
cacheEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCachePath() string {
|
// getBaseCachePath returns the base path for the cache storage
|
||||||
|
func getBaseCachePath() string {
|
||||||
userCacheDir, errCache := os.UserCacheDir()
|
userCacheDir, errCache := os.UserCacheDir()
|
||||||
if errCache != nil {
|
if errCache != nil {
|
||||||
logrus.Fatalf("Unable to retrieve cache directory: %s", errCache)
|
logrus.Fatalf("Unable to retrieve cache directory: %s", errCache)
|
||||||
|
@ -27,25 +30,30 @@ func getCachePath() string {
|
||||||
return filepath.Join(userCacheDir, "go-mangadex")
|
return filepath.Join(userCacheDir, "go-mangadex")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCachePathFor(mangadexURL *url.URL) string {
|
// getCachePath returns the absolute path to the files cache for the provided URL
|
||||||
|
func getCachePath(mangadexURL *url.URL) string {
|
||||||
fileName := getCacheFilename(mangadexURL)
|
fileName := getCacheFilename(mangadexURL)
|
||||||
return filepath.Join(getCachePath(), fileName)
|
return filepath.Join(getBaseCachePath(), fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getCacheFilename generates a cache filename based on the URL of the request
|
||||||
|
// TODO: Use query arguments as well
|
||||||
func getCacheFilename(mangadexURL *url.URL) string {
|
func getCacheFilename(mangadexURL *url.URL) string {
|
||||||
return strings.ReplaceAll(mangadexURL.Path, "/", "_")
|
return strings.ReplaceAll(mangadexURL.Path, "/", "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cacheExists checks that the cache for a certain URL exists or not
|
||||||
func cacheExists(mangadexURL *url.URL) bool {
|
func cacheExists(mangadexURL *url.URL) bool {
|
||||||
stat, err := os.Stat(getCachePathFor(mangadexURL))
|
stat, err := os.Stat(getCachePath(mangadexURL))
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return !stat.IsDir()
|
return !stat.IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initCache makes sure that the cache directory exists so reads and writes on cache folders won't fail
|
||||||
func initCache() {
|
func initCache() {
|
||||||
cachePath := getCachePath()
|
cachePath := getBaseCachePath()
|
||||||
_, err := os.Stat(cachePath)
|
_, err := os.Stat(cachePath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
logrus.Infof("Cache directory does not exist, creating. [%s]", cachePath)
|
logrus.Infof("Cache directory does not exist, creating. [%s]", cachePath)
|
||||||
|
|
14
http.go
14
http.go
|
@ -11,19 +11,18 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APIBaseURL = "https://api.mangadex.org/v2/"
|
const apiBaseURL = "https://api.mangadex.org/v2/"
|
||||||
|
|
||||||
func doRequest(method string, requestURL string) (*MangaDexResponse, error) {
|
func doRequest(method string, requestURL string) (*Response, error) {
|
||||||
result := MangaDexResponse{}
|
result := Response{}
|
||||||
parsedURL, errParse := url.Parse(requestURL)
|
parsedURL, errParse := url.Parse(requestURL)
|
||||||
if errParse != nil {
|
if errParse != nil {
|
||||||
return &result, errParse
|
return &result, errParse
|
||||||
}
|
}
|
||||||
|
|
||||||
if cacheEnabled {
|
if cacheEnabled {
|
||||||
initCache()
|
|
||||||
if cacheExists(parsedURL) {
|
if cacheExists(parsedURL) {
|
||||||
cacheData, errRead := ioutil.ReadFile(getCachePathFor(parsedURL))
|
cacheData, errRead := ioutil.ReadFile(getCachePath(parsedURL))
|
||||||
if errRead != nil {
|
if errRead != nil {
|
||||||
logrus.Fatalf("Error reading cache for URL: %s [%s]: %s", parsedURL.String(), getCacheFilename(parsedURL), errRead)
|
logrus.Fatalf("Error reading cache for URL: %s [%s]: %s", parsedURL.String(), getCacheFilename(parsedURL), errRead)
|
||||||
}
|
}
|
||||||
|
@ -33,9 +32,8 @@ func doRequest(method string, requestURL string) (*MangaDexResponse, error) {
|
||||||
}
|
}
|
||||||
logrus.Debugf("Request loaded from cache: %s", parsedURL.String())
|
logrus.Debugf("Request loaded from cache: %s", parsedURL.String())
|
||||||
return &result, nil
|
return &result, nil
|
||||||
} else {
|
|
||||||
logrus.Debugf("Cache not found for %s", parsedURL.String())
|
|
||||||
}
|
}
|
||||||
|
logrus.Debugf("Cache not found for %s", parsedURL.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Tracef("Making request %s", parsedURL)
|
logrus.Tracef("Making request %s", parsedURL)
|
||||||
|
@ -76,7 +74,7 @@ func doRequest(method string, requestURL string) (*MangaDexResponse, error) {
|
||||||
// Write cache
|
// Write cache
|
||||||
logrus.Infof("Writting cache for %s", parsedURL.String())
|
logrus.Infof("Writting cache for %s", parsedURL.String())
|
||||||
logrus.Infof("Writting cache to: %s", getCacheFilename(parsedURL))
|
logrus.Infof("Writting cache to: %s", getCacheFilename(parsedURL))
|
||||||
errWriteCache := ioutil.WriteFile(getCachePathFor(parsedURL), body, 0644)
|
errWriteCache := ioutil.WriteFile(getCachePath(parsedURL), body, 0644)
|
||||||
if errWriteCache != nil {
|
if errWriteCache != nil {
|
||||||
logrus.Warnf("Can't write to cache: %s", errWriteCache)
|
logrus.Warnf("Can't write to cache: %s", errWriteCache)
|
||||||
}
|
}
|
||||||
|
|
11
public.go
11
public.go
|
@ -16,13 +16,13 @@ func (manga *Manga) GetChapters(params ChaptersParams) ([]MangaChapterList, []Ma
|
||||||
var mangaGroupsResult []MangaGroup
|
var mangaGroupsResult []MangaGroup
|
||||||
params.validate()
|
params.validate()
|
||||||
|
|
||||||
response, errRequest := doRequest("GET", APIBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "chapters")+"?"+params.asQueryParams().Encode())
|
response, errRequest := doRequest("GET", apiBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "chapters")+"?"+params.asQueryParams().Encode())
|
||||||
if errRequest != nil {
|
if errRequest != nil {
|
||||||
logrus.Errorf("Request error: %s", errRequest)
|
logrus.Errorf("Request error: %s", errRequest)
|
||||||
return mangaChaptersResult, mangaGroupsResult, errRequest
|
return mangaChaptersResult, mangaGroupsResult, errRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
var mangaDexChaptersResponse MangaDexChaptersResponse
|
var mangaDexChaptersResponse ChaptersResponse
|
||||||
|
|
||||||
errJSON := json.Unmarshal(response.Data, &mangaDexChaptersResponse)
|
errJSON := json.Unmarshal(response.Data, &mangaDexChaptersResponse)
|
||||||
if errJSON != nil {
|
if errJSON != nil {
|
||||||
|
@ -39,7 +39,7 @@ func (manga *Manga) GetChapters(params ChaptersParams) ([]MangaChapterList, []Ma
|
||||||
func (manga *Manga) GetChapter(chapter string) (MangaChapterDetail, error) {
|
func (manga *Manga) GetChapter(chapter string) (MangaChapterDetail, error) {
|
||||||
var result MangaChapterDetail
|
var result MangaChapterDetail
|
||||||
|
|
||||||
response, errRequest := doRequest("GET", APIBaseURL+path.Join("chapter", chapter))
|
response, errRequest := doRequest("GET", apiBaseURL+path.Join("chapter", chapter))
|
||||||
if errRequest != nil {
|
if errRequest != nil {
|
||||||
logrus.Errorf("Request error: %s", errRequest)
|
logrus.Errorf("Request error: %s", errRequest)
|
||||||
return result, errRequest
|
return result, errRequest
|
||||||
|
@ -57,7 +57,7 @@ func (manga *Manga) GetChapter(chapter string) (MangaChapterDetail, error) {
|
||||||
// GetCovers requests the covers for the provided manga
|
// GetCovers requests the covers for the provided manga
|
||||||
func (manga *Manga) GetCovers() ([]MangaCover, error) {
|
func (manga *Manga) GetCovers() ([]MangaCover, error) {
|
||||||
var result []MangaCover
|
var result []MangaCover
|
||||||
response, errRequest := doRequest("GET", APIBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "covers"))
|
response, errRequest := doRequest("GET", apiBaseURL+path.Join("manga", strconv.Itoa(manga.ID), "covers"))
|
||||||
if errRequest != nil {
|
if errRequest != nil {
|
||||||
logrus.Errorf("Request error: %s", errRequest)
|
logrus.Errorf("Request error: %s", errRequest)
|
||||||
return result, errRequest
|
return result, errRequest
|
||||||
|
@ -73,8 +73,9 @@ func (manga *Manga) GetCovers() ([]MangaCover, error) {
|
||||||
|
|
||||||
// GetManga retrieves the manga information for the provided ID.
|
// GetManga retrieves the manga information for the provided ID.
|
||||||
func GetManga(mangaID int) (Manga, error) {
|
func GetManga(mangaID int) (Manga, error) {
|
||||||
|
initCache()
|
||||||
result := Manga{}
|
result := Manga{}
|
||||||
response, errRequest := doRequest("GET", APIBaseURL+path.Join("manga", strconv.Itoa(mangaID)))
|
response, errRequest := doRequest("GET", apiBaseURL+path.Join("manga", strconv.Itoa(mangaID)))
|
||||||
if errRequest != nil {
|
if errRequest != nil {
|
||||||
logrus.Errorf("Request error: %s", errRequest)
|
logrus.Errorf("Request error: %s", errRequest)
|
||||||
return result, errRequest
|
return result, errRequest
|
||||||
|
|
40
types.go
40
types.go
|
@ -6,7 +6,8 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MangaDexResponse struct {
|
// Response handles the response from MangaDex
|
||||||
|
type Response struct {
|
||||||
// Same as HTTP status code
|
// Same as HTTP status code
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
// `OK` or `error`
|
// `OK` or `error`
|
||||||
|
@ -17,11 +18,19 @@ type MangaDexResponse struct {
|
||||||
Data json.RawMessage `json:"data"`
|
Data json.RawMessage `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MangaDexChaptersResponse struct {
|
// IsOK Checks if the response is correct
|
||||||
|
func (response Response) IsOK() bool {
|
||||||
|
return response.Status == "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChaptersResponse handles the response of the chapters list which returns
|
||||||
|
// two kinds of objects in the `json:"data"` key.
|
||||||
|
type ChaptersResponse struct {
|
||||||
Chapters []MangaChapterList `json:"chapters"`
|
Chapters []MangaChapterList `json:"chapters"`
|
||||||
Groups []MangaGroup `json:"groups"`
|
Groups []MangaGroup `json:"groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaRelation relations between mangas
|
||||||
type MangaRelation struct {
|
type MangaRelation struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
IsHentai bool `json:"isHentai"`
|
IsHentai bool `json:"isHentai"`
|
||||||
|
@ -29,6 +38,8 @@ type MangaRelation struct {
|
||||||
Type int `json:"type"`
|
Type int `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaPublication stores certain information for the publication of the manga
|
||||||
|
// Some values are easily guessed, others are not ...
|
||||||
type MangaPublication struct {
|
type MangaPublication struct {
|
||||||
// ???
|
// ???
|
||||||
Demographic int8 `json:"demographic"`
|
Demographic int8 `json:"demographic"`
|
||||||
|
@ -37,12 +48,19 @@ type MangaPublication struct {
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsComplete returns if the manga has finished publishing
|
||||||
|
func (publication MangaPublication) IsComplete() bool {
|
||||||
|
return publication.Status == 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// MangaRating the rating for a particular manga
|
||||||
type MangaRating struct {
|
type MangaRating struct {
|
||||||
Bayesian float32 `json:"bayesian"`
|
Bayesian float32 `json:"bayesian"`
|
||||||
Mean float32 `json:"mean"`
|
Mean float32 `json:"mean"`
|
||||||
Users int `json:"users"`
|
Users int `json:"users"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaLinks contains the relation of the links map with more verbose names
|
||||||
type MangaLinks struct {
|
type MangaLinks struct {
|
||||||
AniList string `json:"al"`
|
AniList string `json:"al"`
|
||||||
AnimePlanet string `json:"ap"`
|
AnimePlanet string `json:"ap"`
|
||||||
|
@ -56,6 +74,7 @@ type MangaLinks struct {
|
||||||
EnglishRaw string `json:"engtl"`
|
EnglishRaw string `json:"engtl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manga stores the base manga object and details
|
||||||
type Manga struct {
|
type Manga struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
AlternativeTitles []string `json:"altTitles"`
|
AlternativeTitles []string `json:"altTitles"`
|
||||||
|
@ -78,11 +97,13 @@ type Manga struct {
|
||||||
Views int `json:"views"`
|
Views int `json:"views"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaCover stores the cover object
|
||||||
type MangaCover struct {
|
type MangaCover struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Volume string `json:"volume"`
|
Volume string `json:"volume"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaChapterBase the base attributes for a chapter for both the list and the detail
|
||||||
type MangaChapterBase struct {
|
type MangaChapterBase struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
|
@ -99,11 +120,15 @@ type MangaChapterBase struct {
|
||||||
Views int `json:"views"`
|
Views int `json:"views"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaChapterList stores the chapter object from the listing, which only uses the
|
||||||
|
// base details and uses the ID for the groups instead of returning the entire object
|
||||||
type MangaChapterList struct {
|
type MangaChapterList struct {
|
||||||
MangaChapterBase
|
MangaChapterBase
|
||||||
Groups []int `json:"groups"`
|
Groups []int `json:"groups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaChapterDetail stores the bases of a chapter plus the required attributes
|
||||||
|
// to retrieve the page blobs
|
||||||
type MangaChapterDetail struct {
|
type MangaChapterDetail struct {
|
||||||
MangaChapterBase
|
MangaChapterBase
|
||||||
Groups []MangaGroup `json:"groups"`
|
Groups []MangaGroup `json:"groups"`
|
||||||
|
@ -113,11 +138,13 @@ type MangaChapterDetail struct {
|
||||||
ServerFallback string `json:"serverFallback"`
|
ServerFallback string `json:"serverFallback"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaGroupMember stores the member of a group
|
||||||
type MangaGroupMember struct {
|
type MangaGroupMember struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MangaGroup stores the group behind releases of a particular manga
|
||||||
type MangaGroup struct {
|
type MangaGroup struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -145,12 +172,17 @@ type MangaGroup struct {
|
||||||
Banner string `json:"banner"`
|
Banner string `json:"banner"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChaptersParams the request parameters for the chapters listing
|
||||||
type ChaptersParams struct {
|
type ChaptersParams struct {
|
||||||
Limit int `json:"limit"`
|
// How many items per page (max 100)
|
||||||
Page int `json:"p"`
|
Limit int `json:"limit"`
|
||||||
|
// Page to retrieve (default 0)
|
||||||
|
Page int `json:"p"`
|
||||||
|
// Hide groups blocked by the user (auth not implemented)
|
||||||
BlockGroups bool `json:"blockgroups"`
|
BlockGroups bool `json:"blockgroups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewChaptersParams returns a ChapterParams object with sensible defaults
|
||||||
func NewChaptersParams() ChaptersParams {
|
func NewChaptersParams() ChaptersParams {
|
||||||
return ChaptersParams{
|
return ChaptersParams{
|
||||||
Limit: 100,
|
Limit: 100,
|
||||||
|
|
Loading…
Reference in New Issue