Skip to content

Commit

Permalink
Added Preview support
Browse files Browse the repository at this point in the history
  • Loading branch information
robrotheram committed Dec 30, 2023
1 parent eb1ff65 commit cb7c9f8
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 19 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ jobs:
fail-fast: false
matrix:
build:
- name: 'gogallery-linux'
- name: 'gogallery'
platform: 'linux/amd64'
os: 'ubuntu-latest'
- name: 'gogallery-win'
- name: 'gogallery'
platform: 'windows/amd64'
os: 'windows-latest'
- name: 'gogallery-macos'
- name: 'gogallery'
platform: 'darwin/universal'
os: 'macos-latest'

Expand Down
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"mode": "auto",
"cwd": "${workspaceFolder}",
"program": "main.go",
"args": ["build"]
"args": ["dev"]
}
]
}
106 changes: 106 additions & 0 deletions backend/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ package api

import (
"fmt"
"io"
"log"
"net/http"
"os"
"path"
"path/filepath"
"strings"

"github.com/gorilla/handlers"
"github.com/gorilla/mux"
Expand All @@ -12,6 +17,7 @@ import (
"github.com/robrotheram/gogallery/backend/monitor"
"github.com/robrotheram/gogallery/backend/pipeline"
templateengine "github.com/robrotheram/gogallery/backend/templateEngine"
"golang.org/x/net/html"
)

type GoGalleryAPI struct {
Expand Down Expand Up @@ -81,6 +87,10 @@ func (api *GoGalleryAPI) DashboardAPI() {
methods := handlers.AllowedMethods([]string{"GET", "POST", "PUT", "HEAD", "OPTIONS"})
origins := handlers.AllowedOrigins([]string{"*"})

api.router.PathPrefix("/preview-build").Handler(&home{
base: api.config.Gallery.Destpath,
})

log.Println("Starting api server on port: http://" + api.config.Server.GetLocalAddr())
log.Fatal(http.ListenAndServe(api.config.Server.GetLocalAddr(), handlers.CORS(origins, headers, methods)(api.router)))
}
Expand All @@ -91,3 +101,99 @@ func (api *GoGalleryAPI) Serve() {
log.Println("Starting server on port: http://" + api.config.Server.GetAddr())
log.Fatal(http.ListenAndServe(api.config.Server.GetAddr(), nil))
}

type home struct {
base string
}

func getAttribute(n *html.Node, attributeName string) string {
for _, attr := range n.Attr {
if attr.Key == attributeName {
return attr.Val
}
}
return ""
}

func updateLinks(n *html.Node) {
if n.Type == html.ElementNode {
if n.Data == "a" || n.Data == "img" || (n.Data == "link" && getAttribute(n, "rel") == "stylesheet") {
updateHrefAttribute(n, "href")
updateHrefAttribute(n, "src")
}
}

for c := n.FirstChild; c != nil; c = c.NextSibling {
updateLinks(c)
}
}

func updateHrefAttribute(n *html.Node, attributeName string) {
if hrefAttr := findAttribute(n, attributeName); hrefAttr != nil {
href := hrefAttr.Val
if href != "" && !strings.HasPrefix(href, "http") {
// Update the href attribute value by adding the "/dev/" prefix
hrefAttr.Val = "/preview-build" + href
}
}
}

func findAttribute(n *html.Node, attributeName string) *html.Attribute {
for i := range n.Attr {
if n.Attr[i].Key == attributeName {
return &n.Attr[i]
}
}
return nil
}

func GetFileContentType(ouput *os.File) (string, error) {
buf := make([]byte, 512)
_, err := ouput.Read(buf)
if err != nil {
return "", err
}
contentType := http.DetectContentType(buf)
if contentType == "text/plain; charset=utf-8" && filepath.Ext(ouput.Name()) == ".svg" {
contentType = "image/svg+xml; charset=utf-8"
} else if contentType == "text/plain; charset=utf-8" && filepath.Ext(ouput.Name()) == ".css" {
contentType = "text/css; charset=utf-8"
}
ouput.Seek(0, 0)
return contentType, nil
}

func IsHtml(constentType string) bool {
return strings.Contains(constentType, "text/html")
}

func (h *home) ServeHTTP(w http.ResponseWriter, r *http.Request) {
data := strings.Replace(r.URL.Path, "/preview-build", "", -1)

data = path.Join(h.base, data)
fileInfo, err := os.Stat(data)
if err != nil {
return
}
if fileInfo.IsDir() {
data = path.Join(data, "index.html")
}
fmt.Println(data)
file, err := os.Open(data)
if err != nil {
return
}
contentType, _ := GetFileContentType(file)
if IsHtml(contentType) {
doc, err := html.Parse(file)
if err != nil {
fmt.Println(err)
}
updateLinks(doc)
html.Render(w, doc)
} else {
w.Header().Set("Content-Type", contentType)
io.Copy(w, file)
}

}
2 changes: 1 addition & 1 deletion backend/cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var devCMD = &cobra.Command{
config := config.LoadConfig()
db := datastore.Open(config.Gallery.Basepath)
defer db.Close()
db.ScanPath(config.Gallery.Basepath)
// db.ScanPath(config.Gallery.Basepath)
config.Server.Port = "8800"
api.NewGoGalleryAPI(config, db).DashboardAPI()
},
Expand Down
24 changes: 15 additions & 9 deletions frontend/src/components/header.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { LogoutOutlined, SearchOutlined, SettingOutlined } from '@ant-design/icons';
import { DesktopOutlined, SearchOutlined, SettingOutlined } from '@ant-design/icons';
// as an array
import { Layout, Menu, Input, Avatar } from 'antd';
import { userActions } from '../store/actions';
Expand All @@ -20,21 +20,27 @@ const HeaderComponent = ({ search }) => {
const get_gravatar = (size) => {
var MD5 = function (s) { function L(k, d) { return (k << d) | (k >>> (32 - d)) } function K(G, k) { var I, d, F, H, x; F = (G & 2147483648); H = (k & 2147483648); I = (G & 1073741824); d = (k & 1073741824); x = (G & 1073741823) + (k & 1073741823); if (I & d) { return (x ^ 2147483648 ^ F ^ H) } if (I | d) { if (x & 1073741824) { return (x ^ 3221225472 ^ F ^ H) } else { return (x ^ 1073741824 ^ F ^ H) } } else { return (x ^ F ^ H) } } function r(d, F, k) { return (d & F) | ((~d) & k) } function q(d, F, k) { return (d & k) | (F & (~k)) } function p(d, F, k) { return (d ^ F ^ k) } function n(d, F, k) { return (F ^ (d | (~k))) } function u(G, F, aa, Z, k, H, I) { G = K(G, K(K(r(F, aa, Z), k), I)); return K(L(G, H), F) } function f(G, F, aa, Z, k, H, I) { G = K(G, K(K(q(F, aa, Z), k), I)); return K(L(G, H), F) } function D(G, F, aa, Z, k, H, I) { G = K(G, K(K(p(F, aa, Z), k), I)); return K(L(G, H), F) } function t(G, F, aa, Z, k, H, I) { G = K(G, K(K(n(F, aa, Z), k), I)); return K(L(G, H), F) } function e(G) { var Z; var F = G.length; var x = F + 8; var k = (x - (x % 64)) / 64; var I = (k + 1) * 16; var aa = Array(I - 1); var d = 0; var H = 0; while (H < F) { Z = (H - (H % 4)) / 4; d = (H % 4) * 8; aa[Z] = (aa[Z] | (G.charCodeAt(H) << d)); H++ } Z = (H - (H % 4)) / 4; d = (H % 4) * 8; aa[Z] = aa[Z] | (128 << d); aa[I - 2] = F << 3; aa[I - 1] = F >>> 29; return aa } function B(x) { var k = "", F = "", G, d; for (d = 0; d <= 3; d++) { G = (x >>> (d * 8)) & 255; F = "0" + G.toString(16); k = k + F.substr(F.length - 2, 2) } return k } function J(k) { k = k.replace(/rn/g, "n"); var d = ""; for (var F = 0; F < k.length; F++) { var x = k.charCodeAt(F); if (x < 128) { d += String.fromCharCode(x) } else { if ((x > 127) && (x < 2048)) { d += String.fromCharCode((x >> 6) | 192); d += String.fromCharCode((x & 63) | 128) } else { d += String.fromCharCode((x >> 12) | 224); d += String.fromCharCode(((x >> 6) & 63) | 128); d += String.fromCharCode((x & 63) | 128) } } } return d } var C = []; var P, h, E, v, g, Y, X, W, V; var S = 7, Q = 12, N = 17, M = 22; var A = 5, z = 9, y = 14, w = 20; var o = 4, m = 11, l = 16, j = 23; var U = 6, T = 10, R = 15, O = 21; s = J(s); C = e(s); Y = 1732584193; X = 4023233417; W = 2562383102; V = 271733878; for (P = 0; P < C.length; P += 16) { h = Y; E = X; v = W; g = V; Y = u(Y, X, W, V, C[P + 0], S, 3614090360); V = u(V, Y, X, W, C[P + 1], Q, 3905402710); W = u(W, V, Y, X, C[P + 2], N, 606105819); X = u(X, W, V, Y, C[P + 3], M, 3250441966); Y = u(Y, X, W, V, C[P + 4], S, 4118548399); V = u(V, Y, X, W, C[P + 5], Q, 1200080426); W = u(W, V, Y, X, C[P + 6], N, 2821735955); X = u(X, W, V, Y, C[P + 7], M, 4249261313); Y = u(Y, X, W, V, C[P + 8], S, 1770035416); V = u(V, Y, X, W, C[P + 9], Q, 2336552879); W = u(W, V, Y, X, C[P + 10], N, 4294925233); X = u(X, W, V, Y, C[P + 11], M, 2304563134); Y = u(Y, X, W, V, C[P + 12], S, 1804603682); V = u(V, Y, X, W, C[P + 13], Q, 4254626195); W = u(W, V, Y, X, C[P + 14], N, 2792965006); X = u(X, W, V, Y, C[P + 15], M, 1236535329); Y = f(Y, X, W, V, C[P + 1], A, 4129170786); V = f(V, Y, X, W, C[P + 6], z, 3225465664); W = f(W, V, Y, X, C[P + 11], y, 643717713); X = f(X, W, V, Y, C[P + 0], w, 3921069994); Y = f(Y, X, W, V, C[P + 5], A, 3593408605); V = f(V, Y, X, W, C[P + 10], z, 38016083); W = f(W, V, Y, X, C[P + 15], y, 3634488961); X = f(X, W, V, Y, C[P + 4], w, 3889429448); Y = f(Y, X, W, V, C[P + 9], A, 568446438); V = f(V, Y, X, W, C[P + 14], z, 3275163606); W = f(W, V, Y, X, C[P + 3], y, 4107603335); X = f(X, W, V, Y, C[P + 8], w, 1163531501); Y = f(Y, X, W, V, C[P + 13], A, 2850285829); V = f(V, Y, X, W, C[P + 2], z, 4243563512); W = f(W, V, Y, X, C[P + 7], y, 1735328473); X = f(X, W, V, Y, C[P + 12], w, 2368359562); Y = D(Y, X, W, V, C[P + 5], o, 4294588738); V = D(V, Y, X, W, C[P + 8], m, 2272392833); W = D(W, V, Y, X, C[P + 11], l, 1839030562); X = D(X, W, V, Y, C[P + 14], j, 4259657740); Y = D(Y, X, W, V, C[P + 1], o, 2763975236); V = D(V, Y, X, W, C[P + 4], m, 1272893353); W = D(W, V, Y, X, C[P + 7], l, 4139469664); X = D(X, W, V, Y, C[P + 10], j, 3200236656); Y = D(Y, X, W, V, C[P + 13], o, 681279174); V = D(V, Y, X, W, C[P + 0], m, 3936430074); W = D(W, V, Y, X, C[P + 3], l, 3572445317); X = D(X, W, V, Y, C[P + 6], j, 76029189); Y = D(Y, X, W, V, C[P + 9], o, 3654602809); V = D(V, Y, X, W, C[P + 12], m, 3873151461); W = D(W, V, Y, X, C[P + 15], l, 530742520); X = D(X, W, V, Y, C[P + 2], j, 3299628645); Y = t(Y, X, W, V, C[P + 0], U, 4096336452); V = t(V, Y, X, W, C[P + 7], T, 1126891415); W = t(W, V, Y, X, C[P + 14], R, 2878612391); X = t(X, W, V, Y, C[P + 5], O, 4237533241); Y = t(Y, X, W, V, C[P + 12], U, 1700485571); V = t(V, Y, X, W, C[P + 3], T, 2399980690); W = t(W, V, Y, X, C[P + 10], R, 4293915773); X = t(X, W, V, Y, C[P + 1], O, 2240044497); Y = t(Y, X, W, V, C[P + 8], U, 1873313359); V = t(V, Y, X, W, C[P + 15], T, 4264355552); W = t(W, V, Y, X, C[P + 6], R, 2734768916); X = t(X, W, V, Y, C[P + 13], O, 1309151649); Y = t(Y, X, W, V, C[P + 4], U, 4149444226); V = t(V, Y, X, W, C[P + 11], T, 3174756917); W = t(W, V, Y, X, C[P + 2], R, 718787259); X = t(X, W, V, Y, C[P + 9], O, 3951481745); Y = K(Y, h); X = K(X, E); W = K(W, v); V = K(V, g) } var i = B(Y) + B(X) + B(W) + B(V); return i.toLowerCase() };
size = size || 80;
return 'https://www.gravatar.com/avatar/' + MD5(email || "" ) + '.jpg?s=' + size;
return 'https://www.gravatar.com/avatar/' + MD5(email || "") + '.jpg?s=' + size;
}

const menuItems = [{
label: (<Link to="/settings"><SettingOutlined style={{fontSize:"18px"}} /></Link>),
key: 'settings'
}]

return (
<Header className="header" style={{ padding: 0 }}>
<Link to="/"><div className="brand">GoGallery</div></Link>
{location.pathname === "/" &&
<Input size="large" bordered={false} prefix={<SearchOutlined />} placeholder="Filter Photos" onChange={handleSearch} style={{ width: "400px" }} />
}
<Menu theme="dark" mode="horizontal" selectable={true} style={{ float: "right" }} items={menuItems}/>
<Menu theme="dark" mode="horizontal" selectable={true} style={{ float: "right" }} items={[
{
label: (<Link to="/settings"><SettingOutlined style={{ fontSize: "18px" }} /></Link>),
key: 'settings'
}
]} />
<Menu theme="dark" mode="horizontal" selectable={true} style={{ float: "right" }} items={[
{
label: (<Link to="/preview"><DesktopOutlined style={{ fontSize: "18px" }} /></Link>),
key: 'preview'
}
]} />

</Header>
);
}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,13 @@ const SideBar = ({ photo }) => {
</Form.Item>
</Panel>
<Panel header="History" key="3">
<Form.Item label="Captured">
<Form.Item label="Captured" style={{marginBottom:"10px"}}>
{data.exif ? formatDate(data.exif.date_taken) : ""}
</Form.Item>
<Form.Item label="Uploaded">
<Form.Item label="Uploaded" style={{marginBottom:"10px"}}>
{data.meta ? formatDate(data.meta.date_added) : ""}
</Form.Item>
<Form.Item label="Modified">
<Form.Item label="Modified" style={{marginBottom:"10px"}}>
{data.meta ? formatDate(data.meta.date_modified) : ""}
</Form.Item>
</Panel>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import Main from './pages/Main';
import Settings from './pages/Settings'
import { Button, ConfigProvider, Layout, theme } from 'antd';
import Preview from './pages/Preview';

const NoMatch = ({ location }) => (
<Navigate to="/" />
Expand All @@ -27,6 +28,7 @@ const AppComponent = () => {
<Routes>
<Route path="/" element={(<Main/>)} />
<Route path="/settings" element={(<Settings/>)} />
<Route path="/preview" element={(<Preview/>)} />
<Route element={NoMatch} />
</Routes>
</BrowserRouter>
Expand Down
22 changes: 22 additions & 0 deletions frontend/src/pages/Preview.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { useEffect, useState } from 'react';
import './Main.css';

import { Layout } from 'antd';
import { useDispatch } from 'react-redux';
import Header from '../components/header'
const { Content } = Layout;

const Preview = () => {
return (
<Layout style={{ minHeight: '100vh' }}>
<Header />
<Layout>
<Content style={{ padding: '20px', height: 'calc( 100vh - 60px)', overflow:"auto"}}>
<iframe src='http://localhost:8800/preview-build' width={"100%"} height={"100%"}/>
</Content>
</Layout>
</Layout>
);

}
export default Preview;
2 changes: 1 addition & 1 deletion frontend/src/pages/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const Settings = () => {
<Layout style={{ minHeight: '100vh' }}>
<Header />
<Layout>
<Content style={{ padding: '50px' }}>
<Content style={{ padding: '50px', height: '100px', overflow:"auto"}}>
<Row gutter={16}>
<Col span={8}>
<Card>
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ require (
github.com/tdewolff/minify/v2 v2.20.10
github.com/wailsapp/wails/v2 v2.7.1
golang.org/x/image v0.14.0
golang.org/x/net v0.19.0
)

require (
Expand Down Expand Up @@ -113,7 +114,6 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
Expand Down

0 comments on commit cb7c9f8

Please sign in to comment.