Compare commits
19 Commits
26f1008dc4
...
server/tem
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f44974c58 | ||
|
|
a62b445f19 | ||
|
|
13fae1c23f | ||
|
|
21719a6cf7 | ||
| addaade269 | |||
|
|
6ee6c9c8d9 | ||
|
|
a0133e0981 | ||
| 70c668bdf1 | |||
|
|
68c89de1a4 | ||
|
|
0b7de76874 | ||
|
|
797e115191 | ||
|
|
16a65df664 | ||
|
|
4e87c77ccb | ||
|
|
94b3f4c0f2 | ||
|
|
f574a00a8f | ||
|
|
5bce49eed4 | ||
|
|
51b788bb50 | ||
|
|
7f43eb43e0 | ||
|
|
81b960c231 |
@@ -13,7 +13,7 @@ go install gitea.elara.ws/Hazel/transfem-startpage
|
||||
Then you can run the program `transfem-startpage`
|
||||
|
||||
```sh
|
||||
transfem-startpage
|
||||
transfem-startpage help
|
||||
```
|
||||
|
||||
To configure this new tab page as website, you can install the firefox extension [New Tab Override](https://addons.mozilla.org/en-US/firefox/addon/new-tab-override/). Then just configure the url as `http://127.0.0.1:{port}/`. The default port should be `5500` but it will also print it out when starting the server. Make sure to check the box `Set focus to the web page instead of the address bar` in the extension settings, because the new tab page auto focuses the search bar.
|
||||
@@ -55,9 +55,8 @@ air dev
|
||||
|
||||
## TODO
|
||||
|
||||
- implementing proper command line args
|
||||
- clear cache
|
||||
- implement fetching in intervals
|
||||
- implement templating for every one of the frontend files
|
||||
- implement functionality to clear and clean cache
|
||||
- host this website on a demo page
|
||||
- implement ctl
|
||||
- implement autocomplete with a nice go backend and fast communication. Since it all runs locally nobody should have privacy concerns NEEDS TO BE ABLE TO TOGGLED OFF FOR DEMO PAGE
|
||||
|
||||
17
demo.toml
Normal file
17
demo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[Server]
|
||||
Port = 1312
|
||||
|
||||
[DiyHrt]
|
||||
FetchIntervals = 60
|
||||
|
||||
[Template]
|
||||
ActiveCard = "listings"
|
||||
PageTitle = "TransfemStartpage demo"
|
||||
HeaderPhrases = [
|
||||
"GirlJuice.Inject();",
|
||||
"You.Cute = true;",
|
||||
"You.Gay = true;",
|
||||
"Nazi.Punch();",
|
||||
"Dolls.GiveGuns();",
|
||||
"Firefox > Chrome"
|
||||
]
|
||||
@@ -1,293 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="350mm"
|
||||
height="250mm"
|
||||
viewBox="0 0 350 250"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="bg.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:export-bgcolor="#00000000"
|
||||
inkscape:zoom="0.48315491"
|
||||
inkscape:cx="734.75399"
|
||||
inkscape:cy="595.04724"
|
||||
inkscape:window-width="1672"
|
||||
inkscape:window-height="957"
|
||||
inkscape:window-x="816"
|
||||
inkscape:window-y="1259"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<rect
|
||||
x="1105.2356"
|
||||
y="300.11078"
|
||||
width="161.4389"
|
||||
height="53.812968"
|
||||
id="rect4" />
|
||||
<rect
|
||||
x="203.42924"
|
||||
y="897.13763"
|
||||
width="220.99149"
|
||||
height="62.931351"
|
||||
id="rect3" />
|
||||
<rect
|
||||
x="140.49789"
|
||||
y="166.84126"
|
||||
width="339.53659"
|
||||
height="86.347672"
|
||||
id="rect2" />
|
||||
<rect
|
||||
x="125.8627"
|
||||
y="753.71271"
|
||||
width="357.09882"
|
||||
height="87.811188"
|
||||
id="rect1" />
|
||||
<rect
|
||||
x="125.8627"
|
||||
y="753.71271"
|
||||
width="357.09882"
|
||||
height="87.811188"
|
||||
id="rect1-7" />
|
||||
<rect
|
||||
x="125.8627"
|
||||
y="753.71271"
|
||||
width="357.09882"
|
||||
height="87.811188"
|
||||
id="rect1-2" />
|
||||
<rect
|
||||
x="125.8627"
|
||||
y="753.71271"
|
||||
width="357.09882"
|
||||
height="87.811188"
|
||||
id="rect1-9" />
|
||||
<rect
|
||||
x="125.8627"
|
||||
y="753.71271"
|
||||
width="357.09882"
|
||||
height="87.811188"
|
||||
id="rect1-6" />
|
||||
<rect
|
||||
x="140.49789"
|
||||
y="166.84126"
|
||||
width="339.53659"
|
||||
height="86.347672"
|
||||
id="rect2-0" />
|
||||
<rect
|
||||
x="140.49789"
|
||||
y="166.84126"
|
||||
width="339.53659"
|
||||
height="86.347672"
|
||||
id="rect2-2" />
|
||||
<rect
|
||||
x="140.49789"
|
||||
y="166.84126"
|
||||
width="339.53659"
|
||||
height="86.347672"
|
||||
id="rect2-2-6" />
|
||||
<rect
|
||||
x="1105.2356"
|
||||
y="300.11078"
|
||||
width="161.4389"
|
||||
height="53.812969"
|
||||
id="rect4-4" />
|
||||
<rect
|
||||
x="1105.2356"
|
||||
y="300.11078"
|
||||
width="161.4389"
|
||||
height="53.812969"
|
||||
id="rect4-3" />
|
||||
<rect
|
||||
x="1105.2356"
|
||||
y="300.11078"
|
||||
width="161.4389"
|
||||
height="53.812969"
|
||||
id="rect4-3-2" />
|
||||
<rect
|
||||
x="125.8627"
|
||||
y="753.71271"
|
||||
width="357.09882"
|
||||
height="87.811188"
|
||||
id="rect1-2-4" />
|
||||
<rect
|
||||
x="1105.2356"
|
||||
y="300.11078"
|
||||
width="161.4389"
|
||||
height="53.812969"
|
||||
id="rect4-3-3" />
|
||||
<rect
|
||||
x="1105.2356"
|
||||
y="300.11078"
|
||||
width="161.4389"
|
||||
height="53.812969"
|
||||
id="rect6" />
|
||||
<rect
|
||||
x="140.49789"
|
||||
y="166.84126"
|
||||
width="339.53659"
|
||||
height="86.347672"
|
||||
id="rect2-2-6-7" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26273149,-0.03124901,0.03124901,0.26273149,9.6318685,1.010781)"
|
||||
id="text1"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="125.86328"
|
||||
y="784.2323"
|
||||
id="tspan7">Meow</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26223034,0.03520772,-0.03520772,0.26223034,181.67491,-73.913601)"
|
||||
id="text1-3"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-7);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="125.86328"
|
||||
y="784.2323"
|
||||
id="tspan8">Meow</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.2637851,0.02053679,-0.02053679,0.2637851,9.5700315,-96.792778)"
|
||||
id="text1-1"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-2);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="125.86328"
|
||||
y="784.2323"
|
||||
id="tspan9">Meow</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26279038,-0.03074987,0.03074987,0.26279038,54.519132,-87.602003)"
|
||||
id="text1-1-6"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-2-4);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="125.86328"
|
||||
y="784.2323"
|
||||
id="tspan10">Meow</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26273149,-0.03124901,0.03124901,0.26273149,160.00124,-138.94545)"
|
||||
id="text1-6"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-9);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="125.86328"
|
||||
y="784.2323"
|
||||
id="tspan11">Meow</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26430785,-0.01207042,0.01207042,0.26430785,123.83488,0.36913542)"
|
||||
id="text1-8"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect1-6);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="125.86328"
|
||||
y="784.2323"
|
||||
id="tspan12">Meow</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,-21.357022,-13.142783)"
|
||||
id="text2"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect2);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="140.49805"
|
||||
y="197.36121"
|
||||
id="tspan13">gock <333</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26309895,-0.02798714,0.02798714,0.26309895,43.481131,24.812837)"
|
||||
id="text2-3"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect2-0);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="140.49805"
|
||||
y="197.36121"
|
||||
id="tspan14">gock <333</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26094671,-0.04371676,0.04371676,0.26094671,222.97079,141.94755)"
|
||||
id="text2-8"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect2-2);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="140.49805"
|
||||
y="197.36121"
|
||||
id="tspan15">gock <333</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26260965,-0.03225692,0.03225692,0.26260965,163.16927,187.98351)"
|
||||
id="text2-8-2"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect2-2-6);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="140.49805"
|
||||
y="197.36121"
|
||||
id="tspan16">gock <333</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26261141,0.03224256,-0.03224256,0.26261141,-26.436727,169.44502)"
|
||||
id="text2-8-2-4"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect2-2-6-7);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="140.49805"
|
||||
y="197.36121"
|
||||
id="tspan17">gock <333</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="scale(0.26458333)"
|
||||
id="text3"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect3);display:inline;fill:#ffffff;stroke-width:4.91339" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,20.26179,-16.976094)"
|
||||
id="text4"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect4);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="1105.2363"
|
||||
y="330.63074"
|
||||
id="tspan18">Gay :3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.25941349,0.05204788,-0.05204788,0.25941349,14.622996,-20.113934)"
|
||||
id="text4-8"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect4-4);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="1105.2363"
|
||||
y="330.63074"
|
||||
id="tspan19">Gay :3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,-185.03108,79.899068)"
|
||||
id="text4-1"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect4-3);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="1105.2363"
|
||||
y="330.63074"
|
||||
id="tspan20">Gay :3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.26300551,-0.02885206,0.02885206,0.26300551,-153.43986,-14.753595)"
|
||||
id="text4-1-6"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect4-3-2);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="1105.2363"
|
||||
y="330.63074"
|
||||
id="tspan21">Gay :3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.25999838,0.04904269,-0.04904269,0.25999838,-255.80374,45.596021)"
|
||||
id="text4-1-4"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect4-3-3);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="1105.2363"
|
||||
y="330.63074"
|
||||
id="tspan22">Gay :3</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
transform="matrix(0.25999838,0.04904269,-0.04904269,0.25999838,-255.80374,45.596021)"
|
||||
id="text6"
|
||||
style="font-size:37.7953px;line-height:1;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect6);display:inline;fill:#ffffff;stroke-width:4.91339"><tspan
|
||||
x="1105.2363"
|
||||
y="330.63074"
|
||||
id="tspan23">Gay :3</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 26 KiB |
@@ -1,93 +0,0 @@
|
||||
console.log("adding features to search...");
|
||||
|
||||
const form = document.getElementById("search-form");
|
||||
const input = document.getElementById("search-input");
|
||||
|
||||
// https://stackoverflow.com/a/3809435/16804841
|
||||
const expression = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi;
|
||||
const urlRegex = new RegExp(expression);
|
||||
|
||||
const searchEngines = {
|
||||
"g": {
|
||||
action: "https://www.google.com/search",
|
||||
name: "q",
|
||||
},
|
||||
"d": {
|
||||
action: "https://duckduckgo.com/",
|
||||
name: "q",
|
||||
},
|
||||
"y": {
|
||||
action: "https://yandex.com/search/",
|
||||
name: "text",
|
||||
},
|
||||
"lure": {
|
||||
action: "https://lure.sh/pkgs",
|
||||
name: "q",
|
||||
},
|
||||
};
|
||||
|
||||
const translationPrefixes = [
|
||||
"t",
|
||||
"translation",
|
||||
]
|
||||
|
||||
|
||||
function getDeepLUrl(s) {
|
||||
const parts = s.split("-")
|
||||
if (parts.length != 3) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return `https://www.deepl.com/en/translator?/#${encodeURIComponent(parts[0].trim())}/${encodeURIComponent(parts[1].trim())}/${encodeURIComponent(parts[2].trim())}`;
|
||||
}
|
||||
|
||||
|
||||
form.addEventListener("submit", event => {
|
||||
event.preventDefault();
|
||||
|
||||
s = input.value;
|
||||
|
||||
// check if url
|
||||
if (s.match(urlRegex)) {
|
||||
window.open(s, "_self");
|
||||
return
|
||||
}
|
||||
|
||||
// deepl translations
|
||||
let doTranslation = false;
|
||||
for (const value of translationPrefixes) {
|
||||
const prefix = `!${value} `;
|
||||
if (s.startsWith(prefix)) {
|
||||
doTranslation = true;
|
||||
s = s.slice(prefix.length); // Remove the !{key} prefix
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (doTranslation) {
|
||||
const url = getDeepLUrl(s);
|
||||
if (url) {
|
||||
window.open(url.toString(), "_self");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the string starts with ! followed by a key from searchEngines
|
||||
let selectedEngine = {
|
||||
action: form.getAttribute("action"),
|
||||
name: input.getAttribute("name"),
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(searchEngines)) {
|
||||
const prefix = `!${key} `;
|
||||
if (s.startsWith(prefix)) {
|
||||
selectedEngine = value;
|
||||
s = s.slice(prefix.length); // Remove the !{key} prefix
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const url = new URL(selectedEngine.action);
|
||||
url.searchParams.set(selectedEngine.name, s.trim());
|
||||
window.open(url.toString(), "_self");
|
||||
});
|
||||
97
frontend/templates/search.js
Normal file
97
frontend/templates/search.js
Normal file
@@ -0,0 +1,97 @@
|
||||
console.log("adding features to search...");
|
||||
|
||||
const form = document.getElementById("search-form");
|
||||
const input = document.getElementById("search-input");
|
||||
|
||||
// https://stackoverflow.com/a/3809435/16804841
|
||||
const expression =
|
||||
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi;
|
||||
const urlRegex = new RegExp(expression);
|
||||
|
||||
const searchEngines = {
|
||||
g: {
|
||||
action: "https://www.google.com/search",
|
||||
name: "q",
|
||||
},
|
||||
d: {
|
||||
action: "https://duckduckgo.com/",
|
||||
name: "q",
|
||||
},
|
||||
y: {
|
||||
action: "https://www.youtube.com/results",
|
||||
name: "search_query",
|
||||
},
|
||||
ya: {
|
||||
action: "https://yandex.com/search/",
|
||||
name: "text",
|
||||
},
|
||||
lure: {
|
||||
action: "https://lure.sh/pkgs",
|
||||
name: "q",
|
||||
},
|
||||
};
|
||||
|
||||
const translationPrefixes = ["t", "translation"];
|
||||
|
||||
function getDeepLUrl(s) {
|
||||
const parts = s.split("-");
|
||||
if (parts.length != 3) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return `https://www.deepl.com/en/translator?/#${encodeURIComponent(
|
||||
parts[0].trim()
|
||||
)}/${encodeURIComponent(parts[1].trim())}/${encodeURIComponent(
|
||||
parts[2].trim()
|
||||
)}`;
|
||||
}
|
||||
|
||||
form.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
s = input.value;
|
||||
|
||||
// check if url
|
||||
if (s.match(urlRegex)) {
|
||||
window.open(s, "_self");
|
||||
return;
|
||||
}
|
||||
|
||||
// deepl translations
|
||||
let doTranslation = false;
|
||||
for (const value of translationPrefixes) {
|
||||
const prefix = `!${value} `;
|
||||
if (s.startsWith(prefix)) {
|
||||
doTranslation = true;
|
||||
s = s.slice(prefix.length); // Remove the !{key} prefix
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (doTranslation) {
|
||||
const url = getDeepLUrl(s);
|
||||
if (url) {
|
||||
window.open(url.toString(), "_self");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the string starts with ! followed by a key from searchEngines
|
||||
let selectedEngine = {
|
||||
action: form.getAttribute("action"),
|
||||
name: input.getAttribute("name"),
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(searchEngines)) {
|
||||
const prefix = `!${key} `;
|
||||
if (s.startsWith(prefix)) {
|
||||
selectedEngine = value;
|
||||
s = s.slice(prefix.length); // Remove the !{key} prefix
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const url = new URL(selectedEngine.action);
|
||||
url.searchParams.set(selectedEngine.name, s.trim());
|
||||
window.open(url.toString(), "_self");
|
||||
});
|
||||
3
go.mod
3
go.mod
@@ -5,6 +5,9 @@ go 1.24.2
|
||||
require github.com/labstack/echo/v4 v4.13.4
|
||||
|
||||
require (
|
||||
github.com/TwiN/go-color v1.4.1 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||
github.com/labstack/echo v3.3.10+incompatible // indirect
|
||||
github.com/labstack/gommon v0.4.2 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@@ -1,9 +1,15 @@
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/TwiN/go-color v1.4.1 h1:mqG0P/KBgHKVqmtL5ye7K0/Gr4l6hTksPgTgMk3mUzc=
|
||||
github.com/TwiN/go-color v1.4.1/go.mod h1:WcPf/jtiW95WBIsEeY1Lc/b8aaWoiqQpu5cf8WFxu+s=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU=
|
||||
github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0=
|
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
|
||||
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
|
||||
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
|
||||
|
||||
98
internal/cache/cache.go
vendored
Normal file
98
internal/cache/cache.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/utils"
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
CacheDir string
|
||||
Disabled bool
|
||||
}
|
||||
|
||||
func getCacheDir() (string, error) {
|
||||
baseDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
baseDir = "/tmp"
|
||||
}
|
||||
cacheDir := filepath.Join(baseDir, utils.Name)
|
||||
err = os.MkdirAll(cacheDir, 0o755)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return cacheDir, nil
|
||||
}
|
||||
|
||||
func getProfileCacheDir(profile string) (string, error) {
|
||||
var profileCacheDir string
|
||||
|
||||
cacheDir, err := getCacheDir()
|
||||
if err != nil {
|
||||
return profileCacheDir, err
|
||||
}
|
||||
|
||||
profileCacheDir = filepath.Join(cacheDir, profile)
|
||||
err = os.MkdirAll(cacheDir, 0o755)
|
||||
return profileCacheDir, err
|
||||
}
|
||||
|
||||
func NewCache(profile string) Cache {
|
||||
cacheDir, err := getProfileCacheDir(profile)
|
||||
|
||||
return Cache{
|
||||
CacheDir: cacheDir,
|
||||
Disabled: err != nil,
|
||||
}
|
||||
}
|
||||
|
||||
const baseCacheUrl = "cache"
|
||||
|
||||
func (c Cache) StartStaticServer(e *echo.Echo) error {
|
||||
e.Static("/"+baseCacheUrl, c.CacheDir)
|
||||
return nil
|
||||
}
|
||||
|
||||
func hashUrl(url string) string {
|
||||
h := sha1.New()
|
||||
io.WriteString(h, url)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func (c Cache) CacheUrl(urlString string) (string, error) {
|
||||
filename := hashUrl(urlString) + filepath.Ext(urlString)
|
||||
targetPath := filepath.Join(c.CacheDir, filename)
|
||||
|
||||
// if the file was already downloaded it doesn't need to be downloaded again
|
||||
if _, err := os.Stat(targetPath); errors.Is(err, os.ErrNotExist) {
|
||||
resp, err := http.Get(urlString)
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
return urlString, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
file, err := os.Create(targetPath)
|
||||
if err != nil {
|
||||
return urlString, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(file, resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return urlString, err
|
||||
}
|
||||
} else {
|
||||
return url.JoinPath(baseCacheUrl, filename)
|
||||
}
|
||||
|
||||
return url.JoinPath(baseCacheUrl, filename)
|
||||
}
|
||||
@@ -4,5 +4,6 @@ import "log"
|
||||
|
||||
func Cache() error {
|
||||
log.Println("running cache")
|
||||
log.Panicln("not implemented yet")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,59 +1,102 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/utils"
|
||||
"github.com/TwiN/go-color"
|
||||
)
|
||||
|
||||
type ProgramFunction func() error
|
||||
type Program struct {
|
||||
Name string
|
||||
Function ProgramFunction
|
||||
ShortDescription string
|
||||
LongDescription string
|
||||
Arguments []Argument
|
||||
}
|
||||
type Argument struct {
|
||||
Name string
|
||||
Type string
|
||||
Required bool
|
||||
Description string
|
||||
}
|
||||
|
||||
var HelpHeader = `Meow
|
||||
Ze
|
||||
Dong`
|
||||
var HelpHeader = `This is the help page of ` + utils.Name + `.
|
||||
` + color.Purple + utils.BinaryName + ` {program} {...args}` + color.Reset + `
|
||||
The following Programs are available:`
|
||||
var Programs = []Program{
|
||||
{
|
||||
Name: "help",
|
||||
Function: Help,
|
||||
Description: "get more information on how the cli or a program works",
|
||||
ShortDescription: "get more information on how the cli in general or a specific program works",
|
||||
LongDescription: "What did you expect to find here?",
|
||||
Arguments: []Argument{
|
||||
{
|
||||
Name: "program",
|
||||
Type: "string",
|
||||
Required: false,
|
||||
Description: "defines the program you want to know more about",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "start",
|
||||
Function: Start,
|
||||
Description: "start the webserver",
|
||||
ShortDescription: "start the webserver",
|
||||
LongDescription: `The start program starts the webserver.
|
||||
It loads the config file of the according profile.
|
||||
It uses the default values if no config file was found.`,
|
||||
Arguments: []Argument{
|
||||
{
|
||||
Name: "profile",
|
||||
Type: "string",
|
||||
Required: false,
|
||||
Description: "tells the program which config to load, default is 'default'",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cache",
|
||||
Function: Cache,
|
||||
Description: "do something with the cache",
|
||||
ShortDescription: "do something with the cache",
|
||||
LongDescription: `Does something with the cache.
|
||||
- clear: delete the whole cache
|
||||
- clean: delete all files that aren't used by any program.`,
|
||||
Arguments: []Argument{
|
||||
{
|
||||
Name: "action",
|
||||
Type: "enum(clear;clean)",
|
||||
Required: true,
|
||||
Description: "defines what to do with the cache",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func GetProgram(programName string) Program {
|
||||
for i, p := range Programs {
|
||||
if p.Name == programName {
|
||||
return Programs[i]
|
||||
}
|
||||
}
|
||||
|
||||
log.Panicln("couldn't find program", programName, ". EXITING")
|
||||
return Program{}
|
||||
}
|
||||
|
||||
func Cli() {
|
||||
fmt.Println("running transfem startpage")
|
||||
// getting around initialization cycle
|
||||
Programs[0].Function = Help
|
||||
|
||||
programName := "help"
|
||||
if len(os.Args) > 1 {
|
||||
programName = os.Args[1]
|
||||
}
|
||||
|
||||
log.Println("running program", programName)
|
||||
|
||||
var selectedProgram *Program = nil
|
||||
for i, p := range Programs {
|
||||
if p.Name == programName {
|
||||
selectedProgram = &Programs[i]
|
||||
break
|
||||
var selectedProgram Program = GetProgram(programName)
|
||||
err := selectedProgram.Function()
|
||||
if err != nil {
|
||||
log.Panicln(err)
|
||||
}
|
||||
}
|
||||
if selectedProgram == nil {
|
||||
log.Panicln("couldn't find program", programName, ". EXITING")
|
||||
}
|
||||
|
||||
selectedProgram.Function()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,90 @@
|
||||
package cli
|
||||
|
||||
import "log"
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
func Help() error {
|
||||
log.Println("running help")
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/utils"
|
||||
"github.com/TwiN/go-color"
|
||||
)
|
||||
|
||||
func padString(s string, n int) string {
|
||||
missing := n - len(s)
|
||||
if missing <= 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
for _ = range missing {
|
||||
s = s + " "
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func getSingleArgumentString(a Argument) string {
|
||||
requiredString := ""
|
||||
if a.Required {
|
||||
requiredString = "*"
|
||||
}
|
||||
return requiredString + a.Name + ":" + a.Type
|
||||
}
|
||||
|
||||
func getArgumentString(arguments []Argument) string {
|
||||
argumentString := color.Blue
|
||||
for _, a := range arguments {
|
||||
argumentString = argumentString + " [" + getSingleArgumentString(a) + "]"
|
||||
}
|
||||
return argumentString + color.Reset
|
||||
}
|
||||
|
||||
func generalHelp() error {
|
||||
fmt.Println()
|
||||
fmt.Println(HelpHeader)
|
||||
fmt.Println()
|
||||
|
||||
for _, p := range Programs {
|
||||
fmt.Print(color.Bold + padString(p.Name, 7) + color.Reset)
|
||||
fmt.Print(padString(getArgumentString(p.Arguments), 40) + p.ShortDescription + "\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func specificHelp(programName string) error {
|
||||
program := GetProgram(programName)
|
||||
|
||||
fmt.Println(color.Bold + "MAN PAGE FOR " + strings.ToUpper(programName) + color.Reset)
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println(color.Purple + utils.BinaryName + " " + programName + color.Reset + getArgumentString(program.Arguments))
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println(color.Bold + "arguments" + color.Reset)
|
||||
|
||||
argumentStrings := make([]string, len(program.Arguments))
|
||||
maxArgumentString := 0
|
||||
for i, a := range program.Arguments {
|
||||
s := getSingleArgumentString(a)
|
||||
argumentStrings[i] = s
|
||||
if len(s) > maxArgumentString {
|
||||
maxArgumentString = len(s)
|
||||
}
|
||||
}
|
||||
|
||||
for i, a := range program.Arguments {
|
||||
fmt.Println(padString(argumentStrings[i], maxArgumentString+4) + a.Description)
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println(program.LongDescription)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Help() error {
|
||||
if len(os.Args) > 2 {
|
||||
return specificHelp(os.Args[2])
|
||||
}
|
||||
|
||||
return generalHelp()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
package cli
|
||||
|
||||
import "log"
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/server"
|
||||
)
|
||||
|
||||
func Start() error {
|
||||
log.Println("starting server")
|
||||
return nil
|
||||
profile := "default"
|
||||
if len(os.Args) > 2 {
|
||||
profile = os.Args[2]
|
||||
}
|
||||
log.Println("starting server with profile " + profile)
|
||||
|
||||
return server.Start(profile)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package diyhrt
|
||||
|
||||
type DiyHrtConfig struct {
|
||||
ApiKey string
|
||||
FetchIntervals int
|
||||
|
||||
StoreFilter StoreFilter
|
||||
ListingFilter ListingFilter
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const endpoint = "https://diyhrt.market/api/listings"
|
||||
|
||||
func GetListings(apiKey string) ([]Listing, error) {
|
||||
if apiKey == "" {
|
||||
return nil, errors.New("API_KEY key not set. Set it as env or in DiyHrt.ApiKey")
|
||||
return nil, errors.New("diyhrt API_KEY key not set. Set it as env or in DiyHrt.ApiKey")
|
||||
}
|
||||
|
||||
// Create HTTP client
|
||||
|
||||
@@ -2,13 +2,12 @@ package rendering
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/diyhrt"
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/utils"
|
||||
"github.com/pelletier/go-toml"
|
||||
)
|
||||
|
||||
@@ -65,6 +64,7 @@ func NewConfig() Config {
|
||||
},
|
||||
DiyHrt: diyhrt.DiyHrtConfig{
|
||||
ApiKey: os.Getenv("API_KEY"),
|
||||
FetchIntervals: 60, // fetch every hour
|
||||
StoreFilter: diyhrt.StoreFilter{
|
||||
Limit: 0,
|
||||
IncludeIds: []int{7},
|
||||
@@ -102,23 +102,12 @@ func NewConfig() Config {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) LoadDiyHrt(listings []diyhrt.Listing) {
|
||||
existingStores := make(map[int]diyhrt.Store)
|
||||
|
||||
for _, listing := range listings {
|
||||
existingStores[listing.Store.Id] = listing.Store
|
||||
}
|
||||
|
||||
c.Template.Listings = c.DiyHrt.ListingFilter.Filter(listings)
|
||||
c.Template.Stores = c.DiyHrt.StoreFilter.Filter(slices.Collect(maps.Values(existingStores)))
|
||||
}
|
||||
|
||||
func (rc *Config) ScanForConfigFile(profile string) error {
|
||||
profileFile := profile + ".toml"
|
||||
|
||||
baseDir, cacheDirErr := os.UserConfigDir()
|
||||
if cacheDirErr == nil {
|
||||
configFile := filepath.Join(baseDir, "startpage", profileFile)
|
||||
configFile := filepath.Join(baseDir, utils.Name, profileFile)
|
||||
|
||||
if err := rc.LoadConfigFile(configFile); !errors.Is(err, os.ErrNotExist) {
|
||||
return err
|
||||
@@ -141,7 +130,7 @@ func (rc *Config) LoadConfigFile(file string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("loading config file: " + file)
|
||||
log.Println("loading config file", file)
|
||||
|
||||
content, err := os.ReadFile(file)
|
||||
|
||||
@@ -151,14 +140,3 @@ func (rc *Config) LoadConfigFile(file string) error {
|
||||
|
||||
return toml.Unmarshal(content, rc)
|
||||
}
|
||||
|
||||
func (c *Config) Init() error {
|
||||
fmt.Print("downloading website icons")
|
||||
for i := range c.Template.Websites {
|
||||
fmt.Print(".")
|
||||
c.Template.Websites[i].Cache()
|
||||
}
|
||||
fmt.Print("\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
28
internal/rendering/diyhrt.go
Normal file
28
internal/rendering/diyhrt.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package rendering
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/diyhrt"
|
||||
)
|
||||
|
||||
func (c *Config) LoadDiyHrt(listings []diyhrt.Listing) {
|
||||
existingStores := make(map[int]diyhrt.Store)
|
||||
|
||||
for _, listing := range listings {
|
||||
existingStores[listing.Store.Id] = listing.Store
|
||||
}
|
||||
|
||||
c.Template.Listings = c.DiyHrt.ListingFilter.Filter(listings)
|
||||
c.Template.Stores = c.DiyHrt.StoreFilter.Filter(slices.Collect(maps.Values(existingStores)))
|
||||
}
|
||||
|
||||
func (c *Config) FetchDiyHrt() error {
|
||||
l, err := diyhrt.GetListings(c.DiyHrt.ApiKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.LoadDiyHrt(l)
|
||||
return nil
|
||||
}
|
||||
82
internal/server/server.go
Normal file
82
internal/server/server.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/rendering"
|
||||
)
|
||||
|
||||
var Config = rendering.NewConfig()
|
||||
|
||||
func StartFetching() {
|
||||
for {
|
||||
log.Println("Fetch DiyHrt data...")
|
||||
Config.FetchDiyHrt()
|
||||
time.Sleep(time.Duration(Config.DiyHrt.FetchIntervals) * time.Second)
|
||||
|
||||
if Config.DiyHrt.FetchIntervals == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetFilepath(u string) string {
|
||||
return filepath.Join("frontend", u)
|
||||
}
|
||||
|
||||
func staticHandler(w http.ResponseWriter, r *http.Request) {
|
||||
filepath := GetFilepath(r.URL.Path)
|
||||
log.Println("serving file:", filepath)
|
||||
http.ServeFileFS(w, r, FrontendFiles, filepath)
|
||||
}
|
||||
|
||||
func Start(profile string) error {
|
||||
err := Config.ScanForConfigFile(profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go StartFetching()
|
||||
|
||||
err = Config.FetchDiyHrt()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
http.HandleFunc("/static", staticHandler)
|
||||
http.ListenAndServe(":"+strconv.Itoa(Config.Server.Port), nil)
|
||||
|
||||
/*
|
||||
e := echo.New()
|
||||
|
||||
// statically serve the file
|
||||
cache := cache.NewCache(profile)
|
||||
if !cache.Disabled {
|
||||
cache.StartStaticServer(e)
|
||||
|
||||
log.Println("downloading website icons...")
|
||||
for i, w := range Config.Template.Websites {
|
||||
u, err := cache.CacheUrl(w.ImageUrl)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
Config.Template.Websites[i].ImageUrl = u
|
||||
Config.Template.Websites[i].IsFetched = true
|
||||
}
|
||||
}
|
||||
|
||||
// https://echo.labstack.com/docs/cookbook/embed-resources
|
||||
staticHandler := http.FileServer(getFileSystem())
|
||||
e.GET("/assets/*", echo.WrapHandler(http.StripPrefix("/", staticHandler)))
|
||||
e.GET("/scripts/*", echo.WrapHandler(http.StripPrefix("/", staticHandler)))
|
||||
e.GET("/", getIndex)
|
||||
StartTemplating(e)
|
||||
|
||||
e.Logger.Fatal(e.Start(":" + strconv.Itoa(Config.Server.Port)))
|
||||
*/
|
||||
return nil
|
||||
}
|
||||
80
internal/server/templates.go
Normal file
80
internal/server/templates.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
var FrontendFiles embed.FS
|
||||
|
||||
func getFileContent() string {
|
||||
content, err := FrontendFiles.ReadFile("frontend/index.html")
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return string(content)
|
||||
}
|
||||
|
||||
func getIndex(c echo.Context) error {
|
||||
IndexTemplate := template.Must(template.New("index").Parse(getFileContent()))
|
||||
|
||||
var tpl bytes.Buffer
|
||||
IndexTemplate.Execute(&tpl, Config.Template)
|
||||
|
||||
return c.HTML(http.StatusOK, tpl.String())
|
||||
}
|
||||
|
||||
func getFileSystem() http.FileSystem {
|
||||
fsys, err := fs.Sub(FrontendFiles, "frontend")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return http.FS(fsys)
|
||||
}
|
||||
|
||||
type Template struct {
|
||||
templates *template.Template
|
||||
}
|
||||
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
|
||||
return t.templates.ExecuteTemplate(w, name, data)
|
||||
}
|
||||
|
||||
var t *template.Template
|
||||
|
||||
func ServeTemplate(c echo.Context) error {
|
||||
filename := filepath.Base(c.Request().URL.Path)
|
||||
if filename == "/" {
|
||||
filename = "index.html"
|
||||
}
|
||||
fmt.Println(filename)
|
||||
|
||||
var tpl bytes.Buffer
|
||||
t.ExecuteTemplate(&tpl, filename, Config.Template)
|
||||
return c.HTML(http.StatusOK, tpl.String())
|
||||
}
|
||||
|
||||
func StartTemplating(e *echo.Echo) {
|
||||
// register templates as renderer
|
||||
t = template.Must(template.ParseFS(
|
||||
FrontendFiles,
|
||||
"frontend/templates/*",
|
||||
))
|
||||
fmt.Println(t.ParseName)
|
||||
|
||||
e.GET("/*", ServeTemplate)
|
||||
staticHandler := http.FileServer(getFileSystem())
|
||||
e.GET("/static/*", echo.WrapHandler(http.StripPrefix("/", staticHandler)))
|
||||
}
|
||||
6
internal/utils/meta.go
Normal file
6
internal/utils/meta.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package utils
|
||||
|
||||
import "os"
|
||||
|
||||
var Name = "transfem-startpage"
|
||||
var BinaryName = os.Args[0]
|
||||
97
main.go
97
main.go
@@ -1,107 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/cli"
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/diyhrt"
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/rendering"
|
||||
"github.com/labstack/echo/v4"
|
||||
"gitea.elara.ws/Hazel/transfem-startpage/internal/server"
|
||||
)
|
||||
|
||||
var CurrentConfig = rendering.NewConfig()
|
||||
|
||||
func FetchDiyHrt() error {
|
||||
fmt.Println("Fetch DiyHrt Marketplaces...")
|
||||
|
||||
l, err := diyhrt.GetListings(CurrentConfig.DiyHrt.ApiKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
CurrentConfig.LoadDiyHrt(l)
|
||||
return nil
|
||||
}
|
||||
|
||||
//go:embed frontend/*
|
||||
var frontendFiles embed.FS
|
||||
|
||||
func getFileContent() string {
|
||||
content, err := frontendFiles.ReadFile("frontend/index.html")
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return string(content)
|
||||
}
|
||||
|
||||
var IndexTemplate = template.Must(template.New("index").Parse(getFileContent()))
|
||||
|
||||
func getIndex(c echo.Context) error {
|
||||
var tpl bytes.Buffer
|
||||
IndexTemplate.Execute(&tpl, CurrentConfig.Template)
|
||||
|
||||
return c.HTML(http.StatusOK, tpl.String())
|
||||
}
|
||||
|
||||
func getFileSystem() http.FileSystem {
|
||||
fsys, err := fs.Sub(frontendFiles, "frontend")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return http.FS(fsys)
|
||||
}
|
||||
|
||||
func backMain() {
|
||||
profile := "default"
|
||||
if len(os.Args) > 1 {
|
||||
profile = os.Args[1]
|
||||
}
|
||||
fmt.Println("loading profile " + profile)
|
||||
|
||||
err := CurrentConfig.ScanForConfigFile(profile)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
err = CurrentConfig.Init()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
err = FetchDiyHrt()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
e := echo.New()
|
||||
|
||||
// statically serve the file
|
||||
cacheDir, err := rendering.GetCacheDir()
|
||||
if err == nil {
|
||||
e.Static("/cache", cacheDir)
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// https://echo.labstack.com/docs/cookbook/embed-resources
|
||||
staticHandler := http.FileServer(getFileSystem())
|
||||
e.GET("/assets/*", echo.WrapHandler(http.StripPrefix("/", staticHandler)))
|
||||
e.GET("/scripts/*", echo.WrapHandler(http.StripPrefix("/", staticHandler)))
|
||||
e.GET("/", getIndex)
|
||||
|
||||
e.Logger.Fatal(e.Start(":" + strconv.Itoa(CurrentConfig.Server.Port)))
|
||||
}
|
||||
var FrontendFiles embed.FS
|
||||
|
||||
func main() {
|
||||
server.FrontendFiles = FrontendFiles
|
||||
cli.Cli()
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
|
||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
|
||||
Reference in New Issue
Block a user