Fix old Reddit comment discovery
This commit is contained in:
parent
1a9ab6ebdf
commit
803df7feee
5 changed files with 50 additions and 12 deletions
|
|
@ -78,7 +78,7 @@ export class DefinitionEngine {
|
|||
const matches = Array.from(post.querySelectorAll(selector));
|
||||
const contents = post.matches(selector) ? [post, ...matches] : matches;
|
||||
for (const content of contents) {
|
||||
const text = visibleText(content, this.definition.post.excludedSelectors ?? []);
|
||||
const text = visibleText(content, this.definition.post.excludedSelectors ?? [], post);
|
||||
if (text) return text;
|
||||
}
|
||||
}
|
||||
|
|
@ -140,13 +140,19 @@ function wildcardMatches(pattern: string, value: string): boolean {
|
|||
|
||||
function escapeRegex(value: string): string { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }
|
||||
|
||||
function visibleText(element: Element, excludedSelectors: string[]): string {
|
||||
function visibleText(element: Element, excludedSelectors: string[], postBoundary: Element): string {
|
||||
const chunks: string[] = [];
|
||||
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
||||
let node: Node | null;
|
||||
while ((node = walker.nextNode())) {
|
||||
const parent = node.parentElement;
|
||||
if (!parent || excludedSelectors.some((selector) => parent.closest(selector))) continue;
|
||||
// An excluded container only applies when it is inside this post's
|
||||
// boundary. Nested Reddit comments are themselves inside an ancestor
|
||||
// `.child` container, which must not exclude the comment's own text.
|
||||
if (!parent || excludedSelectors.some((selector) => {
|
||||
const excluded = parent.closest(selector);
|
||||
return excluded !== null && postBoundary.contains(excluded);
|
||||
})) continue;
|
||||
if (isVisible(parent, element)) chunks.push(node.textContent ?? "");
|
||||
}
|
||||
return normalizeText(chunks.join(" "));
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@
|
|||
"https://old.reddit.com/*"
|
||||
],
|
||||
"requiredSelectors": [
|
||||
"#siteTable .thing.link, #siteTable .thing.comment"
|
||||
"#siteTable .thing.link, .commentarea .thing.comment > .entry"
|
||||
],
|
||||
"post": {
|
||||
"rootSelectors": [
|
||||
"#siteTable > .thing.link",
|
||||
"#siteTable .thing.comment"
|
||||
".commentarea .thing.comment > .entry"
|
||||
],
|
||||
"textSelectors": [
|
||||
".md",
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
"id": "reddit-old",
|
||||
"name": "Reddit (old interface)",
|
||||
"urlPatterns": ["https://old.reddit.com/*"],
|
||||
"requiredSelectors": ["#siteTable .thing.link, #siteTable .thing.comment"],
|
||||
"requiredSelectors": ["#siteTable .thing.link, .commentarea .thing.comment > .entry"],
|
||||
"post": {
|
||||
"rootSelectors": ["#siteTable > .thing.link", "#siteTable .thing.comment"],
|
||||
"rootSelectors": ["#siteTable > .thing.link", ".commentarea .thing.comment > .entry"],
|
||||
"textSelectors": [".md", ".title"],
|
||||
"excludedSelectors": [".expando", ".child"],
|
||||
"idAttributes": ["data-fullname"],
|
||||
|
|
|
|||
|
|
@ -95,12 +95,35 @@ describe("DefinitionEngine", () => {
|
|||
expect(posts.map((post) => post.text)).toEqual(["the main post on the threads detail page", "a reply on the threads detail page"]);
|
||||
});
|
||||
|
||||
it("discovers posts from the old Reddit interface using fullname IDs", () => {
|
||||
it("discovers old Reddit posts and comment entries from their separate page containers", () => {
|
||||
document.body.innerHTML = readFileSync("tests/fixtures/reddit-old-feed.html", "utf8");
|
||||
const reddit = BUILTIN_DEFINITIONS.find((candidate) => candidate.id === "reddit-old")!;
|
||||
const posts = new DefinitionEngine(reddit).discover(document);
|
||||
expect(posts.map((post) => post.id)).toEqual(["reddit-old:t3_abc123", "reddit-old:t1_def456"]);
|
||||
expect(posts.map((post) => post.text)).toEqual(["the post body with visible text.", "a useful comment with visible text."]);
|
||||
expect(posts.map((post) => post.id)).toEqual([
|
||||
"reddit-old:t3_abc123",
|
||||
"reddit-old:https://old.reddit.com/r/example/comments/abc123/example_post/def456/",
|
||||
"reddit-old:https://old.reddit.com/r/example/comments/abc123/example_post/ghi789/"
|
||||
]);
|
||||
expect(posts.map((post) => post.text)).toEqual([
|
||||
"the post body with visible text.",
|
||||
"a useful comment with visible text.",
|
||||
"a nested reply with its own visible text."
|
||||
]);
|
||||
});
|
||||
|
||||
it("discovers old Reddit comment entries appended after observation starts", async () => {
|
||||
document.body.innerHTML = readFileSync("tests/fixtures/reddit-old-feed.html", "utf8");
|
||||
const reddit = BUILTIN_DEFINITIONS.find((candidate) => candidate.id === "reddit-old")!;
|
||||
const engine = new DefinitionEngine(reddit);
|
||||
const observed: string[] = [];
|
||||
const stop = engine.observe((posts) => observed.push(...posts.map((post) => post.text)));
|
||||
const comment = document.createElement("div");
|
||||
comment.className = "thing comment";
|
||||
comment.innerHTML = '<div class="entry"><div class="md"><p>A newly loaded reply.</p></div><a class="bylink" href="/r/example/comments/abc123/example_post/jkl012/">permalink</a></div>';
|
||||
document.querySelector(".commentarea .sitetable")?.append(comment);
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
stop();
|
||||
expect(observed).toContain("a newly loaded reply.");
|
||||
});
|
||||
|
||||
it("discovers X posts using semantic tweet markers and permalink IDs", () => {
|
||||
|
|
|
|||
13
tests/fixtures/reddit-old-feed.html
vendored
13
tests/fixtures/reddit-old-feed.html
vendored
|
|
@ -3,7 +3,16 @@
|
|||
<p class="title"><a class="title" href="https://old.reddit.com/r/example/comments/abc123/example_post/">A useful Reddit post</a></p>
|
||||
<div class="entry"><div class="expando"><div class="md">Hidden expanded media controls</div></div><div class="md"><p>The post body with visible text.</p></div></div>
|
||||
</div>
|
||||
<div class="thing comment" data-fullname="t1_def456">
|
||||
<div class="entry"><div class="md"><p>A useful comment with visible text.</p></div><a class="bylink" href="https://old.reddit.com/r/example/comments/abc123/example_post/def456/">permalink</a></div>
|
||||
</div>
|
||||
<div class="commentarea">
|
||||
<div class="sitetable nestedlisting">
|
||||
<div class="thing comment" data-fullname="t1_def456">
|
||||
<div class="entry"><div class="md"><p>A useful comment with visible text.</p></div><a class="bylink" href="https://old.reddit.com/r/example/comments/abc123/example_post/def456/">permalink</a></div>
|
||||
<div class="child">
|
||||
<div class="thing comment" data-fullname="t1_ghi789">
|
||||
<div class="entry"><div class="md"><p>A nested reply with its own visible text.</p></div><a class="bylink" href="https://old.reddit.com/r/example/comments/abc123/example_post/ghi789/">permalink</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue