@rmdes/indiekit-endpoint-podroll 1.0.6 → 1.0.8
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.
- package/assets/styles.css +80 -0
- package/lib/controllers/dashboard.js +72 -26
- package/package.json +2 -1
- package/views/dashboard.njk +53 -223
- package/views/layouts/podroll.njk +6 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/* Podroll endpoint styles */
|
|
2
|
+
|
|
3
|
+
/* Stats grid */
|
|
4
|
+
.podroll-stats {
|
|
5
|
+
display: grid;
|
|
6
|
+
gap: var(--space-s);
|
|
7
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.podroll-stat {
|
|
11
|
+
background: var(--color-offset);
|
|
12
|
+
border-radius: var(--radius-m);
|
|
13
|
+
padding: var(--space-s);
|
|
14
|
+
text-align: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.podroll-stat dt {
|
|
18
|
+
color: var(--color-text-secondary);
|
|
19
|
+
font-size: var(--step--1);
|
|
20
|
+
margin-block-end: var(--space-3xs);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.podroll-stat dd {
|
|
24
|
+
font-size: var(--step-1);
|
|
25
|
+
font-weight: var(--font-weight-semibold);
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* Settings form */
|
|
30
|
+
.podroll-form {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
gap: var(--space-m);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.podroll-field {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
gap: var(--space-3xs);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.podroll-field-static {
|
|
43
|
+
align-items: baseline;
|
|
44
|
+
border-block-start: 1px solid var(--color-border);
|
|
45
|
+
display: flex;
|
|
46
|
+
justify-content: space-between;
|
|
47
|
+
padding: var(--space-2xs) 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.podroll-field-static dt {
|
|
51
|
+
color: var(--color-text-secondary);
|
|
52
|
+
font-size: var(--step--1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.podroll-field-static dd {
|
|
56
|
+
font-size: var(--step--1);
|
|
57
|
+
margin: 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* API list */
|
|
61
|
+
.podroll-api-list {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
gap: var(--space-xs);
|
|
65
|
+
list-style: none;
|
|
66
|
+
margin: 0;
|
|
67
|
+
padding: 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.podroll-api-list li {
|
|
71
|
+
background: var(--color-offset);
|
|
72
|
+
border-radius: var(--radius-s);
|
|
73
|
+
font-size: var(--step--1);
|
|
74
|
+
padding: var(--space-xs) var(--space-s);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.podroll-api-list code {
|
|
78
|
+
color: var(--color-accent);
|
|
79
|
+
font-weight: var(--font-weight-semibold);
|
|
80
|
+
}
|
|
@@ -23,6 +23,22 @@ async function getEffectiveUrls(db, podrollConfig) {
|
|
|
23
23
|
return { episodesUrl, opmlUrl };
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Extract and clear flash messages from session
|
|
28
|
+
* Returns { success, error } for Indiekit's native notificationBanner
|
|
29
|
+
*/
|
|
30
|
+
function consumeFlashMessage(request) {
|
|
31
|
+
const result = {};
|
|
32
|
+
if (request.session?.messages?.length) {
|
|
33
|
+
const msg = request.session.messages[0];
|
|
34
|
+
if (msg.type === "success") result.success = msg.content;
|
|
35
|
+
else if (msg.type === "error" || msg.type === "warning")
|
|
36
|
+
result.error = msg.content;
|
|
37
|
+
request.session.messages = null;
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
26
42
|
/**
|
|
27
43
|
* Dashboard controller for admin UI
|
|
28
44
|
*/
|
|
@@ -44,12 +60,17 @@ export const dashboardController = {
|
|
|
44
60
|
};
|
|
45
61
|
|
|
46
62
|
if (db) {
|
|
47
|
-
const [episodeCount, sourceCount, episodesMeta, sourcesMeta] =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
63
|
+
const [episodeCount, sourceCount, episodesMeta, sourcesMeta] =
|
|
64
|
+
await Promise.all([
|
|
65
|
+
db.collection("podrollEpisodes").countDocuments(),
|
|
66
|
+
db.collection("podrollSources").countDocuments(),
|
|
67
|
+
db
|
|
68
|
+
.collection("podrollMeta")
|
|
69
|
+
.findOne({ key: "lastEpisodesSync" }),
|
|
70
|
+
db
|
|
71
|
+
.collection("podrollMeta")
|
|
72
|
+
.findOne({ key: "lastSourcesSync" }),
|
|
73
|
+
]);
|
|
53
74
|
|
|
54
75
|
// Convert Date objects to ISO strings for Nunjucks date filter
|
|
55
76
|
const toISO = (d) => (d instanceof Date ? d.toISOString() : d);
|
|
@@ -64,6 +85,9 @@ export const dashboardController = {
|
|
|
64
85
|
|
|
65
86
|
const urls = await getEffectiveUrls(db, application.podrollConfig);
|
|
66
87
|
|
|
88
|
+
// Extract flash messages for native Indiekit notification banner
|
|
89
|
+
const flash = consumeFlashMessage(request);
|
|
90
|
+
|
|
67
91
|
response.render("dashboard", {
|
|
68
92
|
title: response.__("podroll.title"),
|
|
69
93
|
stats,
|
|
@@ -72,6 +96,8 @@ export const dashboardController = {
|
|
|
72
96
|
opmlUrl: urls.opmlUrl,
|
|
73
97
|
syncInterval: application.podrollConfig?.syncInterval || 900000,
|
|
74
98
|
},
|
|
99
|
+
mountPath: request.baseUrl,
|
|
100
|
+
...flash,
|
|
75
101
|
});
|
|
76
102
|
} catch (error) {
|
|
77
103
|
console.error("[Podroll] Dashboard error:", error);
|
|
@@ -111,14 +137,16 @@ export const dashboardController = {
|
|
|
111
137
|
);
|
|
112
138
|
|
|
113
139
|
console.log("[Podroll] Settings saved");
|
|
114
|
-
|
|
140
|
+
request.session.messages = [
|
|
141
|
+
{ type: "success", content: request.__("podroll.settingsSaved") },
|
|
142
|
+
];
|
|
143
|
+
response.redirect(request.baseUrl);
|
|
115
144
|
} catch (error) {
|
|
116
145
|
console.error("[Podroll] Settings save error:", error);
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
);
|
|
146
|
+
request.session.messages = [
|
|
147
|
+
{ type: "error", content: error.message },
|
|
148
|
+
];
|
|
149
|
+
response.redirect(request.baseUrl);
|
|
122
150
|
}
|
|
123
151
|
},
|
|
124
152
|
|
|
@@ -143,13 +171,18 @@ export const dashboardController = {
|
|
|
143
171
|
opmlUrl: urls.opmlUrl,
|
|
144
172
|
};
|
|
145
173
|
|
|
146
|
-
|
|
174
|
+
await runSync(db, syncOptions);
|
|
147
175
|
|
|
148
|
-
|
|
149
|
-
|
|
176
|
+
request.session.messages = [
|
|
177
|
+
{ type: "success", content: request.__("podroll.syncSuccess") },
|
|
178
|
+
];
|
|
179
|
+
response.redirect(request.baseUrl);
|
|
150
180
|
} catch (error) {
|
|
151
181
|
console.error("[Podroll] Sync error:", error);
|
|
152
|
-
|
|
182
|
+
request.session.messages = [
|
|
183
|
+
{ type: "error", content: error.message },
|
|
184
|
+
];
|
|
185
|
+
response.redirect(request.baseUrl);
|
|
153
186
|
}
|
|
154
187
|
},
|
|
155
188
|
|
|
@@ -170,7 +203,9 @@ export const dashboardController = {
|
|
|
170
203
|
await Promise.all([
|
|
171
204
|
db.collection("podrollEpisodes").deleteMany({}),
|
|
172
205
|
db.collection("podrollSources").deleteMany({}),
|
|
173
|
-
db
|
|
206
|
+
db
|
|
207
|
+
.collection("podrollMeta")
|
|
208
|
+
.deleteMany({ key: { $ne: "settings" } }),
|
|
174
209
|
]);
|
|
175
210
|
|
|
176
211
|
console.log("[Podroll] Cleared all data, starting fresh sync...");
|
|
@@ -183,12 +218,18 @@ export const dashboardController = {
|
|
|
183
218
|
opmlUrl: urls.opmlUrl,
|
|
184
219
|
};
|
|
185
220
|
|
|
186
|
-
|
|
221
|
+
await runSync(db, syncOptions);
|
|
187
222
|
|
|
188
|
-
|
|
223
|
+
request.session.messages = [
|
|
224
|
+
{ type: "success", content: request.__("podroll.clearSuccess") },
|
|
225
|
+
];
|
|
226
|
+
response.redirect(request.baseUrl);
|
|
189
227
|
} catch (error) {
|
|
190
228
|
console.error("[Podroll] Clear/resync error:", error);
|
|
191
|
-
|
|
229
|
+
request.session.messages = [
|
|
230
|
+
{ type: "error", content: error.message },
|
|
231
|
+
];
|
|
232
|
+
response.redirect(request.baseUrl);
|
|
192
233
|
}
|
|
193
234
|
},
|
|
194
235
|
|
|
@@ -208,12 +249,17 @@ export const dashboardController = {
|
|
|
208
249
|
});
|
|
209
250
|
}
|
|
210
251
|
|
|
211
|
-
const [episodeCount, sourceCount, episodesMeta, sourcesMeta] =
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
252
|
+
const [episodeCount, sourceCount, episodesMeta, sourcesMeta] =
|
|
253
|
+
await Promise.all([
|
|
254
|
+
db.collection("podrollEpisodes").countDocuments(),
|
|
255
|
+
db.collection("podrollSources").countDocuments(),
|
|
256
|
+
db
|
|
257
|
+
.collection("podrollMeta")
|
|
258
|
+
.findOne({ key: "lastEpisodesSync" }),
|
|
259
|
+
db
|
|
260
|
+
.collection("podrollMeta")
|
|
261
|
+
.findOne({ key: "lastSourcesSync" }),
|
|
262
|
+
]);
|
|
217
263
|
|
|
218
264
|
response.json({
|
|
219
265
|
status: "ok",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rmdes/indiekit-endpoint-podroll",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Podcast roll endpoint for Indiekit. Aggregates podcast episodes from FreshRSS, displays on frontend with OPML sidebar.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"indiekit",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
".": "./index.js"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
|
+
"assets",
|
|
36
37
|
"lib",
|
|
37
38
|
"locales",
|
|
38
39
|
"views",
|
package/views/dashboard.njk
CHANGED
|
@@ -1,250 +1,80 @@
|
|
|
1
|
-
{% extends "
|
|
1
|
+
{% extends "layouts/podroll.njk" %}
|
|
2
2
|
|
|
3
|
-
{% block
|
|
4
|
-
|
|
5
|
-
.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
gap: var(--space-xl, 2rem);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.pr-section {
|
|
12
|
-
background: var(--color-offset, #f5f5f5);
|
|
13
|
-
border-radius: var(--border-radius-small, 0.5rem);
|
|
14
|
-
padding: var(--space-m, 1.5rem);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.pr-section h2 {
|
|
18
|
-
font: var(--font-heading, bold 1.25rem/1.4 sans-serif);
|
|
19
|
-
margin-block-end: var(--space-s, 0.75rem);
|
|
20
|
-
padding-block-end: var(--space-xs, 0.5rem);
|
|
21
|
-
border-block-end: 1px solid var(--color-outline-variant, #ddd);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.pr-section p.pr-hint {
|
|
25
|
-
color: var(--color-on-offset, #666);
|
|
26
|
-
font: var(--font-caption, 0.875rem/1.4 sans-serif);
|
|
27
|
-
margin-block-end: var(--space-m, 1rem);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.pr-stats-grid {
|
|
31
|
-
display: grid;
|
|
32
|
-
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
33
|
-
gap: var(--space-s, 0.75rem);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
.pr-stat {
|
|
37
|
-
background: var(--color-background, #fff);
|
|
38
|
-
border-radius: var(--border-radius-small, 0.5rem);
|
|
39
|
-
padding: var(--space-s, 0.75rem);
|
|
40
|
-
text-align: center;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.pr-stat dt {
|
|
44
|
-
color: var(--color-on-offset, #666);
|
|
45
|
-
font: var(--font-caption, 0.875rem/1.4 sans-serif);
|
|
46
|
-
margin-block-end: var(--space-2xs, 0.25rem);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.pr-stat dd {
|
|
50
|
-
font: var(--font-subhead, bold 1.125rem/1.4 sans-serif);
|
|
51
|
-
margin: 0;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.pr-form {
|
|
55
|
-
display: flex;
|
|
56
|
-
flex-direction: column;
|
|
57
|
-
gap: var(--space-m, 1rem);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.pr-field {
|
|
61
|
-
display: flex;
|
|
62
|
-
flex-direction: column;
|
|
63
|
-
gap: var(--space-2xs, 0.25rem);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.pr-field label {
|
|
67
|
-
font: var(--font-label, bold 0.875rem/1.4 sans-serif);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.pr-field .pr-field-hint {
|
|
71
|
-
color: var(--color-on-offset, #666);
|
|
72
|
-
font: var(--font-caption, 0.875rem/1.4 sans-serif);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.pr-field input {
|
|
76
|
-
appearance: none;
|
|
77
|
-
background-color: var(--color-background, #fff);
|
|
78
|
-
border: 1px solid var(--color-outline-variant, #ccc);
|
|
79
|
-
border-radius: var(--border-radius-small, 0.25rem);
|
|
80
|
-
font: var(--font-body, 0.875rem/1.4 sans-serif);
|
|
81
|
-
padding: calc(var(--space-s, 0.75rem) / 2) var(--space-s, 0.75rem);
|
|
82
|
-
width: 100%;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.pr-field input:focus {
|
|
86
|
-
border-color: var(--color-primary, #0066cc);
|
|
87
|
-
outline: 2px solid var(--color-primary, #0066cc);
|
|
88
|
-
outline-offset: 1px;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
.pr-field-static {
|
|
92
|
-
display: flex;
|
|
93
|
-
justify-content: space-between;
|
|
94
|
-
align-items: baseline;
|
|
95
|
-
padding: calc(var(--space-s, 0.75rem) / 2) 0;
|
|
96
|
-
border-block-start: 1px solid var(--color-outline-variant, #eee);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.pr-field-static dt {
|
|
100
|
-
color: var(--color-on-offset, #666);
|
|
101
|
-
font: var(--font-caption, 0.875rem/1.4 sans-serif);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.pr-field-static dd {
|
|
105
|
-
margin: 0;
|
|
106
|
-
font: var(--font-body, 0.875rem/1.4 sans-serif);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
.pr-api-list {
|
|
110
|
-
list-style: none;
|
|
111
|
-
padding: 0;
|
|
112
|
-
margin: 0;
|
|
113
|
-
display: flex;
|
|
114
|
-
flex-direction: column;
|
|
115
|
-
gap: var(--space-xs, 0.5rem);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.pr-api-list li {
|
|
119
|
-
background: var(--color-background, #fff);
|
|
120
|
-
border-radius: var(--border-radius-small, 0.25rem);
|
|
121
|
-
padding: var(--space-xs, 0.5rem) var(--space-s, 0.75rem);
|
|
122
|
-
font: var(--font-caption, 0.875rem/1.4 sans-serif);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.pr-api-list code {
|
|
126
|
-
font-weight: 600;
|
|
127
|
-
color: var(--color-primary, #0066cc);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
.pr-notification {
|
|
131
|
-
border-radius: var(--border-radius-small, 0.25rem);
|
|
132
|
-
padding: var(--space-s, 0.75rem) var(--space-m, 1rem);
|
|
133
|
-
margin-block-end: var(--space-s, 0.75rem);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.pr-notification--success {
|
|
137
|
-
background: var(--color-success, #d4edda);
|
|
138
|
-
color: var(--color-on-success, #155724);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.pr-notification--error {
|
|
142
|
-
background: var(--color-error, #f8d7da);
|
|
143
|
-
color: var(--color-on-error, #721c24);
|
|
144
|
-
}
|
|
145
|
-
</style>
|
|
146
|
-
|
|
147
|
-
<header class="page-header">
|
|
148
|
-
<h1 class="page-header__title">{{ __("podroll.title") }}</h1>
|
|
149
|
-
<p class="page-header__description">{{ __("podroll.description") }}</p>
|
|
150
|
-
</header>
|
|
151
|
-
|
|
152
|
-
{% if request.query.synced %}
|
|
153
|
-
<div class="pr-notification pr-notification--success">
|
|
154
|
-
{{ __("podroll.syncSuccess") }}
|
|
155
|
-
</div>
|
|
156
|
-
{% endif %}
|
|
157
|
-
|
|
158
|
-
{% if request.query.cleared %}
|
|
159
|
-
<div class="pr-notification pr-notification--success">
|
|
160
|
-
{{ __("podroll.clearSuccess") }}
|
|
161
|
-
</div>
|
|
162
|
-
{% endif %}
|
|
163
|
-
|
|
164
|
-
{% if request.query.saved %}
|
|
165
|
-
<div class="pr-notification pr-notification--success">
|
|
166
|
-
{{ __("podroll.settingsSaved") }}
|
|
167
|
-
</div>
|
|
168
|
-
{% endif %}
|
|
169
|
-
|
|
170
|
-
{% if request.query.error %}
|
|
171
|
-
<div class="pr-notification pr-notification--error">
|
|
172
|
-
{{ __("podroll.syncError") }}: {{ request.query.error }}
|
|
173
|
-
</div>
|
|
174
|
-
{% endif %}
|
|
175
|
-
|
|
176
|
-
<div class="pr-dashboard">
|
|
177
|
-
<section class="pr-section">
|
|
178
|
-
<h2>{{ __("podroll.stats") }}</h2>
|
|
179
|
-
<dl class="pr-stats-grid">
|
|
180
|
-
<div class="pr-stat">
|
|
3
|
+
{% block podroll %}
|
|
4
|
+
{# Stats #}
|
|
5
|
+
{% call section({ title: __("podroll.stats") }) %}
|
|
6
|
+
<dl class="podroll-stats">
|
|
7
|
+
<div class="podroll-stat">
|
|
181
8
|
<dt>{{ __("podroll.episodeCount") }}</dt>
|
|
182
9
|
<dd>{{ stats.episodeCount }}</dd>
|
|
183
10
|
</div>
|
|
184
|
-
<div class="
|
|
11
|
+
<div class="podroll-stat">
|
|
185
12
|
<dt>{{ __("podroll.sourceCount") }}</dt>
|
|
186
13
|
<dd>{{ stats.sourceCount }}</dd>
|
|
187
14
|
</div>
|
|
188
|
-
<div class="
|
|
15
|
+
<div class="podroll-stat">
|
|
189
16
|
<dt>{{ __("podroll.lastEpisodesSync") }}</dt>
|
|
190
|
-
<dd>{{ stats.lastEpisodesSync | date("PPpp")
|
|
17
|
+
<dd>{% if stats.lastEpisodesSync %}{{ stats.lastEpisodesSync | date("PPpp") }}{% else %}{{ __("podroll.never") }}{% endif %}</dd>
|
|
191
18
|
</div>
|
|
192
|
-
<div class="
|
|
19
|
+
<div class="podroll-stat">
|
|
193
20
|
<dt>{{ __("podroll.lastSourcesSync") }}</dt>
|
|
194
|
-
<dd>{{ stats.lastSourcesSync | date("PPpp")
|
|
21
|
+
<dd>{% if stats.lastSourcesSync %}{{ stats.lastSourcesSync | date("PPpp") }}{% else %}{{ __("podroll.never") }}{% endif %}</dd>
|
|
195
22
|
</div>
|
|
196
23
|
</dl>
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
<p class="
|
|
202
|
-
<form method="post" action="{{
|
|
203
|
-
<div class="
|
|
204
|
-
<label for="episodesUrl">{{ __("podroll.episodesUrl") }}</label>
|
|
205
|
-
<span class="
|
|
206
|
-
<input type="url" id="episodesUrl" name="episodesUrl" value="{{ config.episodesUrl }}" aria-describedby="episodesUrl-hint" placeholder="https://...">
|
|
24
|
+
{% endcall %}
|
|
25
|
+
|
|
26
|
+
{# Configuration #}
|
|
27
|
+
{% call section({ title: __("podroll.configuration") }) %}
|
|
28
|
+
<p class="hint">{{ __("podroll.configurationHelp") }}</p>
|
|
29
|
+
<form method="post" action="{{ mountPath }}/settings" class="podroll-form">
|
|
30
|
+
<div class="podroll-field">
|
|
31
|
+
<label class="label" for="episodesUrl">{{ __("podroll.episodesUrl") }}</label>
|
|
32
|
+
<span class="hint" id="episodesUrl-hint">{{ __("podroll.episodesUrlHelp") }}</span>
|
|
33
|
+
<input class="input" type="url" id="episodesUrl" name="episodesUrl" value="{{ config.episodesUrl }}" aria-describedby="episodesUrl-hint" placeholder="https://...">
|
|
207
34
|
</div>
|
|
208
|
-
<div class="
|
|
209
|
-
<label for="opmlUrl">{{ __("podroll.opmlUrl") }}</label>
|
|
210
|
-
<span class="
|
|
211
|
-
<input type="url" id="opmlUrl" name="opmlUrl" value="{{ config.opmlUrl }}" aria-describedby="opmlUrl-hint" placeholder="https://...">
|
|
35
|
+
<div class="podroll-field">
|
|
36
|
+
<label class="label" for="opmlUrl">{{ __("podroll.opmlUrl") }}</label>
|
|
37
|
+
<span class="hint" id="opmlUrl-hint">{{ __("podroll.opmlUrlHelp") }}</span>
|
|
38
|
+
<input class="input" type="url" id="opmlUrl" name="opmlUrl" value="{{ config.opmlUrl }}" aria-describedby="opmlUrl-hint" placeholder="https://...">
|
|
212
39
|
</div>
|
|
213
|
-
<dl class="
|
|
40
|
+
<dl class="podroll-field-static">
|
|
214
41
|
<dt>{{ __("podroll.syncInterval") }}</dt>
|
|
215
42
|
<dd>{{ (config.syncInterval / 60000) | round }} {{ __("podroll.minutes") }}</dd>
|
|
216
43
|
</dl>
|
|
217
44
|
<div>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
45
|
+
{{ button({
|
|
46
|
+
type: "submit",
|
|
47
|
+
text: __("podroll.saveSettings")
|
|
48
|
+
}) }}
|
|
221
49
|
</div>
|
|
222
50
|
</form>
|
|
223
|
-
|
|
51
|
+
{% endcall %}
|
|
224
52
|
|
|
225
|
-
|
|
226
|
-
|
|
53
|
+
{# Actions #}
|
|
54
|
+
{% call section({ title: __("podroll.actions") }) %}
|
|
227
55
|
<div class="button-group">
|
|
228
|
-
<form method="post" action="{{
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
56
|
+
<form method="post" action="{{ mountPath }}/sync" style="display: inline;">
|
|
57
|
+
{{ button({
|
|
58
|
+
type: "submit",
|
|
59
|
+
text: __("podroll.syncNow")
|
|
60
|
+
}) }}
|
|
232
61
|
</form>
|
|
233
|
-
<form method="post" action="{{
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
62
|
+
<form method="post" action="{{ mountPath }}/clear-resync" style="display: inline;" onsubmit="return confirm('{{ __("podroll.clearConfirm") }}');">
|
|
63
|
+
{{ button({
|
|
64
|
+
classes: "button--secondary",
|
|
65
|
+
type: "submit",
|
|
66
|
+
text: __("podroll.clearResync")
|
|
67
|
+
}) }}
|
|
237
68
|
</form>
|
|
238
69
|
</div>
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
<ul class="
|
|
244
|
-
<li><code>GET {{
|
|
245
|
-
<li><code>GET {{
|
|
246
|
-
<li><code>GET {{
|
|
70
|
+
{% endcall %}
|
|
71
|
+
|
|
72
|
+
{# API Endpoints #}
|
|
73
|
+
{% call section({ title: __("podroll.apiEndpoints") }) %}
|
|
74
|
+
<ul class="podroll-api-list">
|
|
75
|
+
<li><code>GET {{ mountPath }}/api/episodes</code> - {{ __("podroll.apiEpisodes") }}</li>
|
|
76
|
+
<li><code>GET {{ mountPath }}/api/sources</code> - {{ __("podroll.apiSources") }}</li>
|
|
77
|
+
<li><code>GET {{ mountPath }}/api/status</code> - {{ __("podroll.apiStatus") }}</li>
|
|
247
78
|
</ul>
|
|
248
|
-
|
|
249
|
-
</div>
|
|
79
|
+
{% endcall %}
|
|
250
80
|
{% endblock %}
|