<commit_before>package main

//go:generate go-bindata-assetfs static/...

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

// DownloadHandler handles file download
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	bid := filepath.Base(r.URL.Path)
	bid = strings.Replace(bid, filepath.Ext(bid), "", 1)

	if bid == "download" {
		w.Header().Set("Content-Type", "text/html")
		for _, b := range books {
			io.WriteString(w, fmt.Sprintf("<a href=\"/download/%s\">%s</a><br>", b.ID, b.Title))
		}
		return
	}

	for _, b := range books {
		if b.ID == bid {
			rd, err := os.Open(b.Filepath)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				io.WriteString(w, "Error handling request")
				log.Printf("Error handling request for %s: %s\n", r.URL.Path, err)
			}

			w.Header().Set("Content-Disposition", "attachment; filename="+url.PathEscape(b.Title)+".epub")
			w.Header().Set("Content-Type", "application/epub+zip")
			_, err = io.Copy(w, rd)
			rd.Close()
			if err != nil {
				log.Printf("Error handling request for %s: %s\n", r.URL.Path, err)
			}
			return
		}
	}

	w.WriteHeader(http.StatusNotFound)
	io.WriteString(w, pageHTML("Not Found", "Could not find book with id "+bid))
}

// AuthorsHandler handles the authors page
func AuthorsHandler(w http.ResponseWriter, r *http.Request) {
	aid := filepath.Base(r.URL.Path)

	if aid == "authors" {
		w.Header().Set("Content-Type", "text/html")
		var listHTML bytes.Buffer
		doneAuthors := map[string]bool{}
		for _, b := range books {
			if doneAuthors[b.AuthorID] {
				continue
			}
			doneAuthors[b.AuthorID] = true
			listHTML.WriteString(itemCardHTML(b.Author, "", "/authors/"+b.AuthorID))
		}
		io.WriteString(w, pageHTML("Authors", listHTML.String()))
		return
	}

	found := false
	w.Header().Set("Content-Type", "text/html")
	var booksHTML bytes.Buffer
	booksHTML.WriteString(`<div class="books cards">`)
	aname := ""
	for _, b := range books {
		if b.AuthorID == aid {
			aname = b.Author
			booksHTML.WriteString(bookHTML(&b, true))
			found = true
		}
	}
	booksHTML.WriteString(`</div>`)
	if found != true {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, pageHTML("Not Found", "Could not find author with id "+aid))
	}
	io.WriteString(w, pageHTML(aname, booksHTML.String()))
}

// SeriesHandler handles the series page
func SeriesHandler(w http.ResponseWriter, r *http.Request) {
	sid := filepath.Base(r.URL.Path)
<commit_msg>Sort books on author page alphabetically<commit_after>package main

//go:generate go-bindata-assetfs static/...

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"math/rand"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"time"
)

// DownloadHandler handles file download
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	bid := filepath.Base(r.URL.Path)
	bid = strings.Replace(bid, filepath.Ext(bid), "", 1)

	if bid == "download" {
		w.Header().Set("Content-Type", "text/html")
		for _, b := range books {
			io.WriteString(w, fmt.Sprintf("<a href=\"/download/%s\">%s</a><br>", b.ID, b.Title))
		}
		return
	}

	for _, b := range books {
		if b.ID == bid {
			rd, err := os.Open(b.Filepath)
			if err != nil {
				w.WriteHeader(http.StatusInternalServerError)
				io.WriteString(w, "Error handling request")
				log.Printf("Error handling request for %s: %s\n", r.URL.Path, err)
			}

			w.Header().Set("Content-Disposition", "attachment; filename="+url.PathEscape(b.Title)+".epub")
			w.Header().Set("Content-Type", "application/epub+zip")
			_, err = io.Copy(w, rd)
			rd.Close()
			if err != nil {
				log.Printf("Error handling request for %s: %s\n", r.URL.Path, err)
			}
			return
		}
	}

	w.WriteHeader(http.StatusNotFound)
	io.WriteString(w, pageHTML("Not Found", "Could not find book with id "+bid))
}

// AuthorsHandler handles the authors page
func AuthorsHandler(w http.ResponseWriter, r *http.Request) {
	aid := filepath.Base(r.URL.Path)

	if aid == "authors" {
		w.Header().Set("Content-Type", "text/html")
		var listHTML bytes.Buffer
		doneAuthors := map[string]bool{}
		for _, b := range books {
			if doneAuthors[b.AuthorID] {
				continue
			}
			doneAuthors[b.AuthorID] = true
			listHTML.WriteString(itemCardHTML(b.Author, "", "/authors/"+b.AuthorID))
		}
		io.WriteString(w, pageHTML("Authors", listHTML.String()))
		return
	}

	found := false
	w.Header().Set("Content-Type", "text/html")
	var booksHTML bytes.Buffer
	booksHTML.WriteString(`<div class="books cards">`)
	aname := ""
	matched := []Book{}
	for _, b := range books {
		if b.AuthorID == aid {
			aname = b.Author
			matched = append(matched, b)
			found = true
		}
	}
	sort.Slice(matched, func(i, j int) bool {
		return matched[i].Title < matched[j].Title
	})
	for _, b := range matched {
		booksHTML.WriteString(bookHTML(&b, true))
	}
	booksHTML.WriteString(`</div>`)
	if found != true {
		w.WriteHeader(http.StatusNotFound)
		io.WriteString(w, pageHTML("Not Found", "Could not find author with id "+aid))
	}
	io.WriteString(w, pageHTML(aname, booksHTML.String()))
}

// SeriesHandler handles the series page
func SeriesHandler(w http.ResponseWriter, r *http.Request) {
	sid := filepath.Base(r.URL.Path)

{'fraction_non_alphanumeric': 0.1729123073996576, 'fraction_numerical': 0.00038044512079132587, 'mean_word_length': 3.7974452554744524, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1481354', 'n_tokens_mistral': 2057, 'n_tokens_neox': 1898, 'n_words': 418}