social media crossposting tool. 3rd time's the charm
mastodon misskey crossposting bluesky

fix b/o not using options, add option to skip encoding videos

zenfyr.dev f8af2065 d2985ac9

verified
Changed files
+35 -11
+1
README.md
···
"did": "env:BLUESKY_DID", // use a DID instead of handle (avoids handle resolution)
"pds": "env:BLUESKY_PDS", // specify Your PDS directly (avoids DID doc lookup)
"options": {
+
"encode_videos": true, // bluesky only accepts mp4 videos, try to convert if the video is not mp4
"quote_gate": false, // block users from quoting the post
"thread_gate": [ // block replies. leave empty to disable replies
"mentioned",
+2 -3
atproto2.py
···
)
return self.app.bsky.feed.post.create(repo, record)
-
def create_gates(self, options: dict, post_uri: str, time_iso: str | None = None):
+
def create_gates(self, thread_gate_opts: list[str], quote_gate: bool, post_uri: str, time_iso: str | None = None):
account = self.me
if not account:
raise Exception("Client not logged in!")
···
rkey = AtUri.from_str(post_uri).rkey
time_iso = time_iso or self.get_current_time_iso()
-
thread_gate_opts = options.get('thread_gate', [])
if 'everybody' not in thread_gate_opts:
allow = []
if thread_gate_opts:
···
self.app.bsky.feed.threadgate.create(account.did, thread_gate, rkey)
-
if options.get('quote_gate', False):
+
if quote_gate:
post_gate = models.AppBskyFeedPostgate.Record(
post=post_uri,
created_at=time_iso,
+32 -8
bluesky.py
···
class BlueskyOutputOptions:
def __init__(self, o: dict) -> None:
-
self.quote_gate = False
-
self.thread_gate = ['everybody']
+
self.quote_gate: bool = False
+
self.thread_gate: list[str] = ['everybody']
+
self.encode_videos: bool = True
quote_gate = o.get('quote_gate')
if quote_gate is not None:
···
thread_gate = o.get('thread_gate')
if thread_gate is not None:
-
if any([v not in ALLOWED_GATES for v in ALLOWED_GATES]):
+
if any([v not in ALLOWED_GATES for v in thread_gate]):
raise ValueError(f"'thread_gate' only accepts {', '.join(ALLOWED_GATES)} or [], got: {thread_gate}")
self.thread_gate = thread_gate
+
+
encode_videos = o.get('encode_videos')
+
if encode_videos is not None:
+
self.encode_videos = bool(encode_videos)
class BlueskyOutput(cross.Output):
def __init__(self, input: cross.Input, settings: dict, db: DataBaseWorker) -> None:
super().__init__(input, settings, db)
-
self.options = settings.get('options') or {}
+
self.options = BlueskyOutputOptions(settings.get('options') or {})
if not util.as_envvar(settings.get('app-password')):
raise Exception("Account app password not provided!")
···
return
if m.mime.startswith('video/'):
+
if m.mime != 'video/mp4' and not self.options.encode_videos:
+
LOGGER.info("Video is not mp4, but encoding is disabled. Skipping '%s'...", post.get_id())
+
return
+
if len(m.io) > 100_000_000:
LOGGER.error("Skipping post_id '%s', failed to download attachment! File too large?", post.get_id())
return
···
new_post = self.bsky.send_post(text, labels=labels, time_iso=post.get_post_date_iso())
root_ref = models.create_strong_ref(new_post)
-
self.bsky.create_gates(self.options, new_post.uri, time_iso=post.get_post_date_iso())
+
self.bsky.create_gates(
+
self.options.thread_gate,
+
self.options.quote_gate,
+
new_post.uri,
+
time_iso=post.get_post_date_iso()
+
)
reply_ref = models.create_strong_ref(new_post)
created_records.append(new_post)
else:
···
if not root_ref:
root_ref = models.create_strong_ref(new_post)
-
self.bsky.create_gates(self.options, new_post.uri, time_iso=post.get_post_date_iso())
+
self.bsky.create_gates(
+
self.options.thread_gate,
+
self.options.quote_gate,
+
new_post.uri,
+
time_iso=post.get_post_date_iso()
+
)
reply_ref = models.create_strong_ref(new_post)
created_records.append(new_post)
else: # video is guarantedd to be one
···
video_io = attachments[0].io
if attachments[0].mime != 'video/mp4':
-
LOGGER.error("Converting %s to mp4...", attachments[0].name)
+
LOGGER.info("Converting %s to mp4...", attachments[0].name)
video_io = media_util.convert_to_mp4(video_io)
aspect_ratio = models.AppBskyEmbedDefs.AspectRatio(
···
if not root_ref:
root_ref = models.create_strong_ref(new_post)
-
self.bsky.create_gates(self.options, new_post.uri, time_iso=post.get_post_date_iso())
+
self.bsky.create_gates(
+
self.options.thread_gate,
+
self.options.quote_gate,
+
new_post.uri,
+
time_iso=post.get_post_date_iso()
+
)
reply_ref = models.create_strong_ref(new_post)
created_records.append(new_post)