2023-03-28 21:55:37 +09:00
|
|
|
package pages
|
|
|
|
|
|
|
|
import (
|
2023-03-30 04:01:15 +09:00
|
|
|
"bufio"
|
|
|
|
"bytes"
|
2023-04-29 02:08:04 +09:00
|
|
|
"codeberg.org/gothub/gothub/utils"
|
2023-03-30 04:01:15 +09:00
|
|
|
"context"
|
|
|
|
htmlfmt "github.com/alecthomas/chroma/v2/formatters/html"
|
|
|
|
"github.com/alecthomas/chroma/v2/lexers"
|
|
|
|
"github.com/alecthomas/chroma/v2/styles"
|
|
|
|
"github.com/carlmjohnson/requests"
|
2023-03-28 21:55:37 +09:00
|
|
|
"github.com/gocolly/colly"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
2023-03-30 04:01:15 +09:00
|
|
|
"html/template"
|
2023-03-28 21:55:37 +09:00
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
2023-03-30 04:01:15 +09:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2023-03-28 21:55:37 +09:00
|
|
|
)
|
|
|
|
|
|
|
|
type Gist struct {
|
2023-04-22 23:59:08 +09:00
|
|
|
Fullname string
|
|
|
|
Refname string
|
|
|
|
Description string
|
|
|
|
Revision string
|
|
|
|
Parent string
|
|
|
|
Stars string
|
|
|
|
Forks string
|
2023-03-28 21:55:37 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
type GistFiles struct {
|
|
|
|
Name string
|
2023-03-30 04:01:15 +09:00
|
|
|
File template.HTML
|
|
|
|
Css template.CSS
|
2023-03-28 21:55:37 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
func HandleGist(c *fiber.Ctx) error {
|
|
|
|
var gistArray []Gist
|
|
|
|
var gistFilesArray []GistFiles
|
|
|
|
|
2023-04-01 19:17:08 +09:00
|
|
|
resp, statusErr := http.Get("https://gists.github.com/" + c.Params("user") + "/" + c.Params("gistID"))
|
2023-03-28 21:55:37 +09:00
|
|
|
if statusErr != nil {
|
|
|
|
log.Println(statusErr)
|
|
|
|
}
|
|
|
|
if resp.StatusCode == 404 {
|
|
|
|
// I need a better way to do this
|
|
|
|
return c.Status(404).Render("error", fiber.Map{
|
|
|
|
"title": "Error",
|
2023-04-01 19:17:08 +09:00
|
|
|
"error": "Gist repository " + c.Params("user") + "/" + c.Params("gistID") + " not found",
|
2023-03-28 21:55:37 +09:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scraping
|
|
|
|
Scrape := Gist{}
|
|
|
|
|
|
|
|
UserAgent, ok := os.LookupEnv("GOTHUB_USER_AGENT")
|
|
|
|
if !ok {
|
|
|
|
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
|
|
|
|
}
|
|
|
|
|
|
|
|
sc := colly.NewCollector(colly.AllowedDomains("gist.github.com"), colly.UserAgent(UserAgent))
|
|
|
|
|
|
|
|
sc.OnHTML("div.gisthead", func(e *colly.HTMLElement) {
|
2023-04-01 19:17:08 +09:00
|
|
|
Scrape.Refname = c.Params("user") + "/" + c.Params("gistID")
|
|
|
|
Scrape.Fullname = c.Params("user") + "/" + e.ChildText("a[href='/"+c.Params("user")+"/"+c.Params("gistID")+"' i]")
|
2023-04-01 04:56:14 +09:00
|
|
|
dl := e.ChildAttr("a[href$='.zip']", "href")
|
2023-04-22 23:59:08 +09:00
|
|
|
Scrape.Revision = dl[strings.LastIndex(dl, "/")+1 : len(dl)-len(".zip")]
|
2023-04-01 19:17:08 +09:00
|
|
|
Scrape.Stars = e.ChildText("li a[href*='/" + c.Params("user") + "/" + c.Params("gistID") + "/stargazers' i]")
|
2023-03-28 21:55:37 +09:00
|
|
|
Scrape.Parent = e.ChildText("span.note a")
|
|
|
|
Scrape.Forks = e.ChildText("li span.social-count")
|
|
|
|
// I need a better way to do this
|
|
|
|
if Scrape.Forks == "" {
|
2023-04-01 19:17:08 +09:00
|
|
|
Scrape.Forks = e.ChildText("li a[href*='/" + c.Params("user") + "/" + c.Params("gistID") + "/forks' i]")
|
2023-03-28 21:55:37 +09:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
sc.OnHTML("div[itemprop='about']", func(e *colly.HTMLElement) {
|
|
|
|
Scrape.Description = e.Text
|
|
|
|
})
|
|
|
|
|
|
|
|
sc.OnHTML("div.repository-content.gist-content", func(e *colly.HTMLElement) {
|
2023-03-30 04:01:15 +09:00
|
|
|
e.ForEach("div.file-header", func(i int, el *colly.HTMLElement) {
|
|
|
|
var file string
|
2023-04-06 10:40:23 +09:00
|
|
|
url := "https://gist.github.com" + el.ChildAttr("div.file-actions a.Button", "href")
|
2023-03-30 04:01:15 +09:00
|
|
|
err := requests.
|
|
|
|
URL(url).
|
|
|
|
ToString(&file).
|
|
|
|
Fetch(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
lexer := lexers.Match(el.ChildText("strong.user-select-contain.gist-blob-name.css-truncate-target"))
|
|
|
|
if lexer == nil {
|
|
|
|
lexer = lexers.Fallback
|
|
|
|
}
|
|
|
|
formatter := htmlfmt.New(
|
|
|
|
htmlfmt.WithClasses(true),
|
|
|
|
htmlfmt.ClassPrefix(strings.TrimPrefix(filepath.Ext(el.ChildText("strong.user-select-contain.gist-blob-name.css-truncate-target")), ".")),
|
|
|
|
htmlfmt.WithLineNumbers(true),
|
|
|
|
htmlfmt.PreventSurroundingPre(false),
|
|
|
|
)
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
writer := bufio.NewWriter(&buf)
|
|
|
|
style := styles.Get("native")
|
|
|
|
|
|
|
|
tokens, err := lexer.Tokenise(nil, file)
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
formatter.Format(writer, style, tokens)
|
|
|
|
cssbuf := bytes.Buffer{}
|
|
|
|
cssw := bufio.NewWriter(&cssbuf)
|
|
|
|
formatter.WriteCSS(cssw, style)
|
|
|
|
cssw.Flush()
|
|
|
|
writer.Flush()
|
|
|
|
|
|
|
|
fileFmt := template.HTML(buf.String())
|
|
|
|
cssFmt := template.CSS(cssbuf.String())
|
|
|
|
|
2023-03-28 21:55:37 +09:00
|
|
|
gistFilesArray = append(gistFilesArray, GistFiles{
|
2023-03-30 04:01:15 +09:00
|
|
|
Name: el.ChildText("strong.user-select-contain.gist-blob-name.css-truncate-target"),
|
|
|
|
File: fileFmt,
|
|
|
|
Css: cssFmt,
|
2023-03-28 21:55:37 +09:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2023-04-01 19:17:08 +09:00
|
|
|
sc.Visit("https://gist.github.com/" + c.Params("user") + "/" + c.Params("gistID") + "/")
|
2023-03-28 21:55:37 +09:00
|
|
|
// Add scrape-based info to gistArray
|
|
|
|
gistArray = append(gistArray, Scrape)
|
|
|
|
|
|
|
|
return c.Render("gist", fiber.Map{
|
2023-04-29 02:08:04 +09:00
|
|
|
"title": "Repository " + c.Params("user") + "/" + c.Params("gistID"),
|
|
|
|
"branch": utils.Branch,
|
|
|
|
"gist": gistArray,
|
|
|
|
"files": gistFilesArray,
|
2023-03-28 21:55:37 +09:00
|
|
|
})
|
|
|
|
}
|