merge dev into master

This commit is contained in:
Arya Kiran
2024-07-19 20:05:04 +05:30
28 changed files with 893 additions and 191 deletions
+46
View File
@@ -0,0 +1,46 @@
---
name: Bug report
about: Create a bug report to help us improve Invidious
title: "[Bug] "
labels: bug
assignees: ""
---
<!--
BEFORE TRYING TO REPORT A BUG:
* Use the search function to check if there is already an issue open for your problem!
* Read the docs (docs.gothub.app)
If you want to suggest a new feature please use "Feature request" instead
If you want to suggest an enhancement to an existing feature please use "Enhancement" instead
-->
### Describe the bug
<!-- A clear and concise description of what the bug is. -->
### Steps to Reproduce
<!-- Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
### Logs
<!-- If applicable, copy the log that appear in the browser page where the error is reported. -->
### Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
### Additional context
<!-- Add any other context about the problem here.
- Browser (if applicable):
- OS (if applicable):
- Instance: https://gothub.example.com
-->
+27
View File
@@ -0,0 +1,27 @@
---
name: Enhancement
about: Suggest an enhancement for an existing feature
title: "[Enhancement] "
labels: enhancement
assignees: ""
---
<!-- Please use the search function to check if the desired function has already been requested by someone else -->
<!-- If you want to suggest a new feature please use "Feature request" instead -->
<!-- If you want to report a bug, please use "Bug report" instead -->
### Is your enhancement request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. -->
### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
### Additional context
<!-- Add any other context or screenshots about the enhancement here. -->
+27
View File
@@ -0,0 +1,27 @@
---
name: Feature request
about: Suggest an idea for this project
title: "[Feature request] "
labels: feature
assignees: ""
---
<!-- Please use the search function to check if the desired function has already been requested by someone else -->
<!-- If you want to suggest an enhancement to an existing feature please use "Enhancement" instead -->
<!-- If you want to report a bug, please use "Bug report" instead -->
### Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. -->
### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
### Additional context
<!-- Add any other context or screenshots about the feature request here. -->
+6 -1
View File
@@ -48,4 +48,9 @@ body:
label: Contact details
description: Input your contact information should we need to contact you privately. We recommend Matrix. If you don't have a contact method, or don't want your contact method public, tell us.
placeholder: "@foo:example.org"
- type: checkboxes
attributes:
label: Instance Rules
description: I have read and accepted the [instance rules](https://codeberg.org/gothub/gothub#instance-rules)
options:
- label: I have read and accepted the instance rules
+1
View File
@@ -5,6 +5,7 @@ ARG TARGETARCH
WORKDIR /src
RUN apk --no-cache add git
RUN git clone https://codeberg.org/gothub/gothub .
RUN git checkout master
RUN go mod download
RUN GOOS=linux GOARCH=$TARGETARCH go build -o /src/gothub -ldflags="-X codeberg.org/gothub/gothub/utils.Branch=master"
+1
View File
@@ -5,6 +5,7 @@ ARG TARGETARCH
WORKDIR /src
RUN apk --no-cache add git
RUN git clone https://codeberg.org/gothub/gothub .
RUN git checkout dev
RUN go mod download
RUN GOOS=linux GOARCH=$TARGETARCH go build -o /src/gothub -ldflags="-X codeberg.org/gothub/gothub/utils.Branch=dev"
+46 -31
View File
@@ -1,12 +1,15 @@
# GotHub
**GotHub is looking for new maintainers. If you are interested, please checkout [#131](https://codeberg.org/gothub/gothub/issues/131).**
Alternative front-end for GitHub written with Go. (WIP)
[Matrix](https://matrix.to/#/#gothub:matrix.org)
[![Matrix](https://img.shields.io/matrix/gothub:matrix.org?label=Matrix)](https://matrix.to/#/#gothub:matrix.org)
[![Go Report Card](https://goreportcard.com/badge/codeberg.org/gothub/gothub)](https://goreportcard.com/report/codeberg.org/gothub/gothub)
[![Website](https://img.shields.io/website?down_color=red&down_message=offline&up_color=green&up_message=online&url=https%3A%2F%2Fgothub.app)](https://gothub.app)
## Features
- Lightweight - for both you and the instance host
- No JavaScript - pure HTML and CSS goodness
- No requests made to GitHub from the client side - they won't even know you made a request!
@@ -17,45 +20,62 @@ Alternative front-end for GitHub written with Go. (WIP)
Tested with PageSpeed Insights. Using ansible/ansible as a test repo.
| | [GotHub](https://pagespeed.web.dev/analysis/https-gh-dev-odyssey346-dev-ansible-ansible/2430mn1ece?form_factor=mobile) | [GitHub](https://pagespeed.web.dev/analysis/https-github-com-ansible-ansible/maetxu2zat?form_factor=mobile) |
| -------- | ---------- | ----------- |
| Performance | 100 | 81 |
| Requests | 3 | 88 |
| Resource Size | 8kb | 629kb |
| Time to Interactive | 0.9s | 2.7s |
| | [GotHub](https://pagespeed.web.dev/analysis/https-gh-psf-lt-ansible-ansible/6ssup87ipo?form_factor=mobile) | [GitHub](https://pagespeed.web.dev/analysis/https-github-com-ansible-ansible/maetxu2zat?form_factor=mobile) |
| ------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Performance | 100 | 81 |
| Requests | 3 | 88 |
| Resource Size | 8kb | 629kb |
| Time to Interactive | 0.9s | 2.7s |
Quite the difference, isn't it?
## Instances
### Difference between branches
The ``master`` branch runs on the master branch of GotHub. This means that the instance is running a stable, tested version of GotHub that doesn't get updated as much as ``dev``. Doesn't mean they're bad, though.
``dev`` instances run on the dev branch of GotHub. This might mean they are more up-to-date than other instances, but at the same time, they might not be (instance admin might not always update their instance, no auto-updates etc.). You can get the latest and greatest straight out of Git, but you could meet on bugs and other nasty things.
| Link | Cloudflare | Country | ISP | Branch |
| -------- | ---------- | ----------- | ----- | ----- |
| [gh.akisblack.dev](https://gh.akisblack.dev) | No | Germany | OVHcloud | master |
| [gh.odyssey346.dev](https://gh.odyssey346.dev) | No | France | OVHcloud (Trolling Solutions) | master |
| [gh.phreedom.club](https://gh.phreedom.club) | No | Iceland | Flokinet | master |
| [gothub.projectsegfau.lt](https://gothub.projectsegfau.lt) | No | GeoDNS (Luxembourg/USA/India) | BuyVM/Digital Ocean/Airtel | master |
| [gh.riverside.rocks](https://gh.riverside.rocks) | No | USA | Comcast | master |
| [gh.fascinated.cc](https://gh.fascinated.cc) | Yes | Germany | Contabo | master |
| [gothub.lunar.icu](https://gothub.lunar.icu) | Yes | Germany | Unesty | master |
| [gothub.xbdm.fun](https://gothub.xbdm.fun) | Yes | Germany | Hetzner | master |
| [dev.gh.akisblack.dev](https://dev.gh.akisblack.dev) | No | Germany | OVHcloud | dev |
| [gh.creller.net](https://gh.creller.net) | No | Scotland | British Telecommunications PLC | dev |
| [gothub.esmailelbob.xyz](https://gothub.esmailelbob.xyz) | No | Canada | OVHcloud | dev |
| [gothub.no-logs.com](https://gothub.no-logs.com/) | No | Sweden | Vultr | dev |
| [gh.dev.odyssey346.dev](https://gh.dev.odyssey346.dev) | No | France | OVHcloud (Trolling Solutions) | dev |
| [gothub.dev.projectsegfau.lt](https://gothub.dev.projectsegfau.lt) | No | Luxembourg | BuyVM | dev |
### Difference between branches
The `master` branch runs on the master branch of GotHub. This means that the instance is running a stable, tested version of GotHub that doesn't get updated as much as `dev`. Doesn't mean they're bad, though.
`dev` instances run on the dev branch of GotHub. This might mean they are more up-to-date than other instances, but at the same time, they might not be (instance admin might not always update their instance, no auto-updates etc.). You can get the latest and greatest straight out of Git, but you could meet on bugs and other nasty things.
| Link | Tor | Cloudflare | Country | ISP | Branch |
| -------- | -------- | ---------- | ----------- | ----- | ----- |
| [gh.bloatcat.tk](https://gh.bloatcat.tk) | No | No | Iceland | 1984 | master |
| [gothub.frontendfriendly.xyz](https://gothub.frontendfriendly.xyz) | No | No | USA | Hetzner | master |
| [gothub.hyperreal.coffee](https://gh.hyperreal.coffee) | No | No | USA | Linode | master |
| [gothub.lunar.icu](https://gothub.lunar.icu) | No | No | Germany | Avoro | master |
| [gothub.no-logs.com](https://gothub.no-logs.com/) | No | No | Sweden | Vultr | master |
| [g.opnxng.com](https://g.opnxng.com/) | No | No | Singapore | Vultr | master |
| [gh.owo.si](https://gh.owo.si/) | [Yes](http://gh.pk47sgwhncn5cgidm7bofngmh7lc7ukjdpk5bjwfemmyp27ovl25ikyd.onion/) | No | Germany | Contabo | master |
| [gothub.projectsegfau.lt](https://gothub.projectsegfau.lt) | [Yes](http://gothub.pjsfkvpxlinjamtawaksbnnaqs2fc2mtvmozrzckxh7f3kis6yea25ad.onion/) | No | GeoDNS (Germany/USA/India) | Avoro/Racknerd/Airtel | master |
| [gh.whateveritworks.org](https://gh.whateveritworks.org) | No | No | Germany | Hetzner | master |
| [gothub.r4fo.com](https://gothub.r4fo.com) | [Yes](http://gothub.r4focoma7gu2zdwwcjjad47ysxt634lg73sxmdbkdozanwqslho5ohyd.onion/) | No | Netherlands | Oracle | master |
| [gothub.dev.projectsegfau.lt](https://gothub.dev.projectsegfau.lt) | [Yes](http://gothub.dev.pjsfkvpxlinjamtawaksbnnaqs2fc2mtvmozrzckxh7f3kis6yea25ad.onion/) | No | India | Airtel | dev |
| [gh.phreedom.club](https://gh.phreedom.club/) | No | No | Iceland | Flokinet | dev |
| [gothub.ducks.party](https://gothub.ducks.party) | No | No | Netherlands | Timeweb | dev |
Have an instance you want on the list? Make an issue or PR!
You can find a json-list of the same in [gothub/gothub-instances](https://codeberg.org/gothub/gothub-instances).
### Instance rules
These are the rules an instance must follow to be in our official instance list.
Most of these rules have been copied from the [invidious project](https://docs.invidious.io/instances).
- Instance MUST have been updated in the last month.
- Instances using any EXTERNAL DDoS Protection / MITM / Anti-Bot protection MUST be marked as such.
- Instances MUST NOT use any sort of web analytics
- Instances MUST NOT serve ads
- Instances MUST NOT restrict or disallow the access / usage to any natural person (eg. a country's IP range MUST NOT be blocked, access by a natural person MUST NOT be disallowed for arbirary reason) - this rule doesn't apply to juridical persons.
These rules may change at any time, we will inform the current hosters in the list, and give them 2 weeks so they can correct it
## Setup
See [gothub.app/docs](https://gothub.app/docs) for information about setting up GotHub.
## Scraping
GotHub utilizes scraping powered by [Colly](http://go-colly.org/) to retrieve information from GitHub for everything except the explore page. By default, GotHub uses Chrome on Windows 10 as the user agent, but you can change it by setting the `GOTHUB_USER_AGENT` environment variable.
## Funding
@@ -67,8 +87,3 @@ Our domain [gothub.app](https://gothub.app) is funded by the [Project Segfault](
All content shown on a GotHub instance is from GitHub. Any issues with content shown on a GotHub instance need to be reported to GitHub, not the instance host's internet or domain provider.
GitHub is a registered trademark of GitHub, Inc. GotHub is not affiliated with GitHub, Inc.
## Credits
- [Arya](https://aryak.me) - Main maintainer
- [Midou](https://midou.dev) - GotHub logo and many parts of the frontend
- [Odyssey346](https://odyssey346.dev) - Creator and ex-maintainer
+2
View File
@@ -29,6 +29,8 @@ func env() {
} else {
fmt.Println("Docker: false")
}
// Proxying
fmt.Println("Proxying: " + os.Getenv("GOTHUB_PROXYING_ENABLED"))
// IP logging
fmt.Println("IP logging: " + os.Getenv("GOTHUB_IP_LOGGED"))
// URL request logging
+13 -1
View File
@@ -29,6 +29,7 @@ type Vars struct {
InstanceCountry string
InstanceProvider string
CloudflareStatus string
Proxying string
}
func setup() {
@@ -130,6 +131,16 @@ func setup() {
vars.CloudflareStatus = "false"
}
// ask user whether they want proxying enabled
fmt.Print("Do you want proxying enabled? (y/n) ")
var proxying string
fmt.Scanln(&proxying)
if proxying == "y" {
vars.Proxying = "true"
} else {
vars.Proxying = "false"
}
// save to .env file
fmt.Println("Saving environment variables to .env file...")
f, err := os.Create(".env")
@@ -150,7 +161,8 @@ func setup() {
f.WriteString("GOTHUB_INSTANCE_PRIVACY_POLICY=" + vars.PrivacyPolicy + "\n")
f.WriteString("GOTHUB_INSTANCE_COUNTRY=" + vars.InstanceCountry + "\n")
f.WriteString("GOTHUB_INSTANCE_PROVIDER=" + vars.InstanceProvider + "\n")
f.WriteString("GOTHUB_INSTANCE_CLOUDFLARE=" + vars.CloudflareStatus)
f.WriteString("GOTHUB_INSTANCE_CLOUDFLARE=" + vars.CloudflareStatus + "\n")
f.WriteString("GOTHUB_PROXYING_ENABLED=" + vars.Proxying)
println("All done! You can now start your GotHub instance with 'gothub serve'.")
println("You can review the environment variables with 'gothub env'.")
+3 -2
View File
@@ -1,7 +1,7 @@
version: "3"
services:
gothub:
image: codeberg.org/gothub/gothub:latest
image: codeberg.org/gothub/gothub:latest # Master branch
# image: codeberg.org/gothub/gothub:dev # Dev branch
restart: unless-stopped
ports:
@@ -9,6 +9,7 @@ services:
environment:
- DOCKER=true
- GOTHUB_SETUP_COMPLETE=false
- GOTHUB_PROXYING_ENABLED=true/false
- GOTHUB_IP_LOGGED=true/false
- GOTHUB_REQUEST_URL_LOGGED=true/false
- GOTHUB_USER_AGENT_LOGGED=true/false
@@ -21,4 +22,4 @@ services:
test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/version || exit 1
interval: 30s
timeout: 5s
retries: 2
retries: 2
+1 -1
View File
@@ -1,6 +1,6 @@
module codeberg.org/gothub/gothub
go 1.19
go 1.20
require (
github.com/alecthomas/chroma/v2 v2.7.0
+2
View File
@@ -8,6 +8,7 @@ import (
)
type PrivacyInfo struct {
ProxyEnabled string
IPAddr string
ReqURL string
UserAgent string
@@ -24,6 +25,7 @@ type PrivacyInfo struct {
func HandleAbout(c *fiber.Ctx) error {
var privacyInfoArray []PrivacyInfo
privacyInfoArray = append(privacyInfoArray, PrivacyInfo{
ProxyEnabled: os.Getenv("GOTHUB_PROXYING_ENABLED"),
IPAddr: os.Getenv("GOTHUB_IP_LOGGED"),
ReqURL: os.Getenv("GOTHUB_REQUEST_URL_LOGGED"),
UserAgent: os.Getenv("GOTHUB_USER_AGENT_LOGGED"),
+123
View File
@@ -0,0 +1,123 @@
package pages
import (
"bufio"
"bytes"
"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"
"github.com/gocolly/colly"
"github.com/gofiber/fiber/v2"
"html/template"
"log"
"net/http"
"os"
"regexp"
"strings"
)
type Commit struct {
CommitName string
CommitDesc string
CommitHashShortened string
CommitDate string
Commiter []string
CommitToBranch string
PreviousCommit string
Additions int64
Deletions int64
ChangedFiles int64
FullName string
}
func HandleCommit(c *fiber.Ctx) error {
var commitArray []Commit
resp, statusErr := http.Get("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + "/")
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",
"error": "Commit" + c.Params("commit") + "not found",
})
}
var file string
url := "https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + ".patch"
err := requests.
URL(url).
ToString(&file).
Fetch(context.Background())
if err != nil {
return c.Status(404).Render("error", fiber.Map{
"error": err,
})
}
re := regexp.MustCompile("\\A(?s).*?---(?-s).*\\n")
file = re.ReplaceAllString(file, "---\n")
lexer := lexers.Match("something.diff")
if lexer == nil {
lexer = lexers.Fallback
}
formatter := htmlfmt.New(
htmlfmt.WithClasses(true),
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 {
return c.Status(500).Render("error", fiber.Map{
"error": err,
})
}
formatter.Format(writer, style, tokens)
cssbuf := bytes.Buffer{}
cssw := bufio.NewWriter(&cssbuf)
formatter.WriteCSS(cssw, style)
writer.Flush()
cssw.Flush()
// Scraping
Scrape := Commit{}
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("github.com"), colly.UserAgent(UserAgent))
sc.OnHTML("div.commit", func(e *colly.HTMLElement) {
Scrape.CommitName = e.ChildText("div.commit-title")
Scrape.CommitDesc = e.ChildText("div.commit-desc pre")
Scrape.CommitHashShortened = e.ChildText("div.text-lg-right span.m-0 span.sha")
Scrape.PreviousCommit = e.ChildText("div.text-lg-right span.ml-0 a.sha")
Scrape.CommitDate = e.ChildText("div.flex-self-start relative-time")
Scrape.CommitToBranch = e.ChildText("ul.branches-list li.branch a")
e.ForEach("div.flex-self-start .commit-author", func(i int, el *colly.HTMLElement) {
Scrape.Commiter = append(Scrape.Commiter, strings.TrimPrefix(el.Attr("title"), "View all commits by "))
})
})
Scrape.FullName = c.Params("user") + "/" + c.Params("repo")
sc.Visit("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + "/")
if len(Scrape.PreviousCommit) > 7 {
Minus := len(Scrape.PreviousCommit) - 7
Scrape.PreviousCommit = Scrape.PreviousCommit[:len(Scrape.PreviousCommit)-Minus]
}
// Add scrape-based info to commitArray
commitArray = append(commitArray, Scrape)
return c.Render("commit", fiber.Map{
"title": "Commit " + Scrape.CommitName + " | " + c.Params("user") + "/" + c.Params("repo"),
"commit": commitArray,
"file": template.HTML(buf.String()),
"css": template.CSS(cssbuf.String()),
})
}
+52 -32
View File
@@ -4,7 +4,8 @@ import (
"log"
"net/http"
"os"
"strings"
"github.com/tidwall/gjson"
"codeberg.org/gothub/gothub/utils"
"github.com/gocolly/colly"
@@ -12,21 +13,52 @@ import (
)
type Dir struct {
Readme string
Fullname string
DirName string
Branch string
Readme string
Fullname string
DirName string
Branch string
// TruncationWarning string
}
// TODO: Handle repository truncation warning.
// Example text: "Sorry, we had to truncate this directory to 1,000 files.
// 718 entries were omitted from the list. Latest commit info may be omitted."
type DirFiles struct {
Name string
Path string
Type string
Branch string
Fullname string
DirName string
}
// Given a gjson object, as well as branch name and fullname ('user/repository' format),
// return an array of directory files
func return_dir_files_array(dirList gjson.Result, branch string, fullname string) []DirFiles {
var dirFilesArray []DirFiles
dirList.ForEach(func(i, e gjson.Result) bool {
var FileType string
if e.Get("contentType").Str == "directory" {
FileType = "dir"
} else {
FileType = "file"
}
dirFilesArray = append(dirFilesArray, DirFiles{
Name: e.Get("name").Str,
// Path is the path to the file/folder from the repository root
Path: e.Get("path").Str,
Type: FileType,
Branch: branch,
Fullname: fullname,
})
return true //keep iterating
})
return dirFilesArray
}
func DirView(c *fiber.Ctx) error {
var dirArray []Dir
var dirFilesArray []DirFiles
@@ -40,7 +72,7 @@ func DirView(c *fiber.Ctx) error {
// I need a better way to do this
return c.Status(404).Render("error", fiber.Map{
"title": "Error",
"error": "Directory" + c.Params("+") + "not found",
"error": "Directory " + c.Params("+") + " not found",
})
}
@@ -56,33 +88,21 @@ func DirView(c *fiber.Ctx) error {
}
sc := colly.NewCollector(colly.AllowedDomains("github.com"), colly.UserAgent(UserAgent))
sc.OnHTML("div#readme", func(e *colly.HTMLElement) {
Scrape.Readme = e.ChildText("a[href='#readme']")
sc.OnHTML("react-app script[data-target]", func(e *colly.HTMLElement) {
jsonMess := e.Text
dirList := gjson.Get(jsonMess, "payload.tree.items")
dirFilesArray = return_dir_files_array(dirList, Scrape.Branch, Scrape.Fullname)
})
sc.OnHTML("div#readme div.Box-body", func(e *colly.HTMLElement) {
Content, _ := e.DOM.Html()
readmeOutput = strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1)
})
sc.OnHTML("div.js-details-container div.Details-content--hidden-not-important", func(e *colly.HTMLElement) {
e.ForEach("div.js-navigation-item", func(i int, el *colly.HTMLElement) {
var FileType string
if el.ChildAttr("div.flex-shrink-0 svg", "aria-label") == "Directory" {
FileType = "dir"
} else {
FileType = "file"
}
if el.ChildText("div.flex-auto span.d-block a.js-navigation-open") != "" {
dirFilesArray = append(dirFilesArray, DirFiles{
Name: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"),
Path: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"),
Type: FileType,
Fullname: Scrape.Fullname,
DirName: Scrape.DirName,
Branch: Scrape.Branch,
})
}
// Get repository truncation warning. This only works with js enabled, so it does not work with colly
/*
sc.OnHTML("[data-testid='repo-truncation-warning']", func(e *colly.HTMLElement) {
fmt.Printf("Truncation warning: %s", e.Text)
Scrape.TruncationWarning = e.Text
})
})
*/
sc.Visit("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/tree/" + c.Params("branch") + "/" + c.Params("+"))
// Add scrape-based info to dirArray
dirArray = append(dirArray, Scrape)
+33
View File
@@ -5,12 +5,15 @@ import (
"bytes"
"codeberg.org/gothub/gothub/utils"
"context"
"encoding/base64"
htmlfmt "github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
"github.com/carlmjohnson/requests"
"github.com/gofiber/fiber/v2"
"html/template"
"net/http"
"path/filepath"
)
// FileView is the file view page
@@ -27,6 +30,35 @@ func FileView(c *fiber.Ctx) error {
})
}
ext := filepath.Ext(c.Params("+"))
// Make an issue for other formats thanks
if ext == ".jpeg" || ext == ".jpg" || ext == ".png" || ext == ".svg" || ext == ".gif" || ext == ".webp" {
data := []byte(file)
dst := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(dst, data)
dstStr := string(dst)
// Detect content-type since base64 encoding needs content-type
mimeType := http.DetectContentType(data)
if ext == ".svg" {
mimeType = "image/svg+xml"
}
css := `img {
object-fit: cover;
width: 100%;
height: 250px;
}`
html := "<img src='data:" + mimeType + ";base64," + dstStr + "' alt=" + c.Params("+") + ">"
return c.Render("file", fiber.Map{
"title": c.Params("+") + " | " + c.Params("user") + "/" + c.Params("repo"),
"branch": utils.Branch,
"file": html,
"css": css,
"fullname": c.Params("user") + "/" + c.Params("repo"),
"name": c.Params("+"),
"fileBranch": c.Params("branch"),
"type": "img",
})
}
lexer := lexers.Match(c.Params("+"))
if lexer == nil {
lexer = lexers.Fallback
@@ -64,5 +96,6 @@ func FileView(c *fiber.Ctx) error {
"fullname": c.Params("user") + "/" + c.Params("repo"),
"name": c.Params("+"),
"fileBranch": c.Params("branch"),
"type": "code",
})
}
+53 -24
View File
@@ -6,11 +6,19 @@ import (
"os"
"strings"
"github.com/tidwall/gjson"
"codeberg.org/gothub/gothub/utils"
"github.com/gocolly/colly"
"github.com/gofiber/fiber/v2"
)
type Languages struct {
Name string
Percent string
Color string
}
type Repo struct {
Fullname string
Description string
@@ -18,8 +26,9 @@ type Repo struct {
Stars string
Forks string
CommitsBehind string
CommitsAhead string
Watchers string
Language []string
Language []Languages
License string
DefaultBranch string
Readme string
@@ -56,7 +65,6 @@ func HandleRepo(c *fiber.Ctx) error {
"error": "Repository " + c.Params("user") + "/" + repoUrl + branchExists + " not found",
})
}
// Scraping
Scrape := Repo{}
@@ -79,18 +87,55 @@ func HandleRepo(c *fiber.Ctx) error {
})
})
sc.OnHTML("div.Box-body div.d-flex div span", func(e *colly.HTMLElement) {
Scrape.CommitsBehind = strings.TrimSuffix(e.ChildText("a"), " commits behind")
Scrape.CommitsBehind = strings.TrimSuffix(e.ChildText("a[data-analytics-event*='Behind Compare']"), " commits behind")
Scrape.CommitsAhead = strings.TrimSuffix(e.ChildText("a[data-analytics-event*='Ahead Compare']"), " commits ahead")
})
sc.OnHTML("div#readme", func(e *colly.HTMLElement) {
Scrape.Readme = e.ChildText("a[href='#readme']")
})
sc.OnHTML("div#readme div.Box-body", func(e *colly.HTMLElement) {
Content, _ := e.DOM.Html()
readmeOutput = strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1)
// jq '.props.initialPayload.overview.overviewFiles[]|select(.tabName == "README").richText'
sc.OnHTML("div.Layout-main react-partial script", func(e *colly.HTMLElement) {
jsonMess := e.Text
result := gjson.Get(jsonMess, "props.initialPayload.overview.overviewFiles")
result.ForEach(func(i, e gjson.Result) bool {
if e.Get("tabName").Str == "README" {
unsanitizedOutput := e.Get("richText").Str
readmeOutput = strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(unsanitizedOutput))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1), "https://user-images.githubusercontent.com", "/user-images", -1)
return false
}
return true // keep iterating
})
result = gjson.Get(jsonMess, "props.initialPayload.tree.items")
//jq '.props.initialPayload.tree.items'
result.ForEach(func(i, e gjson.Result) bool {
var FileType string
if e.Get("contentType").Str == "directory" {
FileType = "dir"
} else {
FileType = "file"
}
repoFilesArray = append(repoFilesArray, RepoFiles{
Name: e.Get("name").Str,
Path: e.Get("path").Str,
Type: FileType,
DefaultBranch: gjson.Get(jsonMess, "props.initialPayload.repo.defaultBranch").Str,
Fullname: Scrape.Fullname,
})
return true //keep iterating
})
})
sc.OnHTML("div.BorderGrid-cell ul.list-style-none", func(e *colly.HTMLElement) {
e.ForEach("li.d-inline .d-inline-flex", func(i int, el *colly.HTMLElement) {
Scrape.Language = append(Scrape.Language, el.ChildText("span.text-bold")+" "+el.ChildText("span:contains('%')"))
var lang Languages
lang.Name = el.ChildText("span.text-bold")
lang.Percent = el.ChildText("span:contains('%')")
lang.Color = strings.ReplaceAll(strings.ReplaceAll(el.ChildAttr("svg", "style"), "color:", ""), ";", "")
Scrape.Language = append(Scrape.Language, lang)
})
})
sc.OnHTML("div#repository-container-header", func(e *colly.HTMLElement) {
@@ -99,24 +144,8 @@ func HandleRepo(c *fiber.Ctx) error {
sc.OnHTML("summary[title*='Switch branches or tags']", func(e *colly.HTMLElement) {
Scrape.DefaultBranch = e.ChildText("span.css-truncate-target")
})
sc.OnHTML("div.js-details-container div.Details-content--hidden-not-important", func(e *colly.HTMLElement) {
e.ForEach("div.js-navigation-item", func(i int, el *colly.HTMLElement) {
var FileType string
if el.ChildAttr("div.flex-shrink-0 svg", "aria-label") == "Directory" {
FileType = "dir"
} else {
FileType = "file"
}
repoFilesArray = append(repoFilesArray, RepoFiles{
Name: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"),
Path: el.ChildText("div.flex-auto span.d-block a.js-navigation-open"),
Type: FileType,
Fullname: Scrape.Fullname,
DefaultBranch: Scrape.DefaultBranch,
})
})
})
sc.Visit("https://github.com/" + c.Params("user") + "/" + repoUrl + branchExists)
// Add scrape-based info to repoArray
repoArray = append(repoArray, Scrape)
return c.Render("repo", fiber.Map{
+1
View File
@@ -158,6 +158,7 @@ func HandleUser(c *fiber.Ctx) error {
sc.OnHTML("article.markdown-body", func(e *colly.HTMLElement) {
Content, _ := e.DOM.Html()
Scrape.Readme = strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1)
})
sc.OnHTML("div.text-mono", func(e *colly.HTMLElement) {
Scrape.ReadmeUrl = strings.Replace(e.ChildAttr("a", "href"), "tree", "blob", -1)
+87
View File
@@ -0,0 +1,87 @@
package pages
import (
"codeberg.org/gothub/gothub/utils"
"github.com/gocolly/colly"
"github.com/gofiber/fiber/v2"
"log"
"net/http"
"os"
"regexp"
"strings"
)
type Wiki struct {
RepoUser string
RepoName string
Title string
LastEdit string
LastEditor string
RevisionNum string
PageNum string
PageContent string
Sidebar []Sidebar
}
type Sidebar struct {
Name string
Link string
}
func WikiView(c *fiber.Ctx) error {
var wikiArray []Wiki
resp, statusErr := http.Get("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/wiki/" + c.Params("page"))
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",
"error": "Wiki" + c.Params("page") + "not found",
})
}
// Scraping
Scrape := Wiki{}
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("github.com"), colly.UserAgent(UserAgent))
sc.OnHTML("div#repository-container-header", func(e *colly.HTMLElement) {
Scrape.RepoUser = e.ChildText("span.author a")
Scrape.RepoName = e.ChildText("strong a")
})
sc.OnHTML("div#wiki-wrapper", func(e *colly.HTMLElement) {
Scrape.Title = e.ChildText("div.d-flex h1")
Scrape.LastEdit = e.ChildText("div.gh-header-meta relative-time")
re := regexp.MustCompile(`\ edited.*`)
Scrape.LastEditor = re.ReplaceAllString(strings.Replace(e.ChildText("div.gh-header-meta"), "\n", "", -1), "${1}")
Scrape.RevisionNum = strings.TrimSuffix(e.ChildText("a.Link--muted"), " revisions")
})
sc.OnHTML("div.wiki-pages-box div.Box--condensed", func(e *colly.HTMLElement) {
Scrape.PageNum = e.ChildText("span.Counter--primary")
e.ForEach("ul.list-style-none li.Box-row", func(i int, el *colly.HTMLElement) {
Scrape.Sidebar = append(Scrape.Sidebar, Sidebar{
Name: el.ChildText("summary span a.Truncate-text"),
Link: el.ChildAttr("summary span a.Truncate-text", "href"),
})
})
})
sc.OnHTML("div#wiki-body > div.markdown-body", func(e *colly.HTMLElement) {
Content, _ := e.DOM.Html()
Scrape.PageContent = strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Replace(string(utils.UGCPolicy().SanitizeBytes([]byte(Content))), "https://github.com", "", -1), "user-content-", "", -1), "https://camo.githubusercontent.com", "/camo", -1), "https://raw.githubusercontent.com", "/raw", -1), "https://user-images.githubusercontent.com", "/user-images", -1)
})
sc.Visit("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/wiki/" + c.Params("page"))
// Add scrape-based info to wikiArray
wikiArray = append(wikiArray, Scrape)
return c.Render("wiki", fiber.Map{
"title": "Wiki page " + c.Params("page") + " | " + c.Params("user") + "/" + c.Params("repo"),
"wiki": wikiArray,
})
}
+71 -7
View File
@@ -6,12 +6,14 @@
--secondary-background: #353535;
--background-darker: #151515;
--accent: #00b7c3;
--yellow: #8B8000;
--yellow: #8b8000;
color-scheme: dark;
}
body {
font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui,
helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial,
sans-serif;
color: var(--text);
background-color: var(--background-darker);
transition: ease-in-out 0.25s;
@@ -32,6 +34,20 @@ main {
margin: 0 24vw;
}
.margin-ow {
margin: 0 12vw;
}
pre {
overflow: scroll;
background: var(--secondary-background);
border-radius: 4px;
padding: 4px;
}
#wrap {
display: flex;
}
.navbar {
display: flex;
align-items: center;
@@ -73,7 +89,9 @@ main {
background-color: var(--background);
padding: 8px;
border-radius: 4px;
font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui,
helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial,
sans-serif;
color: var(--text);
}
@@ -95,7 +113,9 @@ a:hover {
background-color: var(--yellow);
padding: 8px;
border-radius: 4px;
font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui,
helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial,
sans-serif;
color: var(--text);
}
@@ -111,7 +131,8 @@ a:hover {
/* URI: /explore */
.explore-card, .user-repo-card {
.explore-card,
.user-repo-card {
background-color: var(--background);
padding: 8px;
border-radius: 4px;
@@ -125,7 +146,8 @@ a:hover {
transition: ease-in-out 0.25s;
}
.explore-card:hover, .user-repo-card:hover {
.explore-card:hover,
.user-repo-card:hover {
background-color: var(--secondary-background);
color: var(--text);
}
@@ -147,6 +169,7 @@ a:hover {
margin: 4px;
word-wrap: nowrap;
text-overflow: ellipsis;
overflow-wrap: anywhere;
}
.user-profile h2 {
@@ -211,6 +234,20 @@ a:hover {
color: var(--text);
}
.lang-bar:last-child {
margin-bottom: 0;
}
.lang-bar {
width: 100%;
display: inherit;
height: 10px;
border-radius:4px;
overflow: hidden; /* To force the corners to be round. */
user-select: none; /* Prevent the selection */
-webkit-user-select: none; /* Safari specific fix. */
}
/* URI: /:user/:repo */
.button {
background-color: var(--background);
@@ -266,6 +303,23 @@ a:hover {
background-color: var(--secondary-background);
}
/* Overwrite */
.no-margin {
margin: 0;
}
.no-padding {
padding: 0;
}
.float-right {
float: right;
display: grid;
flex: none;
align-self: flex-start;
}
@media screen and (prefers-color-scheme: light) {
:root {
--text: #000;
@@ -293,6 +347,16 @@ a:hover {
margin: 8px;
}
#wrap {
display: flex;
flex-direction: column;
}
.float-right {
float: none;
display: inline-grid;
}
.navbar-slogan {
display: none;
}
@@ -312,5 +376,5 @@ a:hover {
}
}
.cl {
padding-left: 8px
padding-left: 8px;
}
+97 -15
View File
@@ -15,6 +15,8 @@ import (
"github.com/gofiber/fiber/v2/middleware/cache"
"github.com/gofiber/fiber/v2/middleware/compress"
"github.com/gofiber/fiber/v2/middleware/limiter"
// For debugging purposes
// "github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/template/html"
@@ -62,6 +64,10 @@ func Serve(port string) {
app.Use(cache.New(cache.Config{
Expiration: 5 * time.Minute,
}))
// For debugging purposes
// app.Use(logger.New(logger.Config{
// Format: "[${ip}]:${port} ${status} - ${method} ${path} ${queryParams}\n",
// }))
app.Use(compress.New(compress.Config{
Level: compress.LevelBestSpeed, // 1
@@ -86,13 +92,21 @@ func Serve(port string) {
MaxAge: 31536000,
}
proxying, ok := os.LookupEnv("GOTHUB_PROXYING_ENABLED")
if !ok {
proxying = "true"
}
// add global headers
app.Use(func(c *fiber.Ctx) error {
c.Set("X-Frame-Options", "SAMEORIGIN")
c.Set("X-XSS-Protection", "1; mode=block")
c.Set("X-Content-Type-Options", "nosniff")
c.Set("Referrer-Policy", "no-referrer")
c.Set("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data; font-src 'self'; script-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; connect-src 'self';")
if proxying == "true" {
c.Set("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; script-src 'self'; frame-ancestors 'self'; form-action 'self'; base-uri 'self'; connect-src 'self';")
} else {
c.Set("Content-Security-Policy", "default-src 'self' https://camo.githubusercontent.com https://avatars.githubusercontent.com https://user-images.githubusercontent.com https://github.com https://raw.githubusercontent.com https://gist.github.com; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://user-images.githubusercontent.com https://camo.githubusercontent.com https://avatars.githubusercontent.com https://gist.github.com; font-src 'self'; connect-src 'self' https://user-images.githubusercontent.com https://camo.githubusercontent.com https://avatars.githubusercontent.com https://github.com https://raw.githubusercontent.com https://gist.github.com; frame-ancestors 'self'; form-action 'self'; base-uri 'self'")
}
c.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
return c.Next()
@@ -107,30 +121,98 @@ func Serve(port string) {
app.Get("/explore", ratelimiter, pages.HandleExplore)
app.Get("/:user", pages.HandleUser)
app.Get("/avatar/:id", func(c *fiber.Ctx) error {
utils.ProxyRequest(c, "https://avatars.githubusercontent.com/u/"+c.Params("id")+"?v=4")
return nil
if proxying == "true" {
utils.ProxyRequest(c, "https://avatars.githubusercontent.com/u/"+c.Params("id")+"?v=4")
return nil
} else {
c.Redirect("https://avatars.githubusercontent.com/u/" + c.Params("id") + "?v=4")
return nil
}
})
app.Get("/user-images/:id/:img", func(c *fiber.Ctx) error {
if proxying == "true" {
utils.ProxyRequest(c, "https://user-images.githubusercontent.com/"+c.Params("id")+"/"+c.Params("img")+"?v=4")
return nil
} else {
c.Redirect("https://user-images.githubusercontent.com/" + c.Params("id") + "/" + c.Params("img") + "?v=4")
return nil
}
})
app.Get("/:user/:repo", pages.HandleRepo)
app.Get("/:user/:repo/commit/:commit", pages.HandleCommit)
app.Get("/diff/:user/:repo/commit/:commit", func(c *fiber.Ctx) error {
if proxying == "true" {
utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+"/commit/"+c.Params("commit")+".diff")
return nil
} else {
c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/commit/" + c.Params("commit") + ".diff")
return nil
}
})
app.Get("/:user/:repo/info/+", func(c *fiber.Ctx) error {
// This is needed but it looks like git doesn't send it. Or maybe i just shouldn't program at midnight
param := "?service=git-upload-pack"
if proxying == "true" {
utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+".git/info/"+c.Params("+")+param)
return nil
} else {
c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + ".git/info/" + c.Params("+") + param)
return nil
}
})
app.Post("/:user/:repo/git-upload-pack", func(c *fiber.Ctx) error {
if proxying == "true" {
utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+".git/git-upload-pack")
return nil
} else {
c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + ".git/git-upload-pack")
return nil
}
})
app.Get("/:user/:repo/blob/:branch/+", pages.FileView)
app.Get("/:user/:repo/tree/:branch/+", pages.DirView)
app.Get("/:user/:repo/tree/:branch", pages.HandleRepo)
app.Get("/download/:user/:repo/:branch", func(c *fiber.Ctx) error {
utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+"/archive/"+c.Params("branch")+".zip")
app.Get("/:user/:repo/wiki", func(c *fiber.Ctx) error {
c.Redirect("/" + c.Params("user") + "/" + c.Params("repo") + "/wiki/Home")
return nil
})
app.Get("/:user/:repo/wiki/:page", pages.WikiView)
app.Get("/:user/:repo/tree/:branch", pages.HandleRepo)
app.Get("/:user/:repo/archive/:branch", func(c *fiber.Ctx) error {
if proxying == "true" {
utils.ProxyRequest(c, "https://github.com/"+c.Params("user")+"/"+c.Params("repo")+"/archive/"+c.Params("branch"))
return nil
} else {
c.Redirect("https://github.com/" + c.Params("user") + "/" + c.Params("repo") + "/archive/" + c.Params("branch"))
return nil
}
})
app.Get("/raw/:user/:repo/:branch/+", func(c *fiber.Ctx) error {
if proxying == "true" {
utils.ProxyRequest(c, "https://raw.githubusercontent.com/"+c.Params("user")+"/"+c.Params("repo")+"/"+c.Params("branch")+"/"+c.Params("+"))
return nil
} else {
c.Redirect("https://raw.githubusercontent.com/" + c.Params("user") + "/" + c.Params("repo") + "/" + c.Params("branch") + "/" + c.Params("+"))
return nil
}
})
app.Get("/camo/:p1/:p2", func(c *fiber.Ctx) error {
utils.ProxyRequest(c, "https://camo.githubusercontent.com/"+c.Params("p1")+"/"+c.Params("p2"))
return nil
if proxying == "true" {
utils.ProxyRequest(c, "https://camo.githubusercontent.com/"+c.Params("p1")+"/"+c.Params("p2"))
return nil
} else {
c.Redirect("https://camo.githubusercontent.com/" + c.Params("p1") + "/" + c.Params("p2"))
return nil
}
})
app.Get("/gist/:user/:gistID", pages.HandleGist)
app.Get("/download/gist/:user/:gistID/:revision", func(c *fiber.Ctx) error {
utils.ProxyRequest(c, "https://gist.github.com/"+c.Params("user")+"/"+c.Params("gistID")+"/archive/"+c.Params("revision")+".zip")
return nil
})
app.Get("/raw/:user/:repo/:branch/:file", func(c *fiber.Ctx) error {
utils.ProxyRequest(c, "https://raw.githubusercontent.com/"+c.Params("user")+"/"+c.Params("repo")+"/"+c.Params("branch")+"/"+c.Params("file"))
return nil
if proxying == "true" {
utils.ProxyRequest(c, "https://gist.github.com/"+c.Params("user")+"/"+c.Params("gistID")+"/archive/"+c.Params("revision")+".zip")
return nil
} else {
c.Redirect("https://gist.github.com/" + c.Params("user") + "/" + c.Params("gistID") + "/archive/" + c.Params("revision") + ".zip")
return nil
}
})
api := app.Group("/api")
+1
View File
@@ -10,6 +10,7 @@
</p>
<p>If this page isn't filled, please contact your instance's maintainer.</p>
<ul>
<li><b>Proxying enabled:</b> {{.ProxyEnabled}}</li>
<li><b>IP Address logged:</b> {{.IPAddr}}</li>
<li><b>Request URL logged:</b> {{.ReqURL}}</li>
<li><b>User Agent logged:</b> {{.UserAgent}}</li>
+46
View File
@@ -0,0 +1,46 @@
{{ template "header" .}}
<main>
{{ if.commit }}
<style>
// prettier-ignore
{{.css}}
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
{{ range $key, $value := .commit}}
<div class="download-parent">
<a href="/{{.FullName}}" class="button">Back to {{.FullName}}</a>
</div>
<div class="user-readme">
<div class="user-container">
<h3>{{.CommitHashShortened}} | {{.CommitName}}</h3>
<a
href="/diff/{{.FullName}}/commit/{{.CommitHashShortened}}"
class="button secondary"
>Raw</a
>
</div>
{{.CommitName}} {{ if .CommitDesc }}
<pre>{{.CommitDesc}}</pre>
{{end}}
<p>
Commited on {{.CommitDate}} by {{range .Commiter}}
<a href="/{{.}}" target="_blank">@{{.}}</a>{{ end }}
</p>
<p>
Previous Commit:
<a href="/{{.FullName}}/commit/{{.PreviousCommit}}"
>{{.PreviousCommit}}</a
>
</p>
</div>
{{end}} {{ .file}} {{ else }}
<h2>Commit not found</h2>
<p>That commit doesn't exist.</p>
{{ end }}
</main>
{{ template "footer" .}}
+57 -51
View File
@@ -1,57 +1,63 @@
{{ template "header" .}}
<main>
{{ if .dir }} {{ range $key, $value := .dir}}
<div class="button-parent">
<a
rel="noreferrer"
href="https://github.com/{{.Fullname}}/tree/{{.Branch}}/{{.DirName}}"
class="button"
>View on GitHub</a
>
<a href="/{{.Fullname}}/tree/{{.Branch}}/{{.Branch}}" class="button"
>Back to {{.Fullname}}</a
>
</div>
<div class="user-profile">
<h1>{{.Fullname}} | {{.DirName}}</h1>
</div>
{{end}} {{ if .files}}
<div class="user-readme">
<h3>Files</h3>
<div class="user-readme-text">
<ul class="file-u-list">
{{ range $key, $value := .files}} {{ if eq .Type "dir" }}
<li class="file-list">
📁
<a
href="/{{.Fullname}}/tree/{{.Branch}}/{{.DirName}}/{{.Path}}"
class="file-a"
>{{.Path}}</a
>
</li>
{{ else }}
<li class="file-list">
🗒️
<a href="/{{.Fullname}}/blob/{{.Branch}}/{{.DirName}}/{{.Path}}"
>{{.Path}}</a
>
</li>
{{ end }} {{ end }}
</ul>
{{ if .dir }} {{ range $key, $value := .dir}}
<div class="button-parent">
<a
rel="noreferrer"
href="https://github.com/{{.Fullname}}/tree/{{.Branch}}/{{.DirName}}"
class="button"
>View on GitHub</a
>
<a href="/{{.Fullname}}/tree/{{.Branch}}" class="button"
>Back to {{.Fullname}}</a
>
</div>
</div>
{{ end }} {{ if .readme}}
<div class="user-readme">
{{ if .dir }} {{ range $key, $value := .dir }}
<h3>{{.Readme}}</h3>
{{end}} {{end}}
<div class="user-readme-text">{{ unescape .readme}}</div>
</div>
{{ end }} {{ else }}
<h2>Directory not found</h2>
<p>That directory doesn't exist.</p>
{{ end }}
<div class="user-profile">
<h1>{{.Fullname}} | {{.DirName}}</h1>
</div>
{{end}}
{{ if .TruncationWarning }}
<blockquote>{{.TruncationWarning}}</blockquote>
{{ end }}
{{ if .files}}
<div class="user-readme">
<h3>Files</h3>
<div class="user-readme-text">
<ul class="file-u-list">
{{ range $key, $value := .files}} {{ if eq .Type "dir" }}
<li class="file-list">
📁
<a
href="/{{.Fullname}}/tree/{{.Branch}}/{{.Path}}"
class="file-a"
>{{.Name}}</a
>
</li>
{{ else }}
<li class="file-list">
🗒️
<a href="/{{.Fullname}}/blob/{{.Branch}}/{{.Path}}"
>{{.Name}}</a
>
</li>
{{ end }} {{ end }}
</ul>
</div>
</div>
{{ end }} {{ if .readme}}
<div class="user-readme">
{{ if .dir }} {{ range $key, $value := .dir }}
<h3>{{.Readme}}</h3>
{{end}} {{end}}
<div class="user-readme-text">{{ unescape .readme}}</div>
</div>
{{ end }} {{ else }}
<h2>Directory not found</h2>
<p>That directory doesn't exist.</p>
{{ end }}
</main>
{{ template "footer" .}}
+6 -1
View File
@@ -9,6 +9,11 @@
white-space: pre-wrap;
word-wrap: break-word;
}
div.user-readme img {
display: block;
width: 100%;
height: auto;
}
</style>
<div class="download-parent">
<a href="/{{.fullname}}/tree/{{.fileBranch}}" class="button"
@@ -25,7 +30,7 @@
>Raw</a
>
</div>
{{ .file}}
{{ if eq .type "img" }} {{ unescape .file }} {{else}} {{ .file }} {{end}}
</div>
{{end}}
</main>
+8
View File
@@ -60,6 +60,14 @@
using a VPN if you have to clone a GitHub repository and want to keep
yourself private from them instead.</i
>
<h3>Credits</h3>
<p style="margin: 0; padding: 0">
<a href="https://midou.dev">Midou36O</a> - designing the GotHub logo
</p>
<p style="margin: 0; padding: 0">
<a href="https://arya.projectsegfau.lt">Arya</a> - code contributions and
maintainer
</p>
<h3>Info</h3>
{{ if eq .version "unknown, please build with Go 1.13+ or use Git"}} GotHub
version: <code>unknown</code> {{ else }} GotHub version:
+18 -5
View File
@@ -3,7 +3,7 @@
<main>
{{ if .repo }} {{ range $key, $value := .repo}}
<div class="button-parent">
<a href="/download/{{.Fullname}}/{{.DefaultBranch}}" class="button"
<a href="/{{.Fullname}}/archive/{{.DefaultBranch}}.zip" class="button"
>Download (zip)</a
>
<a rel="noreferrer" href="https://github.com/{{.Fullname}}" class="button"
@@ -30,10 +30,23 @@
⭐ {{.Stars}} 🍴 {{.Forks}} 👀 {{.Watchers}} ⚖️ No license 🌿
{{.DefaultBranch}}
</p>
{{ end }} {{ if .Language }}
<p>🗒️ {{range .Language}} {{.}} {{end}}</p>
{{end}} {{ if .CommitsBehind }} This repository is {{.CommitsBehind}}
commits behind its parent. {{end}}
<p><a href="/{{.Fullname}}/wiki">Wiki</a></p>
{{ end }} {{ if .Language }} {{range $o := .Language}}{{$o.Name}}
{{$o.Percent}}, {{end}}
<div class="lang-bar">
{{range $i, $o := .Language}}
<span style="width: {{$o.Percent}}; background-color: {{$o.Color}}">
&nbsp;
</span>
{{end}}
</div>
{{end}} {{ if or .CommitsAhead .CommitsBehind }}
<p>
This repository is {{if .CommitsBehind}} {{.CommitsBehind}} commits behind
{{end}} {{if and .CommitsBehind .CommitsAhead}} and {{end}} {{if
.CommitsAhead}} {{ .CommitsAhead }} commits ahead of {{end}} its parent.
</p>
{{end}}
</div>
{{end}} {{ if .files}}
<div class="user-readme">
+31 -20
View File
@@ -74,27 +74,38 @@
{{ end }} {{ if .MainRepos }}
<div class="user-readme">
<h3>{{.PinOrPopular}} repositories</h3>
{{range .MainRepos}}
<a class="user-repo-card" href="{{.Link}}">
<p class="user-repo-header">{{.Name}} ({{.Type}})</p>
{{if .ForkOf}} Forked from: <a href="/{{.ForkOf}}">{{.ForkOf}}</a>
{{else}} {{end}} {{if .Desc}} {{if eq .Type "Gist"}}
<style>
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
<pre> {{.Desc}} </pre>
{{range .MainRepos}} {{ if .ForkOf }}
<div class="user-repo-card">
{{else}}
<p class="">{{.Desc}}</p>
{{end}} {{else}} {{end}}
<p class="">
{{if .Stars}}⭐ {{.Stars}}{{else}}{{end}} {{if .Forks}} 🍴 {{.Forks}}
{{else}}{{end}} {{if .Lang}} 🗒️ {{.Lang}} {{else}}{{end}}
</p>
</a>
{{ end }}
<a class="user-repo-card" href="{{.Link}}">
{{end}} {{if .ForkOf}}
<p class="user-repo-header">
<a href="{{.Link}}">{{.Name}} ({{.Type}})</a>
</p>
{{else}}
<p class="user-repo-header">{{.Name}} ({{.Type}})</p>
{{end}} {{if .ForkOf}}
<p class="">Forked from: <a href="/{{.ForkOf}}">{{.ForkOf}}</a></p>
{{else}} {{end}} {{if .Desc}} {{if eq .Type "Gist"}}
<style>
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
</style>
<pre> {{.Desc}} </pre>
{{else}}
<p class="">{{.Desc}}</p>
{{end}} {{else}} {{end}}
<p class="">
{{if .Stars}}⭐ {{.Stars}}{{else}}{{end}} {{if .Forks}} 🍴 {{.Forks}}
{{else}}{{end}} {{if .Lang}} 🗒️ {{.Lang}} {{else}}{{end}}
</p>
{{ if .ForkOf }} {{else}}
</a>
{{end}} {{ if .ForkOf }}
</div>
{{end}} {{ end }}
</div>
{{ end }} {{ end }} {{ else }}
<h2>User not found</h2>
+34
View File
@@ -0,0 +1,34 @@
{{ template "header" .}}
<!-- prettier-ignore -->
<main class="margin-ow">
{{ if .wiki }} {{ range $key, $value := .wiki}}
<div id="wrap">
<div>
<h1>{{.Title}}</h1>
<h2>{{.RepoUser}}/{{.RepoName}}</h2>
<p>
{{.LastEditor}} edited this page on {{.LastEdit}} · {{.RevisionNum}} revisions
</p>
<hr style="border-color: #252525;">
<div style="margin-right: auto; width: 50vw;">
{{ unescape .PageContent }}
</div>
</div>
<div class="user-readme float-right">
<h3><b>{{.PageNum}}</b> pages</h3>
<div class="no-padding user-readme-text">
{{ range $key, $value := .Sidebar }}
<hr style="border-color: #252525;">
<a href="{{.Link}}"><p style="padding:0px 8px 0px 8px;">{{.Name}}</p></a>
{{end}}
</div>
</div>
</div>
{{ end }}
{{ else }}
<h2>Wiki not found</h2>
<p>That wiki doesn't exist.</p>
{{ end }}
</main>
{{ template "footer" .}}