3 Commits 6fc5f9f27a ... f105a00b3c

Author SHA1 Message Date
  Toby Chui f105a00b3c Photo app compression feature 6 months ago
  Toby Chui c748c9095e Fixed TFTP UI bug 6 months ago
  Toby Chui ea2529f385 Replaced .system with .html file extension 6 months ago

+ 2 - 2
src/auth.go

@@ -32,9 +32,9 @@ func AuthInit() {
 
 
 	//Create an Authentication Agent
 	//Create an Authentication Agent
 	authAgent = auth.NewAuthenticationAgent("ao_auth", []byte(*session_key), sysdb, *allow_public_registry, func(w http.ResponseWriter, r *http.Request) {
 	authAgent = auth.NewAuthenticationAgent("ao_auth", []byte(*session_key), sysdb, *allow_public_registry, func(w http.ResponseWriter, r *http.Request) {
-		//Login Redirection Handler, redirect it login.system
+		//Login Redirection Handler, redirect it login.html
 		w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
 		w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
-		http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect="+r.URL.Path, http.StatusTemporaryRedirect)
+		http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.html")+"?redirect="+r.URL.Path, http.StatusTemporaryRedirect)
 	})
 	})
 
 
 	if *allow_autologin {
 	if *allow_autologin {

+ 1 - 1
src/ldap.go

@@ -44,6 +44,6 @@ func ldapInit() {
 	http.HandleFunc("/system/auth/ldap/login", ldapHandler.HandleLogin)
 	http.HandleFunc("/system/auth/ldap/login", ldapHandler.HandleLogin)
 	http.HandleFunc("/system/auth/ldap/setPassword", ldapHandler.HandleSetPassword)
 	http.HandleFunc("/system/auth/ldap/setPassword", ldapHandler.HandleSetPassword)
 	http.HandleFunc("/system/auth/ldap/newPassword", ldapHandler.HandleNewPasswordPage)
 	http.HandleFunc("/system/auth/ldap/newPassword", ldapHandler.HandleNewPasswordPage)
-	http.HandleFunc("/ldapLogin.system", ldapHandler.HandleLoginPage)
+	http.HandleFunc("/ldapLogin.html", ldapHandler.HandleLoginPage)
 	http.HandleFunc("/system/auth/ldap/checkldap", ldapHandler.HandleCheckLDAP)
 	http.HandleFunc("/system/auth/ldap/checkldap", ldapHandler.HandleCheckLDAP)
 }
 }

+ 8 - 8
src/main.router.go

@@ -4,7 +4,7 @@ package main
 	ArOZ Online System Main Request Router
 	ArOZ Online System Main Request Router
 
 
 	This is used to check authentication before actually serving file to the target client
 	This is used to check authentication before actually serving file to the target client
-	This function also handle the special page (login.system and user.system) delivery
+	This function also handle the special page (login.html and user.html) delivery
 */
 */
 
 
 import (
 import (
@@ -27,7 +27,7 @@ func mrouter(h http.Handler) http.Handler {
 		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/manifest.webmanifest" || r.URL.Path == "/robots.txt" || r.URL.Path == "/humans.txt" {
 		if r.URL.Path == "/favicon.ico" || r.URL.Path == "/manifest.webmanifest" || r.URL.Path == "/robots.txt" || r.URL.Path == "/humans.txt" {
 			//Serving web specification files. Allow no auth access.
 			//Serving web specification files. Allow no auth access.
 			h.ServeHTTP(w, r)
 			h.ServeHTTP(w, r)
-		} else if r.URL.Path == "/login.system" {
+		} else if r.URL.Path == "/login.html" {
 			//Login page. Require special treatment for template.
 			//Login page. Require special treatment for template.
 			//Get the redirection address from the request URL
 			//Get the redirection address from the request URL
 			red, _ := utils.GetPara(r, "redirect")
 			red, _ := utils.GetPara(r, "redirect")
@@ -38,7 +38,7 @@ func mrouter(h http.Handler) http.Handler {
 				imgsrc = "./web/img/public/auth_icon.png"
 				imgsrc = "./web/img/public/auth_icon.png"
 			}
 			}
 			imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
 			imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
-			parsedPage, err := utils.Templateload("web/login.system", map[string]string{
+			parsedPage, err := utils.Templateload("web/login.html", map[string]string{
 				"redirection_addr": red,
 				"redirection_addr": red,
 				"usercount":        strconv.Itoa(authAgent.GetUserCounts()),
 				"usercount":        strconv.Itoa(authAgent.GetUserCounts()),
 				"service_logo":     imageBase64,
 				"service_logo":     imageBase64,
@@ -49,10 +49,10 @@ func mrouter(h http.Handler) http.Handler {
 			}
 			}
 			w.Header().Add("Content-Type", "text/html; charset=UTF-8")
 			w.Header().Add("Content-Type", "text/html; charset=UTF-8")
 			w.Write([]byte(parsedPage))
 			w.Write([]byte(parsedPage))
-		} else if r.URL.Path == "/reset.system" && authAgent.GetUserCounts() > 0 {
+		} else if r.URL.Path == "/reset.html" && authAgent.GetUserCounts() > 0 {
 			//Password restart page. Allow access only when user number > 0
 			//Password restart page. Allow access only when user number > 0
 			system_resetpw_handlePasswordReset(w, r)
 			system_resetpw_handlePasswordReset(w, r)
-		} else if r.URL.Path == "/user.system" && authAgent.GetUserCounts() == 0 {
+		} else if r.URL.Path == "/user.html" && authAgent.GetUserCounts() == 0 {
 			//Serve user management page. This only allows serving of such page when the total usercount = 0 (aka System Initiation)
 			//Serve user management page. This only allows serving of such page when the total usercount = 0 (aka System Initiation)
 			h.ServeHTTP(w, r)
 			h.ServeHTTP(w, r)
 
 
@@ -102,7 +102,7 @@ func mrouter(h http.Handler) http.Handler {
 			} else {
 			} else {
 				interfaceModule := userinfo.GetInterfaceModules()
 				interfaceModule := userinfo.GetInterfaceModules()
 				if len(interfaceModule) == 1 && interfaceModule[0] == "Desktop" {
 				if len(interfaceModule) == 1 && interfaceModule[0] == "Desktop" {
-					http.Redirect(w, r, "./desktop.system", http.StatusTemporaryRedirect)
+					http.Redirect(w, r, "./desktop.html", http.StatusTemporaryRedirect)
 				} else if len(interfaceModule) == 1 {
 				} else if len(interfaceModule) == 1 {
 					//User with default interface module not desktop
 					//User with default interface module not desktop
 					modileInfo := moduleHandler.GetModuleInfoByID(interfaceModule[0])
 					modileInfo := moduleHandler.GetModuleInfoByID(interfaceModule[0])
@@ -120,7 +120,7 @@ func mrouter(h http.Handler) http.Handler {
 					http.Redirect(w, r, "./SystemAO/boot/no_interfaceing.html", http.StatusTemporaryRedirect)
 					http.Redirect(w, r, "./SystemAO/boot/no_interfaceing.html", http.StatusTemporaryRedirect)
 				} else {
 				} else {
 					//For unknown operations, send it to desktop
 					//For unknown operations, send it to desktop
-					http.Redirect(w, r, "./desktop.system", http.StatusTemporaryRedirect)
+					http.Redirect(w, r, "./desktop.html", http.StatusTemporaryRedirect)
 				}
 				}
 			}
 			}
 		} else if ((len(r.URL.Path) >= 5 && r.URL.Path[:5] == "/www/") || r.URL.Path == "/www") && *allow_homepage {
 		} else if ((len(r.URL.Path) >= 5 && r.URL.Path[:5] == "/www/") || r.URL.Path == "/www") && *allow_homepage {
@@ -184,7 +184,7 @@ func mrouter(h http.Handler) http.Handler {
 				//Other paths
 				//Other paths
 				//Rediect to login page
 				//Rediect to login page
 				w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
 				w.Header().Set("Cache-Control", "no-cache, no-store, no-transform, must-revalidate, private, max-age=0")
-				http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect="+r.URL.String(), 307)
+				http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.html")+"?redirect="+r.URL.String(), 307)
 			}
 			}
 
 
 		}
 		}

+ 88 - 0
src/mod/agi/agi.image.go

@@ -2,6 +2,7 @@ package agi
 
 
 import (
 import (
 	"bytes"
 	"bytes"
+	"encoding/base64"
 	"encoding/json"
 	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
@@ -233,6 +234,92 @@ func (g *Gateway) injectImageLibFunctions(payload *static.AgiLibInjectionPayload
 		return otto.TrueValue()
 		return otto.TrueValue()
 	})
 	})
 
 
+	//Resize image and return as base64 data URL, require (filepath, width, height, format)
+	vm.Set("_imagelib_resizeImageBase64", func(call otto.FunctionCall) otto.Value {
+		vsrc, err := call.Argument(0).ToString()
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		width, err := call.Argument(1).ToInteger()
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		height, err := call.Argument(2).ToInteger()
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		format := "jpeg"
+		if !call.Argument(3).IsUndefined() {
+			format, err = call.Argument(3).ToString()
+			if err != nil {
+				format = "jpeg"
+			}
+		}
+
+		//Convert the virtual path to real path
+		srcfsh, rsrc, err := static.VirtualPathToRealPath(vsrc, u)
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		resizeOpeningFile := rsrc
+		var srcFile arozfs.File
+		if srcfsh.RequireBuffer {
+			resizeOpeningFile, _, err = g.bufferRemoteResourcesToLocal(srcfsh, u, rsrc)
+			if err != nil {
+				g.RaiseError(err)
+				return otto.FalseValue()
+			}
+
+			srcFile, err = os.Open(resizeOpeningFile)
+			if err != nil {
+				g.RaiseError(err)
+				return otto.FalseValue()
+			}
+		} else {
+			srcFile, err = srcfsh.FileSystemAbstraction.Open(resizeOpeningFile)
+			if err != nil {
+				g.RaiseError(err)
+				return otto.FalseValue()
+			}
+		}
+		defer srcFile.Close()
+
+		//Decode and resize the image
+		src, err := imaging.Decode(srcFile)
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+		src = imaging.Resize(src, int(width), int(height), imaging.Lanczos)
+
+		//Encode to bytes buffer
+		var buf bytes.Buffer
+		if format == "png" {
+			err = png.Encode(&buf, src)
+		} else {
+			err = jpeg.Encode(&buf, src, &jpeg.Options{Quality: 85})
+		}
+		if err != nil {
+			g.RaiseError(err)
+			return otto.FalseValue()
+		}
+
+		//Convert to base64
+		imageBytes := buf.Bytes()
+		base64String := "data:image/" + format + ";base64," + base64.StdEncoding.EncodeToString(imageBytes)
+
+		result, _ := vm.ToValue(base64String)
+		return result
+	})
+
 	//Crop the given image, require (input, output, posx, posy, width, height)
 	//Crop the given image, require (input, output, posx, posy, width, height)
 	vm.Set("_imagelib_cropImage", func(call otto.FunctionCall) otto.Value {
 	vm.Set("_imagelib_cropImage", func(call otto.FunctionCall) otto.Value {
 		vsrc, err := call.Argument(0).ToString()
 		vsrc, err := call.Argument(0).ToString()
@@ -516,6 +603,7 @@ func (g *Gateway) injectImageLibFunctions(payload *static.AgiLibInjectionPayload
 		var imagelib = {};
 		var imagelib = {};
 		imagelib.getImageDimension = _imagelib_getImageDimension;
 		imagelib.getImageDimension = _imagelib_getImageDimension;
 		imagelib.resizeImage = _imagelib_resizeImage;
 		imagelib.resizeImage = _imagelib_resizeImage;
+		imagelib.resizeImageBase64 = _imagelib_resizeImageBase64;
 		imagelib.cropImage = _imagelib_cropImage;
 		imagelib.cropImage = _imagelib_cropImage;
 		imagelib.loadThumbString = _imagelib_loadThumbString;
 		imagelib.loadThumbString = _imagelib_loadThumbString;
 		imagelib.hasExif = _imagelib_hasExif;
 		imagelib.hasExif = _imagelib_hasExif;

+ 1 - 1
src/mod/auth/ldap/web_login.go

@@ -26,7 +26,7 @@ func (ldap *ldapHandler) HandleLoginPage(w http.ResponseWriter, r *http.Request)
 		imgsrc = "./web/img/public/auth_icon.png"
 		imgsrc = "./web/img/public/auth_icon.png"
 	}
 	}
 	imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
 	imageBase64, _ := utils.LoadImageAsBase64(imgsrc)
-	parsedPage, err := utils.Templateload("web/login.system", map[string]string{
+	parsedPage, err := utils.Templateload("web/login.html", map[string]string{
 		"redirection_addr": red,
 		"redirection_addr": red,
 		"usercount":        strconv.Itoa(ldap.ag.GetUserCounts()),
 		"usercount":        strconv.Itoa(ldap.ag.GetUserCounts()),
 		"service_logo":     imageBase64,
 		"service_logo":     imageBase64,

+ 1 - 1
src/mod/auth/oauth2/oauth2.go

@@ -134,7 +134,7 @@ func (oh *OauthHandler) HandleAuthorize(w http.ResponseWriter, r *http.Request)
 		//also makr the login as fail.
 		//also makr the login as fail.
 		if oh.reg.AllowRegistry {
 		if oh.reg.AllowRegistry {
 			oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
 			oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
-			http.Redirect(w, r, "/public/register/register.system?user="+username, http.StatusFound)
+			http.Redirect(w, r, "/public/register/register.html?user="+username, http.StatusFound)
 		} else {
 		} else {
 			oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
 			oh.ag.Logger.LogAuthByRequestInfo(username, r.RemoteAddr, time.Now().Unix(), false, "web")
 			w.Header().Set("Content-Type", "text/html")
 			w.Header().Set("Content-Type", "text/html")

+ 2 - 2
src/mod/auth/register/register.go

@@ -97,12 +97,12 @@ func (h *RegisterHandler) HandleRegisterInterface(w http.ResponseWriter, r *http
 		//Load the vendor icon as base64
 		//Load the vendor icon as base64
 		imagecontent, _ := readImageFileAsBase64(h.options.VendorIcon)
 		imagecontent, _ := readImageFileAsBase64(h.options.VendorIcon)
 
 
-		s, err := utils.Templateload("./system/auth/register.system", map[string]string{
+		s, err := utils.Templateload("./system/auth/register.html", map[string]string{
 			"host_name":   h.options.Hostname,
 			"host_name":   h.options.Hostname,
 			"vendor_logo": imagecontent,
 			"vendor_logo": imagecontent,
 		})
 		})
 		if err != nil {
 		if err != nil {
-			log.Println("Template not found: system/auth/register.system")
+			log.Println("Template not found: system/auth/register.html")
 			http.NotFound(w, r)
 			http.NotFound(w, r)
 			return
 			return
 		}
 		}

+ 5 - 4
src/mod/share/share.go

@@ -390,7 +390,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
 				} else {
-					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.html")+"?redirect=/share/"+id, 307)
 				}
 				}
 				return
 				return
 			} else {
 			} else {
@@ -403,7 +403,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
 				} else {
-					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.html")+"?redirect=/share/"+id, 307)
 				}
 				}
 				return
 				return
 			}
 			}
@@ -443,7 +443,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
 				} else {
-					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.html")+"?redirect=/share/"+id, 307)
 				}
 				}
 				return
 				return
 			}
 			}
@@ -468,7 +468,7 @@ func (s *Manager) HandleShareAccess(w http.ResponseWriter, r *http.Request) {
 					w.WriteHeader(http.StatusUnauthorized)
 					w.WriteHeader(http.StatusUnauthorized)
 					w.Write([]byte("401 - Unauthorized"))
 					w.Write([]byte("401 - Unauthorized"))
 				} else {
 				} else {
-					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.system")+"?redirect=/share/"+id, 307)
+					http.Redirect(w, r, utils.ConstructRelativePathFromRequestURL(r.RequestURI, "login.html")+"?redirect=/share/"+id, 307)
 				}
 				}
 				return
 				return
 			}
 			}
@@ -1417,3 +1417,4 @@ func getPathHashFromUsernameAndVpath(userinfo *user.User, vpath string) (string,
 	}
 	}
 	return shareEntry.GetPathHash(fsh, vpath, userinfo.Username)
 	return shareEntry.GetPathHash(fsh, vpath, userinfo.Username)
 }
 }
+

+ 8 - 8
src/mod/storage/tftp/tftp.go

@@ -65,12 +65,12 @@ func NewTFTPHandler(userHandler *user.UserHandler, ServerName string, Port int,
 func (h *Handler) Start() error {
 func (h *Handler) Start() error {
 	if h.server != nil {
 	if h.server != nil {
 		addr := ":" + strconv.Itoa(h.Port)
 		addr := ":" + strconv.Itoa(h.Port)
-		log.Println("TFTP Server Started, listening at: " + strconv.Itoa(h.Port))
+		log.Println("[TFTP] Server Started, listening at: " + strconv.Itoa(h.Port))
 
 
 		go func() {
 		go func() {
 			err := h.server.ListenAndServe(addr)
 			err := h.server.ListenAndServe(addr)
 			if err != nil {
 			if err != nil {
-				log.Println("TFTP Server error:", err)
+				log.Println("[TFTP] Server error:", err)
 			}
 			}
 		}()
 		}()
 
 
@@ -117,7 +117,7 @@ func (d *tftpDriver) readHandler(filename string, rf io.ReaderFrom) error {
 	// Open file for reading
 	// Open file for reading
 	file, err := afs.Open(filename)
 	file, err := afs.Open(filename)
 	if err != nil {
 	if err != nil {
-		log.Printf("TFTP READ: Failed to open %s: %v", filename, err)
+		log.Printf("[TFTP] READ: Failed to open %s: %v", filename, err)
 		return err
 		return err
 	}
 	}
 	defer file.Close()
 	defer file.Close()
@@ -136,11 +136,11 @@ func (d *tftpDriver) readHandler(filename string, rf io.ReaderFrom) error {
 
 
 	n, err := rf.ReadFrom(file)
 	n, err := rf.ReadFrom(file)
 	if err != nil {
 	if err != nil {
-		log.Printf("TFTP READ: Transfer error for %s: %v", filename, err)
+		log.Printf("[TFTP] READ: Transfer error for %s: %v", filename, err)
 		return err
 		return err
 	}
 	}
 
 
-	log.Printf("TFTP READ: Sent %s (%d bytes)", filename, n)
+	log.Printf("[TFTP] READ: Sent %s (%d bytes)", filename, n)
 	return nil
 	return nil
 }
 }
 
 
@@ -171,17 +171,17 @@ func (d *tftpDriver) writeHandler(filename string, wt io.WriterTo) error {
 	// Check if user can write
 	// Check if user can write
 	file, err := afs.Create(filename)
 	file, err := afs.Create(filename)
 	if err != nil {
 	if err != nil {
-		log.Printf("TFTP WRITE: Failed to create %s: %v", filename, err)
+		log.Printf("[TFTP] WRITE: Failed to create %s: %v", filename, err)
 		return err
 		return err
 	}
 	}
 	defer file.Close()
 	defer file.Close()
 
 
 	n, err := wt.WriteTo(file)
 	n, err := wt.WriteTo(file)
 	if err != nil {
 	if err != nil {
-		log.Printf("TFTP WRITE: Transfer error for %s: %v", filename, err)
+		log.Printf("[TFTP] WRITE: Transfer error for %s: %v", filename, err)
 		return err
 		return err
 	}
 	}
 
 
-	log.Printf("TFTP WRITE: Received %s (%d bytes)", filename, n)
+	log.Printf("[TFTP] WRITE: Received %s (%d bytes)", filename, n)
 	return nil
 	return nil
 }
 }

+ 1 - 1
src/network.go

@@ -450,7 +450,7 @@ func FileServerInit() {
 		ID:                "tftp",
 		ID:                "tftp",
 		Name:              "TFTP",
 		Name:              "TFTP",
 		Desc:              "Trivial File Transfer Protocol Server",
 		Desc:              "Trivial File Transfer Protocol Server",
-		IconPath:          "img/system/network-folder.svg",
+		IconPath:          "img/system/network-folder-black.svg",
 		DefaultPorts:      []int{69},
 		DefaultPorts:      []int{69},
 		Ports:             []int{},
 		Ports:             []int{},
 		ForwardPortIfUpnp: false,
 		ForwardPortIfUpnp: false,

+ 2 - 2
src/register.go

@@ -37,8 +37,8 @@ func RegisterSystemInit() {
 		registerHandler.AllowRegistry = false
 		registerHandler.AllowRegistry = false
 	}
 	}
 
 
-	http.HandleFunc("/public/register/register.system", registerHandler.HandleRegisterInterface)
-	http.HandleFunc("/public/register/handleRegister.system", registerHandler.HandleRegisterRequest)
+	http.HandleFunc("/public/register/register.html", registerHandler.HandleRegisterInterface)
+	http.HandleFunc("/public/register/handleRegister.html", registerHandler.HandleRegisterRequest)
 	http.HandleFunc("/public/register/checkPublicRegister", registerHandler.HandleRegisterCheck)
 	http.HandleFunc("/public/register/checkPublicRegister", registerHandler.HandleRegisterCheck)
 
 
 	//General user functions
 	//General user functions

+ 0 - 0
src/system/auth/register.system → src/system/auth/register.html


+ 77 - 0
src/web/Photo/backend/getCompressedImg.js

@@ -0,0 +1,77 @@
+/*
+    Compressed Image Retrieval Module
+    Retrieves compressed images for display in the Photo application.
+    
+    This module compresses images to a maximum of 2048x2048 pixels
+    while maintaining aspect ratio and returns as base64 data URL.
+*/
+
+requirelib("imagelib");
+
+function main() {
+    // Get the filepath from the request
+    if (typeof(filepath) == "undefined") {
+        sendJSONResp(JSON.stringify({
+            error: "filepath parameter is required"
+        }));
+        return;
+    }
+
+    // Define max dimensions
+    var maxWidth = 1024;
+    var maxHeight = 1024;
+
+    // Get original image dimensions
+    var imgInfo = imagelib.getImageDimension(filepath);
+    if (!imgInfo || !imgInfo[0] || !imgInfo[1]) {
+        // If we can't get dimensions, return error
+        sendJSONResp(JSON.stringify({
+            error: "Cannot read image dimensions"
+        }));
+        return;
+    }
+
+    var originalWidth = imgInfo[0];
+    var originalHeight = imgInfo[1];
+
+    // Calculate new dimensions while maintaining aspect ratio
+    var newWidth = originalWidth;
+    var newHeight = originalHeight;
+
+    if (originalWidth > maxWidth || originalHeight > maxHeight) {
+        var widthRatio = maxWidth / originalWidth;
+        var heightRatio = maxHeight / originalHeight;
+        var ratio = Math.min(widthRatio, heightRatio);
+
+        newWidth = Math.round(originalWidth * ratio);
+        newHeight = Math.round(originalHeight * ratio);
+    }
+
+    // Determine output format from file extension
+    var ext = filepath.split(".").pop().toLowerCase();
+    var format = "jpeg";
+    if (ext == "png") {
+        format = "png";
+    }
+
+    // Resize the image and get base64 data URL
+    try {
+        var base64DataUrl = imagelib.resizeImageBase64(filepath, newWidth, newHeight, format);
+        
+        if (base64DataUrl) {
+            // Return the base64 data URL as plain text
+            sendResp(base64DataUrl);
+        } else {
+            sendJSONResp(JSON.stringify({
+                error: "Failed to resize image"
+            }));
+        }
+    } catch (error) {
+        sendJSONResp(JSON.stringify({
+            error: "Failed to compress image: " + error.toString()
+        }));
+    }
+}
+
+main();
+

+ 12 - 1
src/web/Photo/backend/listFolder.js

@@ -121,7 +121,18 @@ function main(){
     // Filter out JPG duplicates when RAW files exist
     // Filter out JPG duplicates when RAW files exist
     files = filterDuplicates(files);
     files = filterDuplicates(files);
 
 
-    sendJSONResp(JSON.stringify([folders, files]));
+    // Add filesize information to each file
+    var filesWithSize = [];
+    for (var i = 0; i < files.length; i++){
+        var filepath = files[i];
+        var filesize = filelib.filesize(filepath);
+        filesWithSize.push({
+            filepath: filepath,
+            filesize: filesize
+        });
+    }
+
+    sendJSONResp(JSON.stringify([folders, filesWithSize]));
 }
 }
 
 
 main();
 main();

+ 180 - 80
src/web/Photo/index.html

@@ -148,6 +148,7 @@
             padding: 20px;
             padding: 20px;
             overflow: hidden;
             overflow: hidden;
             cursor: grab;
             cursor: grab;
+            position: relative;
         }
         }
 
 
         .viewer-left img {
         .viewer-left img {
@@ -159,6 +160,21 @@
             user-select: none;
             user-select: none;
         }
         }
 
 
+        #compressedImage {
+            position: absolute;
+            top: 50%;
+            left: 50%;
+            transform: translate(-50%, -50%);
+            opacity: 1;
+            transition: opacity 0.3s ease-out;
+            z-index: 2;
+        }
+
+        #compressedImage.hidden {
+            opacity: 0;
+            pointer-events: none;
+        }
+
         .viewer-left img.zoomed {
         .viewer-left img.zoomed {
             max-width: none;
             max-width: none;
             max-height: none;
             max-height: none;
@@ -301,37 +317,94 @@
             }
             }
         }
         }
 
 
-        /* Zoom Snackbar Styles */
-        .zoom-snackbar {
+        /* Zoom Controls Styles */
+        .zoom-controls {
             position: absolute;
             position: absolute;
             bottom: 20px;
             bottom: 20px;
             left: 20px;
             left: 20px;
-            background: rgba(0, 0, 0, 0.8);
+            display: flex;
+            flex-direction: column;
+            gap: 8px;
+            z-index: 10;
+        }
+
+        .zoom-btn {
+            background: rgba(0, 0, 0, 0.7);
             color: white;
             color: white;
-            padding: 8px 12px;
+            border: 1px solid rgba(255, 255, 255, 0.2);
+            width: 40px;
+            height: 40px;
             border-radius: 4px;
             border-radius: 4px;
+            cursor: pointer;
+            font-size: 20px;
+            font-weight: bold;
+            transition: all 0.2s;
             display: flex;
             display: flex;
             align-items: center;
             align-items: center;
-            gap: 10px;
-            font-size: 14px;
-            font-family: Arial, sans-serif;
-            z-index: 1001;
+            justify-content: center;
             backdrop-filter: blur(4px);
             backdrop-filter: blur(4px);
         }
         }
 
 
-        .zoom-reset-btn {
-            background: #f76c5d;
+        .zoom-btn:hover {
+            background: rgba(247, 108, 93, 0.9);
+            border-color: #f76c5d;
+        }
+
+        .zoom-btn:active {
+            transform: scale(0.95);
+        }
+
+        .zoom-level-indicator {
+            background: rgba(0, 0, 0, 0.7);
             color: white;
             color: white;
-            border: none;
-            padding: 4px 8px;
-            border-radius: 3px;
-            cursor: pointer;
+            padding: 6px 10px;
+            border-radius: 4px;
             font-size: 12px;
             font-size: 12px;
-            transition: background-color 0.2s;
+            text-align: center;
+            backdrop-filter: blur(4px);
+            border: 1px solid rgba(255, 255, 255, 0.2);
         }
         }
 
 
-        .zoom-reset-btn:hover {
-            background: #e55a4f;
+        /* Navigation Controls Styles */
+        .nav-controls {
+            position: absolute;
+            bottom: 20px;
+            right: 20px;
+            display: flex;
+            flex-direction: row;
+            gap: 8px;
+            z-index: 10;
+        }
+
+        .nav-btn {
+            background: rgba(0, 0, 0, 0.7);
+            color: white;
+            border: 1px solid rgba(255, 255, 255, 0.2);
+            width: 40px;
+            height: 40px;
+            border-radius: 4px;
+            cursor: pointer;
+            font-size: 20px;
+            font-weight: bold;
+            transition: all 0.2s;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            backdrop-filter: blur(4px);
+        }
+
+        .nav-btn:hover:not(:disabled) {
+            background: rgba(247, 108, 93, 0.9);
+            border-color: #f76c5d;
+        }
+
+        .nav-btn:active:not(:disabled) {
+            transform: scale(0.95);
+        }
+
+        .nav-btn:disabled {
+            opacity: 0.3;
+            cursor: not-allowed;
         }
         }
 
 
         @media (max-width: 768px) {
         @media (max-width: 768px) {
@@ -339,6 +412,23 @@
                 display: none !important;
                 display: none !important;
             }
             }
         }
         }
+
+        /* Loading Progress Indicator */
+        .loading-progress {
+            position: absolute;
+            bottom: 20px;
+            left: 50%;
+            transform: translateX(-50%);
+            background: rgba(0, 0, 0, 0.7);
+            color: white;
+            padding: 8px 16px;
+            border-radius: 4px;
+            font-size: 14px;
+            backdrop-filter: blur(4px);
+            border: 1px solid rgba(255, 255, 255, 0.2);
+            z-index: 10;
+            display: none;
+        }
     </style>
     </style>
 
 
 </head>
 </head>
@@ -410,21 +500,21 @@
             <div id="viewboxContainer">
             <div id="viewboxContainer">
                 <div x-show="viewMode === 'grid'" id="viewbox" class="ui six cards viewbox">
                 <div x-show="viewMode === 'grid'" id="viewbox" class="ui six cards viewbox">
                     <template x-for="image in images">
                     <template x-for="image in images">
-                        <div class="imagecard" style="cursor: pointer;" x-on:click="showImage($el); ShowModal();" :style="{width: renderSize + 'px', height: renderSize + 'px'}" :filedata="encodeURIComponent(JSON.stringify({'filename':image.split('/').pop(),'filepath':image}))">
+                        <div class="imagecard" style="cursor: pointer;" x-on:click="showImage($el); ShowModal();" :style="{width: renderSize + 'px', height: renderSize + 'px'}" :filedata="encodeURIComponent(JSON.stringify({'filename':image.filepath.split('/').pop(),'filepath':image.filepath,'filesize':image.filesize}))">
                             <a class="image" x-init="updateImageSizes();">
                             <a class="image" x-init="updateImageSizes();">
-                                <img :src="'../system/file_system/loadThumbnail?bytes=true&vpath=' + image">
+                                <img :src="'../system/file_system/loadThumbnail?bytes=true&vpath=' + image.filepath">
                             </a>
                             </a>
                         </div>
                         </div>
                     </template>
                     </template>
                 </div>
                 </div>
                 <div x-show="viewMode === 'list'" class="ui relaxed divided inverted list">
                 <div x-show="viewMode === 'list'" class="ui relaxed divided inverted list">
                     <template x-for="image in images">
                     <template x-for="image in images">
-                        <div class="item" style="cursor: pointer; padding-left: 10px; " x-on:click="showImage($el); ShowModal();" :filedata="encodeURIComponent(JSON.stringify({'filename':image.split('/').pop(),'filepath':image}))">
-                            <img class="ui small image" :src="'../system/file_system/loadThumbnail?bytes=true&vpath=' + image"
+                        <div class="item" style="cursor: pointer; padding-left: 10px; " x-on:click="showImage($el); ShowModal();" :filedata="encodeURIComponent(JSON.stringify({'filename':image.filepath.split('/').pop(),'filepath':image.filepath,'filesize':image.filesize}))">
+                            <img class="ui small image" :src="'../system/file_system/loadThumbnail?bytes=true&vpath=' + image.filepath"
                                  style="width: 60px; height: 60px;">
                                  style="width: 60px; height: 60px;">
                             <div class="content">
                             <div class="content">
-                                <div class="header" x-text="image.split('/').pop()"></div>
-                                <div class="description" x-text="image"></div>
+                                <div class="header" x-text="image.filepath.split('/').pop()"></div>
+                                <div class="description" x-text="image.filepath"></div>
                             </div>
                             </div>
                         </div>
                         </div>
                     </template>
                     </template>
@@ -442,9 +532,26 @@
                 <img id="bg-image" src="" />
                 <img id="bg-image" src="" />
             </div>
             </div>
             <div class="viewer-left">
             <div class="viewer-left">
+                <img id="compressedImage" src="" style="display: none;" />
                 <img id="fullImage" src="img/loading.png" />
                 <img id="fullImage" src="img/loading.png" />
                 <button class="close-btn" onclick="closeViewer()">×</button>
                 <button class="close-btn" onclick="closeViewer()">×</button>
                 <button class="show-info-btn" onclick="showInfoPanel()">ℹ</button>
                 <button class="show-info-btn" onclick="showInfoPanel()">ℹ</button>
+                
+                <!-- Loading Progress -->
+                <div id="loading-progress" class="loading-progress">Loading 0%</div>
+                
+                <!-- Zoom Controls -->
+                <div id="zoom-controls" class="zoom-controls">
+                    <button class="zoom-btn" onclick="zoomIn()" title="Zoom In">+</button>
+                    <div class="zoom-level-indicator" id="zoom-level-display">100%</div>
+                    <button class="zoom-btn" onclick="zoomOut()" title="Zoom Out">−</button>
+                </div>
+                
+                <!-- Navigation Controls -->
+                <div id="nav-controls" class="nav-controls">
+                    <button id="prev-btn" class="nav-btn" onclick="showPreviousImage()" title="Previous Photo">‹</button>
+                    <button id="next-btn" class="nav-btn" onclick="showNextImage()" title="Next Photo">›</button>
+                </div>
             </div>
             </div>
             <div class="viewer-right">
             <div class="viewer-right">
                 <div>
                 <div>
@@ -590,12 +697,6 @@
                 </div>
                 </div>
             </div>
             </div>
         </div>
         </div>
-        
-        <!-- Zoom Snackbar -->
-        <div id="zoom-snackbar" class="zoom-snackbar" style="display: none;">
-            <span id="zoom-level-display">x1.0</span>
-            <button id="zoom-reset-btn" class="zoom-reset-btn" onclick="resetZoom()">Reset</button>
-        </div>
     </div>
     </div>
 
 
 </body>
 </body>
@@ -622,6 +723,31 @@
         document.querySelector('.viewer-right').style.display = 'block';
         document.querySelector('.viewer-right').style.display = 'block';
     }
     }
 
 
+    // Navigation functionality
+    function showPreviousImage() {
+        if (typeof prePhoto !== 'undefined' && prePhoto != null) {
+            showImage(prePhoto);
+        }
+    }
+
+    function showNextImage() {
+        if (typeof nextPhoto !== 'undefined' && nextPhoto != null) {
+            showImage(nextPhoto);
+        }
+    }
+
+    function updateNavigationButtons() {
+        const prevBtn = document.getElementById('prev-btn');
+        const nextBtn = document.getElementById('next-btn');
+        
+        if (prevBtn) {
+            prevBtn.disabled = (typeof prePhoto === 'undefined' || prePhoto == null || !$(prePhoto).hasClass("imagecard"));
+        }
+        if (nextBtn) {
+            nextBtn.disabled = (typeof nextPhoto === 'undefined' || nextPhoto == null || !$(nextPhoto).hasClass("imagecard"));
+        }
+    }
+
     // Zoom and Pan functionality
     // Zoom and Pan functionality
     let zoomLevel = 1;
     let zoomLevel = 1;
     let panX = 0;
     let panX = 0;
@@ -642,25 +768,40 @@
 
 
     function updateImageTransform() {
     function updateImageTransform() {
         const img = document.getElementById('fullImage');
         const img = document.getElementById('fullImage');
-        const snackbar = document.getElementById('zoom-snackbar');
+        const controls = document.getElementById('zoom-controls');
         const zoomDisplay = document.getElementById('zoom-level-display');
         const zoomDisplay = document.getElementById('zoom-level-display');
         
         
         if (zoomLevel > 1) {
         if (zoomLevel > 1) {
             img.style.transform = `scale(${zoomLevel}) translate(${panX}px, ${panY}px)`;
             img.style.transform = `scale(${zoomLevel}) translate(${panX}px, ${panY}px)`;
             img.classList.add('zoomed');
             img.classList.add('zoomed');
-            
-            // Show zoom snackbar
-            zoomDisplay.textContent = 'x' + zoomLevel.toFixed(1);
-            snackbar.style.display = 'flex';
         } else {
         } else {
             img.style.transform = 'none';
             img.style.transform = 'none';
             img.classList.remove('zoomed');
             img.classList.remove('zoomed');
             panX = 0;
             panX = 0;
             panY = 0;
             panY = 0;
-            
-            // Hide zoom snackbar
-            snackbar.style.display = 'none';
         }
         }
+        
+        // Always show zoom controls and update display
+        zoomDisplay.textContent = Math.round(zoomLevel * 100) + '%';
+        controls.style.display = 'flex';
+    }
+
+    function zoomIn() {
+        const img = document.getElementById('fullImage');
+        const rect = img.getBoundingClientRect();
+        const centerX = rect.left + rect.width / 2;
+        const centerY = rect.top + rect.height / 2;
+        let newZoom = Math.min(3, zoomLevel + 0.2);
+        zoomAtPoint(newZoom, centerX, centerY);
+    }
+
+    function zoomOut() {
+        const img = document.getElementById('fullImage');
+        const rect = img.getBoundingClientRect();
+        const centerX = rect.left + rect.width / 2;
+        const centerY = rect.top + rect.height / 2;
+        let newZoom = Math.max(1, zoomLevel - 0.2);
+        zoomAtPoint(newZoom, centerX, centerY);
     }
     }
 
 
     function zoomAtPoint(scale, centerX, centerY) {
     function zoomAtPoint(scale, centerX, centerY) {
@@ -707,26 +848,6 @@
         // Reset zoom state
         // Reset zoom state
         resetZoom();
         resetZoom();
 
 
-        // Define handler functions to allow removal and re-addition
-        let handleDblClick = function(e) {
-            console.log(e);
-            e.preventDefault();
-            if (zoomLevel > 1) {
-                resetZoom();
-            } else {
-                zoomAtPoint(2, e.clientX, e.clientY);
-            }
-        };
-
-        let handleWheel = function(e) {
-            e.preventDefault();
-            const delta = e.deltaY > 0 ? 0.9 : 1.1;
-            let actualZoomLevel = zoomLevel * delta;
-            if (actualZoomLevel < 1) actualZoomLevel = 1;
-            if (actualZoomLevel > 3.3) actualZoomLevel = 3.3;
-            zoomAtPoint(actualZoomLevel, e.clientX, e.clientY);
-        };
-
         let handleMouseDown = function(e) {
         let handleMouseDown = function(e) {
             if (zoomLevel > 1) {
             if (zoomLevel > 1) {
                 e.preventDefault();
                 e.preventDefault();
@@ -830,8 +951,6 @@
         };
         };
 
 
         // Remove existing listeners to prevent double triggering
         // Remove existing listeners to prevent double triggering
-        img.removeEventListener('dblclick', handleDblClick);
-        img.removeEventListener('wheel', handleWheel);
         img.removeEventListener('mousedown', handleMouseDown);
         img.removeEventListener('mousedown', handleMouseDown);
         document.removeEventListener('mousemove', handleMouseMove);
         document.removeEventListener('mousemove', handleMouseMove);
         document.removeEventListener('mouseup', handleMouseUp);
         document.removeEventListener('mouseup', handleMouseUp);
@@ -840,8 +959,6 @@
         img.removeEventListener('touchend', handleTouchEnd);
         img.removeEventListener('touchend', handleTouchEnd);
 
 
         // Add listeners back
         // Add listeners back
-        img.addEventListener('dblclick', handleDblClick);
-        img.addEventListener('wheel', handleWheel);
         img.addEventListener('mousedown', handleMouseDown);
         img.addEventListener('mousedown', handleMouseDown);
         document.addEventListener('mousemove', handleMouseMove);
         document.addEventListener('mousemove', handleMouseMove);
         document.addEventListener('mouseup', handleMouseUp);
         document.addEventListener('mouseup', handleMouseUp);
@@ -849,26 +966,9 @@
         img.addEventListener('touchmove', handleTouchMove);
         img.addEventListener('touchmove', handleTouchMove);
         img.addEventListener('touchend', handleTouchEnd);
         img.addEventListener('touchend', handleTouchEnd);
         
         
-        // Double click to zoom
-        img.addEventListener('dblclick', function(e) {
-            console.log(e);
-            e.preventDefault();
-            if (zoomLevel > 1) {
-                resetZoom();
-            } else {
-                zoomAtPoint(2, e.clientX, e.clientY);
-            }
-        });
+        // Double-click zoom removed - use +/- buttons instead
         
         
-        // Mouse wheel zoom
-        img.addEventListener('wheel', function(e) {
-            e.preventDefault();
-            const delta = e.deltaY > 0 ? 0.9 : 1.1;
-            let actualZoomLevel = zoomLevel * delta;
-            if (actualZoomLevel < 1) actualZoomLevel = 1;
-            if (actualZoomLevel > 3.3) actualZoomLevel = 3.3;;
-            zoomAtPoint(actualZoomLevel, e.clientX, e.clientY);
-        });
+        // Mouse wheel zoom removed - use +/- buttons instead
         
         
         // Mouse drag pan
         // Mouse drag pan
         img.addEventListener('mousedown', function(e) {
         img.addEventListener('mousedown', function(e) {

+ 189 - 20
src/web/Photo/photo.js

@@ -11,6 +11,14 @@ let prePhoto = "";
 let nextPhoto = "";
 let nextPhoto = "";
 let currentModel = "";
 let currentModel = "";
 
 
+// Check if image should use compression (only JPG/PNG)
+function shouldUseCompression(filepath, filesize) {
+    const ext = filepath.split('.').pop().toLowerCase();
+    const isJpgOrPng = (ext === 'jpg' || ext === 'jpeg' || ext === 'png');
+    const COMPRESSION_THRESHOLD = 5 * 1024 * 1024; // 5MB
+    return isJpgOrPng && filesize && filesize > COMPRESSION_THRESHOLD;
+}
+
 // Get viewable image URL (handles RAW files)
 // Get viewable image URL (handles RAW files)
 function getViewableImageUrl(filepath, callback) {
 function getViewableImageUrl(filepath, callback) {
     // Both RAW and regular images now use backend rendering
     // Both RAW and regular images now use backend rendering
@@ -212,6 +220,7 @@ function closeViewer(){
 
 
     setTimeout(function(){
     setTimeout(function(){
         $("#fullImage").attr("src","img/loading.png");
         $("#fullImage").attr("src","img/loading.png");
+        $("#compressedImage").attr("src","").hide().removeClass('hidden');
         $("#bg-image").attr("src","");
         $("#bg-image").attr("src","");
         $("#info-filename").text("");
         $("#info-filename").text("");
         $("#info-filepath").text("");
         $("#info-filepath").text("");
@@ -243,33 +252,83 @@ function showImage(object){
         resetZoom();
         resetZoom();
     }
     }
 
 
+    if (!$(object).hasClass("imagecard")){
+        // Not an image card, do nothing
+        return;
+    }
     var fd = JSON.parse(decodeURIComponent($(object).attr("filedata")));
     var fd = JSON.parse(decodeURIComponent($(object).attr("filedata")));
-
-    // Update image dimensions and generate histogram when loaded
-    $("#fullImage").off("load").on('load', function() {
-        let width = this.naturalWidth;
-        let height = this.naturalHeight;
-        $("#info-dimensions").text(width + ' × ' + height + "px");
-
-        // Wait for image to be ready, then generate histogram
-        const canvas = document.getElementById('histogram-canvas');
-        if (canvas) {
-            generateHistogram(document.getElementById('fullImage'), canvas);
-        }
-    });
+    $("#info-dimensions").text("Calculating...");
+    // Check if we should use compression (only for JPG/PNG > 5MB)
+    const useCompression = shouldUseCompression(fd.filepath, fd.filesize);
 
 
     // Get image URL (backend handles RAW files automatically)
     // Get image URL (backend handles RAW files automatically)
     getViewableImageUrl(fd.filepath, (imageUrl, isSupported, isBlob, method) => {
     getViewableImageUrl(fd.filepath, (imageUrl, isSupported, isBlob, method) => {
-        $("#fullImage").attr('src', imageUrl);
-        $("#bg-image").attr('src', imageUrl);
+        const compressedImg = document.getElementById('compressedImage');
+        const fullImg = document.getElementById('fullImage');
+        const bgImg = document.getElementById('bg-image');
+        
+        // Reset compressed image
+        compressedImg.style.display = 'none';
+        compressedImg.classList.remove('hidden');
+         
+        if (useCompression) {
+            // Use compressed version for large JPG/PNG files
+            console.log('Large JPG/PNG detected (' + (fd.filesize / 1024 / 1024).toFixed(2) + 'MB), loading compressed version first');
+
+            fetch(ao_root + "system/ajgi/interface?script=Photo/backend/getCompressedImg.js", {
+                method: 'POST',
+                cache: 'no-cache',
+                headers: {
+                    'Content-Type': 'application/json'
+                },
+                body: JSON.stringify({
+                    "filepath": fd.filepath
+                })
+            }).then(resp => {
+                resp.text().then(dataURL => {
+                    // Show compressed image
+                    compressedImg.src = dataURL;
+                    compressedImg.style.display = 'block';
+                    bgImg.src = dataURL;
+
+                    // Start loading full-size image in background
+                    loadFullSizeImageInBackground(imageUrl, fd);
+                });
+            }).catch(error => {
+                console.error('Failed to load compressed image:', error);
+                // Fall back to full size image
+                fullImg.src = imageUrl;
+                bgImg.src = imageUrl;
+            });
+        } else {
+            $("#compressedImage").hide();
+            // Use full image URL directly for RAW, WEBP, or small JPG/PNG files
+            if (method === 'backend_raw') {
+                console.log('RAW file: Rendered by backend');
+            }
+            fullImg.src = imageUrl;
+            bgImg.src = imageUrl;
+        }
+
+        // Update image dimensions and generate histogram when full image loads
+        $("#fullImage").off("load").on('load', function() {
+            let width = this.naturalWidth;
+            let height = this.naturalHeight;
+            $("#info-dimensions").text(width + ' × ' + height + "px");
+
+            // Hide the compressed image once full image is loaded
+            $("#compressedImage").hide();
+
+            // Wait for image to be ready, then generate histogram
+            const canvas = document.getElementById('histogram-canvas');
+            if (canvas) {
+                generateHistogram(this, canvas);
+            }
+        });
+
         $("#info-filename").text(fd.filename);
         $("#info-filename").text(fd.filename);
         $("#info-filepath").text(fd.filepath);
         $("#info-filepath").text(fd.filepath);
 
 
-        // Log the rendering method used
-        if (method === 'backend_raw') {
-            console.log('RAW file: Rendered by backend');
-        }
-
         var nextCard = $(object).next();
         var nextCard = $(object).next();
         var prevCard = $(object).prev();
         var prevCard = $(object).prev();
         if (nextCard.length > 0){
         if (nextCard.length > 0){
@@ -284,6 +343,11 @@ function showImage(object){
             prePhoto = null;
             prePhoto = null;
         }
         }
 
 
+        // Update navigation buttons state
+        if (typeof updateNavigationButtons === 'function') {
+            updateNavigationButtons();
+        }
+
         ao_module_setWindowTitle("Photo - " + fd.filename);
         ao_module_setWindowTitle("Photo - " + fd.filename);
 
 
         window.location.hash = encodeURIComponent(JSON.stringify({filename: fd.filename, filepath: fd.filepath}));
         window.location.hash = encodeURIComponent(JSON.stringify({filename: fd.filename, filepath: fd.filepath}));
@@ -309,6 +373,111 @@ function showImage(object){
     });
     });
 }
 }
 
 
+
+// Function to load full-size image in background with progress tracking
+function loadFullSizeImageInBackground(fullSizeUrl, fileData) {
+    console.log('Starting background download of full-size image...');
+    
+  
+
+    const loadingIndicator = document.getElementById('loading-progress');
+    const fullImage = document.getElementById('fullImage');
+    const compressedImage = document.getElementById('compressedImage');
+    const bgImage = document.getElementById('bg-image');
+    fullImage.src = fullSizeUrl;
+
+    return;
+    // Legacy blob loading method
+    // Show loading indicator
+    /*
+    if (loadingIndicator) {
+        loadingIndicator.style.display = 'block';
+        loadingIndicator.textContent = 'Loading 0%';
+    }
+    
+    const xhr = new XMLHttpRequest();
+    xhr.open('GET', fullSizeUrl, true);
+    xhr.responseType = 'arraybuffer';
+    
+    // Track download progress
+    xhr.onprogress = function(event) {
+        if (event.lengthComputable) {
+            const percentComplete = (event.loaded / event.total) * 100;
+            console.log('Download progress: ' + percentComplete.toFixed(2) + '% (' + 
+                       (event.loaded / 1024 / 1024).toFixed(2) + 'MB / ' + 
+                       (event.total / 1024 / 1024).toFixed(2) + 'MB)');
+            
+            // Update loading indicator
+            if (loadingIndicator) {
+                loadingIndicator.textContent = 'Loading ' + Math.round(percentComplete) + '%';
+            }
+        } else {
+            console.log('Download progress: ' + (event.loaded / 1024 / 1024).toFixed(2) + 'MB downloaded');
+            
+            // Update loading indicator without percentage
+            if (loadingIndicator) {
+                loadingIndicator.textContent = 'Loading...';
+            }
+        }
+    };
+    
+    // Handle successful download
+    xhr.onload = function() {
+        // Hide loading indicator
+        if (loadingIndicator) {
+            loadingIndicator.style.display = 'none';
+        }
+        
+        if (xhr.status === 200) {
+            console.log('Full-size image downloaded successfully, swapping images...');
+            
+            // Set full image src directly (browser will cache it)
+            fullImage.onload = function() {
+                console.log('Full-size image loaded and cached');
+                
+                // Fade out compressed image
+                if (compressedImage.style.display !== 'none') {
+                    compressedImage.classList.add('hidden');
+                    setTimeout(() => {
+                        compressedImage.style.display = 'none';
+                    }, 300); // Match CSS transition duration
+                }
+                
+                // Update background
+                bgImage.src = fullSizeUrl;
+                
+                // Update dimensions with full-size image dimensions
+                $("#info-dimensions").text(fullImage.naturalWidth + ' × ' + fullImage.naturalHeight + "px");
+                
+                // Regenerate histogram with full-size image
+                const canvas = document.getElementById('histogram-canvas');
+                if (canvas) {
+                    generateHistogram(fullImage, canvas);
+                }
+            };
+            
+            // Set the source to trigger browser caching
+            fullImage.src = fullSizeUrl;
+        }
+    };
+    
+    // Handle errors
+    xhr.onerror = function() {
+        // Hide loading indicator
+        if (loadingIndicator) {
+            loadingIndicator.style.display = 'none';
+        }
+        console.error('Failed to download full-size image');
+        
+        // Try to load directly as fallback
+        fullImage.src = fullSizeUrl;
+    };
+    
+    // Start the download
+    xhr.send();
+    */
+}
+
 $(document).on("keydown", function(e){
 $(document).on("keydown", function(e){
     if (e.keyCode == 27){ // Escape
     if (e.keyCode == 27){ // Escape
         if ($('#photo-viewer').is(':visible')) {
         if ($('#photo-viewer').is(':visible')) {

+ 2 - 2
src/web/SystemAO/boot/interface_selector.html

@@ -71,7 +71,7 @@
                         var targetPath = mod.StartDir;
                         var targetPath = mod.StartDir;
                         if (targetPath == ""){
                         if (targetPath == ""){
                             //Redirect to desktop
                             //Redirect to desktop
-                            window.location.href = "../../desktop.system";
+                            window.location.href = "../../desktop.html";
                         }else{
                         }else{
                             //Redirect to module
                             //Redirect to module
                             window.location.href = "../../" + targetPath;
                             window.location.href = "../../" + targetPath;
@@ -89,7 +89,7 @@
             }
             }
             if (path == ""){
             if (path == ""){
                 //Redirect to desktop
                 //Redirect to desktop
-                window.location.href = "../../desktop.system";
+                window.location.href = "../../desktop.html";
             }else{
             }else{
                 //Redirect to module
                 //Redirect to module
                 window.location.href = "../../" + path;
                 window.location.href = "../../" + path;

+ 3 - 0
src/web/SystemAO/disk/tftp.html

@@ -41,6 +41,9 @@
     <script>
     <script>
         $(".ui.dropdown").dropdown();
         $(".ui.dropdown").dropdown();
         $(document).ready(function(){
         $(document).ready(function(){
+            //Load current TFTP server status including port
+            initTFTPServerStatus();
+            
             //Load user list for default user selection
             //Load user list for default user selection
             $.get("../../system/users/list?noicon=true", function(data){
             $.get("../../system/users/list?noicon=true", function(data){
                 if (data.error !== undefined){
                 if (data.error !== undefined){

+ 7 - 3
src/web/SystemAO/system_setting/index.html

@@ -119,6 +119,9 @@
                             
                             
                     });
                     });
 
 
+                }else{
+                    //No hash, load default Info page
+                    initSettingGroup("Info");
                 }
                 }
                  pageStateRestored = true;
                  pageStateRestored = true;
             }
             }
@@ -129,11 +132,12 @@
                 initMainSideMenu(function(){
                 initMainSideMenu(function(){
                     //Menu is now loaded
                     //Menu is now loaded
                     hideToolBar();
                     hideToolBar();
-                     if (!pageStateRestored){
+                    if (!pageStateRestored){
                         restorePageFromHash();
                         restorePageFromHash();
-                    }else{
-                        initSettingGroup("Info");
+                        return;
                     }
                     }
+
+                    initSettingGroup("Info");
                 });
                 });
             });
             });
  
  

+ 1 - 1
src/web/SystemAO/users/editUser.html

@@ -236,7 +236,7 @@
                             initContents();
                             initContents();
                             $("#confirmUpdate").stop().finish().slideDown('fast').delay(3000).slideUp('fast');
                             $("#confirmUpdate").stop().finish().slideDown('fast').delay(3000).slideUp('fast');
                             console.log(data);
                             console.log(data);
-                            $("#tmppw").val(location.protocol + '//' + location.host + "/reset.system?acc=" + username +  "&rkey=" + data);
+                            $("#tmppw").val(location.protocol + '//' + location.host + "/reset.html?acc=" + username +  "&rkey=" + data);
                             $("#tmppwui").slideDown('fast');
                             $("#tmppwui").slideDown('fast');
                         }
                         }
                     }
                     }

+ 1 - 1
src/web/SystemAO/users/userList.html

@@ -322,7 +322,7 @@
 
 
             function showNewUserUI(){
             function showNewUserUI(){
                 ao_module_newfw({
                 ao_module_newfw({
-                    url: "user.system",
+                    url: "user.html",
                     width: 530,
                     width: 530,
                     height: 740,
                     height: 740,
                     appicon: "SystemAO/users/img/user-white.svg",
                     appicon: "SystemAO/users/img/user-white.svg",

+ 1 - 1
src/web/SystemAO/www/index_legacy.html

@@ -23,7 +23,7 @@
         <!-- Main website content goes here-->
         <!-- Main website content goes here-->
         <br><br>
         <br><br>
         <div class="ui container">
         <div class="ui container">
-            <a class="ui black right floated button" href="../login.system"><i class="key icon"></i>Login</a>
+            <a class="ui black right floated button" href="../login.html"><i class="key icon"></i>Login</a>
             <h1>My Home</h1>
             <h1>My Home</h1>
             <div class="ui divider"></div>
             <div class="ui divider"></div>
             <div class="ui two column stackable grid">
             <div class="ui two column stackable grid">

+ 2 - 2
src/web/desktop.system → src/web/desktop.html

@@ -1094,7 +1094,7 @@
     <script>
     <script>
         //Force redirection if it is on mobile
         //Force redirection if it is on mobile
         if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
         if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
-            window.location.href = "mobile.system";
+            window.location.href = "mobile.html";
         }
         }
     </script>
     </script>
 </head>
 </head>
@@ -2025,7 +2025,7 @@
                     console.log("Unable to open module " + moduleName);
                     console.log("Unable to open module " + moduleName);
                     if (data.error == "Not logged in."){
                     if (data.error == "Not logged in."){
                         //Session expired
                         //Session expired
-                        window.location.href = "login.system";
+                        window.location.href = "login.html";
                     }
                     }
                 } else {
                 } else {
                     //Launch the given module
                     //Launch the given module

File diff suppressed because it is too large
+ 27 - 0
src/web/img/system/network-folder-black.ai


+ 23 - 0
src/web/img/system/network-folder-black.svg

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="128px"
+	 height="128px" viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve">
+<g id="圖層_2">
+	<polygon points="110.998,23.424 110.998,84.064 17.001,84.064 17.001,13.652 48.449,13.469 55.315,23.669 	"/>
+</g>
+<g id="圖層_3">
+	<polygon fill="#3E3A39" points="110.998,84.064 17.001,84.064 17.087,31.401 110.57,31.401 	"/>
+	<g>
+		<path fill="#FFFFFF" d="M41.777,55.843l7.216-2.331l5.772-1.998v-0.148l-5.772-1.999l-7.216-2.331v-5.402l19.648,7.548v4.515
+			l-19.648,7.548V55.843z"/>
+		<path fill="#FFFFFF" d="M63.385,67.869h20.128v3.662H63.385V67.869z"/>
+	</g>
+</g>
+<g id="圖層_4">
+	<rect x="17.001" y="103.51" fill="#443F5D" width="93.997" height="4.691"/>
+	<rect x="60.985" y="84.064" fill="#443F5D" width="6.029" height="19.445"/>
+	<path fill="#55516E" d="M72.935,110.512c0,2.221-1.8,4.02-4.021,4.02h-9.827c-2.221,0-4.021-1.799-4.021-4.02v-9.828
+		c0-2.221,1.8-4.021,4.021-4.021h9.827c2.221,0,4.021,1.801,4.021,4.021V110.512z"/>
+</g>
+</svg>

+ 0 - 0
src/web/login.system → src/web/login.html


+ 0 - 0
src/web/mobile.system → src/web/mobile.html


+ 0 - 0
src/web/reset.system → src/web/reset.html


+ 101 - 100
src/web/robots.txt

@@ -3,74 +3,74 @@
 # If you want SEO on your cloud system, remove this file from the web root.
 # If you want SEO on your cloud system, remove this file from the web root.
 
 
 User-agent: Applebot
 User-agent: Applebot
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: baiduspider
 User-agent: baiduspider
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: Bingbot
 User-agent: Bingbot
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: Discordbot
 User-agent: Discordbot
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: facebookexternalhit
 User-agent: facebookexternalhit
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: Googlebot
 User-agent: Googlebot
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
@@ -79,58 +79,58 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: ia_archiver
 User-agent: ia_archiver
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: LinkedInBot
 User-agent: LinkedInBot
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: msnbot
 User-agent: msnbot
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
 User-agent: Naverbot
 User-agent: Naverbot
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
@@ -139,11 +139,11 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: seznambot
 User-agent: seznambot
@@ -151,11 +151,11 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: Slurp
 User-agent: Slurp
@@ -163,11 +163,11 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: teoma
 User-agent: teoma
@@ -175,11 +175,11 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: TelegramBot
 User-agent: TelegramBot
@@ -188,11 +188,11 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: Twitterbot
 User-agent: Twitterbot
@@ -200,11 +200,11 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: Yandex
 User-agent: Yandex
@@ -212,11 +212,11 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: Yeti
 User-agent: Yeti
@@ -224,22 +224,23 @@ Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /img/
 Disallow: /img/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /login.system
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /login.html
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 
 
 User-agent: *
 User-agent: *
-Allow: /login.system
+Allow: /login.html
 Disallow: /SystemAO/
 Disallow: /SystemAO/
 Disallow: /system/
 Disallow: /system/
 Disallow: /index.html
 Disallow: /index.html
-Disallow: /mobile.system
-Disallow: /desktop.system
-Disallow: /reset.system
-Disallow: /user.system
+Disallow: /mobile.html
+Disallow: /desktop.html
+Disallow: /reset.html
+Disallow: /user.html
 Disallow: /homepage/
 Disallow: /homepage/
 Disallow: /fileview/
 Disallow: /fileview/
 
 
+

+ 1 - 1
src/web/user.system → src/web/user.html

@@ -165,7 +165,7 @@
                                     window.location.href = "SystemAO/closeTabInsturction.html"
                                     window.location.href = "SystemAO/closeTabInsturction.html"
                                 }
                                 }
                             }else{
                             }else{
-                                window.location.href = "/login.system";
+                                window.location.href = "/login.html";
                             }
                             }
                         });
                         });
                        
                        

Some files were not shown because too many files changed in this diff