├── go.mod
├── img
└── gohome.jpg
├── sample_scripts
├── memory.sh
└── cpu.sh
├── templates
├── entrie.txt
├── default.html
└── default.css
├── README.md
└── main.go
/go.mod:
--------------------------------------------------------------------------------
1 | module SeungheonOh/GoHome
2 |
3 | go 1.13
4 |
--------------------------------------------------------------------------------
/img/gohome.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SeungheonOh/GoHome/HEAD/img/gohome.jpg
--------------------------------------------------------------------------------
/sample_scripts/memory.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | free -m | awk 'NR==2{printf "%.2f",$3*100/$2 }'
3 |
--------------------------------------------------------------------------------
/sample_scripts/cpu.sh:
--------------------------------------------------------------------------------
1 | top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}'
2 |
--------------------------------------------------------------------------------
/templates/entrie.txt:
--------------------------------------------------------------------------------
1 | !GitLab
2 | MyDots Redirect('https://www.github.com/SeungheonOh/Dots')
3 |
4 | !Reddit
5 | *Nix Redirect('https://www.reddit.com/r/unixporn')
6 |
7 | !AnyOtherCustomGroups
8 | a Redirect('https://www.github.com/SeungheonOh/GoHome')
9 | b Redirect('https://www.github.com/SeungheonOh/GoHome')
10 | c Redirect('https://www.github.com/SeungheonOh/GoHome')
11 |
12 | !Application
13 | terminal Launch('st')
14 | htop Launch('st -e htop')
15 | vim Launch('st -e vim')
16 |
17 | +Memory: ${Launch('bash -c ./sample_scripts/memory.sh')}%
18 |
--------------------------------------------------------------------------------
/templates/default.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
20 | New Tab
21 |
22 |
23 |
24 |
25 |
[GoHome ~]$ tree
26 |
27 |
.
28 |
29 | {{range .EntrieGroups}}
30 | -
31 |
{{.SubTitle}}
32 |
33 | {{range .Entries}}
34 | - {{.Name}}
35 | {{end}}
36 |
37 |
38 | {{end}}
39 |
40 |
41 |
42 | {{range .Labels}}
43 |
Loading
44 | {{end}}
45 |
46 |
[GoHome ~]$ ddg
47 |
51 |
52 |
53 |
54 |
55 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GoHome
2 | Have you guys seen those cool looking single filed homepages on Linux communites? It looks really cool, but it's just a shallow shell
3 | which only can let you go to pre-setted internet pages. GoHome in other hand, can do much more, such as opening applications,
4 | shutting your system down, or fetching your system data to your local homepage. Not only that, GoHome also comes with
5 | easy setup system that does not require any tidious html coding processes, just simple and nice entrie lists-you can customize css as you desire.
6 |
7 | 
8 | Theme from [/u/nytly](https://www.reddit.com/user/nytly/), Thanks!
9 |
10 | # Installation
11 | GoHome is only written with go standard libraries! So you can just download ordinary go compiler, run it!
12 | You can also add gohome to system service so it starts up automatically on your system's startup.
13 |
14 | # Example Entrie File
15 | ```
16 | !Application
17 | terminal Launch('st')
18 | chrome Launch('google-chrome-stable')
19 | htop Launch('st -e htop')
20 | vim Launch('st -e vim')
21 | code Launch('code')
22 | pipes Launch('st -e pipes.sh')
23 | cowsayToConsole console.log(Launch('cowsay hello world'))
24 |
25 | !Website
26 | reddit Launch('xdg-open https://www.reddit.com')
27 | google Launch('xdg-open https://www.google.com')
28 | ArchWiki Launch('xdg-open https://wiki.archlinux.org')
29 | *nix Launch('xdg-open https://www.reddit.com/r/unixporn')
30 |
31 | !FunStuff
32 | youtube Launch('xdg-open https://www.youtube.com')
33 | DankMemes Launch('xdg-open https://www.reddit.com/r/dankmemes')
34 | MoonBuggy Launch('st -e moon-buggy')
35 |
36 | +CPU: ${Launch('bash -c ./sample_scripts/cpu.sh')}%
37 | +Memory: ${Launch('bash -c ./sample_scripts/memory.sh')}%
38 |
39 | ```
40 |
41 | # Options
42 | ```
43 | -c Set CSS file
44 | -t Set Template file
45 | -e Set Entrie file
46 | ```
47 |
48 | #Inspired by
49 | 
50 | and many other *nix porn posts!
51 |
--------------------------------------------------------------------------------
/templates/default.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "Iosevka Regular";
3 | font-weight: "bold"
4 | }
5 |
6 | :root {
7 | --font: "Iosevka Regular";
8 | --background: #0f0f13;
9 | --foreground: #fffffe;
10 | --pink: #62b3e4;
11 | --red: #f25f4c;
12 | --orange: #ff8906;
13 | --branch: 1px solid #a7a9be;
14 | }
15 |
16 | html {
17 | font-size: 18px;
18 | font-weight: bold;
19 | }
20 |
21 | body {
22 | background: var(--background);
23 | }
24 |
25 | .container {
26 | position: absolute;
27 | top: 50%;
28 | left: 45%;
29 | transform: translate(-50%, -50%);
30 | }
31 |
32 | .prompt {
33 | font-family: var(--font);
34 | font-weight: bold;
35 | color: var(--foreground);
36 | }
37 |
38 | .prompt~.prompt {
39 | padding: 1.5rem 0 0.3125rem;
40 | }
41 |
42 | span {
43 | color: var(--pink);
44 | }
45 |
46 | h1 {
47 | display: inline;
48 | font-family: var(--font);
49 | font-size: 1rem;
50 | font-weight: bold;
51 | color: var(--red);
52 | }
53 |
54 | .tree > ul {
55 | margin: 0;
56 | padding-left: 1rem;
57 | }
58 |
59 | ul {
60 | list-style: none;
61 | padding-left: 2.5rem;
62 | }
63 |
64 | li {
65 | position: relative;
66 | }
67 |
68 | li::before, li::after {
69 | content: "";
70 | position: absolute;
71 | left: -0.75rem;
72 | }
73 |
74 | li::before {
75 | border-top: var(--branch);
76 | top: 0.75rem;
77 | width: 0.5rem;
78 | }
79 |
80 | li::after {
81 | border-left: var(--branch);
82 | height: 100%;
83 | top: 0.25rem;
84 | }
85 |
86 | li:last-child::after {
87 | height: 0.5rem;
88 | }
89 |
90 | a {
91 | font-family: var(--font);
92 | font-size: 1rem;
93 | font-weight: bold;
94 | color: var(--foreground);
95 | text-decoration: none;
96 | outline: none;
97 | }
98 |
99 | a:hover {
100 | color: var(--background);
101 | background: var(--orange);
102 | }
103 |
104 | form h1 {
105 | padding-left: 0.125rem;
106 | }
107 |
108 | input {
109 | font-family: var(--font);
110 | font-size: 1rem;
111 | font-weight: bold;
112 | color: var(--foreground);
113 | background-color: var(--background);
114 | border: none;
115 | }
116 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "flag"
6 | "fmt"
7 | "io/ioutil"
8 | "log"
9 | "net/http"
10 | "os"
11 | "os/exec"
12 | "strings"
13 | "text/template"
14 | "time"
15 | )
16 |
17 | type Cmd struct {
18 | Output []byte
19 | Error error
20 | }
21 |
22 | func RunCommand(ch chan<- Cmd, s []string) {
23 | output, err := exec.Command(s[0], s[1:]...).Output()
24 | ch <- Cmd{Output: output, Error: err}
25 | }
26 |
27 | type Entrie struct {
28 | Name string
29 | Command string
30 | }
31 |
32 | type EntrieGroup struct {
33 | SubTitle string
34 | Entries []Entrie
35 | }
36 |
37 | type Label struct {
38 | Prompt string
39 | }
40 |
41 | type HomeMenu struct {
42 | Title string
43 | CSS string
44 | EntrieGroups []EntrieGroup
45 | Labels []Label
46 | }
47 |
48 | var (
49 | CSSFile string
50 | HTMLTemplate string
51 | EntrieFile string
52 | ServerPort string
53 | NoLog bool
54 | )
55 |
56 | func init() {
57 | flag.StringVar(&CSSFile, "c", "", "Set CSS")
58 | flag.StringVar(&CSSFile, "css", "./templates/default.css", "Set CSS")
59 |
60 | flag.StringVar(&HTMLTemplate, "t", "", "Set Tamplate")
61 | flag.StringVar(&HTMLTemplate, "tamplate", "./templates/default.html", "Set Tamplate")
62 |
63 | flag.StringVar(&EntrieFile, "e", "", "Set Tamplate")
64 | flag.StringVar(&EntrieFile, "entrie", "./templates/entrie.txt", "Set Entries")
65 |
66 | flag.StringVar(&ServerPort, "p", "", "Set server port")
67 | flag.StringVar(&ServerPort, "port", "8080", "Set server port")
68 |
69 | flag.BoolVar(&NoLog, "n", false, "Disable Log")
70 | flag.BoolVar(&NoLog, "nolog", false, "Disable Log")
71 | }
72 |
73 | func main() {
74 | flag.Parse()
75 |
76 | log.SetFlags(log.Ltime | log.Llongfile)
77 | if NoLog {
78 | log.SetFlags(0)
79 | log.SetOutput(ioutil.Discard)
80 | }
81 |
82 | css, err := ioutil.ReadFile(CSSFile)
83 | if err != nil {
84 | log.Fatal(err)
85 | }
86 | html, err := ioutil.ReadFile(HTMLTemplate)
87 | if err != nil {
88 | log.Fatal(err)
89 | }
90 |
91 | file, err := os.Open(EntrieFile)
92 | if err != nil {
93 | log.Fatal(err)
94 | }
95 | defer file.Close()
96 |
97 | scanner := bufio.NewScanner(file)
98 |
99 | HomePage := HomeMenu{
100 | Title: "",
101 | CSS: string(css),
102 | }
103 |
104 | for scanner.Scan() {
105 | line := scanner.Text()
106 | if len(line) <= 0 {
107 | continue
108 | }
109 |
110 | var group EntrieGroup
111 | if line[0] == '!' {
112 | group.SubTitle = line[1:]
113 | for scanner.Scan() {
114 | if len(scanner.Text()) <= 0 || scanner.Text()[0] == '!' {
115 | HomePage.EntrieGroups = append(HomePage.EntrieGroups, group)
116 | break
117 | }
118 | divided := strings.Fields(scanner.Text())
119 | group.Entries = append(group.Entries, Entrie{divided[0], strings.Join(divided[1:], " ")})
120 | }
121 | } else if line[0] == '+' {
122 | HomePage.Labels = append(HomePage.Labels, Label{line[1:]})
123 | }
124 | }
125 |
126 | tmpl, err := template.New("").Parse(string(html))
127 | if err != nil {
128 | log.Fatal(err)
129 | }
130 |
131 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
132 | w.Header().Set("Access-Control-Allow-Origin", "*")
133 | w.Header().Set("Access-Control-Allow-Methods", "GET,POST")
134 | w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
135 |
136 | tmpl.Execute(w, HomePage)
137 | log.Printf("requested to home")
138 | })
139 | http.HandleFunc("/run/", func(w http.ResponseWriter, r *http.Request) {
140 | path := r.URL.Path
141 | log.Printf("Command: %s\n", path[len("/run/"):len(path)])
142 |
143 | c := make(chan Cmd)
144 |
145 | app := strings.Fields(path[len("/run/"):len(path)])
146 | go RunCommand(c, app)
147 |
148 | var out Cmd
149 | select {
150 | case o := (<-c):
151 | out = o
152 | case <-time.After(300 * time.Millisecond):
153 | return
154 | }
155 | if out.Error != nil {
156 | log.Println(err)
157 | }
158 |
159 | log.Printf("\n%s", string(out.Output))
160 |
161 | fmt.Fprintf(w, string(out.Output))
162 | })
163 |
164 | serverAddress := ":" + ServerPort
165 | log.Fatal(http.ListenAndServe(serverAddress, nil))
166 | }
167 |
--------------------------------------------------------------------------------