Index: trunk/.gitignore
===================================================================
--- trunk/.gitignore	(revision 52)
+++ trunk/.gitignore	(revision 53)
@@ -1,1 +1,0 @@
-simplytranslate
Index: trunk/README.md
===================================================================
--- trunk/README.md	(revision 52)
+++ trunk/README.md	(revision 53)
@@ -25,7 +25,13 @@
     proxy_pass http://localhost:5000;
 }
-location /static {
-    alias /path/to/static/files;
-    autoindex off;
-}
 ```
+
+### Legal notice
+SimplyTranslate does not host any content. All content shown on any SimplyTranslate instances is from [Google Translate](https://translate.google.com) and [Reverso](https://www.reverso.net/). 
+
+SimplyTranslate is not affiliated with Google Translate nor Reverso that SimplyTranslate relays.
+
+Trademarks belong to their respective owners. 
+Google Translate is a trademark of Google LLC. Reverso is a trademark of Reverso.
+
+The creators and maintainers of this repository assume no liability for the accuracy and timeliness of any information provided above. Trademark owner information was researched to the best of the author's knowledge at the time of curation and may be outdated or incorrect.
Index: trunk/cmd/simplytranslate/main.go
===================================================================
--- trunk/cmd/simplytranslate/main.go	(revision 53)
+++ trunk/cmd/simplytranslate/main.go	(revision 53)
@@ -0,0 +1,257 @@
+package main
+
+import (
+	"bytes"
+	"net/http"
+	"net/url"
+	"time"
+	"flag"
+
+	"git.chaotic.ninja/yakumo.izuru/simplytranslate/engines"
+	"github.com/gofiber/fiber/v2"
+	"github.com/gofiber/template/html/v2"
+	"gopkg.in/ini.v1"
+)
+
+var conf struct {
+	listen string
+	staticpath string
+	tmplpath string
+}
+func readConf(file string) error {
+	cfg, err := ini.Load(file)
+	if err != nil {
+		return err
+	}
+	conf.listen = cfg.Section("").Key("listen").String()
+	conf.staticpath = cfg.Section("").Key("rootdir").String()
+	conf.tmplpath = cfg.Section("").Key("tmplpath").String()
+
+	return nil
+}
+func main() {
+	var configfile string
+	flag.StringVar(&configfile, "f", "", "Configuration file")
+	flag.Parse()
+
+	if configfile != "" {
+		readConf(configfile)
+	}
+
+	conf.listen = "127.0.0.1:5000"
+	conf.staticpath = "./static"
+	conf.tmplpath = "./views"
+	
+	engine := html.New(conf.tmplpath, ".html")
+	engine.AddFunc("inc", func(i int) int { return i + 1 })
+
+	app := fiber.New(fiber.Config{
+		Views: engine,
+	})
+
+	app.All("/", func(c *fiber.Ctx) error {
+		engine := c.Cookies("engine")
+		if c.Query("engine") != "" {
+			engine = c.Query("engine")
+		}
+		if _, ok := engines.Engines[engine]; !ok {
+			engine = "google"
+		}
+		targetLanguages, err := engines.Engines[engine].TargetLanguages()
+		if err != nil {
+			return c.SendStatus(500)
+		}
+		sourceLanguages, err := engines.Engines[engine].SourceLanguages()
+		if err != nil {
+			return c.SendStatus(500)
+		}
+		originalText := ""
+		translatedText := ""
+		from := ""
+		to := ""
+		ttsFrom := ""
+		ttsTo := ""
+		sourceLanguage := ""
+
+		var translation engines.TranslationResult
+		if c.Method() == "POST" {
+			from = c.FormValue("from")
+			to = c.FormValue("to")
+			originalText = c.FormValue("text")
+			if result, err := engines.Engines[engine].Translate(originalText, from, to); err != nil {
+				return c.SendStatus(500)
+			} else {
+				translatedText = result.TranslatedText
+				translation = result
+				sourceLanguage = result.SourceLanguage
+			}
+
+			ttsFromURL, _ := url.Parse("api/tts")
+			fromQuery := url.Values{}
+			fromQuery.Add("lang", from)
+			fromQuery.Add("text", originalText)
+			ttsFromURL.RawQuery = fromQuery.Encode()
+			ttsFrom = ttsFromURL.String()
+
+			ttsToURL, _ := url.Parse("api/tts")
+			toQuery := url.Values{}
+			toQuery.Add("lang", to)
+			toQuery.Add("text", translatedText)
+			ttsToURL.RawQuery = toQuery.Encode()
+			ttsTo = ttsToURL.String()
+
+			fromCookie := new(fiber.Cookie)
+			fromCookie.Name = "from"
+			fromCookie.Value = from
+			fromCookie.Expires = time.Now().Add(time.Hour * 24 * 365)
+			c.Cookie(fromCookie)
+
+			toCookie := new(fiber.Cookie)
+			toCookie.Name = "to"
+			toCookie.Value = to
+			toCookie.Expires = time.Now().Add(time.Hour * 24 * 365)
+			c.Cookie(toCookie)
+
+			engineCookie := new(fiber.Cookie)
+			engineCookie.Name = "engine"
+			engineCookie.Value = engine
+			engineCookie.Expires = time.Now().Add(time.Hour * 24 * 365)
+			c.Cookie(engineCookie)
+		} else if c.Method() == "GET" {
+			from = c.Cookies("from")
+			to = c.Cookies("to")
+		} else {
+			return c.SendStatus(400)
+		}
+
+		if from == "" {
+			from = "auto"
+		}
+
+		enginesNames := map[string]string{}
+		for k, v := range engines.Engines {
+			enginesNames[k] = v.DisplayName()
+		}
+
+		return c.Render("index", fiber.Map{
+			"Engine":          engine,
+			"enginesNames":    enginesNames,
+			"SourceLanguages": sourceLanguages,
+			"TargetLanguages": targetLanguages,
+			"OriginalText":    originalText,
+			"Translation":     translation,
+			"From":            from,
+			"To":              to,
+			"TtsFrom":         ttsFrom,
+			"TtsTo":           ttsTo,
+			"SourceLanguage":  sourceLanguage,
+		})
+	})
+
+	app.All("/api/translate", func(c *fiber.Ctx) error {
+		from := ""
+		to := ""
+		engine := ""
+		text := ""
+		if c.Method() == "GET" {
+			engine = c.Query("engine")
+			text = c.Query("text")
+			from = c.Query("from")
+			to = c.Query("to")
+		} else if c.Method() == "POST" {
+			engine = c.FormValue("engine")
+			text = c.FormValue("text")
+			from = c.FormValue("from")
+			to = c.FormValue("to")
+		} else {
+			return c.SendStatus(400)
+		}
+		if _, ok := engines.Engines[engine]; !ok || engine == "" {
+			engine = "google"
+		}
+		if to == "" {
+			return c.SendStatus(400)
+		}
+		if result, err := engines.Engines[engine].Translate(text, from, to); err != nil {
+			return c.SendStatus(500)
+		} else {
+			return c.JSON(result)
+		}
+	})
+
+	app.Get("/api/source_languages", func(c *fiber.Ctx) error {
+		engine := c.Query("engine")
+		if _, ok := engines.Engines[engine]; !ok || engine == "" {
+			engine = "google"
+		}
+		if result, err := engines.Engines[engine].SourceLanguages(); err != nil {
+			return c.SendStatus(500)
+		} else {
+			return c.JSON(result)
+		}
+	})
+
+	app.Get("/api/target_languages", func(c *fiber.Ctx) error {
+		engine := c.Query("engine")
+		if _, ok := engines.Engines[engine]; !ok || engine == "" {
+			engine = "google"
+		}
+		if result, err := engines.Engines[engine].TargetLanguages(); err != nil {
+			return c.SendStatus(500)
+		} else {
+			return c.JSON(result)
+		}
+	})
+
+	app.Get("/api/tts", func(c *fiber.Ctx) error {
+		engine := c.Query("engine")
+		if _, ok := engines.Engines[engine]; !ok || engine == "" {
+			engine = "google"
+		}
+
+		text := c.Query("text")
+		if text == "" {
+			return c.SendStatus(400)
+		}
+
+		lang := c.Query("lang")
+
+		if url, err := engines.Engines[engine].Tts(text, lang); err != nil {
+			return c.SendStatus(500)
+		} else {
+			if response, err := http.Get(url); err != nil {
+				return c.SendStatus(500)
+			} else {
+				defer response.Body.Close()
+				var buf bytes.Buffer
+				response.Write(&buf)
+				c.Context().SetContentType("audio/mpeg")
+				return c.Send(buf.Bytes())
+			}
+		}
+	})
+
+	app.Post("/switchlanguages", func(c *fiber.Ctx) error {
+		if c.Cookies("from") != "" {
+			fromCookie := new(fiber.Cookie)
+			fromCookie.Name = "from"
+			fromCookie.Value = c.Cookies("to")
+			fromCookie.Expires = time.Now().Add(24 * time.Hour * 365)
+
+			toCookie := new(fiber.Cookie)
+			toCookie.Name = "to"
+			toCookie.Value = c.Cookies("from")
+			toCookie.Expires = time.Now().Add(24 * time.Hour * 365)
+
+			c.Cookie(fromCookie)
+			c.Cookie(toCookie)
+		}
+		return c.Redirect("/")
+	})
+	app.Static("/static", conf.staticpath, fiber.Static{
+		Compress: true,
+		ByteRange: true,
+		Browse: true,
+	})
+	app.Listen(conf.listen)
+}
Index: trunk/engines/engine.go
===================================================================
--- trunk/engines/engine.go	(revision 52)
+++ trunk/engines/engine.go	(revision 53)
@@ -20,6 +20,4 @@
 var Engines = map[string]Engine{
 	"google": &GoogleTranslate{},
-	//	"iciba": &ICIBA{},
-	//	"libre":    &LibreTranslate{},
 	"reverso": &Reverso{},
 }
Index: trunk/example/simplytranslate.ini
===================================================================
--- trunk/example/simplytranslate.ini	(revision 53)
+++ trunk/example/simplytranslate.ini	(revision 53)
@@ -0,0 +1,3 @@
+listen = "127.0.0.1:5000"
+rootdir = "/home/yakumo_izuru/Repos/simplytranslate/static"
+tmplpath = "./views"
Index: trunk/go.mod
===================================================================
--- trunk/go.mod	(revision 52)
+++ trunk/go.mod	(revision 53)
@@ -1,11 +1,11 @@
-module git.chaotic.ninja/yakumo.izuru/simplytranslate-mod
+module git.chaotic.ninja/yakumo.izuru/simplytranslate
 
 go 1.20
 
 require (
-	codeberg.org/SimpleWeb/SimplyTranslate/engines v0.0.0-20230920112526-526a2c0ed1dd
 	github.com/PuerkitoBio/goquery v1.8.1
 	github.com/gofiber/fiber/v2 v2.49.2
 	github.com/gofiber/template/html/v2 v2.0.5
+	gopkg.in/ini.v1 v1.67.0
 )
 
@@ -21,4 +21,5 @@
 	github.com/mattn/go-runewidth v0.0.15 // indirect
 	github.com/rivo/uniseg v0.2.0 // indirect
+	github.com/stretchr/testify v1.8.4 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/valyala/fasthttp v1.49.0 // indirect
@@ -27,4 +28,2 @@
 	golang.org/x/sys v0.12.0 // indirect
 )
-
-replace codeberg.org/SimpleWeb/SimplyTranslate/engines v0.0.0 => ./engines
Index: trunk/go.sum
===================================================================
--- trunk/go.sum	(revision 52)
+++ trunk/go.sum	(revision 53)
@@ -1,4 +1,2 @@
-codeberg.org/SimpleWeb/SimplyTranslate/engines v0.0.0-20230920112526-526a2c0ed1dd h1:7of7Y4s8COfEcCqTIclI+EgObPRdhX/H4o2cXFGBymY=
-codeberg.org/SimpleWeb/SimplyTranslate/engines v0.0.0-20230920112526-526a2c0ed1dd/go.mod h1:sEsqyflt+UgTVk1Z9hcwEexilsPOosOUPX6dlffsA1w=
 github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
 github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
@@ -7,4 +5,5 @@
 github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
 github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/gofiber/fiber/v2 v2.49.2 h1:ONEN3/Vc+dUCxxDgZZwpqvhISgHqb+bu+isBiEyKEQs=
 github.com/gofiber/fiber/v2 v2.49.2/go.mod h1:gNsKnyrmfEWFpJxQAV0qvW6l70K1dZGno12oLtukcts=
@@ -26,6 +25,9 @@
 github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
 github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@@ -38,10 +40,8 @@
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
@@ -49,5 +49,4 @@
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -64,5 +63,4 @@
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -70,8 +68,9 @@
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Index: trunk/legal_notice.txt
===================================================================
--- trunk/legal_notice.txt	(revision 52)
+++ 	(revision )
@@ -1,6 +1,0 @@
-SimplyTranslate does not host any content. All content shown on any SimplyTranslate instances is from Google Translate, DeepL, ICIBA, Reverso and LibreTranslate. SimplyTranslate is not affiliated with Google Translate, DeepL, ICIBA, Reverso or LibreTranslate that SimplyTranslate relays.
-
-Trademarks belong to their respective owners. Google Translate is a trademark of Google LLC. DeepL is a trademark of DeepL SE. Reverso is a trademark of Reverso. LibreTranslate is a trademark of LibreTranslate.
-
-The creators of this repository assume no liability for the accuracy and timeliness of any information provided above. Trademark owner information was researched to the best of the author's knowledge at the time of curation and may be outdated or incorrect.
-
