Clickable usernames and hashtags
Should work well enough. Report edge cases.
This commit is contained in:
@@ -42,7 +42,8 @@ let constants = {
|
||||
shortcode_query_hash: "2b0673e0dc4580674a88d426fe00ea90",
|
||||
timeline_fetch_first: 12,
|
||||
username_regex: "[\\w.]+",
|
||||
shortcode_regex: "[\\w-]+"
|
||||
shortcode_regex: "[\\w-]+",
|
||||
hashtag_regex: "[\\w]+"
|
||||
},
|
||||
|
||||
resources: {
|
||||
|
||||
@@ -2,6 +2,7 @@ const constants = require("../constants")
|
||||
const {proxyImage, proxyExtendedOwner} = require("../utils/proxyurl")
|
||||
const {compile} = require("pug")
|
||||
const collectors = require("../collectors")
|
||||
const {structure} = require("../utils/structuretext")
|
||||
const TimelineBaseMethods = require("./TimelineBaseMethods")
|
||||
const TimelineChild = require("./TimelineChild")
|
||||
require("../testimports")(collectors, TimelineChild, TimelineBaseMethods)
|
||||
@@ -87,6 +88,12 @@ class TimelineEntry extends TimelineBaseMethods {
|
||||
else return edge.node.text.replace(/\u2063/g, "") // I don't know why U+2063 INVISIBLE SEPARATOR is in here, but it is, and it causes rendering issues with certain fonts, so let's just remove it.
|
||||
}
|
||||
|
||||
getStructuredCaption() {
|
||||
const caption = this.getCaption()
|
||||
if (!caption) return null // no caption
|
||||
else return structure(caption)
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the first meaningful line or sentence from the caption.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const constants = require("../constants")
|
||||
const {proxyImage} = require("../utils/proxyurl")
|
||||
const {structure} = require("../utils/structuretext")
|
||||
const Timeline = require("./Timeline")
|
||||
require("../testimports")(constants, Timeline)
|
||||
|
||||
@@ -17,6 +18,11 @@ class User {
|
||||
this.proxyProfilePicture = proxyImage(this.data.profile_pic_url)
|
||||
}
|
||||
|
||||
getStructuredBio() {
|
||||
if (!this.data.biography) return null
|
||||
return structure(this.data.biography)
|
||||
}
|
||||
|
||||
getTtl(scale = 1) {
|
||||
const expiresAt = this.cachedAt + constants.caching.resource_cache_time
|
||||
const ttl = expiresAt - Date.now()
|
||||
|
||||
53
src/lib/utils/structuretext.js
Normal file
53
src/lib/utils/structuretext.js
Normal file
@@ -0,0 +1,53 @@
|
||||
const constants = require("../constants")
|
||||
const {Parser} = require("./parser/parser")
|
||||
|
||||
function tryMatch(text, against, callback) {
|
||||
let matched = text.match(against)
|
||||
if (matched) callback(matched)
|
||||
}
|
||||
|
||||
function textToParts(text) {
|
||||
return [{type: "text", text: text}]
|
||||
}
|
||||
|
||||
function replacePart(parts, index, match, replacements) {
|
||||
const toReplace = parts.splice(index, 1)[0]
|
||||
const before = toReplace.text.slice(0, match.index)
|
||||
const after = toReplace.text.slice(match.index + match[0].length)
|
||||
parts.splice(index, 0, ...textToParts(before), ...replacements, ...textToParts(after))
|
||||
}
|
||||
|
||||
function partsUsername(parts) {
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
if (parts[i].type === "text") {
|
||||
tryMatch(parts[i].text, `@(${constants.external.username_regex})`, match => {
|
||||
replacePart(parts, i, match, [
|
||||
{type: "user", text: match[0], user: match[1]}
|
||||
])
|
||||
i += 1 // skip parts: user
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function partsHashtag(parts) {
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
if (parts[i].type === "text") {
|
||||
tryMatch(parts[i].text, `#(${constants.external.hashtag_regex})`, match => {
|
||||
replacePart(parts, i, match, [
|
||||
{type: "hashtag", text: match[0], hashtag: match[1]}
|
||||
])
|
||||
i += 1 // skip parts: hashtag
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function structure(text) {
|
||||
const parts = textToParts(text)
|
||||
partsUsername(parts)
|
||||
partsHashtag(parts)
|
||||
return parts
|
||||
}
|
||||
|
||||
module.exports.structure = structure
|
||||
Reference in New Issue
Block a user