From 9510345e01ea8e308c339163d8e8b030ce5ac7f1 Mon Sep 17 00:00:00 2001
From: dgtlmoon
Date: Wed, 17 Jan 2024 22:35:29 +0100
Subject: [PATCH 1/9] Test - tidy up backup test (#2117)
---
changedetectionio/tests/test_backup.py | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/changedetectionio/tests/test_backup.py b/changedetectionio/tests/test_backup.py
index f03fcf37..9f381755 100644
--- a/changedetectionio/tests/test_backup.py
+++ b/changedetectionio/tests/test_backup.py
@@ -1,8 +1,8 @@
#!/usr/bin/python3
-from .util import set_original_response, set_modified_response, live_server_setup, wait_for_all_checks
+from .util import set_original_response, live_server_setup, wait_for_all_checks
from flask import url_for
-from urllib.request import urlopen
+import io
from zipfile import ZipFile
import re
import time
@@ -37,15 +37,10 @@ def test_backup(client, live_server):
# Should be PK/ZIP stream
assert res.data.count(b'PK') >= 2
- # ZipFile from buffer seems non-obvious, just save it instead
- with open("download.zip", 'wb') as f:
- f.write(res.data)
-
- zip = ZipFile('download.zip')
- l = zip.namelist()
+ backup = ZipFile(io.BytesIO(res.data))
+ l = backup.namelist()
uuid4hex = re.compile('^[a-f0-9]{8}-?[a-f0-9]{4}-?4[a-f0-9]{3}-?[89ab][a-f0-9]{3}-?[a-f0-9]{12}.*txt', re.I)
newlist = list(filter(uuid4hex.match, l)) # Read Note below
# Should be two txt files in the archive (history and the snapshot)
assert len(newlist) == 2
-
From 402f1e47e78ecd155b1e90f30cce424ff7763e0f Mon Sep 17 00:00:00 2001
From: dgtlmoon
Date: Thu, 18 Jan 2024 22:29:44 +0100
Subject: [PATCH 2/9] Security update - Adding API token secure check for API
endpoint `/api/v1/watch//history` @rozpuszczalny
---
changedetectionio/api/api_v1.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/changedetectionio/api/api_v1.py b/changedetectionio/api/api_v1.py
index 190bd449..92b4728c 100644
--- a/changedetectionio/api/api_v1.py
+++ b/changedetectionio/api/api_v1.py
@@ -133,6 +133,7 @@ class WatchHistory(Resource):
# Get a list of available history for a watch by UUID
# curl http://localhost:5000/api/v1/watch//history
+ @auth.check_token
def get(self, uuid):
"""
@api {get} /api/v1/watch//history Get a list of all historical snapshots available for a watch
From b30b718373c22eba3610cc9346b477af1c7325ad Mon Sep 17 00:00:00 2001
From: dgtlmoon
Date: Fri, 19 Jan 2024 10:24:47 +0100
Subject: [PATCH 3/9] 0.45.13
---
changedetectionio/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py
index 5dbf208e..57f2f139 100644
--- a/changedetectionio/__init__.py
+++ b/changedetectionio/__init__.py
@@ -2,7 +2,7 @@
# Read more https://github.com/dgtlmoon/changedetection.io/wiki
-__version__ = '0.45.12'
+__version__ = '0.45.13'
from distutils.util import strtobool
from json.decoder import JSONDecodeError
From 2e88872b7ea0972ba51b980e0e3c1a276bd21ef5 Mon Sep 17 00:00:00 2001
From: dgtlmoon
Date: Fri, 19 Jan 2024 23:14:55 +0100
Subject: [PATCH 4/9] Update docker-compose.yml
---
docker-compose.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/docker-compose.yml b/docker-compose.yml
index 017a9c59..a7e7e166 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -95,6 +95,7 @@ services:
# Used for fetching pages via Playwright+Chrome where you need Javascript support.
# Note: works well but is deprecated, does not fetch full page screenshots (doesnt work with Visual Selector) and other issues
+ # More information about the advantages of playwright/browserless https://www.browserless.io/blog/2023/12/13/migrating-selenium-to-playwright/
# browser-chrome:
# hostname: browser-chrome
# image: selenium/standalone-chrome:4
From 7d67ad057cc9ab0115fdf83100abf40c7375a474 Mon Sep 17 00:00:00 2001
From: Andrew Peabody
Date: Sat, 20 Jan 2024 01:03:24 -0800
Subject: [PATCH 5/9] Enable dependabot for github-actions (#2119)
---
.github/dependabot.yml | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 .github/dependabot.yml
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..67ef6cd3
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ schedule:
+ interval: "weekly"
+ groups:
+ all:
+ patterns:
+ - "*"
From 29ca2521eb663c73aaf8dc17193b49aba2b70c8c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Sat, 20 Jan 2024 11:47:14 +0100
Subject: [PATCH 6/9] Build maintenance - dependabot - Bump the all build
helpers (#2121)
---
.github/workflows/codeql-analysis.yml | 6 +++---
.github/workflows/containers.yml | 2 +-
.github/workflows/pypi-release.yml | 8 ++++----
.github/workflows/test-container-build.yml | 2 +-
.github/workflows/test-only.yml | 2 +-
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index a45f0597..5394090d 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -34,7 +34,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -45,7 +45,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@v3
# âšī¸ Command-line programs to run using the OS shell.
# đ https://git.io/JvXDl
@@ -59,4 +59,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml
index 244b4d04..0397c026 100644
--- a/.github/workflows/containers.yml
+++ b/.github/workflows/containers.yml
@@ -41,7 +41,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.11
diff --git a/.github/workflows/pypi-release.yml b/.github/workflows/pypi-release.yml
index f9839aad..0f38941f 100644
--- a/.github/workflows/pypi-release.yml
+++ b/.github/workflows/pypi-release.yml
@@ -9,7 +9,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install pypa/build
@@ -21,7 +21,7 @@ jobs:
- name: Build a binary wheel and a source tarball
run: python3 -m build
- name: Store the distribution packages
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
@@ -34,7 +34,7 @@ jobs:
- build
steps:
- name: Download all the dists
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
@@ -64,7 +64,7 @@ jobs:
steps:
- name: Download all the dists
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: python-package-distributions
path: dist/
diff --git a/.github/workflows/test-container-build.yml b/.github/workflows/test-container-build.yml
index 00857a9f..ff453523 100644
--- a/.github/workflows/test-container-build.yml
+++ b/.github/workflows/test-container-build.yml
@@ -26,7 +26,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.11
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: 3.11
diff --git a/.github/workflows/test-only.yml b/.github/workflows/test-only.yml
index 8655964f..6f762437 100644
--- a/.github/workflows/test-only.yml
+++ b/.github/workflows/test-only.yml
@@ -11,7 +11,7 @@ jobs:
# Mainly just for link/flake8
- name: Set up Python 3.11
- uses: actions/setup-python@v4
+ uses: actions/setup-python@v5
with:
python-version: '3.11'
From 04391551271ddf427d7decb35c482f2c3314b4dd Mon Sep 17 00:00:00 2001
From: dgtlmoon
Date: Mon, 22 Jan 2024 11:06:55 +0100
Subject: [PATCH 7/9] Notification - Templates - Adding an example of how to
use |tojson for JSON payloads
---
changedetectionio/templates/_common_fields.jinja | 3 +++
1 file changed, 3 insertions(+)
diff --git a/changedetectionio/templates/_common_fields.jinja b/changedetectionio/templates/_common_fields.jinja
index fa113e17..ddccaf82 100644
--- a/changedetectionio/templates/_common_fields.jinja
+++ b/changedetectionio/templates/_common_fields.jinja
@@ -115,6 +115,9 @@
Warning: Contents of {{ '{{diff}}' }}, {{ '{{diff_removed}}' }}, and {{ '{{diff_added}}' }} depend on how the difference algorithm perceives the change.
For example, an addition or removal could be perceived as a change in some cases. More Here
+
+ For JSON payloads, use |tojson without quotes for automatic escaping, for example - { "name": {{ '{{ watch_title|tojson }}' }} }
+
From 96793890f859f0a19f4811288f3c7336e71ffeaa Mon Sep 17 00:00:00 2001
From: dgtlmoon
Date: Mon, 22 Jan 2024 12:20:23 +0100
Subject: [PATCH 8/9] Notification - Templates - Adding an example of how to
use URL encoding with tokens
---
changedetectionio/templates/_common_fields.jinja | 3 +++
1 file changed, 3 insertions(+)
diff --git a/changedetectionio/templates/_common_fields.jinja b/changedetectionio/templates/_common_fields.jinja
index ddccaf82..8b44ebbd 100644
--- a/changedetectionio/templates/_common_fields.jinja
+++ b/changedetectionio/templates/_common_fields.jinja
@@ -118,6 +118,9 @@
For JSON payloads, use |tojson without quotes for automatic escaping, for example - { "name": {{ '{{ watch_title|tojson }}' }} }
+
+ URL encoding, use |urlencode, for example - gets://hook-website.com/test.php?title={{ '{{ watch_title|urlencode }}' }}
+
From 677082723ced7c0f53b43cf860384b6198e81461 Mon Sep 17 00:00:00 2001
From: dgtlmoon
Date: Tue, 23 Jan 2024 13:31:05 +0100
Subject: [PATCH 9/9] Restock tweaks - use a single regex, tidy up height
detection (#2125)
---
changedetectionio/res/stock-not-in-stock.js | 24 ++++++++++-----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/changedetectionio/res/stock-not-in-stock.js b/changedetectionio/res/stock-not-in-stock.js
index abc6578e..3d633303 100644
--- a/changedetectionio/res/stock-not-in-stock.js
+++ b/changedetectionio/res/stock-not-in-stock.js
@@ -1,3 +1,10 @@
+// Restock Detector
+// (c) Leigh Morresi dgtlmoon@gmail.com
+//
+// Assumes the product is in stock to begin with, unless the following appears above the fold ;
+// - outOfStockTexts appears above the fold (out of stock)
+// - negateOutOfStockRegex (really is in stock)
+
function isItemInStock() {
// @todo Pass these in so the same list can be used in non-JS fetchers
const outOfStockTexts = [
@@ -56,6 +63,7 @@ function isItemInStock() {
'íė '
];
+ const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0);
function getElementBaseText(element) {
// .textContent can include text from children which may give the wrong results
// scan only immediate TEXT_NODEs, which will be a child of the element
@@ -66,19 +74,13 @@ function isItemInStock() {
return text.toLowerCase().trim();
}
- const negateOutOfStockRegexs = [
- '[0-9] in stock'
- ]
- var negateOutOfStockRegexs_r = [];
- for (let i = 0; i < negateOutOfStockRegexs.length; i++) {
- negateOutOfStockRegexs_r.push(new RegExp(negateOutOfStockRegexs[0], 'g'));
- }
+ const negateOutOfStockRegex = new RegExp('([0-9] in stock|add to cart)', 'ig');
// The out-of-stock or in-stock-text is generally always above-the-fold
// and often below-the-fold is a list of related products that may or may not contain trigger text
// so it's good to filter to just the 'above the fold' elements
// and it should be atleast 100px from the top to ignore items in the toolbar, sometimes menu items like "Coming soon" exist
- const elementsToScan = Array.from(document.getElementsByTagName('*')).filter(element => element.getBoundingClientRect().top + window.scrollY <= window.innerHeight && element.getBoundingClientRect().top + window.scrollY >= 100);
+ const elementsToScan = Array.from(document.getElementsByTagName('*')).filter(element => element.getBoundingClientRect().top + window.scrollY <= vh && element.getBoundingClientRect().top + window.scrollY >= 100);
var elementText = "";
@@ -94,10 +96,8 @@ function isItemInStock() {
if (elementText.length) {
// try which ones could mean its in stock
- for (let i = 0; i < negateOutOfStockRegexs.length; i++) {
- if (negateOutOfStockRegexs_r[i].test(elementText)) {
- return 'Possibly in stock';
- }
+ if (negateOutOfStockRegex.test(elementText)) {
+ return 'Possibly in stock';
}
}
}