summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/fetch.fnl8
-rw-r--r--bin/serve.fnl51
-rw-r--r--parser/artoftea.fnl2
-rw-r--r--parser/chaekshop.fnl2
-rw-r--r--parser/clubcha.fnl1
-rw-r--r--parser/gorkovchay.fnl1
-rw-r--r--parser/ipuer.fnl2
-rw-r--r--parser/moychay.fnl1
-rw-r--r--parser/ozchai.fnl7
-rw-r--r--parser/parser.fnl21
-rw-r--r--static/style.css6
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 @@
(.. "<!DOCTYPE html>\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);
}