structables 0.4.3__tar.gz → 0.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {structables-0.4.3 → structables-0.4.4}/.forgejo/workflows/docker.yml +7 -1
- {structables-0.4.3 → structables-0.4.4}/PKG-INFO +1 -1
- {structables-0.4.3 → structables-0.4.4}/pyproject.toml +1 -1
- {structables-0.4.3 → structables-0.4.4}/src/structables/routes/main.py +95 -46
- {structables-0.4.3 → structables-0.4.4}/.dockerignore +0 -0
- {structables-0.4.3 → structables-0.4.4}/.env.example +0 -0
- {structables-0.4.3 → structables-0.4.4}/.forgejo/workflows/release.yml +0 -0
- {structables-0.4.3 → structables-0.4.4}/.gitignore +0 -0
- {structables-0.4.3 → structables-0.4.4}/Dockerfile +0 -0
- {structables-0.4.3 → structables-0.4.4}/LICENSE +0 -0
- {structables-0.4.3 → structables-0.4.4}/README.md +0 -0
- {structables-0.4.3 → structables-0.4.4}/cronjob.txt +0 -0
- {structables-0.4.3 → structables-0.4.4}/docker-compose-example-dev.yml +0 -0
- {structables-0.4.3 → structables-0.4.4}/docker-compose-example.yml +0 -0
- {structables-0.4.3 → structables-0.4.4}/entrypoint.sh +0 -0
- {structables-0.4.3 → structables-0.4.4}/instances.json +0 -0
- {structables-0.4.3 → structables-0.4.4}/renovate.json +0 -0
- {structables-0.4.3 → structables-0.4.4}/requirements-dev.txt +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/__init__.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/config.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/main.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/routes/__init__.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/routes/category.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/routes/contest.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/routes/member.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/routes/proxy.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/static/css/iframe.css +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/static/css/style.css +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/static/img/logo.png +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/static/img/logo_lg.png +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/static/img/magnifying-glass-solid.svg +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/400.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/404.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/429.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/500.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/archives.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/article-review.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/article.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/base.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/category.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/collection.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/contest.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/contests.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/footer.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/header.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/iframe.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/index.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/member-instructables.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/member.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/privacypolicy.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/projects.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/sitemap.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/templates/style.html +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/utils/data.py +0 -0
- {structables-0.4.3 → structables-0.4.4}/src/structables/utils/helpers.py +0 -0
|
@@ -11,8 +11,14 @@ jobs:
|
|
|
11
11
|
name: Docker Build and Push to Docker Hub
|
|
12
12
|
runs-on: docker-privileged
|
|
13
13
|
container:
|
|
14
|
-
image:
|
|
14
|
+
image: node:22-bookworm
|
|
15
|
+
options: >-
|
|
16
|
+
--privileged
|
|
15
17
|
steps:
|
|
18
|
+
- name: Install dependencies
|
|
19
|
+
run: |
|
|
20
|
+
apt update
|
|
21
|
+
apt install -y docker.io
|
|
16
22
|
- name: Set up QEMU
|
|
17
23
|
uses: docker/setup-qemu-action@v3
|
|
18
24
|
- name: Set up Docker Buildx
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: structables
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.4
|
|
4
4
|
Summary: A simple frontend for Instructables
|
|
5
5
|
Project-URL: Homepage, https://git.private.coffee/privatecoffee/structables
|
|
6
6
|
Project-URL: Bug Tracker, https://git.private.coffee/privatecoffee/structables/issues
|
|
@@ -23,60 +23,109 @@ def init_main_routes(app):
|
|
|
23
23
|
@app.route("/")
|
|
24
24
|
def route_explore():
|
|
25
25
|
logger.debug("Rendering explore page")
|
|
26
|
-
|
|
27
|
-
# Check if data needs to be updated
|
|
28
26
|
maybe_update_data(app)
|
|
29
27
|
|
|
30
28
|
try:
|
|
31
|
-
|
|
29
|
+
# Extract API endpoints from the JSON context data
|
|
30
|
+
logger.debug("Fetching data from instructables.com API")
|
|
32
31
|
data = urlopen("https://www.instructables.com/")
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
soup = BeautifulSoup(data.read().decode(), "html.parser")
|
|
33
|
+
|
|
34
|
+
# Try to extract JSON data from script tag
|
|
35
|
+
page_context = None
|
|
36
|
+
script_tag = soup.select("#js-page-context")
|
|
37
|
+
if script_tag:
|
|
38
|
+
try:
|
|
39
|
+
page_context = json.loads(script_tag[0].string)
|
|
40
|
+
logger.debug("Successfully extracted page context JSON")
|
|
41
|
+
except Exception as e:
|
|
42
|
+
logger.error(f"Error parsing page context JSON: {str(e)}")
|
|
43
|
+
|
|
44
|
+
# Use the API endpoints to fetch category data
|
|
45
|
+
categories = [
|
|
46
|
+
"circuits",
|
|
47
|
+
"workshop",
|
|
48
|
+
"design",
|
|
49
|
+
"craft",
|
|
50
|
+
"cooking",
|
|
51
|
+
"living",
|
|
52
|
+
"outside",
|
|
53
|
+
"teachers",
|
|
54
|
+
]
|
|
55
|
+
sections = []
|
|
56
|
+
|
|
57
|
+
for category in categories:
|
|
58
|
+
try:
|
|
59
|
+
# Use the appropriate API endpoint for each category
|
|
60
|
+
api_url = f"https://www.instructables.com/json-api/getHomepageFeatured?limit=5&category={category}"
|
|
61
|
+
logger.debug(
|
|
62
|
+
f"Fetching data for category {category} from {api_url}"
|
|
63
|
+
)
|
|
36
64
|
|
|
37
|
-
|
|
65
|
+
category_data = urlopen(api_url)
|
|
66
|
+
category_json = json.loads(category_data.read().decode())
|
|
67
|
+
|
|
68
|
+
# Process category items
|
|
69
|
+
category_items = []
|
|
70
|
+
for item in category_json["items"]:
|
|
71
|
+
category_items.append(
|
|
72
|
+
{
|
|
73
|
+
"title": item["title"],
|
|
74
|
+
"link": item["url"],
|
|
75
|
+
"img": (
|
|
76
|
+
proxy(item["downloadUrl"])
|
|
77
|
+
if "downloadUrl" in item
|
|
78
|
+
else ""
|
|
79
|
+
),
|
|
80
|
+
"author": item["author"] if "author" in item else "",
|
|
81
|
+
"channel": (
|
|
82
|
+
item["classifications"][0]["channels"][0]["title"]
|
|
83
|
+
if "classifications" in item
|
|
84
|
+
and item["classifications"]
|
|
85
|
+
else ""
|
|
86
|
+
),
|
|
87
|
+
"channel_link": (
|
|
88
|
+
f"/{item['classifications'][0]['name']}/{item['classifications'][0]['channels'][0]['name']}/"
|
|
89
|
+
if "classifications" in item
|
|
90
|
+
and item["classifications"]
|
|
91
|
+
else ""
|
|
92
|
+
),
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
sections.append(
|
|
97
|
+
(category.capitalize(), f"/{category}", category_items)
|
|
98
|
+
)
|
|
99
|
+
logger.debug(
|
|
100
|
+
f"Processed {len(category_items)} items for category {category}"
|
|
101
|
+
)
|
|
38
102
|
|
|
39
|
-
|
|
103
|
+
except Exception as e:
|
|
104
|
+
logger.error(f"Error processing category {category}: {str(e)}")
|
|
105
|
+
raise
|
|
106
|
+
sections.append((category.capitalize(), f"/{category}", []))
|
|
40
107
|
|
|
41
|
-
|
|
42
|
-
logger.debug(f"Explore page title: {title}")
|
|
108
|
+
return render_template("index.html", title="Explore", sections=sections)
|
|
43
109
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
48
|
-
workshop = explore_lists(
|
|
49
|
-
explore.select(".home-content-explore-category-workshop")[0]
|
|
50
|
-
)
|
|
51
|
-
craft = explore_lists(explore.select(".home-content-explore-category-craft")[0])
|
|
52
|
-
cooking = explore_lists(
|
|
53
|
-
explore.select(".home-content-explore-category-cooking")[0]
|
|
54
|
-
)
|
|
55
|
-
living = explore_lists(
|
|
56
|
-
explore.select(".home-content-explore-category-living")[0]
|
|
57
|
-
)
|
|
58
|
-
outside = explore_lists(
|
|
59
|
-
explore.select(".home-content-explore-category-outside")[0]
|
|
60
|
-
)
|
|
61
|
-
teachers = explore_lists(
|
|
62
|
-
explore.select(".home-content-explore-category-teachers")[0]
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
logger.debug("Rendering explore page template")
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.error(f"Error rendering explore page: {str(e)}")
|
|
112
|
+
print_exc()
|
|
66
113
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
114
|
+
# Fallback to a static version if API fails
|
|
115
|
+
return render_template(
|
|
116
|
+
"index.html",
|
|
117
|
+
title="Explore",
|
|
118
|
+
sections=[
|
|
119
|
+
("Circuits", "/circuits", []),
|
|
120
|
+
("Workshop", "/workshop", []),
|
|
121
|
+
("Craft", "/craft", []),
|
|
122
|
+
("Cooking", "/cooking", []),
|
|
123
|
+
("Living", "/living", []),
|
|
124
|
+
("Outside", "/outside", []),
|
|
125
|
+
("Teachers", "/teachers", []),
|
|
126
|
+
],
|
|
127
|
+
message="Instructables.com recently redesigned their site. We're experiencing issues with our scraper.",
|
|
128
|
+
)
|
|
80
129
|
|
|
81
130
|
@app.route("/sitemap/")
|
|
82
131
|
@app.route("/sitemap/<path:path>")
|
|
@@ -341,7 +390,7 @@ def init_main_routes(app):
|
|
|
341
390
|
enumerate=enumerate,
|
|
342
391
|
)
|
|
343
392
|
else:
|
|
344
|
-
|
|
393
|
+
# Collections
|
|
345
394
|
logger.debug("Article is a collection")
|
|
346
395
|
thumbnails = []
|
|
347
396
|
for thumbnail in data["instructables"]:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{structables-0.4.3 → structables-0.4.4}/src/structables/static/img/magnifying-glass-solid.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|