diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml
index 3d8935d6..244b4d04 100644
--- a/.github/workflows/containers.yml
+++ b/.github/workflows/containers.yml
@@ -96,8 +96,9 @@ jobs:
tags: |
${{ secrets.DOCKER_HUB_USERNAME }}/changedetection.io:dev,ghcr.io/${{ github.repository }}:dev
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm/v8
- cache-from: type=local,src=/tmp/.buildx-cache
- cache-to: type=local,dest=/tmp/.buildx-cache
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
+
# Looks like this was disabled
# provenance: false
@@ -116,18 +117,11 @@ jobs:
${{ secrets.DOCKER_HUB_USERNAME }}/changedetection.io:latest
ghcr.io/dgtlmoon/changedetection.io:latest
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7,linux/arm/v8
- cache-from: type=local,src=/tmp/.buildx-cache
- cache-to: type=local,dest=/tmp/.buildx-cache
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
# Looks like this was disabled
# provenance: false
- name: Image digest
run: echo step SHA ${{ steps.vars.outputs.sha_short }} tag ${{steps.vars.outputs.tag}} branch ${{steps.vars.outputs.branch}} digest ${{ steps.docker_build.outputs.digest }}
- - name: Cache Docker layers
- uses: actions/cache@v3
- with:
- path: /tmp/.buildx-cache
- key: ${{ runner.os }}-buildx-${{ github.sha }}
- restore-keys: |
- ${{ runner.os }}-buildx-
diff --git a/Dockerfile b/Dockerfile
index d0f4ea75..e726d26e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -20,17 +20,12 @@ WORKDIR /install
COPY requirements.txt /requirements.txt
-# Instructing pip to fetch wheels from piwheels.org" on ARMv6 and ARMv7 machines
-RUN if [ "$(dpkg --print-architecture)" = "armhf" ] || [ "$(dpkg --print-architecture)" = "armel" ]; then \
- printf "[global]\nextra-index-url=https://www.piwheels.org/simple\n" > /etc/pip.conf; \
- fi;
-
RUN pip install --target=/dependencies -r /requirements.txt
# Playwright is an alternative to Selenium
# Excluded this package from requirements.txt to prevent arm/v6 and arm/v7 builds from failing
# https://github.com/dgtlmoon/changedetection.io/pull/1067 also musl/alpine (not supported)
-RUN pip install --target=/dependencies playwright~=1.27.1 \
+RUN pip install --target=/dependencies playwright~=1.39 \
|| echo "WARN: Failed to install Playwright. The application can still run, but the Playwright option will be disabled."
# Final image stage
diff --git a/MANIFEST.in b/MANIFEST.in
index 41ed620d..f7393309 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -16,3 +16,4 @@ global-exclude venv
global-exclude test-datastore
global-exclude changedetection.io*dist-info
+global-exclude changedetectionio/tests/proxy_socks5/test-datastore
diff --git a/README.md b/README.md
index 76595426..67de6c11 100644
--- a/README.md
+++ b/README.md
@@ -232,6 +232,13 @@ See the wiki https://github.com/dgtlmoon/changedetection.io/wiki/Proxy-configura
Raspberry Pi and linux/arm/v6 linux/arm/v7 arm64 devices are supported! See the wiki for [details](https://github.com/dgtlmoon/changedetection.io/wiki/Fetching-pages-with-WebDriver)
+## Import support
+
+Easily [import your list of websites to watch for changes in Excel .xslx file format](https://changedetection.io/tutorial/how-import-your-website-change-detection-lists-excel), or paste in lists of website URLs as plaintext.
+
+Excel import is recommended - that way you can better organise tags/groups of websites and other features.
+
+
## API Support
Supports managing the website watch list [via our API](https://changedetection.io/docs/api_v1/index.html)
diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py
index eeddb8cc..fd2e6256 100644
--- a/changedetectionio/__init__.py
+++ b/changedetectionio/__init__.py
@@ -38,7 +38,7 @@ from flask_paginate import Pagination, get_page_parameter
from changedetectionio import html_tools
from changedetectionio.api import api_v1
-__version__ = '0.45.5'
+__version__ = '0.45.7.3'
from changedetectionio.store import BASE_URL_NOT_SET_TEXT
@@ -105,6 +105,10 @@ def get_darkmode_state():
css_dark_mode = request.cookies.get('css_dark_mode', 'false')
return 'true' if css_dark_mode and strtobool(css_dark_mode) else 'false'
+@app.template_global()
+def get_css_version():
+ return __version__
+
# We use the whole watch object from the store/JSON so we can see if there's some related status in terms of a thread
# running or something similar.
@app.template_filter('format_last_checked_time')
@@ -1210,8 +1214,7 @@ def changedetection_app(config=None, datastore_o=None):
# These files should be in our subdirectory
try:
# set nocache, set content-type
- watch_dir = datastore_o.datastore_path + "/" + filename
- response = make_response(send_from_directory(filename="elements.json", directory=watch_dir, path=watch_dir + "/elements.json"))
+ response = make_response(send_from_directory(os.path.join(datastore_o.datastore_path, filename), "elements.json"))
response.headers['Content-type'] = 'application/json'
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response.headers['Pragma'] = 'no-cache'
diff --git a/changedetectionio/blueprint/check_proxies/__init__.py b/changedetectionio/blueprint/check_proxies/__init__.py
index 06abdfee..ea68376a 100644
--- a/changedetectionio/blueprint/check_proxies/__init__.py
+++ b/changedetectionio/blueprint/check_proxies/__init__.py
@@ -41,7 +41,7 @@ def construct_blueprint(datastore: ChangeDetectionStore):
now = time.time()
try:
update_handler = text_json_diff.perform_site_check(datastore=datastore, watch_uuid=uuid)
- changed_detected, update_obj, contents = update_handler.call_browser()
+ update_handler.call_browser()
# title, size is len contents not len xfer
except content_fetcher.Non200ErrorCodeReceived as e:
if e.status_code == 404:
diff --git a/changedetectionio/processors/__init__.py b/changedetectionio/processors/__init__.py
index c719d7a2..10c9138c 100644
--- a/changedetectionio/processors/__init__.py
+++ b/changedetectionio/processors/__init__.py
@@ -7,12 +7,13 @@ from copy import deepcopy
from distutils.util import strtobool
class difference_detection_processor():
+
+ browser_steps = None
datastore = None
fetcher = None
screenshot = None
- xpath_data = None
- browser_steps = None
watch = None
+ xpath_data = None
def __init__(self, *args, datastore, watch_uuid, **kwargs):
super().__init__(*args, **kwargs)
diff --git a/changedetectionio/static/js/toggle-theme.js b/changedetectionio/static/js/toggle-theme.js
index 885b8907..774729d0 100644
--- a/changedetectionio/static/js/toggle-theme.js
+++ b/changedetectionio/static/js/toggle-theme.js
@@ -3,45 +3,50 @@
* Toggles theme between light and dark mode.
*/
$(document).ready(function () {
- const button = document.getElementById("toggle-light-mode");
+ const button = document.getElementById("toggle-light-mode");
- button.onclick = () => {
- const htmlElement = document.getElementsByTagName("html");
- const isDarkMode = htmlElement[0].dataset.darkmode === "true";
- htmlElement[0].dataset.darkmode = !isDarkMode;
- setCookieValue(!isDarkMode);
- };
+ button.onclick = () => {
+ const htmlElement = document.getElementsByTagName("html");
+ const isDarkMode = htmlElement[0].dataset.darkmode === "true";
+ htmlElement[0].dataset.darkmode = !isDarkMode;
+ setCookieValue(!isDarkMode);
+ };
- const setCookieValue = (value) => {
- document.cookie = `css_dark_mode=${value};max-age=31536000;path=/`
- }
+ const setCookieValue = (value) => {
+ document.cookie = `css_dark_mode=${value};max-age=31536000;path=/`
+ }
- // Search input box behaviour
+ // Search input box behaviour
const toggle_search = document.getElementById("toggle-search");
- const search_q = document.getElementById("search-q");
- window.addEventListener('keydown', function (e) {
-
- if (e.altKey == true && e.keyCode == 83)
- search_q.classList.toggle('expanded');
- search_q.focus();
- });
+ const search_q = document.getElementById("search-q");
+ if(search_q) {
+ window.addEventListener('keydown', function (e) {
+ if (e.altKey == true && e.keyCode == 83) {
+ search_q.classList.toggle('expanded');
+ search_q.focus();
+ }
+ });
-
- search_q.onkeydown = (e) => {
- var key = e.keyCode || e.which;
- if (key === 13) {
- document.searchForm.submit();
- }
- };
- toggle_search.onclick = () => {
- // Could be that they want to search something once text is in there
- if (search_q.value.length) {
- document.searchForm.submit();
- } else {
- // If not..
- search_q.classList.toggle('expanded');
- search_q.focus();
+ search_q.onkeydown = (e) => {
+ var key = e.keyCode || e.which;
+ if (key === 13) {
+ document.searchForm.submit();
+ }
+ };
+ toggle_search.onclick = () => {
+ // Could be that they want to search something once text is in there
+ if (search_q.value.length) {
+ document.searchForm.submit();
+ } else {
+ // If not..
+ search_q.classList.toggle('expanded');
+ search_q.focus();
+ }
+ };
}
- };
+ $('#heart-us').click(function () {
+ $("#overlay").toggleClass('visible');
+ heartpath.style.fill = document.getElementById("overlay").classList.contains("visible") ? '#ff0000' : 'var(--color-background)';
+ });
});
diff --git a/changedetectionio/static/styles/scss/parts/_darkmode.scss b/changedetectionio/static/styles/scss/parts/_darkmode.scss
index a9719d3c..6a80ecf6 100644
--- a/changedetectionio/static/styles/scss/parts/_darkmode.scss
+++ b/changedetectionio/static/styles/scss/parts/_darkmode.scss
@@ -1,6 +1,6 @@
#toggle-light-mode {
- width: 3rem;
+/* width: 3rem;*/
/* default */
.icon-dark {
display: none;
diff --git a/changedetectionio/static/styles/scss/parts/_love.scss b/changedetectionio/static/styles/scss/parts/_love.scss
new file mode 100644
index 00000000..d2aad23d
--- /dev/null
+++ b/changedetectionio/static/styles/scss/parts/_love.scss
@@ -0,0 +1,38 @@
+#overlay {
+
+ opacity: 0.95;
+ position: fixed;
+
+ width: 350px;
+ max-width: 100%;
+ height: 100%;
+ top: 0;
+ right: -350px;
+ background-color: var(--color-table-stripe);
+ z-index: 2;
+
+ transform: translateX(0);
+ transition: transform .5s ease;
+
+
+ &.visible {
+ transform: translateX(-100%);
+
+ }
+
+ .content {
+ font-size: 0.875rem;
+ padding: 1rem;
+ margin-top: 5rem;
+ max-width: 400px;
+ color: var(--color-watch-table-row-text);
+ }
+}
+
+#heartpath {
+ &:hover {
+ fill: #ff0000 !important;
+ transition: all ease 0.3s !important;
+ }
+ transition: all ease 0.3s !important;
+}
diff --git a/changedetectionio/static/styles/scss/parts/_menu.scss b/changedetectionio/static/styles/scss/parts/_menu.scss
new file mode 100644
index 00000000..22322eb8
--- /dev/null
+++ b/changedetectionio/static/styles/scss/parts/_menu.scss
@@ -0,0 +1,25 @@
+.pure-menu-link {
+ padding: 0.5rem 1em;
+ line-height: 1.2rem;
+}
+
+.pure-menu-item {
+ svg {
+ height: 1.2rem;
+ }
+ * {
+ vertical-align: middle;
+ }
+ .github-link {
+ height: 1.8rem;
+ display: block;
+ svg {
+ height: 100%;
+ }
+ }
+ .bi-heart {
+ &:hover {
+ cursor: pointer;
+ }
+ }
+}
diff --git a/changedetectionio/static/styles/scss/styles.scss b/changedetectionio/static/styles/scss/styles.scss
index 77cee346..ed98a1c6 100644
--- a/changedetectionio/static/styles/scss/styles.scss
+++ b/changedetectionio/static/styles/scss/styles.scss
@@ -10,10 +10,13 @@
@import "parts/_spinners";
@import "parts/_variables";
@import "parts/_darkmode";
+@import "parts/_menu";
+@import "parts/_love";
body {
color: var(--color-text);
background: var(--color-background-page);
+ font-family: Helvetica Neue, Helvetica, Lucida Grande, Arial, Ubuntu, Cantarell, Fira Sans, sans-serif;
}
.visually-hidden {
@@ -56,11 +59,6 @@ a.github-link {
}
}
-
-#toggle-search {
- width: 2rem;
-}
-
#search-q {
opacity: 0;
-webkit-transition: all .9s ease;
@@ -1083,3 +1081,4 @@ ul {
border-radius: 3px;
white-space: nowrap;
}
+
diff --git a/changedetectionio/static/styles/styles.css b/changedetectionio/static/styles/styles.css
index 3431d250..c1865879 100644
--- a/changedetectionio/static/styles/styles.css
+++ b/changedetectionio/static/styles/styles.css
@@ -352,7 +352,7 @@ html[data-darkmode="true"] {
color: var(--color-watch-table-error); }
#toggle-light-mode {
- width: 3rem;
+ /* width: 3rem;*/
/* default */ }
#toggle-light-mode .icon-dark {
display: none; }
@@ -363,9 +363,56 @@ html[data-darkmode="true"] #toggle-light-mode .icon-light {
html[data-darkmode="true"] #toggle-light-mode .icon-dark {
display: block; }
+.pure-menu-link {
+ padding: 0.5rem 1em;
+ line-height: 1.2rem; }
+
+.pure-menu-item svg {
+ height: 1.2rem; }
+
+.pure-menu-item * {
+ vertical-align: middle; }
+
+.pure-menu-item .github-link {
+ height: 1.8rem;
+ display: block; }
+ .pure-menu-item .github-link svg {
+ height: 100%; }
+
+.pure-menu-item .bi-heart:hover {
+ cursor: pointer; }
+
+#overlay {
+ opacity: 0.95;
+ position: fixed;
+ width: 350px;
+ max-width: 100%;
+ height: 100%;
+ top: 0;
+ right: -350px;
+ background-color: var(--color-table-stripe);
+ z-index: 2;
+ transform: translateX(0);
+ transition: transform .5s ease; }
+ #overlay.visible {
+ transform: translateX(-100%); }
+ #overlay .content {
+ font-size: 0.875rem;
+ padding: 1rem;
+ margin-top: 5rem;
+ max-width: 400px;
+ color: var(--color-watch-table-row-text); }
+
+#heartpath {
+ transition: all ease 0.3s !important; }
+ #heartpath:hover {
+ fill: #ff0000 !important;
+ transition: all ease 0.3s !important; }
+
body {
color: var(--color-text);
- background: var(--color-background-page); }
+ background: var(--color-background-page);
+ font-family: Helvetica Neue, Helvetica, Lucida Grande, Arial, Ubuntu, Cantarell, Fira Sans, sans-serif; }
.visually-hidden {
clip: rect(0 0 0 0);
@@ -397,9 +444,6 @@ a.github-link {
a.github-link:hover {
color: var(--color-icon-github-hover); }
-#toggle-search {
- width: 2rem; }
-
#search-q {
opacity: 0;
-webkit-transition: all .9s ease;
diff --git a/changedetectionio/templates/base.html b/changedetectionio/templates/base.html
index e8ef295a..92cf242d 100644
--- a/changedetectionio/templates/base.html
+++ b/changedetectionio/templates/base.html
@@ -8,10 +8,10 @@
Change Detection{{extra_title}}
-
+
{% if extra_stylesheets %}
{% for m in extra_stylesheets %}
-
+
{% endfor %}
{% endif %}
@@ -108,6 +108,20 @@
+