diff --git a/.env.example b/.env.example index ed4ee0a..b674b53 100644 --- a/.env.example +++ b/.env.example @@ -8,7 +8,6 @@ PIXIVFE_PORT='8282' ## Optional variables PIXIVFE_HOST='127.0.0.1' -# PIXIVFE_TZ= # PIXIVFE_REQUESTLIMIT= # PIXIVFE_IMAGEPROXY= # PIXIVFE_ACCEPTLANGUAGE= diff --git a/assets/views/settings.jet.html b/assets/views/settings.jet.html index e53a27b..f78a9e9 100644 --- a/assets/views/settings.jet.html +++ b/assets/views/settings.jet.html @@ -131,6 +131,36 @@
+
+ Time zone +

+ Setting the time zone ensures that dates are interpreted and displayed correctly in the application. +

+
+
+ + {{- timeZoneValue := CookieList["pixivfe-TZ"] }} + {{- if timeZoneValue != "" -}} + + {{- else }} + + {{ end -}} +
The time zone currently set.
+
+
+ + +
+ The value must be a valid tz database name. +
+
+ +
+
+
+ +
+
Filter artworks

Toggle the switches below to hide specific types of content. Disabled switches will allow the content to be shown.

diff --git a/config/config.go b/config/config.go index 7465ea6..5f5298a 100644 --- a/config/config.go +++ b/config/config.go @@ -7,7 +7,6 @@ import ( "net/url" "strings" "time" - _ "time/tzdata" // TODO: figure out how to properly implement urlx // the implementation in 5f8b659b49 causes config.go to segfault due to a nil pointer dereference when the PIXIVFE_IMAGEPROXY env var is not set @@ -71,9 +70,6 @@ type ServerConfig struct { Port string `env:"PIXIVFE_PORT"` UnixSocket string `env:"PIXIVFE_UNIXSOCKET"` - TimeZone string `env:"PIXIVFE_TZ,overwrite"` - TimeLocation *time.Location - RepoURL string `env:"PIXIVFE_REPO_URL,overwrite"` // used in /about page Token []string `env:"PIXIVFE_TOKEN,required"` // may be multiple tokens. delimiter is ',' @@ -157,8 +153,6 @@ func (s *ServerConfig) LoadConfig() error { s.StartingTime = time.Now().UTC().Format("2006-01-02 15:04") // set default values with env:"...,overwrite" - s.TimeZone = defaultTimeZone - s.RepoURL = defaultRepoUrl s.AcceptLanguage = defaultAcceptLanguage @@ -206,16 +200,6 @@ func (s *ServerConfig) LoadConfig() error { log.Printf("[WARNING] Both PIXIVFE_HOST and PIXIVFE_UNIXSOCKET are set. PIXIVFE_HOST will be ignored when using a Unix socket.\n") } - // Validate TimeZone - location, err := time.LoadLocation(s.TimeZone) - if err != nil { - log.Printf("[WARNING] Invalid time zone '%s', defaulting to UTC\n", s.TimeZone) - s.TimeZone = defaultTimeZone - location, _ = time.LoadLocation(defaultTimeZone) - } - s.TimeLocation = location - log.Printf("Using time zone: %s\n", s.TimeLocation) - // a check for tokens if len(s.Token) < 1 { log.Fatalln("PIXIVFE_TOKEN has to be set. Visit https://pixivfe-docs.pages.dev/hosting/hosting-pixivfe for more details.") diff --git a/doc/hosting/environment-variables.md b/doc/hosting/environment-variables.md index a5201cd..a094da7 100644 --- a/doc/hosting/environment-variables.md +++ b/doc/hosting/environment-variables.md @@ -52,21 +52,6 @@ See the [Obtaining the `PIXIVFE_TOKEN` cookie](obtaining-pixivfe-token.md) guide This setting specifies the hostname or IP address that PixivFE should listen on and accept incoming connections from. For example, if you want PixivFE to only accept connections from the same machine (your local computer), you can set `PIXIVFE_HOST=localhost`. -## `PIXIVFE_TZ` - -**Required**: No - -**Default:** `UTC` - -The time zone used for displaying dates and times throughout the application, including relative times (e.g., "2 hours ago") and full dates. - -The value must be a valid [tz database name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) and match the geolocation of the IP address used for making requests to the Pixiv API, which returns dates in the client's local time. Setting the timezone ensures those dates are interpreted and displayed correctly in the application. - -Example: -``` -PIXIVFE_TZ=Asia/Tokyo -``` - ## `PIXIVFE_REPO_URL` **Required**: No diff --git a/i18n/locale/en/code.json b/i18n/locale/en/code.json index fc993ce..1ea082b 100644 --- a/i18n/locale/en/code.json +++ b/i18n/locale/en/code.json @@ -61,9 +61,12 @@ "server/routes/settings.go:Uva8MntftQ0": "Cannot authorize with supplied token.", "server/routes/settings.go:VgwxpccGkaw": "Cookie %s set successfully.", "server/routes/settings.go:Wtgdxy1i4XI": "Cookie %s cleared successfully.", + "server/routes/settings.go:XpWaRTRsACU": "Timezone updated successfully to %s.", "server/routes/settings.go:ZmGzoByKs64": "Thumbnails will now open in a new tab.", "server/routes/settings.go:_rnu1mx961A": "Successfully logged out.", + "server/routes/settings.go:bSamA2p1_w8": "Timezone reset to UTC.", "server/routes/settings.go:cVMgORK2rwo": "Image proxy server set successfully to: %s", + "server/routes/settings.go:czmbrs0GF-o": "Invalid timezone specified.", "server/routes/settings.go:i-pKOdI41y8": "Image proxy server cleared. Using default proxy.", "server/routes/settings.go:opCtzPsSY5k": "You submitted an empty/invalid form.", "server/routes/settings.go:sFiBTMrk_Hs": "Novel view mode updated successfully.", diff --git a/i18n/locale/en/template.json b/i18n/locale/en/template.json index 7c2fa88..716a2c0 100644 --- a/i18n/locale/en/template.json +++ b/i18n/locale/en/template.json @@ -428,6 +428,7 @@ "assets/views/settings.jet.html:-KqJV0K6wKc": "Log in with your Pixiv account's cookie to access the features below. To learn how to obtain your cookie, please see the guide on obtaining your PixivFE token.", "assets/views/settings.jet.html:-jt6pKwpLrs": "Chinese Traditional", "assets/views/settings.jet.html:01ETImVdw20": "Make bulk changes to multiple preferences at once", + "assets/views/settings.jet.html:01pzPVqBiqs": ".", "assets/views/settings.jet.html:0IsQoCb1wcs": "PIXIVFE_PROXY_CHECK_ENABLED=false", "assets/views/settings.jet.html:0j24jZSabME": "Cookies", "assets/views/settings.jet.html:13n5Qujsem8": "Choose a proxy server to load images through.", @@ -445,6 +446,7 @@ "assets/views/settings.jet.html:6qQEEaPazT4": "Hide explicit content (R-18)", "assets/views/settings.jet.html:78FGmOr-0IE": "Gothic", "assets/views/settings.jet.html:7YMxLXE36Ek": "Add a button at the bottom-right of the thumbnails and open the previewer when you click into it. This provides more control over when previews are shown.", + "assets/views/settings.jet.html:7_xp7UZpYRA": "The value must be a valid", "assets/views/settings.jet.html:7dnsdIMl83k": "Exercise caution when modifying these settings. Incorrect values may adversely affect PixivFE's functionality.", "assets/views/settings.jet.html:8IfoQf-UbIk": "Button", "assets/views/settings.jet.html:8Vjy7zy9rGk": "Force text orientation", @@ -475,6 +477,7 @@ "assets/views/settings.jet.html:JECr1niy_hM": "Disable", "assets/views/settings.jet.html:JKwYHlzzjSo": "Hides artwork tagged as R18G. This includes extremely graphic or violent material (", "assets/views/settings.jet.html:LFaRGbCnLpA": "Like/Bookmark", + "assets/views/settings.jet.html:LgkzbDjSqfE": "Setting the time zone ensures that dates are interpreted and displayed correctly in the application.", "assets/views/settings.jet.html:MJhAtYNrY_I": "Select image proxy server", "assets/views/settings.jet.html:MW0QlG0NWlU": "The image proxy server currently set.", "assets/views/settings.jet.html:NEWGagEJi-Y": "Current image proxy server", @@ -500,8 +503,10 @@ "assets/views/settings.jet.html:Wz5Pxq0uTDE": "Log out", "assets/views/settings.jet.html:ZQwEm6eAScE": "A serif font style that resembles traditional Japanese printing. It's often used for formal or literary content, providing a classic and elegant look.", "assets/views/settings.jet.html:ZejSb38l81A": "Image proxies that fail this check will not be shown unless \"Show all proxy servers\" is enabled.", + "assets/views/settings.jet.html:_cFUPay4h_4": "Current time zone", "assets/views/settings.jet.html:_p0pNeOT7oo": "Raw settings", "assets/views/settings.jet.html:_qLO2Kt327w": "Supported features (for now):", + "assets/views/settings.jet.html:cjCEIfGBhmo": "Time zone", "assets/views/settings.jet.html:g0k22QxjULk": "Select your preferred display language from the dropdown menu below.", "assets/views/settings.jet.html:hRoKWkl2_fA": "Enter the URL of a custom proxy server if you wish to use one not listed above.", "assets/views/settings.jet.html:joLFImgCvYE": "Restore your settings if the current instance's cookies have expired", @@ -527,6 +532,7 @@ "assets/views/settings.jet.html:wD8pVsSJrTg": "has been set).", "assets/views/settings.jet.html:whYA8lpAKsc": "This PixivFE instance has been configured to check the list of built-in image proxies every {{ .ProxyCheckInterval }}.", "assets/views/settings.jet.html:x0quIK1YVQk": "Log out!", + "assets/views/settings.jet.html:xI7Lk-0c_wI": "tz database name", "assets/views/settings.jet.html:y6pXNsQLNSg": "Forces the text to be displayed horizontally, left-to-right. This is common for most languages and easier to read on smaller screens or for those more accustomed to Western text layouts.", "assets/views/settings.jet.html:yEUgkGx647Y": "Choose how images are loaded in PixivFE by selecting either the built-in proxy or one of the provided external proxy servers.", "assets/views/settings.jet.html:yxY72MHqQiw": "Hide ero-guro content (R-18G)", diff --git a/server/routes/settings.go b/server/routes/settings.go index 2fafe77..8c71336 100644 --- a/server/routes/settings.go +++ b/server/routes/settings.go @@ -102,6 +102,24 @@ func handleSelectedProxy(w http.ResponseWriter, selectedProxy string) (string, e return i18n.Sprintf("Image proxy server set successfully to: %s", proxyURL), nil } +func setTimeZone(w http.ResponseWriter, r *http.Request) (string, error) { + tz := r.FormValue("time-zone") + + // Validate timezone + _, err := session.ValidateTimezone(tz) + if err != nil { + return "", i18n.Error("Invalid timezone specified.") + } + + if tz == "" { + session.ClearCookie(w, session.Cookie_TZ) + return i18n.Sprintf("Timezone reset to UTC."), nil + } + + session.SetCookie(w, session.Cookie_TZ, tz) + return i18n.Sprintf("Timezone updated successfully to %s.", tz), nil +} + func setNovelFontType(w http.ResponseWriter, r *http.Request) (string, error) { fontType := r.FormValue("font-type") if fontType != "" { @@ -262,6 +280,8 @@ func SettingsPost(auditor *audit.Auditor, w http.ResponseWriter, r *http.Request message, err = setToken(auditor, w, r) case "logout": message, err = setLogout(w, r) + case "timeZone": + message, err = setTimeZone(w, r) case "reset-all": message, err = resetAll(w, r) case "novelFontType": diff --git a/server/session/cookie.go b/server/session/cookie.go index 6a5c99f..f770c83 100644 --- a/server/session/cookie.go +++ b/server/session/cookie.go @@ -5,6 +5,7 @@ package session import ( "net/http" "time" + _ "time/tzdata" ) type CookieName string @@ -13,6 +14,7 @@ const ( // the __Host thing force it to be secure and same-origin (no subdomain) Cookie_Token CookieName = "pixivfe-Token" Cookie_CSRF CookieName = "pixivfe-CSRF" Cookie_ImageProxy CookieName = "pixivfe-ImageProxy" + Cookie_TZ CookieName = "pixivfe-TZ" Cookie_NovelFontType CookieName = "pixivfe-NovelFontType" Cookie_NovelViewMode CookieName = "pixivfe-NovelViewMode" Cookie_ThumbnailToNewTab CookieName = "pixivfe-ThumbnailToNewTab" @@ -29,6 +31,7 @@ var AllCookieNames []CookieName = []CookieName{ Cookie_Token, Cookie_CSRF, Cookie_ImageProxy, + Cookie_TZ, Cookie_NovelFontType, Cookie_NovelViewMode, Cookie_ThumbnailToNewTab, @@ -81,3 +84,25 @@ func ClearAllCookies(w http.ResponseWriter) { ClearCookie(w, name) } } + +func ValidateTimezone(tz string) (*time.Location, error) { + if tz == "" { + return time.UTC, nil + } + + location, err := time.LoadLocation(tz) + if err != nil { + return time.UTC, err + } + + return location, nil +} + +func GetUserTimezone(r *http.Request) *time.Location { + tz := GetCookie(r, Cookie_TZ) + location, err := ValidateTimezone(tz) + if err != nil { + return time.UTC + } + return location +} diff --git a/server/template/templateFunctions.go b/server/template/templateFunctions.go index 42f2195..b6a7438 100644 --- a/server/template/templateFunctions.go +++ b/server/template/templateFunctions.go @@ -10,7 +10,6 @@ import ( "strings" "time" - "codeberg.org/vnpower/pixivfe/v2/config" "codeberg.org/vnpower/pixivfe/v2/core" "codeberg.org/vnpower/pixivfe/v2/i18n" ) @@ -173,15 +172,13 @@ func ParseTimeCustomFormat(date time.Time, format string) string { // NaturalTime formats a time.Time value as a natural language string // TODO: tailor the format per locale func NaturalTime(date time.Time) string { - date = date.In(config.GlobalConfig.TimeLocation) return date.Format("Monday, 2 January 2006, at 3:04 PM") } // RelativeTime formats a time.Time value // TODO: tailor the format per locale func RelativeTime(date time.Time) string { - now := time.Now().In(config.GlobalConfig.TimeLocation) - date = date.In(config.GlobalConfig.TimeLocation) + now := time.Now() duration := now.Sub(date) // Handle future dates