first commit
This commit is contained in:
commit
be5bb8e131
46
README.md
Normal file
46
README.md
Normal file
@ -0,0 +1,46 @@
|
||||
# Intro
|
||||
babil0nia-server (bserver) is the web gui for [bkli](https://code.lacashita.com/sml/bkli).
|
||||
It can be used to save/organize your favourite urls, URLs are saved into the sqlite3 db and then you can do some
|
||||
searchs, filtering or download the saved url to a file (jpg).
|
||||
|
||||
babil0nia-cli(bkli) and babil0nia-server(bserver) uses the same sqlite3 database, so if you are using both you can
|
||||
share/sync the db file between them.
|
||||
|
||||
Check changelog.txt to see the current status.
|
||||
|
||||
# How it looks
|
||||

|
||||
|
||||
# To know
|
||||
Feel free to change the code in order to adapt the program to your needs.
|
||||
|
||||
During the first run the program:
|
||||
* Creates ~/babil0nia.db file which is the database.
|
||||
* Creates ~/.babil0niafiles which is the folder to store the screenshots.
|
||||
* Creates a link from ~/.babil0niafiles to screenshots/ in the same folder where is the executable.
|
||||
* The server uses the port 8002.
|
||||
|
||||
Check that you have permissions to run the program in the port 8001 and also write permissions in screenshots folder in order to
|
||||
download the screenshots if needed.
|
||||
|
||||
Once started, you can access at http://127.0.0.1:8002.
|
||||
|
||||
# Usage
|
||||
|
||||
| Description | Command |
|
||||
| ----------- | ----------- |
|
||||
| Start the web server (without allowing to archive) | <kbd>bserver</kbd>|
|
||||
| Start the web server (allowing to archive) | <kbd>bserver -a</kbd>|
|
||||
|
||||
# Installation
|
||||
```sh
|
||||
git clone https://code.lacashita.com/sml/bserver
|
||||
go build bserver.go
|
||||
./bserver.go -a
|
||||
```
|
||||
|
||||
# Upgrade
|
||||
Just clone the repo with the last version, compile and replace with the latest binary.
|
||||
|
||||
|
||||
|
||||
BIN
babil0nia.png
Normal file
BIN
babil0nia.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
406
bserver.go
Executable file
406
bserver.go
Executable file
@ -0,0 +1,406 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"github.com/chromedp/chromedp"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// Start Web PART
|
||||
type urlinfo struct {
|
||||
Date string
|
||||
Url string
|
||||
Description string
|
||||
Tags string
|
||||
Screenshot string
|
||||
Separated []string
|
||||
Duplicated []string
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Msj string
|
||||
}
|
||||
|
||||
func main() {
|
||||
var filedb string
|
||||
var homepath = os.Getenv("HOME")
|
||||
if os.Getenv("babil0nia_DB") == "" {
|
||||
filedb = homepath+"/babil0nia.db"
|
||||
} else {
|
||||
filedb = os.Getenv("babil0nia_DB")
|
||||
}
|
||||
// Create ~/.babil0niafiles folder to save screenshots
|
||||
if _, err := os.Stat(homepath+"/.babil0niafiles"); os.IsNotExist(err) {
|
||||
err = os.Mkdir(homepath+"/.babil0niafiles", 0755)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
// Link ~/.babil0niafiles to screenshots/ folder.
|
||||
if _, err := os.Stat("screenshots"); os.IsNotExist(err) {
|
||||
cmd := exec.Command("/usr/bin/ln", "-s", homepath+"/.babil0niafiles", "screenshots")
|
||||
_, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
checkDB(filedb)
|
||||
sqliteDatabase, _ := sql.Open("sqlite3", filedb)
|
||||
defer sqliteDatabase.Close()
|
||||
startServer(sqliteDatabase)
|
||||
}
|
||||
|
||||
// Func to check if DB exists, if not create it.
|
||||
func checkDB(filedb string) {
|
||||
_, err := os.Stat(filedb)
|
||||
//If file htask.db doesnt exist.
|
||||
if err != nil {
|
||||
fmt.Println("[+]Creating Database\n")
|
||||
file, err := os.Create(filedb)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
file.Close()
|
||||
sqlDB, _ := sql.Open("sqlite3",filedb)
|
||||
defer sqlDB.Close()
|
||||
createTable(sqlDB)
|
||||
}
|
||||
}
|
||||
|
||||
// Func to create DB.
|
||||
func createTable(db *sql.DB) {
|
||||
createbabil0niatable := `CREATE TABLE babil0nia (
|
||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"date" TEXT,
|
||||
"url" TEXT,
|
||||
"description" TEXT,
|
||||
"tags" TEXT,
|
||||
"screenshot" TEXT
|
||||
);`
|
||||
statement, err := db.Prepare(createbabil0niatable)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
statement.Exec()
|
||||
log.Println("[+] babil0nia table created")
|
||||
}
|
||||
|
||||
func startServer(db *sql.DB) {
|
||||
// All requests to /screenshots/ will serve the static content of screenshots/
|
||||
fs := http.FileServer(http.Dir("./screenshots"))
|
||||
http.Handle("/screenshots/", http.StripPrefix("/screenshots/", fs))
|
||||
|
||||
http.HandleFunc("/", babil0niaHandler(db))
|
||||
// All requests to /styles/css will serve static/css/bootstrap.min.css.
|
||||
http.HandleFunc("/styles/css", func(response http.ResponseWriter, request *http.Request) {
|
||||
http.ServeFile(response, request, "static/css/bootstrap.min.css")
|
||||
})
|
||||
|
||||
http.HandleFunc("/add", func(response http.ResponseWriter, request *http.Request) {
|
||||
http.ServeFile(response, request, "static/html/add.html")
|
||||
})
|
||||
|
||||
http.ListenAndServe("127.0.0.1:8002", nil)
|
||||
}
|
||||
|
||||
func babil0niaHandler(db *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
enabled := len(os.Args)
|
||||
var repetido int
|
||||
tagtose := r.URL.Query()["tags"]
|
||||
tagtosearch := strings.Join(tagtose ," ")
|
||||
wordtose := r.URL.Query()["wordtosearch"]
|
||||
wordtosearch := strings.Join(wordtose," ")
|
||||
urltoa := r.URL.Query()["url"]
|
||||
urltoadd := strings.Join(urltoa, " ")
|
||||
descript := r.URL.Query()["description"]
|
||||
descriptoinsert := strings.Join(descript," ")
|
||||
repetido = dupURL(db,urltoadd)
|
||||
urltodel := r.URL.Query()["delete"]
|
||||
urltodelete := strings.Join(urltodel ," ")
|
||||
urltoar := r.URL.Query()["archive"]
|
||||
urltoarchive := strings.Join(urltoar ," ")
|
||||
existeurl := dupURL(db,urltoarchive)
|
||||
existdownload := checkDownload(db,urltoarchive)
|
||||
|
||||
if urltoarchive != "" && enabled > 1 && os.Args[1] == "-a" && existeurl != 0 && existdownload == ""{
|
||||
var homepath = os.Getenv("HOME")
|
||||
filename := getFilename(urltoarchive)
|
||||
screenshotname := filename+".jpg"
|
||||
screenshotfullpath := homepath+"/.babil0niafiles/"+filename+".jpg"
|
||||
|
||||
err, filename := archiveURL(db,urltoarchive,screenshotfullpath,w)
|
||||
if err != nil {
|
||||
fmt.Printf("ERROR UPDATING")
|
||||
} else {
|
||||
updateUrl(db,screenshotname,urltoarchive)
|
||||
}
|
||||
}
|
||||
|
||||
if urltoarchive != "" && enabled < 2 || urltoarchive != "" && enabled > 1 && os.Args[1] != "-a" {
|
||||
m := Message{"Archive is disabled."}
|
||||
printMessage(w,m)
|
||||
}
|
||||
|
||||
if urltodelete != "" {
|
||||
imageURLname := getImageName(db,urltodelete)
|
||||
filetodelete := "screenshots/"+imageURLname
|
||||
os.Remove(filetodelete)
|
||||
deleteUrl(db,urltodelete)
|
||||
}
|
||||
|
||||
if urltoadd == "" && descriptoinsert == "" {
|
||||
displaybabil0nia(db, w,tagtosearch,wordtosearch)
|
||||
} else {
|
||||
if repetido != 0 {
|
||||
m := Message{"URL is duplicated."}
|
||||
printMessage(w,m)
|
||||
} else {
|
||||
insertUrl(db,urltoadd,descriptoinsert,tagtosearch)
|
||||
m := Message{"URL added successfully."}
|
||||
printMessage(w,m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func displaybabil0nia(db *sql.DB, w http.ResponseWriter,tagtosearch string, wordtosearch string) {
|
||||
var Arrayurlinfo []urlinfo
|
||||
var Repetidos []string
|
||||
tmpl := template.Must(template.ParseFiles("static/html/main.html"))
|
||||
p := urlinfo{}
|
||||
if tagtosearch == "" && wordtosearch == "" {
|
||||
row, err := db.Query("SELECT date,url,description,tags,screenshot FROM babil0nia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer row.Close()
|
||||
for row.Next() {
|
||||
var date string
|
||||
var url string
|
||||
var description string
|
||||
var tags string
|
||||
var screenshot string
|
||||
row.Scan( &date, &url, &description, &tags, &screenshot)
|
||||
// s is []string where tags are separated by ,
|
||||
s := strings.Split(tags, ",")
|
||||
//All s elementes are appended to Repetidos []string
|
||||
for _,element := range s {
|
||||
Repetidos = append(Repetidos,element)
|
||||
}
|
||||
p = urlinfo{date,url,description,tags,screenshot,s,nil}
|
||||
Arrayurlinfo = append(Arrayurlinfo, p)
|
||||
}
|
||||
}
|
||||
|
||||
if tagtosearch != "" && wordtosearch == "" {
|
||||
row, err := db.Query("SELECT date,url,description,tags,screenshot FROM babil0nia where tags like ?","%"+tagtosearch+"%")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer row.Close()
|
||||
for row.Next() {
|
||||
var date string
|
||||
var url string
|
||||
var description string
|
||||
var tags string
|
||||
var screenshot string
|
||||
row.Scan( &date, &url, &description, &tags, &screenshot)
|
||||
var s []string
|
||||
s = strings.Split(tags, ",")
|
||||
for _,element := range s {
|
||||
Repetidos = append(Repetidos,element)
|
||||
}
|
||||
p = urlinfo{date,url,description,tags,screenshot,s,nil}
|
||||
Arrayurlinfo = append(Arrayurlinfo, p)
|
||||
}
|
||||
}
|
||||
|
||||
if tagtosearch == "" && wordtosearch != "" {
|
||||
row, err := db.Query("SELECT date,url,description,tags,screenshot FROM babil0nia where url like ? or description like ?","%"+wordtosearch+"%","%"+wordtosearch+"%")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer row.Close()
|
||||
for row.Next() {
|
||||
var date string
|
||||
var url string
|
||||
var description string
|
||||
var tags string
|
||||
var screenshot string
|
||||
row.Scan( &date, &url, &description, &tags, &screenshot)
|
||||
var s []string
|
||||
s = strings.Split(tags, ",")
|
||||
for _,element := range s {
|
||||
Repetidos = append(Repetidos,element)
|
||||
}
|
||||
p = urlinfo{date,url,description,tags,screenshot,s,nil}
|
||||
Arrayurlinfo = append(Arrayurlinfo, p)
|
||||
}
|
||||
}
|
||||
|
||||
//Repetidos store now []string without tags duplicated.
|
||||
Repetidos = removeDuplicates(Repetidos)
|
||||
// Creates the last urlinfo struct with Repetidos.
|
||||
lastp := urlinfo{"","","","","",nil,Repetidos}
|
||||
Arrayurlinfo = append(Arrayurlinfo,lastp)
|
||||
tmpl.Execute(w,Arrayurlinfo)
|
||||
}
|
||||
|
||||
// Func to Print Messages through Web.
|
||||
func printMessage(w http.ResponseWriter, msg Message) {
|
||||
tmpl := template.Must(template.ParseFiles("static/html/message.html"))
|
||||
tmpl.Execute(w, msg)
|
||||
}
|
||||
|
||||
// Inserting URL into SQL.
|
||||
func insertUrl(db *sql.DB, url string, descriptoinsert string, tagstoinsert string) {
|
||||
currentTime := time.Now()
|
||||
date := currentTime.Format("01-02-2006")
|
||||
insertURLSQL := `INSERT INTO babil0nia(date,url,description,tags) VALUES (?,?,?,?)`
|
||||
statement, err := db.Prepare(insertURLSQL)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
_, err = statement.Exec(date, url,descriptoinsert, tagstoinsert)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Delete URL.
|
||||
func deleteUrl(db *sql.DB, url string) {
|
||||
deleteURLSQL := `DELETE FROM babil0nia WHERE url = ?`
|
||||
statement, err := db.Prepare(deleteURLSQL)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
_, err = statement.Exec(url)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Func to update an URL to add the filename of the screenshot.
|
||||
func updateUrl(db *sql.DB, filename string, url string) {
|
||||
updateURLSQL := `UPDATE babil0nia set screenshot = ? WHERE url = ?`
|
||||
statement, err := db.Prepare(updateURLSQL)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
_, err = statement.Exec(filename,url)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Func to check if URL is duplicated, it returns an int with the number of times that URL is repeated.
|
||||
func dupURL(db *sql.DB, url string) int{
|
||||
var total int
|
||||
row, err := db.Query("SELECT count(*) as total from babil0nia where url = ?",url)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer row.Close()
|
||||
for row.Next() {
|
||||
var count int
|
||||
row.Scan( &count)
|
||||
total = count
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// Func to check if URL has the file downloaded.
|
||||
func checkDownload(db *sql.DB, url string) string{
|
||||
var total string
|
||||
row, err := db.Query("SELECT screenshot from babil0nia where url = ?",url)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer row.Close()
|
||||
for row.Next() {
|
||||
var screenshot string
|
||||
row.Scan( &screenshot)
|
||||
total = screenshot
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
// Func to get the "id" that will be used as imagename from an given URL, it returns the id.
|
||||
func getImageName(db *sql.DB, url string) string{
|
||||
var imagename string
|
||||
row, err := db.Query("SELECT screenshot from babil0nia where url = ?",url)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer row.Close()
|
||||
for row.Next() {
|
||||
var screenshot string
|
||||
row.Scan( &screenshot)
|
||||
imagename = screenshot
|
||||
}
|
||||
return imagename
|
||||
}
|
||||
|
||||
// Func to remove duplicated strings from an slice.
|
||||
func removeDuplicates(strSlice []string) []string {
|
||||
allKeys := make(map[string]bool)
|
||||
list := []string{}
|
||||
for _, item := range strSlice {
|
||||
if _, value := allKeys[item]; !value {
|
||||
allKeys[item] = true
|
||||
list = append(list, item)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// Func to create a filename using the md5 hash of the url name.
|
||||
func getFilename(text string) string {
|
||||
hash := md5.Sum([]byte(text))
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
// Func to take one screenshot from the given URL and save it to a file. It returns error and the name of the saved (screenshot) file.
|
||||
func archiveURL(db *sql.DB,urltoarchive string, filename string,w http.ResponseWriter) (error,string){
|
||||
var fail error
|
||||
ctx, cancel := chromedp.NewContext(
|
||||
context.Background(),
|
||||
)
|
||||
defer cancel()
|
||||
var buf []byte
|
||||
if err := chromedp.Run(ctx, fullScreenshot(urltoarchive, 100, &buf)); err != nil {
|
||||
m := Message{"Error downloading."}
|
||||
printMessage(w,m)
|
||||
fail = err
|
||||
}
|
||||
if fail != nil {
|
||||
fmt.Println("Fallo la descarga de la imagen asi que nos e guarda")
|
||||
} else {
|
||||
if err := ioutil.WriteFile(filename, buf, 0o644); err != nil {
|
||||
m := Message{"Error saving the image."}
|
||||
printMessage(w,m)
|
||||
fail = err
|
||||
}
|
||||
}
|
||||
return fail, filename
|
||||
}
|
||||
|
||||
func fullScreenshot(urlstr string, quality int, res *[]byte) chromedp.Tasks {
|
||||
return chromedp.Tasks{
|
||||
chromedp.Navigate(urlstr),
|
||||
chromedp.FullScreenshot(res, quality),
|
||||
}
|
||||
}
|
||||
16
go.mod
Executable file
16
go.mod
Executable file
@ -0,0 +1,16 @@
|
||||
module spiderimage
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/chromedp/cdproto v0.0.0-20220725225757-5988d9195a6c // indirect
|
||||
github.com/chromedp/chromedp v0.8.3 // indirect
|
||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.8 // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
||||
)
|
||||
21
go.sum
Executable file
21
go.sum
Executable file
@ -0,0 +1,21 @@
|
||||
github.com/chromedp/cdproto v0.0.0-20220725225757-5988d9195a6c h1:Gm+DujZPVAtQNTLhbg5PExjRNfhdTCSMLvJ/pFfY4aY=
|
||||
github.com/chromedp/cdproto v0.0.0-20220725225757-5988d9195a6c/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
|
||||
github.com/chromedp/chromedp v0.8.3 h1:UwOY+fhC5Vv3uKgRpnvilCbWs/QPz8ciFwRB0q6pH8k=
|
||||
github.com/chromedp/chromedp v0.8.3/go.mod h1:9YfKSJnBNeP77vKecv+DNx2/Tcb+6Gli0d1aZPw/xbk=
|
||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
|
||||
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-sqlite3 v1.14.8 h1:gDp86IdQsN/xWjIEmr9MF6o9mpksUgh0fu+9ByFxzIU=
|
||||
github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
7
static/css/bootstrap.min.css
vendored
Executable file
7
static/css/bootstrap.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
61
static/html/add.html
Executable file
61
static/html/add.html
Executable file
@ -0,0 +1,61 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="styles/css">
|
||||
|
||||
<title>babil0nia</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #FFFDFA;
|
||||
}
|
||||
input[type="text"], textarea {
|
||||
background-color : #FFFDFA;
|
||||
}
|
||||
|
||||
.form-control-sm {
|
||||
font-family: inherit;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-bottom: 2px solid black;
|
||||
outline: 0;
|
||||
font-size: 1.3rem;
|
||||
padding: 7px 0;
|
||||
background: transparent;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column min-vh-100 justify-content-center align-items-center">
|
||||
<h1 class="py-5">babil0nia</h1>
|
||||
<form action="/">
|
||||
<div class="row">
|
||||
<div class="col-7">
|
||||
<input class="form-control-sm" type="text" autocomplete="off" id="url" name="url" placeholder="URL"><br><br>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<input class="form-control-sm" type="text" autocomplete="off" id="tags" name="tags" placeholder="tags"><br><br>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row py-3">
|
||||
<textarea class="form-control-sm" rows="1" id="description" name="description" placeholder="Description"></textarea><br><br>
|
||||
<div class="py-3">
|
||||
<input type="submit" class="btn btn-outline-dark" value="Submit">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
134
static/html/main.html
Executable file
134
static/html/main.html
Executable file
@ -0,0 +1,134 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="styles/css">
|
||||
<title>babil0nia</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #FFFDFA;
|
||||
padding-top: 100px;
|
||||
font-family: "Ubuntu Mono", monospace;
|
||||
}
|
||||
|
||||
|
||||
|
||||
input[type="text"] {
|
||||
background-color : #FFFDFA;
|
||||
}
|
||||
|
||||
.fixed-top {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 1030;
|
||||
}
|
||||
|
||||
.card-group {
|
||||
margin-right:5%;
|
||||
}
|
||||
|
||||
.form-control-sm {
|
||||
font-family: inherit;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
border-bottom: 2px solid black;
|
||||
outline: 0;
|
||||
font-size: 1.3rem;
|
||||
padding: 7px 0;
|
||||
background: transparent;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-light fixed-top navbar-masthead">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand">
|
||||
<form action="/add">
|
||||
<input type="submit" class="btn btn-outline-dark" value="+ Add" />
|
||||
</form>
|
||||
</a>
|
||||
<h1>babil0nia</h1>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="container py-5">
|
||||
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<form class="d-flex" action="/">
|
||||
<input class="form-control-sm me-2" autocomplete="off" type="text" name="wordtosearch" id="wordtosearch" placeholder="Search" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-10">
|
||||
{{range .}}
|
||||
<div>
|
||||
<span class="fw-light">{{.Date}}</span> <a target="_blank" href="{{.Url}}">{{.Url}}</a>
|
||||
|
||||
{{range .Separated}}
|
||||
<span class="badge bg-light"><a href="?tags={{.}}">{{.}}</a></span>
|
||||
{{end}}
|
||||
|
||||
{{ if eq .Url "" }}
|
||||
{{ else }}
|
||||
|
||||
<a href="/?delete={{.Url}}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
|
||||
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
|
||||
<path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
|
||||
</svg></a>
|
||||
|
||||
{{ if eq .Screenshot "" }}
|
||||
<a href="/?archive={{.Url}}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-arrow-down" viewBox="0 0 16 16">
|
||||
<path d="M8.5 6.5a.5.5 0 0 0-1 0v3.793L6.354 9.146a.5.5 0 1 0-.708.708l2 2a.5.5 0 0 0 .708 0l2-2a.5.5 0 0 0-.708-.708L8.5 10.293V6.5z"/>
|
||||
<path d="M14 14V4.5L9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2zM9.5 3A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h5.5v2z"/>
|
||||
</svg></a>
|
||||
{{ else }}
|
||||
<a target="_blank" href="screenshots/{{.Screenshot}}"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-card-image" viewBox="0 0 16 16">
|
||||
<path d="M6.002 5.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/>
|
||||
<path d="M1.5 2A1.5 1.5 0 0 0 0 3.5v9A1.5 1.5 0 0 0 1.5 14h13a1.5 1.5 0 0 0 1.5-1.5v-9A1.5 1.5 0 0 0 14.5 2h-13zm13 1a.5.5 0 0 1 .5.5v6l-3.775-1.947a.5.5 0 0 0-.577.093l-3.71 3.71-2.66-1.772a.5.5 0 0 0-.63.062L1.002 12v.54A.505.505 0 0 1 1 12.5v-9a.5.5 0 0 1 .5-.5h13z"/>
|
||||
</svg></a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{ if eq .Description "" }}
|
||||
{{ else }}
|
||||
<p class="py-2">{{.Description}}</p>
|
||||
<hr>
|
||||
{{end}}
|
||||
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h6>Tags</h6>
|
||||
{{range .}}
|
||||
{{range .Duplicated}}
|
||||
<a href="?tags={{.}}"><span class="badge bg-dark">{{.}}</a></span>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
31
static/html/message.html
Executable file
31
static/html/message.html
Executable file
@ -0,0 +1,31 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="styles/css">
|
||||
|
||||
<title>babil0nia Message</title>
|
||||
<style>
|
||||
body {
|
||||
background-color: #FFFDFA;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div class="d-flex align-items-center hv-100 vh-100">
|
||||
<div class="container text-center">
|
||||
<div>{{.Msj}}</div>
|
||||
<a class="my-3 badge rounded-pill bg-dark" href="/">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user