Commit 4c34236d authored by Ricardo J. Mendez's avatar Ricardo J. Mendez

Merge branch 'release/1.0.6'

Original release was from 2016-03-21, commit date changed since I had
to do some clean-up before open sourcing it.
parents 7a39ddea d2e9027e
(defproject relevance-chrome "1.0.5"
(defproject relevance-chrome "1.0.6"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.228"]
[org.clojure/clojurescript "1.8.34"]
[org.clojure/core.async "0.2.374"]
[com.cognitect/transit-cljs "0.8.237"]
[cljsjs/react-bootstrap "0.28.1-1" :exclusions [org.webjars.bower/jquery]]
[khroma "0.3.0"]
[prismatic/dommy "1.1.0"]
[re-frame "0.6.0" :exclusions [cljsjs/react]]
]
[re-frame "0.7.0" :exclusions [cljsjs/react]]]
:source-paths ["src/ui" "src/common" "src/background" "src/content"]
:test-paths ["test"]
:plugins [[lein-cljsbuild "1.1.1"]
[lein-chromebuild "0.3.1"]
[lein-doo "0.1.6-SNAPSHOT"]
]
[lein-doo "0.1.6-SNAPSHOT"]]
:doo {:build "test"}
......@@ -41,9 +41,9 @@
:output-dir "target/js/ui"
:main "relevance.display"
:optimizations :whitespace
:pretty-print true}}
}
}
:pretty-print true}}}}
:chromebuild {:resource-paths ["resources/js"
"resources/dashboard"
"resources/images"
......@@ -70,6 +70,6 @@
:output-dir "target/js/test"
:main relevance.test.runner
:optimizations :none
:pretty-print :true}}}}
}
})
:pretty-print :true}}}}}})
{
"name": "Relevance - Smart Tab Organizer",
"short_name": "Relevance",
"version": "1.0.5",
"version": "1.0.6",
"browser_action": {
"default_title": "Organize tabs",
"default_icon": {
......
......@@ -4,6 +4,7 @@
[relevance.data :as data]
[relevance.io :as io]
[relevance.migrations :as migrations]
[relevance.order :refer [time-score score-tabs]]
[relevance.utils :refer [on-channel url-key host-key hostname is-http? ms-day]]
[relevance.settings :refer [default-settings]]
[khroma.alarms :as alarms]
......@@ -27,8 +28,6 @@
(def window-alarm "window-alarm")
(def non-http-penalty 0.01)
(def sound-extra-score 9888777666)
(def relevant-tab-keys [:windowId :id :active :url :start-time :title :favIconUrl :audible])
(def select-tab-keys #(select-keys % relevant-tab-keys))
......@@ -96,36 +95,17 @@
(tabs/create {:url ext-url})))))
(defn time-score [tab url-times site-times settings]
(let [url (:url tab)
idx (:index tab)
url-time (:time (get url-times (url-key url)))
is-priority? (and (:sound-to-left? settings)
(:audible tab))
tab-time (if is-priority?
(+ sound-extra-score idx)
url-time)
site-time (:time (get site-times (host-key (hostname url))))
total (+ tab-time site-time)
is-penalized? (and (not (is-http? url))
(not is-priority?))
score (if is-penalized? (* total non-http-penalty) total)
]
(or (when tab-time score)
(- idx))))
(defn sort-tabs! [window-id app-state]
(go
(let [{:keys [settings data]} app-state
{:keys [url-times site-times]} data
tabs (->> (:tabs (<! (windows/get window-id)))
(map #(assoc % :time (time-score % url-times site-times settings)))
(sort-by #(* -1 (:time %)))
(map-indexed #(hash-map :index %1
:id (:id %2))))]
tabs (score-tabs (:tabs (<! (windows/get window-id)))
url-times
site-times
settings)]
(doseq [tab tabs]
(tabs/move (:id tab) {:index (:index tab)}))
)))
(tabs/move (:id tab) {:index (:index tab)})))))
;;;;-------------------------------------
......@@ -147,9 +127,9 @@
last-shown (:last-initialized (<! (storage/get :last-initialized)))]
(when (not= version last-shown)
(open-results-tab)
(storage/set {:last-initialized version}))
)
)
(storage/set {:last-initialized version}))))
{:app-state {}}))
......@@ -190,8 +170,8 @@
(dispatch [:handle-activation old-tab (:start-time old-tab)])
(dispatch [:handle-deactivation old-tab (:time suspend-info)])))
(assoc app-state :data (dissoc new-data :suspend-info)
:settings settings)
)))
:settings settings))))
(register-handler
......@@ -199,8 +179,8 @@
(fn [app-state [_ key item]]
(let [new-state (assoc-in app-state [:data key] item)]
(io/save :data (:data new-state))
new-state)
))
new-state)))
(register-handler
:delete-url
......@@ -212,12 +192,12 @@
new-data (if changed?
(assoc data :url-times new-times
:site-times (accumulate-preserve-icons new-times (:site-times data)))
data)
]
data)]
(when changed?
(io/save :data new-data))
(assoc app-state :data new-data)
)))
(assoc app-state :data new-data))))
(register-handler
:handle-activation
......@@ -253,8 +233,8 @@
action (if (= "active" state) :handle-activation :handle-deactivation)
active-tab (if (= :handle-activation action)
(get-in app-state [:app-state :idle])
(:active-tab app-state))
]
(:active-tab app-state))]
; (console/trace " State changed to " state action)
;; We only store the idle tabs on the app state if we actually idled any.
;; That way we avoid losing the originally stored idled tabs when we
......@@ -267,8 +247,8 @@
(-> app-state
(assoc-in [:app-state :idle] active-tab)
(assoc :active-tab nil)))
app-state)
)))
app-state))))
(register-handler
......@@ -276,8 +256,8 @@
(fn [app-state [_ {:keys [alarm]}]]
(when (= window-alarm (:name alarm))
(check-window-status (:active-tab app-state)))
app-state
))
app-state))
(register-handler
::on-clicked-button
......@@ -287,15 +267,15 @@
(dispatch [:handle-deactivation active-tab])
(dispatch [:handle-activation active-tab]))
(dispatch [:on-relevance-sort-tabs tab])
app-state
))
app-state))
(register-handler
::on-clicked-menu
(fn [app-state [_ {:keys [info tab]}]]
(dispatch [(keyword (:menuItemId info)) tab])
app-state
))
app-state))
(register-handler
::on-message
......@@ -306,11 +286,11 @@
(condp = (keyword action)
:reload-data (go (dispatch [:data-load (<! (io/load :data)) (<! (io/load :settings))]))
:delete-url (dispatch [:delete-url data])
(console/error "Nothing matched" message)
)
)
app-state
))
(console/error "Nothing matched" message)))
app-state))
(register-handler
......@@ -346,9 +326,9 @@
(do
(dispatch [:handle-deactivation active-tab])
(go (dispatch [:handle-activation (<! (tabs/get tabId))]))
(assoc app-state :active-tab nil)) ; :handle-activation is responsible for setting it
app-state
))))
(assoc app-state :active-tab nil)) ; :handle-activation is responsible for setting it
app-state))))
(register-handler
......@@ -370,8 +350,8 @@
;; the URL change condition above).
(if are-same?
(assoc app-state :active-tab (merge active-tab (select-keys tab [:title :url])))
app-state)
)))
app-state))))
(register-handler
......@@ -383,8 +363,8 @@
new-data (assoc data :url-times url-times :site-times site-times)]
; (console/trace time " milliseconds spent at " tab)
(io/save :data new-data)
(assoc app-state :data new-data)
)))
(assoc app-state :data new-data))))
(register-handler
::window-focus
......@@ -403,8 +383,8 @@
(go (dispatch [:handle-activation
(first (<! (tabs/query {:active true :windowId windowId})))])))
(assoc app-state :active-tab nil))
app-state))
))
app-state))))
;;;;-------------------------------------
......@@ -419,8 +399,8 @@
(let [content (<! connections)]
; (console/log "--> Background received" (<! content))
(>! content :background-ack)
(recur connections)))
)
(recur connections))))
(defn ^:export main []
......
......@@ -12,11 +12,11 @@
(map #(vector (host-key (key %))
(hash-map :host (key %)
:time (apply + (map :time (val %)))
:icon (:icon (first (val %))))
))
(into {})
)
)
:icon (:icon (first (val %))))))
(into {})))
(defn clean-up-by-time
......@@ -33,8 +33,8 @@
matches an ignore set"
[url-times ignore-set]
(into {} (remove #(contains? ignore-set (hostname (:url (val %))))
url-times))
)
url-times)))
(defn track-url-time
"Receives a url time database, a tab record and a time to track, and returns
......
......@@ -34,10 +34,10 @@
(assoc data
:data-version 3
:url-times url-times
:site-times (accumulate-site-times url-times))
)
data
))
:site-times (accumulate-site-times url-times)))
data))
(defn migrate-to-latest
......
(ns relevance.order
(:require [relevance.utils :refer [on-channel url-key host-key hostname is-http? ms-day]]))
;;;;------------------------------------
;;;; Settings
;;;;------------------------------------
(def non-http-penalty 0.01)
(def sound-extra-score 9888777666)
;;;;------------------------------------
;;;; Functions
;;;;------------------------------------
(defn time-score
"Returns a score for a tab based on the total time spent at both URLs and sites"
[tab url-times site-times settings]
(let [url (:url tab)
idx (:index tab)
url-time (or (:time (get url-times (url-key url)))
0)
is-priority? (and (:sound-to-left? settings)
(:audible tab))
is-penalized? (and (not (is-http? url))
(not is-priority?))
tab-time (cond
; Add an extra score if it's a priority URL
is-priority? (+ sound-extra-score idx)
; If a URL is penalized, we want it to at least have a
; value of 1, otherwise the tab time gets ignored and
; we'd default to using the raw site time
is-penalized? (max url-time 1)
; ... otherwise we just go with the raw URL time
:else url-time)
site-time (or (:time (get site-times (host-key (hostname url)))) 0)
total (+ tab-time site-time)
score (if is-penalized? (* total non-http-penalty) total)]
(or (when (pos? tab-time) score)
(- site-time idx))))
(defn score-tabs
"Returns a hashmap of the new tab ids and their indexes, based on a tab list and
the score function for time spent on urls and sites."
[tabs url-times site-times settings]
(->> tabs
(map #(assoc % :time (time-score % url-times site-times settings)))
(sort-by #(* -1 (:time %)))
(map-indexed #(hash-map :index %1
:id (:id %2)))))
......@@ -105,5 +105,4 @@
(< seconds 60) (str seconds "s")
(< seconds 3600) (time-label (quot seconds 60) "m" (rem seconds 60) "s")
(< seconds 86400) (time-label (quot seconds 3600) "h" (quot (rem seconds 3600) 60) "m")
:else (time-label (quot seconds 86400) "d" (quot (rem seconds 86400) 3600) "h")))
)
\ No newline at end of file
:else (time-label (quot seconds 86400) "d" (quot (rem seconds 86400) 3600) "h"))))
This diff is collapsed.
This diff is collapsed.
(ns relevance.test.order
(:require [cljs.test :refer-macros [deftest testing is are]]
[relevance.data :as data]
[relevance.order :as order]
[relevance.utils :as utils]))
(deftest empty-test
(is (= 1 1)))
(deftest test-time-score
; A score for an unknown URL with no tab index is zero
(is (= 0 (order/time-score {:url "http://google.com"}
{}
{}
{})))
; A score for an unknown URL with no tab index is the complement of its index
(is (= -20 (order/time-score {:url "http://google.com"
:index 20}
{}
{}
{})))
; A score for a known URL equals its time value
(is (= 291 (order/time-score {:url "http://google.com"}
{(utils/url-key "http://google.com")
{:time 291}}
{}
{})))
; A score for a known URL gets added the time for its site
(is (= 468 (order/time-score {:url "http://google.com/somepage"}
{(utils/url-key "http://google.com") {:time 291}
(utils/url-key "http://google.com/somepage") {:time 345}}
{(utils/host-key "google.com") {:time 123}
(utils/host-key "apple.com") {:time 987}}
{})))
; A score for a known URL is not affected by the score of other URLs for the same site
(is (= 414 (order/time-score {:url "http://google.com/"}
{(utils/url-key "http://google.com") {:time 291}
(utils/url-key "http://google.com/somepage") {:time 345}}
{(utils/host-key "google.com") {:time 123}
(utils/host-key "apple.com") {:time 987}}
{})))
; A page inherits its site's score even if it's unknown
(is (= 987 (order/time-score {:url "http://apple.com/mac"}
{(utils/url-key "http://google.com") {:time 291}
(utils/url-key "http://google.com/somepage") {:time 345}}
{(utils/host-key "google.com") {:time 123}
(utils/host-key "apple.com") {:time 987}}
{})))
; A page inherits its site's score even if it's unknown, but substracts the index so
; that they are placed at the end.
(is (= 975 (order/time-score {:url "http://apple.com/mac" :index 12}
{(utils/url-key "http://google.com") {:time 291}
(utils/url-key "http://google.com/somepage") {:time 345}}
{(utils/host-key "google.com") {:time 123}
(utils/host-key "apple.com") {:time 987}}
{})))
; A page that has sound gets no extra score if the :sound-to-left? key isn't on settings
(is (= 291 (order/time-score {:url "http://google.com"
:audible true}
{(utils/url-key "http://google.com")
{:time 291}}
{}
{})))
; An audible page gets an extra score if the :sound-to-left? key is set to true on the settings,
; but based on the index, not the time spent
(is (= (+ 5 123 order/sound-extra-score)
(order/time-score {:url "http://google.com/translate"
:index 5
:audible true}
{(utils/url-key "http://google.com/translate")
{:time 456}}
{(utils/host-key "google.com") {:time 123}
(utils/host-key "apple.com") {:time 987}}
{:sound-to-left? true})))
; Non-http pages are penalized, but get a minimum score of 1 (they will
; likely have a time of 0 to begin with since they aren't tracked)
(is (= (* 124 order/non-http-penalty)
(order/time-score {:url "chrome://google.com/translate"
:index 5}
{}
{(utils/host-key "google.com") {:time 123}
(utils/host-key "apple.com") {:time 987}}
{}))))
(deftest test-score-tabs
(let [url-times {(utils/url-key "http://google.com") {:time 2910}
(utils/url-key "http://google.com/somepage") {:time 345}
(utils/url-key "http://apple.com/osx") {:time 10101}
(utils/url-key "http://apple.com/") {:time 2120}}
site-times {(utils/host-key "google.com") {:time 4295} ; Includes time from tabs which we have deleted
(utils/host-key "apple.com") {:time 12221}}]
; We have spent the longest at Apple, so it gets prioritized
; The extension tab ends up at the end because it's not http
(is (= [{:index 0 :id 23} {:index 1 :id 9} {:index 2 :id 1}]
(order/score-tabs [{:url "http://google.com"
:id 9
:index 15}
{:url "chrome://extensions/"
:id 1
:index 1}
{:url "https://apple.com/macbook"
:id 23
:index 912}]
url-times
site-times
{})))
; An unknown page ends up at the end
(is (= [{:index 0 :id 23} {:index 1 :id 9} {:index 2 :id 1} {:index 3 :id 2}]
(order/score-tabs [{:url "http://google.com"
:id 9
:index 15}
{:url "http://youtube.com/"
:id 2
:index 27}
{:url "chrome://extensions/"
:id 1
:index 1}
{:url "https://apple.com/macbook"
:id 23
:index 912}]
url-times
site-times
{})))
; Two unknown pages get sorted by their index order
(is (= [{:index 0 :id 23} {:index 1 :id 9} {:index 2 :id 1} {:index 3 :id 123} {:index 4 :id 2}]
(order/score-tabs [{:url "http://google.com"
:id 9
:index 15}
{:url "http://youtube.com/"
:id 2
:index 27}
{:url "http://vimeo.com/"
:id 123
:index 26}
{:url "chrome://extensions/"
:id 1
:index 1}
{:url "https://apple.com/macbook"
:id 23
:index 912}]
url-times
site-times
{})))
; An unknown page that is playing sound gets prioritized according to the settings
(is (= [{:index 0 :id 2} {:index 1 :id 23} {:index 2 :id 9} {:index 3 :id 1}]
(order/score-tabs [{:url "http://google.com"
:id 9
:index 15}
{:url "http://youtube.com/"
:id 2
:audible true
:index 27}
{:url "chrome://extensions/"
:id 1
:index 1}
{:url "https://apple.com/macbook"
:id 23
:index 912}]
url-times
site-times
{:sound-to-left? true})))
; If for any reason the Apple URL is not http, it gets de-prioritized
(is (= [{:index 0 :id 9} {:index 1 :id 1} {:index 2 :id 23}]
(order/score-tabs [{:url "http://google.com"
:id 9
:index 15}
{:url "chrome://extensions/"
:id 1
:index 1}
{:url "apple.com/macbook"
:id 23
:index 912}]
url-times
site-times
{})))
)
)
(ns relevance.test.runner
(:require [doo.runner :refer-macros [doo-tests]]
[relevance.test.order]
[relevance.test.data]
[relevance.test.migrations]
[relevance.test.utils]
))
[relevance.test.utils]))
(enable-console-print!)
(doo-tests 'relevance.test.data
(doo-tests 'relevance.test.order
'relevance.test.data
'relevance.test.migrations
'relevance.test.utils)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment