From 441d7fd5a5a0ccf8d53238d717ec5119024cbbfa Mon Sep 17 00:00:00 2001 From: unwox Date: Thu, 19 Dec 2024 16:03:45 +0600 Subject: parse teaware volume and let users filter by it --- bin/fetch.fnl | 8 +++++--- bin/serve.fnl | 51 +++++++++++++++++++++++++++++++++++++++++---------- parser/artoftea.fnl | 2 +- parser/chaekshop.fnl | 2 +- parser/clubcha.fnl | 1 + parser/gorkovchay.fnl | 1 + parser/ipuer.fnl | 2 +- parser/moychay.fnl | 1 + parser/ozchai.fnl | 7 +++++++ parser/parser.fnl | 21 +++++++++++++++++++-- static/style.css | 6 +++--- 11 files changed, 81 insertions(+), 21 deletions(-) diff --git a/bin/fetch.fnl b/bin/fetch.fnl index 0551d76..a5f8d63 100644 --- a/bin/fetch.fnl +++ b/bin/fetch.fnl @@ -33,6 +33,7 @@ image TEXT NOT NULL, price REAL NOT NULL, weight REAL NOT NULL, + volume REAL NOT NULL, price_per REAL NOT NULL, archived BOOL NOT NULL, creation_time DATETIME NOT NULL @@ -102,7 +103,7 @@ (local sql (.. "INSERT OR REPLACE INTO products VALUES " (array.join - (map (fn [_ _] "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") + (map (fn [_ _] "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") products) ", "))) (local creation-time (now)) @@ -118,6 +119,7 @@ (or product.image "") (or product.price 0) (or product.weight 0) + (or product.volume 0) (or product.price-per 0) (or product.archived false) creation-time])) @@ -152,8 +154,8 @@ ;; replace with with-tx (local tx (must (luna.db.begin db))) (must (luna.db.exec-tx tx "DELETE FROM product_tags;" [])) -(each [_ parser (pairs [ozchai gorkovchay chaekshop clubcha artoftea ipuer - moychay])] +(each [_ parser (pairs [ozchai clubcha ipuer artoftea chaekshop moychay + gorkovchay])] (store-products tx (parser.products))) (cache.clear-tx tx "page:") (must (luna.db.commit tx)) diff --git a/bin/serve.fnl b/bin/serve.fnl index 68dea35..c22becb 100644 --- a/bin/serve.fnl +++ b/bin/serve.fnl @@ -94,6 +94,8 @@ :sort (or (query-string params "sort") "") :min-price (query-number params "min-price") :max-price (query-number params "max-price") + :min-volume (query-number params "min-volume") + :max-volume (query-number params "max-volume") :price-per (= "on" (query-string params "price-per"))}) (fn form-empty? [form] @@ -103,6 +105,8 @@ (= "" form.site) (not form.min-price) (not form.max-price) + (not form.min-volume) + (not form.max-volume) ;; price-per and sort are intentionally left out since they must not ;; trigger search by itself )) @@ -132,6 +136,12 @@ (if form.price-per "&price-per=on" "") + (if (and form.min-volume (< 0 form.min-volume)) + (.. "&min-volume=" (tostring form.min-volume)) + "") + (if (and form.max-volume (< 0 form.max-volume)) + (.. "&max-volume=" (tostring form.max-volume)) + "") (if form.sort (.. "&sort=" form.sort) ""))) @@ -205,7 +215,8 @@ LIMIT 1" [])) 1 1)) -(fn query-products [{: query : tags : min-price : max-price : price-per : site : sort} page] +(fn query-products [{: query : tags : min-price : max-price : price-per + : min-volume : max-volume : site : sort} page] (local tags (or tags [])) (local where-conds []) (local sort-criteria []) @@ -240,6 +251,14 @@ (table.insert where-conds "products.price_per <= ?") (table.insert where-conds "products.price <= ?")) (table.insert query-args max-price)) + (when (and min-volume (< 0 min-volume)) + (table.insert where-conds "products.volume >= ?") + (table.insert query-args min-volume)) + (when (and max-volume (< 0 max-volume)) + (table.insert where-conds + "(products.volume <= ? AND products.volume != 0)") + (table.insert query-args max-volume)) + (local where-sql (if (< 0 (# where-conds)) (.. "AND " (array.join where-conds "\nAND ")) @@ -396,6 +415,8 @@ (item "/teaware" "Посуда")]) (fn aside-template [form path aside-content] + (local teaware? (array.contains form.tags "Посуда")) + [:aside {:class "aside"} [:div {:class "aside-content"} (if (or (not (form-empty? form)) (~= path "/")) @@ -422,15 +443,24 @@ "selected" nil)} tag]) (all-tags)))]] - [:div {:class "form-price"} - [:input {:type :number :name :min-price :min "1" + [:div {:class "form-range"} + [:input {:type :number :name "min-price" :min "1" :placeholder "От ₽" :value (tostring form.min-price)}] - [:input {:type :number :name :max-price :min "1" + [:input {:type :number :name "max-price" :min "1" :placeholder "До ₽" :value (tostring form.max-price)}]] - [:div {:class "form-price-per"} - [:input {:type :checkbox :id "price-per" :name "price-per" - :checked (if form.price-per "checked" nil)}] - [:label {:for "price-per"} "цена за грамм"]] + (if teaware? + [:div {:class "form-range"} + [:input {:type :number :name "min-volume" :min "1" + :placeholder "От мл" :value (tostring form.min-volume)}] + [:input {:type :number :name "max-volume" :min "1" + :placeholder "До мл" :value (tostring form.max-volume)}]] + "") + (if (not teaware?) + [:div {:class "form-price-per"} + [:input {:type :checkbox :id "price-per" :name "price-per" + :checked (if form.price-per "checked" nil)}] + [:label {:for "price-per"} "цена за грамм"]] + "") [:div {} [:select {:name "site"} [:option {:value ""} "~ Сайт ~"] @@ -440,7 +470,8 @@ [:option {:value val :selected (if (= form.site val) "selected" nil)} (. (require (.. "parser." val)) :title)]) - [:ozchai :clubcha :ipuer :artoftea :chaekshop :moychay]))]] + [:ozchai :clubcha :ipuer :artoftea :chaekshop :moychay + :gorkovchay]))]] [:div {} [:select {:name "sort"} [:option {:value ""} "~ Порядок ~"] @@ -586,7 +617,7 @@ (.. "\n" (html.render (base-template form path [:div {} "Страница не найдена!"]) - true))))))) + true))))))) (fn robots-handler [] (values 200 {:content-type "text/plain"} diff --git a/parser/artoftea.fnl b/parser/artoftea.fnl index 265e19b..773f038 100644 --- a/parser/artoftea.fnl +++ b/parser/artoftea.fnl @@ -44,7 +44,6 @@ (local weight (number.string->number product.weight)) (local price (number.string->number product.price)) {:site "artoftea" - :id product.id :title product.title :url product.url :description product.description @@ -52,6 +51,7 @@ :year year :price price :weight weight + :volume (parser.guess-volume product.title) :price-per (if (and price weight (< 0 weight)) (/ (math.ceil (* (/ price weight) 10)) 10) nil)}) diff --git a/parser/chaekshop.fnl b/parser/chaekshop.fnl index 68046c1..21ed49b 100644 --- a/parser/chaekshop.fnl +++ b/parser/chaekshop.fnl @@ -38,7 +38,6 @@ (parser.guess-weight product.title))) (local price (number.string->number (string.gsub product.price "," "."))) {:site "chaekshop" - :id (.. "https://chaekshop.ru" product.url) :title product.title :url (.. "https://chaekshop.ru" product.url) :description "" @@ -46,6 +45,7 @@ :year (parser.guess-year product.title) :price price :weight weight + :volume (parser.guess-volume product.title) :price-per (if (and price weight (< 0 weight)) (/ (math.ceil (* (/ price weight) 10)) 10) nil)}) diff --git a/parser/clubcha.fnl b/parser/clubcha.fnl index 23f9484..affee2b 100644 --- a/parser/clubcha.fnl +++ b/parser/clubcha.fnl @@ -72,6 +72,7 @@ :year 0 :price price :weight weight + :volume (parser.guess-volume product.title) :price-per (if (and price weight (< 0 weight)) (/ (math.ceil (* (/ price weight) 10)) 10) nil)}) diff --git a/parser/gorkovchay.fnl b/parser/gorkovchay.fnl index d094b85..890fffb 100644 --- a/parser/gorkovchay.fnl +++ b/parser/gorkovchay.fnl @@ -59,6 +59,7 @@ :price price :archived product.archived :weight weight + :volume (parser.guess-volume product.title) :price-per price}) (fn products [] diff --git a/parser/ipuer.fnl b/parser/ipuer.fnl index 7a1ae6b..c1a8da7 100644 --- a/parser/ipuer.fnl +++ b/parser/ipuer.fnl @@ -52,7 +52,6 @@ (local weight (parser.guess-weight product.title)) (local price (number.string->number product.price)) {:site "ipuer" - :id product.id :url (.. "https://ipuer.ru" product.url) :title product.title :description product.description @@ -60,6 +59,7 @@ :year (parser.guess-year product.title) :price price :weight weight + :volume (parser.guess-volume product.title) :category product.category :price-per (if (and price weight (< 0 weight)) (/ (math.ceil (* (/ price weight) 10)) 10) diff --git a/parser/moychay.fnl b/parser/moychay.fnl index 565992e..cec6a77 100644 --- a/parser/moychay.fnl +++ b/parser/moychay.fnl @@ -33,6 +33,7 @@ :title product.name :archived (not product.available) :weight weight + :volume (parser.guess-volume product.name) :price price :image (.. "https://moychay.ru" product.image) :url (.. "https://moychay.ru" product.url) diff --git a/parser/ozchai.fnl b/parser/ozchai.fnl index 16a3265..937a35b 100644 --- a/parser/ozchai.fnl +++ b/parser/ozchai.fnl @@ -1,5 +1,6 @@ (import-macros {: map} :lib.macro) +(local parser (require :parser.parser)) (local array (require :lib.array)) (local http (require :lib.http)) (local number (require :lib.number)) @@ -23,6 +24,11 @@ (local gallery (json.decode product.gallery)) (local weight (number.string->number (. product.editions 1 :Вес))) (local price (number.string->number (. product.editions 1 :price))) + (var volume nil) + (each [_ c (ipairs product.characteristics)] + (when (= (. c :title) "Объем") + (set volume (parser.guess-volume c.value)))) + {:site "ozchai" :id product.url :url product.url @@ -33,6 +39,7 @@ (. gallery 1 :img) "") :weight weight + :volume volume :price price :price-per (if (and price weight (< 0 weight)) (/ (math.ceil (* (/ price weight) 10)) 10) diff --git a/parser/parser.fnl b/parser/parser.fnl index bf8feed..55296f2 100644 --- a/parser/parser.fnl +++ b/parser/parser.fnl @@ -107,7 +107,6 @@ (fn guess-tags [text] (local text (if text (must (luna.utf8.lower text)) "")) - (if (: (anywhere (peg.P "зеленый чай")) :match text) ["Зеленый чай"] (: (anywhere (peg.P "улун")) :match text) @@ -142,10 +141,27 @@ (if text (number.string->number (: (anywhere + ;; FIXME: also account for kilograms (* (peg.C pegs.number) (maybe " ") "гр")) :match text)) nil)) +(fn guess-volume [text] + (if text + (let [peg (peg.Ct + (anywhere + (* (peg.C pegs.number) + (maybe " ") + ;; also account for litres + (+ (* (peg.C "л") (+ (peg.P " ") "\n" -1)) + (peg.C "мл")))))] + (let [result (peg:match text)] + (if result + (let [[number metric] result] + (* number (if (= metric "л") 1000 1))) + nil))) + nil)) + {: match-many : tag : anywhere @@ -155,4 +171,5 @@ :not pnot : guess-tags : guess-year - : guess-weight} + : guess-weight + : guess-volume} diff --git a/static/style.css b/static/style.css index 912b809..fdaf120 100644 --- a/static/style.css +++ b/static/style.css @@ -126,7 +126,7 @@ h1, h2, h3, h4, h5, h6 { .form input[type="search"], .form select, -.form-price, +.form-range, .form-price-per { margin-bottom: 0.5rem; } @@ -137,12 +137,12 @@ h1, h2, h3, h4, h5, h6 { width: 100%; } -.form-price { +.form-range { display: flex; gap: 1rem; } -.form-price input { +.form-range input { flex: 1; max-width: calc(50% - 0.5rem); } -- cgit v1.2.3