Skip to content

Commit a005310

Browse files
authored
Add support for organization mentions in LinkedIn (#321)
* Adds support for linking organization mentions in linkedin * Fix markdown formatting handling for organization mentions in LinkedIn posts
1 parent aa9229d commit a005310

3 files changed

Lines changed: 41 additions & 7 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,4 @@ Remember to add the env variable that needed for each social media seperatly.
163163
- Mastodon: Mentions should be in the format `username@server-domain`.
164164
- Matrix: Hashtags can be included in the post but have no special function. Mentions should be in the format `username:server-domain`.
165165
- Slack: Mentions and hashtags are not supported!
166-
- Linkedin: Mentions are not supported!
166+
- Linkedin: Mentions are only supported for organizations. The vanity name (company URL ID) should be used for this purpose.

docs/index.html

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ <h2 id="output-heading" class="text-xl font-semibold mb-2"></h2>
491491

492492
const tagContainer = document.createElement("div");
493493
tagContainer.className = "space-y-2 hidden";
494-
if (!name.includes("slack") && !name.includes("linkedin")) {
494+
if (!name.includes("slack")) {
495495
const mIn = document.createElement("input");
496496
mIn.id = `mention-${name}`;
497497
mIn.placeholder = "Mentions";
@@ -506,14 +506,16 @@ <h2 id="output-heading" class="text-xl font-semibold mb-2"></h2>
506506
let validator = null;
507507

508508
if (name.includes("bluesky")) {
509-
format = "username.server";
509+
format = "username.server (e.g. galaxyproject.bsky.social)";
510510
validator = (tag) => /^[^@:\s]+\.[^@:\s]+$/.test(tag.value);
511511
} else if (name.includes("mastodon")) {
512-
format = "username@server";
512+
format = "username@server (e.g. galaxyproject@mstdn.science)";
513513
validator = (tag) => /^[^@:\s]+@[^@:\s]+$/.test(tag.value);
514514
} else if (name.includes("matrix")) {
515-
format = "username:server";
515+
format = "username:server (e.g. bgruening:matrix.org)";
516516
validator = (tag) => /^[^@:\s]+:[^@:\s]+$/.test(tag.value);
517+
} else if (name.includes("linkedin")) {
518+
format = "vanityName (e.g. galaxy-project)";
517519
}
518520

519521
if (format) {

lib/plugins/linkedin.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,29 @@ def wrap_text_with_index(self, content):
4949
final_lines.append(f"{line} ({i}/{len(wrapped_lines)})")
5050
return final_lines
5151

52+
def build_organization_mentions(self, mentions):
53+
output = []
54+
for mention in mentions:
55+
vanity_name = mention.strip()
56+
urn = None
57+
try:
58+
response = requests.get(
59+
f"{self.api_base_url}/organizations",
60+
headers=self.headers,
61+
params={"q": "vanityName", "vanityName": vanity_name},
62+
)
63+
response.raise_for_status()
64+
elements = response.json().get("elements", [])
65+
if elements and (org_id := elements[0].get("id")):
66+
urn = f"urn:li:organization:{org_id}"
67+
mention = elements[0].get("localizedName")
68+
except Exception as e:
69+
print(f"[WARN] Failed to resolve @{mention}: {e}")
70+
output.append(f"@[{mention}]({urn})" if urn else f"@{mention}")
71+
return " ".join(output)
72+
5273
def format_content(self, content, mentions, hashtags, images, **kwargs):
53-
# the mentions are not linked to anyone!
54-
mentions = " ".join([f"@{v}" for v in mentions])
74+
mentions = self.build_organization_mentions(mentions)
5575
hashtags = " ".join([f"#{v}" for v in hashtags])
5676
if len(images) > 20:
5777
warnings = f"A maximum of 20 images, not {len(images)}, can be included in a single linkedin post."
@@ -60,11 +80,23 @@ def format_content(self, content, mentions, hashtags, images, **kwargs):
6080
warnings = ""
6181

6282
# convert markdown formatting because linkedin doesn't support it
83+
protected_mentions = {}
84+
85+
def protect(match):
86+
key = f"PROTECTED_MENTION_{len(protected_mentions)}"
87+
protected_mentions[key] = match.group(0)
88+
return key
89+
90+
content = re.sub(r"@\[[^\]]+\]\(urn:li:organization:\d+\)", protect, content)
91+
6392
paragraphs = content.split("\n\n\n")
6493
for i, p in enumerate(paragraphs):
6594
paragraphs[i] = strip_markdown_formatting(p)
6695
content = "\n\n\n".join(paragraphs)
6796

97+
for key, value in protected_mentions.items():
98+
content = content.replace(key, value)
99+
68100
content += "\n"
69101
if mentions:
70102
content = f"{content}\n{mentions}"

0 commit comments

Comments
 (0)