Enable go-critic linter and fix various issues detected
This commit is contained in:
parent
f6404290ba
commit
b1e73fafdf
34 changed files with 126 additions and 109 deletions
4
.github/workflows/linters.yml
vendored
4
.github/workflows/linters.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
||||||
run: eslint internal/ui/static/js/*.js
|
run: eslint internal/ui/static/js/*.js
|
||||||
|
|
||||||
golangci:
|
golangci:
|
||||||
name: Golang Linter
|
name: Golang Linters
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
@ -32,7 +32,7 @@ jobs:
|
||||||
- run: "go vet ./..."
|
- run: "go vet ./..."
|
||||||
- uses: golangci/golangci-lint-action@v4
|
- uses: golangci/golangci-lint-action@v4
|
||||||
with:
|
with:
|
||||||
args: --timeout 10m --skip-dirs tests --disable errcheck --enable sqlclosecheck --enable misspell --enable gofmt --enable goimports --enable whitespace
|
args: --timeout 10m --skip-dirs tests --disable errcheck --enable sqlclosecheck --enable misspell --enable gofmt --enable goimports --enable whitespace --enable gocritic
|
||||||
- uses: dominikh/staticcheck-action@v1.3.0
|
- uses: dominikh/staticcheck-action@v1.3.0
|
||||||
with:
|
with:
|
||||||
version: "2023.1.7"
|
version: "2023.1.7"
|
||||||
|
|
|
@ -28,12 +28,12 @@ func NewClient(endpoint string, credentials ...string) *Client {
|
||||||
// Trim trailing slashes and /v1 from the endpoint.
|
// Trim trailing slashes and /v1 from the endpoint.
|
||||||
endpoint = strings.TrimSuffix(endpoint, "/")
|
endpoint = strings.TrimSuffix(endpoint, "/")
|
||||||
endpoint = strings.TrimSuffix(endpoint, "/v1")
|
endpoint = strings.TrimSuffix(endpoint, "/v1")
|
||||||
|
switch len(credentials) {
|
||||||
if len(credentials) == 2 {
|
case 2:
|
||||||
return &Client{request: &request{endpoint: endpoint, username: credentials[0], password: credentials[1]}}
|
return &Client{request: &request{endpoint: endpoint, username: credentials[0], password: credentials[1]}}
|
||||||
} else if len(credentials) == 1 {
|
case 1:
|
||||||
return &Client{request: &request{endpoint: endpoint, apiKey: credentials[0]}}
|
return &Client{request: &request{endpoint: endpoint, apiKey: credentials[0]}}
|
||||||
} else {
|
default:
|
||||||
return &Client{request: &request{endpoint: endpoint}}
|
return &Client{request: &request{endpoint: endpoint}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,9 +265,10 @@ func getStreamFilterModifiers(r *http.Request) (RequestModifiers, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStream(streamID string, userID int64) (Stream, error) {
|
func getStream(streamID string, userID int64) (Stream, error) {
|
||||||
if strings.HasPrefix(streamID, FeedPrefix) {
|
switch {
|
||||||
|
case strings.HasPrefix(streamID, FeedPrefix):
|
||||||
return Stream{Type: FeedStream, ID: strings.TrimPrefix(streamID, FeedPrefix)}, nil
|
return Stream{Type: FeedStream, ID: strings.TrimPrefix(streamID, FeedPrefix)}, nil
|
||||||
} else if strings.HasPrefix(streamID, fmt.Sprintf(UserStreamPrefix, userID)) || strings.HasPrefix(streamID, StreamPrefix) {
|
case strings.HasPrefix(streamID, fmt.Sprintf(UserStreamPrefix, userID)) || strings.HasPrefix(streamID, StreamPrefix):
|
||||||
id := strings.TrimPrefix(streamID, fmt.Sprintf(UserStreamPrefix, userID))
|
id := strings.TrimPrefix(streamID, fmt.Sprintf(UserStreamPrefix, userID))
|
||||||
id = strings.TrimPrefix(id, StreamPrefix)
|
id = strings.TrimPrefix(id, StreamPrefix)
|
||||||
switch id {
|
switch id {
|
||||||
|
@ -288,15 +289,15 @@ func getStream(streamID string, userID int64) (Stream, error) {
|
||||||
default:
|
default:
|
||||||
return Stream{NoStream, ""}, fmt.Errorf("googlereader: unknown stream with id: %s", id)
|
return Stream{NoStream, ""}, fmt.Errorf("googlereader: unknown stream with id: %s", id)
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(streamID, fmt.Sprintf(UserLabelPrefix, userID)) || strings.HasPrefix(streamID, LabelPrefix) {
|
case strings.HasPrefix(streamID, fmt.Sprintf(UserLabelPrefix, userID)) || strings.HasPrefix(streamID, LabelPrefix):
|
||||||
id := strings.TrimPrefix(streamID, fmt.Sprintf(UserLabelPrefix, userID))
|
id := strings.TrimPrefix(streamID, fmt.Sprintf(UserLabelPrefix, userID))
|
||||||
id = strings.TrimPrefix(id, LabelPrefix)
|
id = strings.TrimPrefix(id, LabelPrefix)
|
||||||
return Stream{LabelStream, id}, nil
|
return Stream{LabelStream, id}, nil
|
||||||
} else if streamID == "" {
|
case streamID == "":
|
||||||
return Stream{NoStream, ""}, nil
|
return Stream{NoStream, ""}, nil
|
||||||
|
default:
|
||||||
|
return Stream{NoStream, ""}, fmt.Errorf("googlereader: unknown stream type: %s", streamID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Stream{NoStream, ""}, fmt.Errorf("googlereader: unknown stream type: %s", streamID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStreams(streamIDs []string, userID int64) ([]Stream, error) {
|
func getStreams(streamIDs []string, userID int64) ([]Stream, error) {
|
||||||
|
@ -382,7 +383,7 @@ func getItemIDs(r *http.Request) ([]int64, error) {
|
||||||
return itemIDs, nil
|
return itemIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkOutputFormat(w http.ResponseWriter, r *http.Request) error {
|
func checkOutputFormat(r *http.Request) error {
|
||||||
var output string
|
var output string
|
||||||
if r.Method == http.MethodPost {
|
if r.Method == http.MethodPost {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
|
@ -736,11 +737,12 @@ func getFeed(stream Stream, store *storage.Storage, userID int64) (*model.Feed,
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrCreateCategory(category Stream, store *storage.Storage, userID int64) (*model.Category, error) {
|
func getOrCreateCategory(category Stream, store *storage.Storage, userID int64) (*model.Category, error) {
|
||||||
if category.ID == "" {
|
switch {
|
||||||
|
case category.ID == "":
|
||||||
return store.FirstCategory(userID)
|
return store.FirstCategory(userID)
|
||||||
} else if store.CategoryTitleExists(userID, category.ID) {
|
case store.CategoryTitleExists(userID, category.ID):
|
||||||
return store.CategoryByTitle(userID, category.ID)
|
return store.CategoryByTitle(userID, category.ID)
|
||||||
} else {
|
default:
|
||||||
catRequest := model.CategoryRequest{
|
catRequest := model.CategoryRequest{
|
||||||
Title: category.ID,
|
Title: category.ID,
|
||||||
}
|
}
|
||||||
|
@ -908,7 +910,7 @@ func (h *handler) streamItemContentsHandler(w http.ResponseWriter, r *http.Reque
|
||||||
slog.Int64("user_id", userID),
|
slog.Int64("user_id", userID),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := checkOutputFormat(w, r); err != nil {
|
if err := checkOutputFormat(r); err != nil {
|
||||||
json.BadRequest(w, r, err)
|
json.BadRequest(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1170,7 +1172,7 @@ func (h *handler) tagListHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
slog.String("user_agent", r.UserAgent()),
|
slog.String("user_agent", r.UserAgent()),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := checkOutputFormat(w, r); err != nil {
|
if err := checkOutputFormat(r); err != nil {
|
||||||
json.BadRequest(w, r, err)
|
json.BadRequest(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1205,7 +1207,7 @@ func (h *handler) subscriptionListHandler(w http.ResponseWriter, r *http.Request
|
||||||
slog.String("user_agent", r.UserAgent()),
|
slog.String("user_agent", r.UserAgent()),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := checkOutputFormat(w, r); err != nil {
|
if err := checkOutputFormat(r); err != nil {
|
||||||
json.BadRequest(w, r, err)
|
json.BadRequest(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1224,7 +1226,7 @@ func (h *handler) subscriptionListHandler(w http.ResponseWriter, r *http.Request
|
||||||
URL: feed.FeedURL,
|
URL: feed.FeedURL,
|
||||||
Categories: []subscriptionCategory{{fmt.Sprintf(UserLabelPrefix, userID) + feed.Category.Title, feed.Category.Title, "folder"}},
|
Categories: []subscriptionCategory{{fmt.Sprintf(UserLabelPrefix, userID) + feed.Category.Title, feed.Category.Title, "folder"}},
|
||||||
HTMLURL: feed.SiteURL,
|
HTMLURL: feed.SiteURL,
|
||||||
IconURL: "", //TODO Icons are only base64 encode in DB yet
|
IconURL: "", // TODO: Icons are base64 encoded in the DB.
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
json.OK(w, r, result)
|
json.OK(w, r, result)
|
||||||
|
@ -1251,7 +1253,7 @@ func (h *handler) userInfoHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
slog.String("user_agent", r.UserAgent()),
|
slog.String("user_agent", r.UserAgent()),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := checkOutputFormat(w, r); err != nil {
|
if err := checkOutputFormat(r); err != nil {
|
||||||
json.BadRequest(w, r, err)
|
json.BadRequest(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1276,7 +1278,7 @@ func (h *handler) streamItemIDsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
slog.Int64("user_id", userID),
|
slog.Int64("user_id", userID),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := checkOutputFormat(w, r); err != nil {
|
if err := checkOutputFormat(r); err != nil {
|
||||||
json.BadRequest(w, r, err)
|
json.BadRequest(w, r, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1477,8 +1479,7 @@ func (h *handler) handleFeedStreamHandler(w http.ResponseWriter, r *http.Request
|
||||||
|
|
||||||
if len(rm.ExcludeTargets) > 0 {
|
if len(rm.ExcludeTargets) > 0 {
|
||||||
for _, s := range rm.ExcludeTargets {
|
for _, s := range rm.ExcludeTargets {
|
||||||
switch s.Type {
|
if s.Type == ReadStream {
|
||||||
case ReadStream:
|
|
||||||
builder.WithoutStatus(model.EntryStatusRead)
|
builder.WithoutStatus(model.EntryStatusRead)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Der HTTP-Inhalt kann nicht gelesen werden: %v",
|
"error.http_body_read": "Der HTTP-Inhalt kann nicht gelesen werden: %v",
|
||||||
"error.http_empty_response_body": "Der Inhalt der HTTP-Antwort ist leer.",
|
"error.http_empty_response_body": "Der Inhalt der HTTP-Antwort ist leer.",
|
||||||
"error.http_empty_response": "Die HTTP-Antwort ist leer. Vielleicht versucht die Webseite, sich vor Bots zu schützen?",
|
"error.http_empty_response": "Die HTTP-Antwort ist leer. Vielleicht versucht die Webseite, sich vor Bots zu schützen?",
|
||||||
"error.tls_error": "TLS-Fehler: %v. Wenn Sie mögen, können Sie versuchen die TLS-Verifizierung in den Einstellungen des Abonnements zu deaktivieren.",
|
"error.tls_error": "TLS-Fehler: %q. Wenn Sie mögen, können Sie versuchen die TLS-Verifizierung in den Einstellungen des Abonnements zu deaktivieren.",
|
||||||
"error.network_operation": "Miniflux kann die Webseite aufgrund eines Netzwerk-Fehlers nicht erreichen: %v",
|
"error.network_operation": "Miniflux kann die Webseite aufgrund eines Netzwerk-Fehlers nicht erreichen: %v",
|
||||||
"error.network_timeout": "Die Webseite ist zu langsam und die Anfrage ist abgelaufen: %v.",
|
"error.network_timeout": "Die Webseite ist zu langsam und die Anfrage ist abgelaufen: %v.",
|
||||||
"error.http_client_error": "HTTP-Client-Fehler: %v.",
|
"error.http_client_error": "HTTP-Client-Fehler: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Impossible de lire le corps de la réponse HTTP : %v.",
|
"error.http_body_read": "Impossible de lire le corps de la réponse HTTP : %v.",
|
||||||
"error.http_empty_response_body": "Le corps de la réponse HTTP est vide.",
|
"error.http_empty_response_body": "Le corps de la réponse HTTP est vide.",
|
||||||
"error.http_empty_response": "La réponse HTTP est vide. Peut-être que ce site web bloque Miniflux avec une protection anti-bot ?",
|
"error.http_empty_response": "La réponse HTTP est vide. Peut-être que ce site web bloque Miniflux avec une protection anti-bot ?",
|
||||||
"error.tls_error": "Erreur TLS : %v. Vous pouvez désactiver la vérification TLS dans les paramètres de l'abonnement.",
|
"error.tls_error": "Erreur TLS : %q. Vous pouvez désactiver la vérification TLS dans les paramètres de l'abonnement.",
|
||||||
"error.network_operation": "Miniflux n'est pas en mesure de se connecter à ce site web à cause d'un problème réseau : %v.",
|
"error.network_operation": "Miniflux n'est pas en mesure de se connecter à ce site web à cause d'un problème réseau : %v.",
|
||||||
"error.network_timeout": "Ce site web est trop lent à répondre : %v.",
|
"error.network_timeout": "Ce site web est trop lent à répondre : %v.",
|
||||||
"error.http_client_error": "Erreur du client HTTP : %v.",
|
"error.http_client_error": "Erreur du client HTTP : %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -488,7 +488,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -488,7 +488,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -522,7 +522,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -522,7 +522,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -505,7 +505,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -522,7 +522,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -488,7 +488,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -488,7 +488,7 @@
|
||||||
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
"error.http_body_read": "Unable to read the HTTP body: %v.",
|
||||||
"error.http_empty_response_body": "The HTTP response body is empty.",
|
"error.http_empty_response_body": "The HTTP response body is empty.",
|
||||||
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
"error.http_empty_response": "The HTTP response is empty. Perhaps, this website is using a bot protection mechanism?",
|
||||||
"error.tls_error": "TLS error: %v. You could disable TLS verification in the feed settings if you would like.",
|
"error.tls_error": "TLS error: %q. You could disable TLS verification in the feed settings if you would like.",
|
||||||
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
"error.network_operation": "Miniflux is not able to reach this website due to a network error: %v.",
|
||||||
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
"error.network_timeout": "This website is too slow and the request timed out: %v",
|
||||||
"error.http_client_error": "HTTP client error: %v.",
|
"error.http_client_error": "HTTP client error: %v.",
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package model // import "miniflux.app/v2/internal/model"
|
package model // import "miniflux.app/v2/internal/model"
|
||||||
import "strings"
|
|
||||||
|
|
||||||
// Enclosure represents an attachment.
|
// Enclosure represents an attachment.
|
||||||
type Enclosure struct {
|
type Enclosure struct {
|
||||||
|
@ -17,15 +16,8 @@ type Enclosure struct {
|
||||||
|
|
||||||
// Html5MimeType will modify the actual MimeType to allow direct playback from HTML5 player for some kind of MimeType
|
// Html5MimeType will modify the actual MimeType to allow direct playback from HTML5 player for some kind of MimeType
|
||||||
func (e Enclosure) Html5MimeType() string {
|
func (e Enclosure) Html5MimeType() string {
|
||||||
if strings.HasPrefix(e.MimeType, "video") {
|
if e.MimeType == "video/m4v" {
|
||||||
switch e.MimeType {
|
return "video/x-m4v"
|
||||||
// Solution from this stackoverflow discussion:
|
|
||||||
// https://stackoverflow.com/questions/15277147/m4v-mimetype-video-mp4-or-video-m4v/66945470#66945470
|
|
||||||
// tested at the time of this commit (06/2023) on latest Firefox & Vivaldi on this feed
|
|
||||||
// https://www.florenceporcel.com/podcast/lfhdu.xml
|
|
||||||
case "video/m4v":
|
|
||||||
return "video/x-m4v"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return e.MimeType
|
return e.MimeType
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,11 +179,12 @@ func (a *Atom10Text) Body() string {
|
||||||
func (a *Atom10Text) Title() string {
|
func (a *Atom10Text) Title() string {
|
||||||
var content string
|
var content string
|
||||||
|
|
||||||
if strings.EqualFold(a.Type, "xhtml") {
|
switch {
|
||||||
|
case strings.EqualFold(a.Type, "xhtml"):
|
||||||
content = a.xhtmlContent()
|
content = a.xhtmlContent()
|
||||||
} else if strings.Contains(a.InnerXML, "<![CDATA[") {
|
case strings.Contains(a.InnerXML, "<![CDATA["):
|
||||||
content = html.UnescapeString(a.CharData)
|
content = html.UnescapeString(a.CharData)
|
||||||
} else {
|
default:
|
||||||
content = a.CharData
|
content = a.CharData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
|
||||||
"miniflux.app/v2/internal/locale"
|
"miniflux.app/v2/internal/locale"
|
||||||
)
|
)
|
||||||
|
@ -94,23 +96,18 @@ func (r *ResponseHandler) ReadBody(maxBodySize int64) ([]byte, *locale.Localized
|
||||||
|
|
||||||
func (r *ResponseHandler) LocalizedError() *locale.LocalizedErrorWrapper {
|
func (r *ResponseHandler) LocalizedError() *locale.LocalizedErrorWrapper {
|
||||||
if r.clientErr != nil {
|
if r.clientErr != nil {
|
||||||
switch r.clientErr.(type) {
|
switch {
|
||||||
case x509.CertificateInvalidError, x509.HostnameError:
|
case isSSLError(r.clientErr):
|
||||||
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.tls_error", r.clientErr)
|
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.tls_error", r.clientErr)
|
||||||
case *net.OpError:
|
case isNetworkError(r.clientErr):
|
||||||
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.network_operation", r.clientErr)
|
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.network_operation", r.clientErr)
|
||||||
case net.Error:
|
case os.IsTimeout(r.clientErr):
|
||||||
networkErr := r.clientErr.(net.Error)
|
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.network_timeout", r.clientErr)
|
||||||
if networkErr.Timeout() {
|
case errors.Is(r.clientErr, io.EOF):
|
||||||
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.network_timeout", r.clientErr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if errors.Is(r.clientErr, io.EOF) {
|
|
||||||
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.http_empty_response")
|
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.http_empty_response")
|
||||||
|
default:
|
||||||
|
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.http_client_error", r.clientErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
return locale.NewLocalizedErrorWrapper(fmt.Errorf("fetcher: %w", r.clientErr), "error.http_client_error", r.clientErr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch r.httpResponse.StatusCode {
|
switch r.httpResponse.StatusCode {
|
||||||
|
@ -145,3 +142,32 @@ func (r *ResponseHandler) LocalizedError() *locale.LocalizedErrorWrapper {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isNetworkError(err error) bool {
|
||||||
|
if _, ok := err.(*url.Error); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if err == io.EOF {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
var opErr *net.OpError
|
||||||
|
if ok := errors.As(err, &opErr); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSSLError(err error) bool {
|
||||||
|
var certErr x509.UnknownAuthorityError
|
||||||
|
if errors.As(err, &certErr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var hostErr x509.HostnameError
|
||||||
|
if errors.As(err, &hostErr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var algErr x509.InsecureAlgorithmError
|
||||||
|
return errors.As(err, &algErr)
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ package json // import "miniflux.app/v2/internal/reader/json"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"sort"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -118,24 +118,21 @@ func (j *JSONAdapter) BuildFeed(feedURL string) *model.Feed {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the entry author.
|
// Populate the entry author.
|
||||||
itemAuthors := append(item.Authors, j.jsonFeed.Authors...)
|
itemAuthors := j.jsonFeed.Authors
|
||||||
|
itemAuthors = append(itemAuthors, item.Authors...)
|
||||||
itemAuthors = append(itemAuthors, item.Author, j.jsonFeed.Author)
|
itemAuthors = append(itemAuthors, item.Author, j.jsonFeed.Author)
|
||||||
|
|
||||||
authorNamesMap := make(map[string]bool)
|
var authorNames []string
|
||||||
for _, author := range itemAuthors {
|
for _, author := range itemAuthors {
|
||||||
authorName := strings.TrimSpace(author.Name)
|
authorName := strings.TrimSpace(author.Name)
|
||||||
if authorName != "" {
|
if authorName != "" {
|
||||||
authorNamesMap[authorName] = true
|
authorNames = append(authorNames, authorName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var authors []string
|
slices.Sort(authorNames)
|
||||||
for authorName := range authorNamesMap {
|
authorNames = slices.Compact(authorNames)
|
||||||
authors = append(authors, authorName)
|
entry.Author = strings.Join(authorNames, ", ")
|
||||||
}
|
|
||||||
|
|
||||||
sort.Strings(authors)
|
|
||||||
entry.Author = strings.Join(authors, ", ")
|
|
||||||
|
|
||||||
// Populate the entry enclosures.
|
// Populate the entry enclosures.
|
||||||
for _, attachment := range item.Attachments {
|
for _, attachment := range item.Attachments {
|
||||||
|
|
|
@ -93,8 +93,6 @@ func (mc *Content) MimeType() string {
|
||||||
return "video/*"
|
return "video/*"
|
||||||
case mc.Type == "" && mc.Medium == "audio":
|
case mc.Type == "" && mc.Medium == "audio":
|
||||||
return "audio/*"
|
return "audio/*"
|
||||||
case mc.Type == "" && mc.Medium == "video":
|
|
||||||
return "video/*"
|
|
||||||
case mc.Type != "":
|
case mc.Type != "":
|
||||||
return mc.Type
|
return mc.Type
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -401,11 +401,11 @@ func parseISO8601(from string) (time.Duration, error) {
|
||||||
|
|
||||||
switch name {
|
switch name {
|
||||||
case "hour":
|
case "hour":
|
||||||
d = d + (time.Duration(val) * time.Hour)
|
d += (time.Duration(val) * time.Hour)
|
||||||
case "minute":
|
case "minute":
|
||||||
d = d + (time.Duration(val) * time.Minute)
|
d += (time.Duration(val) * time.Minute)
|
||||||
case "second":
|
case "second":
|
||||||
d = d + (time.Duration(val) * time.Second)
|
d += (time.Duration(val) * time.Second)
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("unknown field %s", name)
|
return 0, fmt.Errorf("unknown field %s", name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,11 +45,12 @@ func (c *candidate) String() string {
|
||||||
id, _ := c.selection.Attr("id")
|
id, _ := c.selection.Attr("id")
|
||||||
class, _ := c.selection.Attr("class")
|
class, _ := c.selection.Attr("class")
|
||||||
|
|
||||||
if id != "" && class != "" {
|
switch {
|
||||||
|
case id != "" && class != "":
|
||||||
return fmt.Sprintf("%s#%s.%s => %f", c.Node().DataAtom, id, class, c.score)
|
return fmt.Sprintf("%s#%s.%s => %f", c.Node().DataAtom, id, class, c.score)
|
||||||
} else if id != "" {
|
case id != "":
|
||||||
return fmt.Sprintf("%s#%s => %f", c.Node().DataAtom, id, c.score)
|
return fmt.Sprintf("%s#%s => %f", c.Node().DataAtom, id, c.score)
|
||||||
} else if class != "" {
|
case class != "":
|
||||||
return fmt.Sprintf("%s.%s => %f", c.Node().DataAtom, class, c.score)
|
return fmt.Sprintf("%s.%s => %f", c.Node().DataAtom, class, c.score)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +223,7 @@ func getCandidates(document *goquery.Document) candidateList {
|
||||||
// should have a relatively small link density (5% or less) and be mostly
|
// should have a relatively small link density (5% or less) and be mostly
|
||||||
// unaffected by this operation
|
// unaffected by this operation
|
||||||
for _, candidate := range candidates {
|
for _, candidate := range candidates {
|
||||||
candidate.score = candidate.score * (1 - getLinkDensity(candidate.selection))
|
candidate.score *= (1 - getLinkDensity(candidate.selection))
|
||||||
}
|
}
|
||||||
|
|
||||||
return candidates
|
return candidates
|
||||||
|
|
|
@ -376,7 +376,8 @@ func addHackerNewsLinksUsing(entryContent, app string) string {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if app == "opener" {
|
switch app {
|
||||||
|
case "opener":
|
||||||
params := url.Values{}
|
params := url.Values{}
|
||||||
params.Add("url", hn_uri.String())
|
params.Add("url", hn_uri.String())
|
||||||
|
|
||||||
|
@ -389,12 +390,12 @@ func addHackerNewsLinksUsing(entryContent, app string) string {
|
||||||
|
|
||||||
open_with_opener := `<a href="` + url.String() + `">Open with Opener</a>`
|
open_with_opener := `<a href="` + url.String() + `">Open with Opener</a>`
|
||||||
a.Parent().AppendHtml(" " + open_with_opener)
|
a.Parent().AppendHtml(" " + open_with_opener)
|
||||||
} else if app == "hack" {
|
case "hack":
|
||||||
url := strings.Replace(hn_uri.String(), hn_prefix, "hack://", 1)
|
url := strings.Replace(hn_uri.String(), hn_prefix, "hack://", 1)
|
||||||
|
|
||||||
open_with_hack := `<a href="` + url + `">Open with HACK</a>`
|
open_with_hack := `<a href="` + url + `">Open with HACK</a>`
|
||||||
a.Parent().AppendHtml(" " + open_with_hack)
|
a.Parent().AppendHtml(" " + open_with_hack)
|
||||||
} else {
|
default:
|
||||||
slog.Warn("Unknown app provided for openHackerNewsLinksWith rewrite rule",
|
slog.Warn("Unknown app provided for openHackerNewsLinksWith rewrite rule",
|
||||||
slog.String("app", app),
|
slog.String("app", app),
|
||||||
)
|
)
|
||||||
|
|
|
@ -190,17 +190,18 @@ func sanitizeAttributes(baseURL, tagName string, attributes []html.Attribute) ([
|
||||||
}
|
}
|
||||||
|
|
||||||
if isExternalResourceAttribute(attribute.Key) {
|
if isExternalResourceAttribute(attribute.Key) {
|
||||||
if tagName == "iframe" {
|
switch {
|
||||||
|
case tagName == "iframe":
|
||||||
if !isValidIframeSource(baseURL, attribute.Val) {
|
if !isValidIframeSource(baseURL, attribute.Val) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
value = rewriteIframeURL(attribute.Val)
|
value = rewriteIframeURL(attribute.Val)
|
||||||
} else if tagName == "img" && attribute.Key == "src" && isValidDataAttribute(attribute.Val) {
|
case tagName == "img" && attribute.Key == "src" && isValidDataAttribute(attribute.Val):
|
||||||
value = attribute.Val
|
value = attribute.Val
|
||||||
} else if isAnchor("a", attribute) {
|
case isAnchor("a", attribute):
|
||||||
value = attribute.Val
|
value = attribute.Val
|
||||||
isAnchorLink = true
|
isAnchorLink = true
|
||||||
} else {
|
default:
|
||||||
value, err = urllib.AbsoluteURL(baseURL, value)
|
value, err = urllib.AbsoluteURL(baseURL, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -27,8 +27,7 @@ func StripTags(input string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
token := tokenizer.Token()
|
token := tokenizer.Token()
|
||||||
switch token.Type {
|
if token.Type == html.TextToken {
|
||||||
case html.TextToken:
|
|
||||||
buffer.WriteString(token.Data)
|
buffer.WriteString(token.Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ func filterValidXMLChar(r rune) rune {
|
||||||
func procInst(param, s string) string {
|
func procInst(param, s string) string {
|
||||||
// TODO: this parsing is somewhat lame and not exact.
|
// TODO: this parsing is somewhat lame and not exact.
|
||||||
// It works for all actual cases, though.
|
// It works for all actual cases, though.
|
||||||
param = param + "="
|
param += "="
|
||||||
idx := strings.Index(s, param)
|
idx := strings.Index(s, param)
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -133,12 +133,12 @@ func (s *Storage) CategoriesWithFeedCount(userID int64) (model.Categories, error
|
||||||
`
|
`
|
||||||
|
|
||||||
if user.CategoriesSortingOrder == "alphabetical" {
|
if user.CategoriesSortingOrder == "alphabetical" {
|
||||||
query = query + `
|
query += `
|
||||||
ORDER BY
|
ORDER BY
|
||||||
c.title ASC
|
c.title ASC
|
||||||
`
|
`
|
||||||
} else {
|
} else {
|
||||||
query = query + `
|
query += `
|
||||||
ORDER BY
|
ORDER BY
|
||||||
count_unread DESC,
|
count_unread DESC,
|
||||||
c.title ASC
|
c.title ASC
|
||||||
|
@ -255,14 +255,14 @@ func (s *Storage) RemoveAndReplaceCategoriesByName(userid int64, titles []string
|
||||||
}
|
}
|
||||||
|
|
||||||
query = `
|
query = `
|
||||||
WITH d_cats AS (SELECT id FROM categories WHERE user_id = $1 AND title = ANY($2))
|
WITH d_cats AS (SELECT id FROM categories WHERE user_id = $1 AND title = ANY($2))
|
||||||
UPDATE feeds
|
UPDATE feeds
|
||||||
SET category_id =
|
SET category_id =
|
||||||
(SELECT id
|
(SELECT id
|
||||||
FROM categories
|
FROM categories
|
||||||
WHERE user_id = $1 AND id NOT IN (SELECT id FROM d_cats)
|
WHERE user_id = $1 AND id NOT IN (SELECT id FROM d_cats)
|
||||||
ORDER BY title ASC
|
ORDER BY title ASC
|
||||||
LIMIT 1)
|
LIMIT 1)
|
||||||
WHERE user_id = $1 AND category_id IN (SELECT id FROM d_cats)
|
WHERE user_id = $1 AND category_id IN (SELECT id FROM d_cats)
|
||||||
`
|
`
|
||||||
_, err = tx.Exec(query, userid, titleParam)
|
_, err = tx.Exec(query, userid, titleParam)
|
||||||
|
|
|
@ -28,7 +28,7 @@ func (h *handler) showJavascript(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
if filename == "service-worker" {
|
if filename == "service-worker" {
|
||||||
variables := fmt.Sprintf(`const OFFLINE_URL=%q;`, route.Path(h.router, "offline"))
|
variables := fmt.Sprintf(`const OFFLINE_URL=%q;`, route.Path(h.router, "offline"))
|
||||||
contents = append([]byte(variables)[:], contents[:]...)
|
contents = append([]byte(variables), contents...)
|
||||||
}
|
}
|
||||||
|
|
||||||
b.WithHeader("Content-Type", "text/javascript; charset=utf-8")
|
b.WithHeader("Content-Type", "text/javascript; charset=utf-8")
|
||||||
|
|
Loading…
Reference in a new issue