Skip to content

Commit 925bcf6

Browse files
committed
Support for more content-types (as discovered in the wild)
1 parent ed816cf commit 925bcf6

File tree

6 files changed

+42
-18
lines changed

6 files changed

+42
-18
lines changed

messages/de.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"HomePage": {
77
"cancel_button": "Abbrechen",
8-
"demo_button": "Demo",
8+
"demo_button": "Demos",
99
"return_help": "Standardmäßig an der Wurzel der URL opml.xml",
1010
"return_label": "Rückkehr-URL (optional)",
1111
"show_exit_label": "Ausgangswerkzeug anzeigen",

messages/en.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"HomePage": {
77
"cancel_button": "Cancel",
8-
"demo_button": "Demo",
8+
"demo_button": "Demos",
99
"return_help": "Defaults to root of opml.xml URL",
1010
"return_label": "Return URL (optional)",
1111
"show_exit_label": "Show Exit Tool",

messages/es.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"HomePage": {
77
"cancel_button": "Cancelar",
8-
"demo_button": "Demostración",
8+
"demo_button": "Demostracións",
99
"return_help": "Por defecto a la raíz de la URL de opml.xml",
1010
"return_label": "URL de retorno (opcional)",
1111
"show_exit_label": "Mostrar herramienta de salida",

messages/fr.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
},
66
"HomePage": {
77
"cancel_button": "Annuler",
8-
"demo_button": "Démo",
8+
"demo_button": "Démos",
99
"return_help": "Par défaut à la racine de l'URL opml.xml",
1010
"return_label": "URL de retour (optionnel)",
1111
"show_exit_label": "Afficher l'outil de sortie",

src/components/ConfigForm.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default function ConfigForm() {
8484
{t("cancel_button")}
8585
</Button>
8686
<Stack direction="row" flex="1" justifyContent="flex-end" spacing={2} sx={{ backgroundColor: 'transparent' }}>
87-
<Button component={NextLink} variant="contained" href={`/view.html?url=${encodeURIComponent(constants.DEMO_URL)}&showmode=1&showlanguage=1&showexit=1&sort=name&return=/&showexit=1`}>
87+
<Button component={NextLink} variant="outlined" href={`https://www.xml.style/opml/#demos`}>
8888
{t("demo_button")}
8989
</Button>
9090
</Stack>

src/lib/loadOutline.ts

+37-13
Original file line numberDiff line numberDiff line change
@@ -63,33 +63,52 @@ async function loadOutline(url_str: string):Promise<OpmlData> {
6363

6464
retVal.messages.push("Fetched url in " + (Date.now() - start) + "ms.");
6565
retVal.messages.push(
66-
`Content length: ${xml_resp.headers.get("Content-Length")}`
66+
`Content length (from header): ${xml_resp.headers.get("Content-Length")}`
6767
);
68-
const contentType = xml_resp.headers.get("Content-Type");
68+
let contentType = xml_resp.headers.get("Content-Type");
6969
retVal.messages.push(`Content type: ${contentType || "(null)"}`);
7070
if (!contentType) {
71-
retVal.errorCount++;
7271
retVal.messages.push("No content type provided.");
73-
return retVal;
72+
contentType = "";
7473
}
74+
75+
let isXml:boolean;
7576
if (
76-
!contentType.startsWith("text/xml") &&
77-
!contentType.startsWith("application/xml") &&
78-
!contentType.startsWith("text/plain")
77+
contentType.startsWith("text/xml") ||
78+
contentType.startsWith("application/xml") ||
79+
contentType.startsWith("text/x-opml")
7980
) {
81+
isXml = true;
82+
} else if (
83+
contentType.startsWith("text/plain") ||
84+
contentType.startsWith("application/octet-stream") ||
85+
contentType == ""
86+
) {
87+
isXml = false;
88+
retVal.messages.push("Content type is not XML.");
89+
} else {
8090
retVal.errorCount++;
8191
retVal.messages.push("Invalid content type: " + contentType);
8292
return retVal;
8393
}
8494

85-
const xml_str = await xml_resp.text();
95+
let xml_str:string;
96+
try {
97+
xml_str = await xml_resp.text();
98+
} catch (err: unknown) {
99+
retVal.errorCount++;
100+
retVal.messages.push("Unable to get text: " + errorMessage(err));
101+
return retVal;
102+
}
86103

87-
if (contentType.startsWith("text/plain")) {
104+
if (isXml == false) {
88105
if (xml_str.trim().startsWith("<")) {
89-
retVal.messages.push("Content type is text/plain but starts with '<'. Parsing as XML.");
106+
retVal.messages.push("Content starts with '<'. Attempting to parse as XML.");
90107
} else {
91108
retVal.errorCount++;
92-
retVal.messages.push("Content type is text/plain and does not start with '<'. Not parsing.");
109+
retVal.messages.push(
110+
"Content does not start with '<'. Not parsing."
111+
);
93112
return retVal;
94113
}
95114
}
@@ -111,17 +130,22 @@ async function loadOutline(url_str: string):Promise<OpmlData> {
111130
return retVal;
112131
}
113132

114-
retVal.messages.push(`Entries: ${retVal.count}`);
115-
retVal.messages.push(`Parsing complete in ${Date.now() - start}ms.`);
133+
retVal.messages.push(`XML parsing complete in ${Date.now() - start}ms.`);
116134

117135
let xmlTitle = xml_data.opml?.head?.title;
118136
if (xmlTitle && xmlTitle.indexOf("&") >= 0) {
119137
xmlTitle = he.decode(xmlTitle);
120138
}
121139
retVal.title = xmlTitle || "";
122140

141+
const outlineStart = Date.now();
123142
processNode(retVal, retVal.root, xml_data.opml.body.outline as OpmlOutline[]);
124143

144+
retVal.messages.push(`Entries: ${retVal.count}`);
145+
retVal.messages.push(`Outline parsing complete in ${Date.now() - outlineStart}ms.`);
146+
147+
retVal.messages.push(`Total time: ${Date.now() - start}ms.`);
148+
125149
retVal.success = retVal.errorCount === 0;
126150

127151
return retVal;

0 commit comments

Comments
 (0)