SHAMEZO
はじめる

ドキュメント

v1.3.13

システム構成

処理を担う3コンポーネント(プロセス)と、共有するデータストアで構成されます。画像処理のような重い処理は専用のコンポーネントへ隔離し、スケールできるように配慮されています。

構成要素役割
web (Node.js)フロントエンドです。レンダリングと軽量なAPIを公開します。
worker-front (Node.js)ジョブ管理です。Web・Bot・メールの各経路からのリクエストを管理し、画像処理ノードへの指示、およびそのためのAPIを公開します。また、一部の定期ジョブのスケジューラーも兼ねています。
worker (Node.js)画像処理です。外部には公開されていません。
PostgreSQL投稿・ユーザー・実績などのデータを保存します。
Object Storage生成した画像やサムネイルを保存します。

画像処理

元画像とパラメーターを受け取ると、即座に画像処理を行い、出力します。処理は、ベータテスト期間中のA/Bテストを通じて、品質を確保しつつより早い処理を実現するパイプライン処理を最適化しています。

画像処理フロー: 回転→HEIC/HEIF判定でJPEG化→長辺2048px判定で縮小→テキスト合成→中間JPEG→AVIF化(上限超過なら品質を下げて再試行)→生成画像
生成リクエスト受信後のサーバー側画像処理フロー(横にスクロールできます)

向きの補正・デコード

スマートフォンなどでは、縦向きで撮影した場合でも、画像自体は横向きに保存されることが多いです。EXIF の Orientation タグを参照したうえで、向きを補正します。

リサイズ

長辺が 2048px を超える入力画像は、あらかじめアスペクト比を保ったまま長辺 2048px へ縮小してから後続の処理に回します。

文字合成

テキストオーバーレイを Canvas 描画し、画像に合成します。パフォーマンスを維持するため、合成画像は一度JPEG(quality 90)で出力します。

最終出力

投稿先に応じた形式・サイズ上限で書き出します。この出力時の再エンコードで、元画像の EXIF メタデータは全て取り除かれます。

投稿先形式サイズ上限EXIF
MastodonAVIF16MB削除
MisskeyAVIF250MB削除

AVIF出力では、 quality 80, effort 2 で書き出し、サイズを確認します。万が一出力がサイズ上限を超えた場合、quality を段階的に下げて再エンコードし、上限以下に収まった時点の出力を採用します。

派生画像

  • カレンダー用サムネイル: WebP, 128×128px, quality 80 / あらかじめ作成し、ストレージに保存
  • OGP用サムネイル: WebP / 必要に応じてオンデマンドで作成し、ストレージに保存しない

通常、OGP用には本来の生成画像を指定することも可能です。しかし、XはAVIFに対応していないため、他のレガシーなフォーマットへの変換が必要です。そこで、SHAMEZO内ではWebP変換を行わず、管理者が開発・運用している別インフラ(自前のMisskeyメディアプロキシ)でオンデマンド変換を行い、OGP用のサムネイルを作成しています。このサムネイルはストレージには格納されず、主にCDNのキャッシュに頼っています。

タイムアウト

不明なエラーを発生させないため、Tier ごとにカスケードタイムアウトを設定しています。

Tier制限時間
画像処理本体18秒
API22秒
ブラウザ(Web投稿の場合)25秒

アップロード処理は全体のタイムアウト値に含まれません。アップロードのタイムアウト値はなく、回線が遅い場合でも原則として永遠に待ち続けます。ただし、アップロードが20秒以上まったく進まなくなった場合のみ、中断されます。

入力制限

画像

  • 枚数: 1枚
  • フォーマット: JPEG, PNG, WebP, AVIF, HEIC, HEIF
  • 最大ファイルサイズ: 20MB
  • 最大ピクセル数: 200MP

合成テキスト

  • 文字数: 1〜140 文字

代替テキスト(ALT)

  • 文字数: 0〜1,500 文字

Misskeyへ投稿する場合、代替テキストの上限は 512 文字に自動で切り詰められます。ただし、その場合でも SHAMEZO 上には最大 1,500 文字が保存されます。

テキスト合成

文字位置

  • 方向: 上下は横書き、左右は縦書き
  • マージン: 全方向に画像短辺の5%または10pxの大きい方のマージンを設けて文字を描画(文字サイズ・文字位置により変動しない)
  • 折り返し: マージンを除いた描画領域で、超過した位置で改行

文字サイズ

サイズ指定(小/中/大/特大)は、画像に対する相対的なサイズです。画像の短辺に14文字が納まる文字サイズを基準(中)とし、指定した倍率で描画します。

設定基準に対する倍率短辺に納まる文字数
0.75倍約18文字
1.0倍約14文字
1.4倍約10文字
特大2.35倍約6文字

文字サイズには下限14px・上限500pxのハードリミットがあり、上記よりも優先されます。

文字幅

  • Noto Sans JP(プロポーショナルフォント): フォントのもつ幅で描画
  • ふい字・ラノベPOP(等幅フォント): 等幅で描画

等幅フォントの場合でも、ASCII文字列 U+0020–U+007E と半角カナ U+FF61–U+FF9F は半分の幅になるよう調整します。また、後述する Emoji は別処理となります。

縦書き

  • 括弧類(「」、()、【】など)・長音記号(ー〜など)・リーダー(…‥)は90度回転して描画
  • 句読点(、。)は右上寄せ

縁取りとカラー

視認性を高めるため、すべての文字に縁取りを追加して描画します。薄い色(白・緑・黄・桃・橙)には黒い縁取り、濃い色(赤・青・茶)には白い縁取りが付きます。縁取りは文字サイズのおよそ0.1倍(ただし最小は2px)となります。

カラー文字色縁取り色
#FFFFFF#000000
#FF0000#FFFFFF
#0000FF#FFFFFF
#00FF00#000000
#FFFF00#000000
#8B4513#FFFFFF
#FFC0CB#000000
#FFA500#000000

Emoji

ユーザーのフォント設定によらず、絵文字は常に Noto Emoji を用いて描画します。このフォントは本来プロポーショナルフォントのため、等幅フォントのふい字・ラノベPOPとともに使う場合は、ラインがずれないよう、 Noto Emoji 側の表示位置を調整しています。

EXIFに関する追加処理

位置情報・撮影日時・カメラ機種などが含まれるEXIF(Exchangeable image file format)情報は、個人情報が含まれる可能性があるため、常に削除してから投稿・アップロードします。 また、受け取った画像のEXIFは通常解析しません。

しかし、ユーザーが明示的に希望した場合に限って、EXIFを解析し、希望した範囲の情報を保存・投稿することもできます。 この場合でも、撮影日時・撮影方向・GPS座標は保存しません。

サーバーに保存される内容

投稿形式カメラ機種カメラ撮影情報位置情報EXIF全体
Web希望時のみ希望時のみ希望時のみ×
Bot××××
メール希望時のみ希望時のみ希望時のみ×
  • カメラ機種: カメラの機種および製造元
  • カメラ撮影情報: F値・シャッター速度・ISO感度・焦点距離・レンズ名・露出補正・フラッシュの有無
  • 位置情報: 国内の場合、都道府県または市町村レベル(GPS座標は含まない)

解析方法

  • Web投稿: 画像を選択した時点で、お使いのブラウザ上で EXIF 解析を行います(サーバー上では解析しません)
  • Bot投稿: Fediverse サーバー投稿時に EXIF が除去されてしまうため、EXIF 解析はサポートしていません
  • メール投稿: メール受信時、サーバー上で元画像の EXIF 解析を行います

位置情報の変換

ユーザーが希望した場合のみ、国土地理院の逆ジオコーディング API に GPS 座標を送信し、市区町村コードを取得します。 この場合でも、保存されるのは都道府県または市町村までの情報で、GPS 座標は詳細なデバッグ用のログを含め、一切記録されません。

ブラウザの制限についての補足

スマートフォンのプライバシー保護機能により、Web投稿の場合、位置情報のみが自動的に除去されることがあります。

  • iOS: 写真選択時、画面下部のオプションにて位置情報を含める設定に変更することで、位置情報をアップロードできます
  • Android: 必ず回避できる方法はありませんが、機種・OSバージョンによって以下いずれの方法かで成功することもあります
    • (1) 「写真を撮る」でその場で撮影
    • (2) OS標準の共有機能で、SHAMEZOのPWAアプリに写真を送信

なお、Web投稿では、写真に位置情報が含まれない場合、過去に一度投稿したことのある都道府県または市町村に限って、手動で設定するオプションがあります。

レート制限

画像生成を短時間に連続して行った場合や、投稿数が普段より急増した場合など、いくつかのレート制限を設けています。詳細はセキュリティ上の理由から非開示とします。

Webブラウザ以外の投稿方法

Bot投稿(メンション投稿)

Bot宛にメンション付きで画像とコメントを送信して投稿します。BotはWebSocketでメンションを監視しており、ほぼ即座に処理が開始されます。定期的なポーリングで取りこぼしを補完します。処理が正常に完了した場合、元投稿は削除される仕組みとなっています(設定で変更可能)。

使い方・稼働状況をみる

メール投稿

メニューで確認できる専用のメールアドレスに画像を添付して送信して投稿します。メールは Cloudflare Email Routing により Cloudflare Workers で処理され、ほぼ即座に処理が開始されます。セキュリティ対策(リスト型攻撃対策・MTAのバウンス防止)のため、投稿の成功・失敗によらず、サービス側からは一切のメール返信を行いません。

使い方をみる

機能: リアクション

公開・未収載の投稿には好きな絵文字でリアクションできます。Fediverse上(Mastodonサーバー・Misskeyサーバー)でのお気に入り・リアクションとSHAMEZOのリアクションは自動で同期され、合算して表示されます。

  • Fediverseサーバー上の情報が元データです
  • SHAMEZO側から投稿元のサーバーに対し、リアクション件数などを取得します(結果はSHAMEZO側にキャッシュされており、投稿日時からの経過時間によりキャッシュTTLが変化します)。
  • Fediverseサーバー上でお気に入り・リアクションをした場合、一定期間後にSHAMEZO側にも反映されます。取り消した場合も同様に反映されます
  • SHAMEZO上でリアクションした場合、あなたの所属するFediverseサーバー上でもお気に入り・リアクションを行うため、Fediverse上・SHAMEZO側の両方にほぼ即時に反映されます(連合による遅延が発生する場合があります)
  • Misskeyサーバーのユーザーは、ご自身のサーバーのカスタム絵文字が使えます。
  • Mastodonサーバーのユーザーは、SHAMEZO独自のカスタム絵文字が使えます。ただしMastodonは連合上「お気に入り」しか送れないため、どの絵文字を選んでもFediverseサーバーへはお気に入りとして伝わり、リアクションした絵文字はSHAMEZO上にのみ残ります
カスタム絵文字の一覧をみる

機能: サーバーで開く

Fediverseでは、同じ投稿でもサーバーごとに別々のローカルID(Mastodonのステータス ID/Misskeyのノート ID)が割り当てられます。そのため、投稿者のサーバー上のURLをそのまま開いても、閲覧者は自分のアカウントで返信・ブースト(リノート)・お気に入りといった操作ができません。「サーバーで開く」は、投稿のActivityPub URIを閲覧者自身のサーバーで解決し、閲覧者のアカウントで操作できる状態にして開く機能です。

閲覧者が自分のFediverseサーバーのWebにログインしており、かつ元投稿が実際にFediverseへ投稿されている場合にのみ利用できます。

ローカルID解決方法

  • Mastodon: 閲覧者のサーバーの authorize_interaction に URI を渡し、サーバー側で解決
  • Misskey: クリック時にSHAMEZO内部で URI を解決し、閲覧者のサーバー上のローカルなノートIDを特定してから開く

機能: 皆勤賞

皆勤賞は、SHAMEZOにおける最も栄誉のある実績です。

  • その月に毎日投稿することで獲得できます
  • 1日の基準は日本標準時間の0:00~23:59です
  • 投稿できなかった日が月3日以下(handon.club のユーザーは月4日以下)であれば救済措置があり、同月中の後日2枚以上投稿すると、投稿できなかった日の穴埋めとして処理されます
  • 穴埋めは古い未投稿日から1日につき1回(1日のダブル投稿で1日分)で、未来の日付や月末以降に残った未投稿日は埋められません
  • 皆勤賞はユーザー画面のカレンダータブ・実績タブで公開され、誰でも確認できます
  • 皆勤賞は月ごとに計算されるため、毎月獲得することができます

機能: カレンダー

ユーザーページの「カレンダー」タブでは、その月の投稿を日ごとのサムネイルで一覧表示します。 編集モードでは、各日に表示するサムネイルを変更できるほか、皆勤賞の穴埋めに使う投稿も選び直せます (サムネイルを変更後、その画像が削除された場合は、自動で再選出されます)。

トークンに必要な権限

ログイン時、連携する Fediverse サーバーに対し、以下の権限スコープを要求します。投稿・画像アップロード・リアクションなど、必要な最小限の範囲に限っています。

  • read

    アカウント情報の読み取り

    ログインのほか、ユーザー名・アイコンの取得、重複投稿有無確認に必要。

  • write:statuses

    ポストの投稿・削除

    ポストの投稿や削除に必要。

  • write:media

    画像のアップロード

    画像投稿に必要。

  • write:favourites

    お気に入りの追加・削除

    Web上でのお気に入り操作に必要。

行いません

  • タイムラインの読み取り
  • あなたの操作によらない投稿・お気に入りの操作

権限を要求せず、技術的にできません

  • フォローする・フォロー解除する・ブロックする・ミュートする
  • プロフィールを変更する
  • パスワードをみる

取得したアクセストークンは暗号化して厳重に保管します。

取得した個人情報はプライバシーポリシーに則り適切に取り扱います。