Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluesky translator #3400

Merged
merged 9 commits into from
Jan 15, 2025
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions Bluesky.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
{
"translatorID": "3bba003a-ad42-457e-9ea1-547df39d9d00",
"label": "Bluesky",
"creator": "Stephan Hügel",
"target": "^https://bsky\\.app/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2024-12-06 20:35:13"
}

/*
***** BEGIN LICENSE BLOCK *****

Copyright © 2024 Stephan Hügel <[email protected]>

This file is part of Zotero.

Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.

***** END LICENSE BLOCK *****
*/

function detectWeb(doc, url) {
if (url.includes('/post/')) {
urschrei marked this conversation as resolved.
Show resolved Hide resolved
return 'forumPost';
}
return false;
}

async function doWeb(doc, url) {
await scrapeAPI(doc, url);
}

async function scrapeAPI(doc, url) {
const handle = /(?:\/profile\/)(([^/]+))/;
const postId = /(?:\/post\/)([a-zA-Z0-9]+)/;

let foundHandle = url.match(handle)[1];
let foundPostId = url.match(postId)[1];

let apiUrl = `https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=at://${foundHandle}/app.bsky.feed.post/${foundPostId}`;
let data = await ZU.requestJSON(apiUrl);
if (data.thread && data.thread.post) {
let post = data.thread.post;
let item = new Zotero.Item("forumPost");
// Main post details
// cut off titles longer than 140 characters
let title = post.record.text || "Bluesky Skeet";
if (title.length < 140) {
item.title = title;
}
else {
item.title = ZU.ellipsize(title, 140, true);
item.abstractNote = title;
// we'll keep the full text in the abstract in this case;
}
urschrei marked this conversation as resolved.
Show resolved Hide resolved
item.forumTitle = "Bluesky";
item.type = "Skeet";
item.url = url;
item.date = post.record.createdAt || post.author.createdAt;
urschrei marked this conversation as resolved.
Show resolved Hide resolved
item.language = post.record.langs ? post.record.langs.join(", ") : "en";
urschrei marked this conversation as resolved.
Show resolved Hide resolved

// Add author information
if (post.author) {
let authorName = post.author.displayName || post.author.handle;
item.creators.push(Zotero.Utilities.cleanAuthor(authorName, "author"));
}

// Add metadata for likes, reposts, etc.
if (post.likeCount !== undefined) item.extra = `Likes: ${post.likeCount}`;
if (post.repostCount !== undefined) item.extra += ` | Reposts: ${post.repostCount}`;
urschrei marked this conversation as resolved.
Show resolved Hide resolved
if (post.quoteCount !== undefined) item.extra += ` | Quotes: ${post.quoteCount}`;

// Handle embedded quote records (if any)
if (post.embed && post.embed.record && post.embed.record.value) {
let embeddedPost = post.embed.record.value;
item.notes.push(`This post is quoting a post by @${post.embed.record.author.handle}: "${embeddedPost.text}"`);
urschrei marked this conversation as resolved.
Show resolved Hide resolved
}

// Handle replies (if any)
if (data.thread.replies && data.thread.replies.length > 0) {
const date = new Date()
const utcStr = date.toUTCString()
item.notes.push(`This post had ${data.thread.replies.length} direct replies as of ${utcStr}`);
urschrei marked this conversation as resolved.
Show resolved Hide resolved
}
item.attachments.push({ document: doc, title: "Snapshot" });
item.complete();
} else {
Zotero.debug("There was an error saving the Skeet")
}
}

/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://bsky.app/profile/watershedlab.bsky.social/post/3lcl3glmdx226",
"defer": true,
"items": [
{
"itemType": "forumPost",
"title": "My first and only job in media was as a reporter on a small newspaper in England in 2002. My salary was £8700. Per year.",
"creators": [
urschrei marked this conversation as resolved.
Show resolved Hide resolved
{
"firstName": "Dan",
"lastName": "Shugar",
"creatorType": "author"
}
],
"date": "2024-12-05T16:25:35.749Z",
"extra": "Likes: 7 | Reposts: 0 | Quotes: 0",
"forumTitle": "Bluesky",
"language": "en",
"postType": "Skeet",
"url": "https://bsky.app/profile/watershedlab.bsky.social/post/3lcl3glmdx226",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [
"This post is quoting a post by @ericwickham.ca: \"Told the guy replacing my car window how much I made at my first job in radio and I feel like it deeply changed what he thought about people in media.\"",
"This post had 1 direct replies as of Fri, 06 Dec 2024 20:31:24 GMT"
],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/
Loading