package routes import ( "archive/zip" "bytes" "encoding/json" "encoding/xml" "errors" "frostfire.io/dir2opdspse/app/opds" "frostfire.io/dir2opdspse/app/utils" "github.com/gorilla/mux" "github.com/urfave/cli/v2" "io" "log" "net/http" "os" "path" "regexp" "slices" "strconv" "time" ) func Init(c *cli.Context, r *mux.Router) { r.HandleFunc("/", Home).Methods("GET") r.HandleFunc("/stream/{manga}/{page}", Stream).Methods("GET") r.HandleFunc("/test/{path:.*}/{page}", Test).Methods("GET") } func Home(w http.ResponseWriter, r *http.Request) { feed := opds.FeedBuilder. ID("dir2opds"). Title("dir2OPDS"). Updated(time.Now()). AddLink(opds.LinkBuilder. Rel("start"). Href("/"). Type("application/atom+xml;profile=opds-catalog;kind=navigation"). Build()) dirEntries, _ := os.ReadDir("books") for _, entry := range dirEntries { if !entry.IsDir() { zFile, _ := zip.OpenReader(path.Join("books", entry.Name())) //zCount := len(zFile.File) _ = zFile.Close() feed = feed.AddEntry(opds.EntryBuilder. ID(utils.FileBasename(entry.Name())). Title(utils.FileBasename(entry.Name())). AddLink(opds.LinkBuilder. Rel("http://opds-spec.org/acquisition"). Href("/manga/" + entry.Name()). Type("application/x-cbz"). Title(utils.FileBasename(entry.Name())). Build()). AddLink(opds.LinkBuilder. Rel("http://opds-spec.org/image"). Href("/stream/" + entry.Name() + "/0"). Type("image/png"). Build()). AddLink(opds.LinkBuilder. Rel("http://opds-spec.org/image/thumbnail"). Href("/stream/" + entry.Name() + "/0"). Type("image/png"). Build()). AddLink(opds.LinkBuilder. Rel("http://vaemendis.net/opds-pse/stream"). Href("/stream/" + entry.Name() + "/{pageNumber}"). Type("image/png"). //PseCount(10). Build()). Build()) } } data, err := xml.MarshalIndent(feed.Build(), "", " ") if err != nil { panic(err) } http.ServeContent(w, r, "feed.xml", time.Now(), bytes.NewReader(data)) } func Stream(w http.ResponseWriter, r *http.Request) { re := regexp.MustCompile(`(\d+)(.*)`) vars := mux.Vars(r) if len(re.FindStringIndex(vars["page"])) <= 0 { w.WriteHeader(404) return } pageNumber := re.FindStringSubmatch(vars["page"])[1] mangaPath := path.Join("books", vars["manga"]) if _, err := os.Stat(mangaPath); errors.Is(err, os.ErrNotExist) { w.WriteHeader(404) return } zf, err := zip.OpenReader(mangaPath) if err != nil { log.Fatal(err) } pageIndex := slices.IndexFunc(zf.File, func(f *zip.File) bool { page, _ := strconv.Atoi(pageNumber) return f.Name == (strconv.Itoa(page+1) + ".png") }) if pageIndex == -1 { w.WriteHeader(404) return } imf, _ := zf.File[pageIndex].Open() imageBytes, _ := io.ReadAll(imf) _ = imf.Close() _ = zf.Close() http.ServeContent(w, r, zf.File[0].Name, time.Now(), bytes.NewReader(imageBytes)) } func Test(w http.ResponseWriter, r *http.Request) { data, _ := json.MarshalIndent(r.URL, "", " ") http.ServeContent(w, r, "data.json", time.Now(), bytes.NewReader(data)) }