Merge branch 'develop' of https://codeberg.org/calckey/calckey into upstream

This commit is contained in:
freeplay 2023-07-02 13:01:54 -04:00
commit 567d94196a
33 changed files with 455 additions and 195 deletions

View file

@ -1601,6 +1601,8 @@ _aboutMisskey:
morePatrons: També agraïm el suport de molts altres ajudants que no figuren aquí. morePatrons: També agraïm el suport de molts altres ajudants que no figuren aquí.
Gràcies! 🥰 Gràcies! 🥰
patrons: Mecenes de Calckey patrons: Mecenes de Calckey
patronsList: Llistats cronològicament, no per la quantitat donada. Fes una donació
amb l'enllaç de dalt per veure el teu nom aquí!
unknown: Desconegut unknown: Desconegut
pageLikesCount: Nombre de pàgines amb M'agrada pageLikesCount: Nombre de pàgines amb M'agrada
youAreRunningUpToDateClient: Estás fent servir la versió del client més nova. youAreRunningUpToDateClient: Estás fent servir la versió del client més nova.
@ -2082,11 +2084,7 @@ _experiments:
alpha: Alfa alpha: Alfa
beta: Beta beta: Beta
release: Publicà release: Publicà
enablePostEditing: Activà l'edició de publicacions
title: Experiments title: Experiments
postEditingCaption: Mostra l'opció perquè els usuaris editin les seves publicacions
mitjançant el menú d'opcions de publicació, i permet rebre publicacions editades
d'altres servidors.
enablePostImports: Activar l'importació de publicacions enablePostImports: Activar l'importació de publicacions
postImportsCaption: Permet els usuaris importar publicacions desde comptes a Calckey, postImportsCaption: Permet els usuaris importar publicacions desde comptes a Calckey,
Misskey, Mastodon, Akkoma i Pleroma. Pot fer que el servidor vagi més lent durant Misskey, Mastodon, Akkoma i Pleroma. Pot fer que el servidor vagi més lent durant

View file

@ -2095,10 +2095,7 @@ jumpToPrevious: Zum Vorherigen springen
silencedWarning: Diese Meldung wird angezeigt, weil diese Nutzer von Servern stammen, silencedWarning: Diese Meldung wird angezeigt, weil diese Nutzer von Servern stammen,
die Ihr Administrator abgeschaltet hat, so dass es sich möglicherweise um Spam handelt. die Ihr Administrator abgeschaltet hat, so dass es sich möglicherweise um Spam handelt.
_experiments: _experiments:
enablePostEditing: Beitragsbearbeitung ermöglichen
title: Funktionstests title: Funktionstests
postEditingCaption: Zeigt die Option für Nutzer an, ihre bestehenden Beiträge über
das Menü "Beitragsoptionen" zu bearbeiten
enablePostImports: Beitragsimporte aktivieren enablePostImports: Beitragsimporte aktivieren
postImportsCaption: Erlaubt es Nutzer:innen ihre Posts von alten Calckey, Misskey, postImportsCaption: Erlaubt es Nutzer:innen ihre Posts von alten Calckey, Misskey,
Mastodon, Akkoma und Pleroma Accounts zu importieren. Bei Engpässen in der Warteschlange Mastodon, Akkoma und Pleroma Accounts zu importieren. Bei Engpässen in der Warteschlange
@ -2152,3 +2149,4 @@ clipsDesc: Clips sind wie teilbare, kategorisierte Lesezeichen. Du kannst Clips
Menü individueller Posts aus erstellen. Menü individueller Posts aus erstellen.
channelFederationWarn: Kanäle föderieren noch nicht zu anderen Servern channelFederationWarn: Kanäle föderieren noch nicht zu anderen Servern
reactionPickerSkinTone: Bevorzugte Emoji-Hautfarbe reactionPickerSkinTone: Bevorzugte Emoji-Hautfarbe
swipeOnMobile: Wischen zwischen den Seiten erlauben

View file

@ -1213,6 +1213,7 @@ _aboutMisskey:
morePatrons: "We also appreciate the support of many other helpers not listed here. morePatrons: "We also appreciate the support of many other helpers not listed here.
Thank you! 🥰" Thank you! 🥰"
patrons: "Calckey patrons" patrons: "Calckey patrons"
patronsList: "Listed chronologically, not by donation size. Donate with the link above to get your name on here!"
_nsfw: _nsfw:
respect: "Hide NSFW media" respect: "Hide NSFW media"
ignore: "Don't hide NSFW media" ignore: "Don't hide NSFW media"
@ -2069,9 +2070,6 @@ _deck:
direct: "Direct messages" direct: "Direct messages"
_experiments: _experiments:
title: "Experiments" title: "Experiments"
enablePostEditing: "Enable post editing"
postEditingCaption: "Shows the option for users to edit their existing posts via\
\ the post options menu, and allows post edits from other instances to be recieved."
enablePostImports: "Enable post imports" enablePostImports: "Enable post imports"
postImportsCaption: "Allows users to import their posts from past Calckey,\ postImportsCaption: "Allows users to import their posts from past Calckey,\
\ Misskey, Mastodon, Akkoma, and Pleroma accounts. It may cause slowdowns during\ \ Misskey, Mastodon, Akkoma, and Pleroma accounts. It may cause slowdowns during\

View file

@ -2028,7 +2028,7 @@ flagShowTimelineRepliesDescription: Si activé, affiche dans le fil les réponse
_experiments: _experiments:
alpha: Alpha alpha: Alpha
beta: Beta beta: Beta
enablePostEditing: Autoriser l'édition de note enablePostImports: Autoriser l'importation de messages
title: Expérimentations title: Expérimentations
findOtherInstance: Trouver un autre serveur findOtherInstance: Trouver un autre serveur
userSaysSomethingReasonQuote: '{name} a cité une note contenant {reason}' userSaysSomethingReasonQuote: '{name} a cité une note contenant {reason}'

View file

@ -1887,9 +1887,7 @@ hiddenTagsDescription: 'トレンドと「みつける」から除外したい
hiddenTags: 非表示にするハッシュタグ hiddenTags: 非表示にするハッシュタグ
apps: "アプリ" apps: "アプリ"
_experiments: _experiments:
enablePostEditing: 投稿の編集機能を有効にする
title: 試験的な機能 title: 試験的な機能
postEditingCaption: 投稿のメニューに既存の投稿を編集するボタンを表示し、他サーバーの編集も受信できるようにします。
postImportsCaption: postImportsCaption:
ユーザーが過去の投稿をCalckey・Misskey・Mastodon・Akkoma・Pleromaからインポートすることを許可します。キューが溜まっているときにインポートするとサーバーに負荷がかかる可能性があります。 ユーザーが過去の投稿をCalckey・Misskey・Mastodon・Akkoma・Pleromaからインポートすることを許可します。キューが溜まっているときにインポートするとサーバーに負荷がかかる可能性があります。
enablePostImports: 投稿のインポートを有効にする enablePostImports: 投稿のインポートを有効にする

View file

@ -1,7 +1,7 @@
---
_lang_: "简体中文" _lang_: "简体中文"
headlineMisskey: "通过帖子连接在一起的网络" headlineMisskey: "通过帖子连接在一起的网络"
introMisskey: "欢迎Misskey是一个开源的、去中心化的“微博客”服务。\n通过编写「帖文」来和大家分享你的以及你周围的事情吧📡\n通过「回应」功能可以让你快速地对大家的帖文表达反馈👍\n来探索新的世界吧🚀" introMisskey: "欢迎Misskey是一个开源的、去中心化的“微博客”服务。\n通过编写「帖文」来和大家分享你的以及你周围的事情吧📡\n通过「回应」功能可以让你快速地对大家的帖文表达反馈👍\n\
来探索新的世界吧!🚀"
monthAndDay: "{month}月 {day}日" monthAndDay: "{month}月 {day}日"
search: "搜索" search: "搜索"
notifications: "通知" notifications: "通知"
@ -14,9 +14,9 @@ gotIt: "我明白了"
cancel: "取消" cancel: "取消"
enterUsername: "输入用户名" enterUsername: "输入用户名"
renotedBy: "由 {user} 转贴" renotedBy: "由 {user} 转贴"
noNotes: "没有帖" noNotes: "没有帖"
noNotifications: "无通知" noNotifications: "无通知"
instance: "实例" instance: "服务器"
settings: "设置" settings: "设置"
basicSettings: "基本设置" basicSettings: "基本设置"
otherSettings: "其他设置" otherSettings: "其他设置"
@ -64,7 +64,7 @@ import: "导入"
export: "导出" export: "导出"
files: "文件" files: "文件"
download: "下载" download: "下载"
driveFileDeleteConfirm: "要删除「{name}」文件吗?附加此文件的帖子也会被删除。" driveFileDeleteConfirm: "要删除文件「{name}」吗?它将被所有作为附件包含它的帖子中删除。"
unfollowConfirm: "要取消对{name}的关注吗?" unfollowConfirm: "要取消对{name}的关注吗?"
exportRequested: "导出请求已提交,这可能需要花一些时间,导出的文件将保存到网盘中。" exportRequested: "导出请求已提交,这可能需要花一些时间,导出的文件将保存到网盘中。"
importRequested: "导入请求已提交,这可能需要花一点时间。" importRequested: "导入请求已提交,这可能需要花一点时间。"
@ -166,7 +166,7 @@ selectUser: "选择用户"
recipient: "收件人" recipient: "收件人"
annotation: "注解" annotation: "注解"
federation: "联合" federation: "联合"
instances: "实例" instances: "服务器"
registeredAt: "初次观测" registeredAt: "初次观测"
latestRequestSentAt: "上次发送的请求" latestRequestSentAt: "上次发送的请求"
latestRequestReceivedAt: "上次收到的请求" latestRequestReceivedAt: "上次收到的请求"
@ -186,14 +186,14 @@ jobQueue: "作业队列"
cpuAndMemory: "CPU和内存" cpuAndMemory: "CPU和内存"
network: "网络" network: "网络"
disk: "存储" disk: "存储"
instanceInfo: "实例信息" instanceInfo: "服务器信息"
statistics: "统计" statistics: "统计"
clearQueue: "清除队列" clearQueue: "清除队列"
clearQueueConfirmTitle: "确定清除队列?" clearQueueConfirmTitle: "确定清除队列?"
clearQueueConfirmText: "未送达的帖子将不会送达。 通常,您不需要这样做。" clearQueueConfirmText: "未送达的帖子将不会送达。 通常,您不需要这样做。"
clearCachedFiles: "清除缓存" clearCachedFiles: "清除缓存"
clearCachedFilesConfirm: "确定要清除缓存文件?" clearCachedFilesConfirm: "确定要清除缓存文件?"
blockedInstances: "被阻拦的实例" blockedInstances: "已屏蔽的服务器"
blockedInstancesDescription: "设定要阻拦的实例,以换行来进行分割。被阻拦的实例将无法与本实例进行交换通讯。" blockedInstancesDescription: "设定要阻拦的实例,以换行来进行分割。被阻拦的实例将无法与本实例进行交换通讯。"
muteAndBlock: "屏蔽/拉黑" muteAndBlock: "屏蔽/拉黑"
mutedUsers: "已屏蔽用户" mutedUsers: "已屏蔽用户"
@ -309,8 +309,8 @@ unwatch: "取消关注"
accept: "允许" accept: "允许"
reject: "拒绝" reject: "拒绝"
normal: "正常" normal: "正常"
instanceName: "实例名称" instanceName: "服务器名称"
instanceDescription: "实例介绍" instanceDescription: "服务器简介"
maintainerName: "管理员名称" maintainerName: "管理员名称"
maintainerEmail: "管理员电子邮箱" maintainerEmail: "管理员电子邮箱"
tosUrl: "服务条款URL" tosUrl: "服务条款URL"
@ -321,7 +321,7 @@ dayX: "{day}日"
monthX: "{month}月" monthX: "{month}月"
yearX: "{year}年" yearX: "{year}年"
pages: "页面" pages: "页面"
integration: "关联" integration: "整合"
connectService: "连接" connectService: "连接"
disconnectService: "断开连接" disconnectService: "断开连接"
enableLocalTimeline: "启用本地时间线功能" enableLocalTimeline: "启用本地时间线功能"
@ -600,7 +600,7 @@ testEmail: "邮件发送测试"
wordMute: "文字屏蔽" wordMute: "文字屏蔽"
regexpError: "正则表达式错误" regexpError: "正则表达式错误"
regexpErrorDescription: "{tab} 屏蔽文字的第 {line} 行的正则表达式有错误:" regexpErrorDescription: "{tab} 屏蔽文字的第 {line} 行的正则表达式有错误:"
instanceMute: "实例的屏蔽" instanceMute: "服务器静音"
userSaysSomething: "{name}说了什么" userSaysSomething: "{name}说了什么"
makeActive: "启用" makeActive: "启用"
display: "显示" display: "显示"
@ -643,7 +643,7 @@ instanceTicker: "帖子的实例信息"
waitingFor: "等待{x}" waitingFor: "等待{x}"
random: "随机" random: "随机"
system: "系统" system: "系统"
switchUi: "切换界面" switchUi: "界面"
desktop: "桌面" desktop: "桌面"
clip: "便签" clip: "便签"
createNew: "新建" createNew: "新建"
@ -701,7 +701,7 @@ showTitlebar: "显示标题栏"
clearCache: "清除缓存" clearCache: "清除缓存"
onlineUsersCount: "{n}人在线" onlineUsersCount: "{n}人在线"
nUsers: "{n}用户" nUsers: "{n}用户"
nNotes: "{n}帖子" nNotes: "{n} 帖子"
sendErrorReports: "发送错误报告" sendErrorReports: "发送错误报告"
sendErrorReportsDescription: "启用后如果出现问题可以与Misskey共享详细的错误信息从而帮助提高软件的质量。" sendErrorReportsDescription: "启用后如果出现问题可以与Misskey共享详细的错误信息从而帮助提高软件的质量。"
myTheme: "我的主题" myTheme: "我的主题"
@ -755,7 +755,7 @@ active: "活动"
offline: "离线" offline: "离线"
notRecommended: "不推荐" notRecommended: "不推荐"
botProtection: "Bot防御" botProtection: "Bot防御"
instanceBlocking: "被阻拦的实例" instanceBlocking: "联邦管理"
selectAccount: "选择账户" selectAccount: "选择账户"
switchAccount: "切换账户" switchAccount: "切换账户"
enabled: "已启用" enabled: "已启用"
@ -816,7 +816,7 @@ controlPanel: "控制面板"
manageAccounts: "管理账户" manageAccounts: "管理账户"
makeReactionsPublic: "将回应设置为公开" makeReactionsPublic: "将回应设置为公开"
makeReactionsPublicDescription: "将您发表过的回应设置成公开可见。" makeReactionsPublicDescription: "将您发表过的回应设置成公开可见。"
classic: "经典" classic: "居中"
muteThread: "屏蔽帖子列表" muteThread: "屏蔽帖子列表"
unmuteThread: "取消屏蔽帖子列表" unmuteThread: "取消屏蔽帖子列表"
ffVisibility: "连接的可见范围" ffVisibility: "连接的可见范围"
@ -896,7 +896,10 @@ shuffle: "随机"
account: "账户" account: "账户"
move: "移动" move: "移动"
customKaTeXMacro: "自定义 KaTeX 宏" customKaTeXMacro: "自定义 KaTeX 宏"
customKaTeXMacroDescription: "使用宏来轻松的输入数学表达式吧!宏的用法与 LaTeX 中的命令定义相同。你可以使用 \\newcommand{\\name}{content} 或 \\newcommand{\\name}[number of arguments]{content} 来输入数学表达式。举个例子,\\newcommand{\\add}[2]{#1 + #2} 会将 \\add{3}{foo} 展开为 3 + foo。此外宏名称外的花括号 {} 可以被替换为圆括号 () 和方括号 [],这会影响用于参数的括号。每行只能够定义一个宏,无法在中间换行,且无效的行将被忽略。只支持简单字符串替换功能,不支持高级语法,如条件分支等。" customKaTeXMacroDescription: "使用宏来轻松的输入数学表达式吧!宏的用法与 LaTeX 中的命令定义相同。你可以使用 \\newcommand{\\
name}{content} 或 \\newcommand{\\name}[number of arguments]{content} 来输入数学表达式。举个例子,\\
newcommand{\\add}[2]{#1 + #2} 会将 \\add{3}{foo} 展开为 3 + foo。此外宏名称外的花括号 {} 可以被替换为圆括号
() 和方括号 [],这会影响用于参数的括号。每行只能够定义一个宏,无法在中间换行,且无效的行将被忽略。只支持简单字符串替换功能,不支持高级语法,如条件分支等。"
enableCustomKaTeXMacro: "启用自定义 KaTeX 宏" enableCustomKaTeXMacro: "启用自定义 KaTeX 宏"
_sensitiveMediaDetection: _sensitiveMediaDetection:
description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。" description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。"
@ -981,6 +984,7 @@ _aboutMisskey:
donate: "赞助Misskey" donate: "赞助Misskey"
morePatrons: "还有很多其他的人也在支持我们,非常感谢🥰" morePatrons: "还有很多其他的人也在支持我们,非常感谢🥰"
patrons: "支持者" patrons: "支持者"
patronsList: 按时间顺序而不是捐赠金额排列。通过上面的链接捐款,让您的名字出现在这里!
_nsfw: _nsfw:
respect: "隐藏敏感内容" respect: "隐藏敏感内容"
ignore: "不隐藏敏感内容" ignore: "不隐藏敏感内容"
@ -1051,6 +1055,24 @@ _mfm:
rotateDescription: "旋转指定的角度。" rotateDescription: "旋转指定的角度。"
plain: "简洁" plain: "简洁"
plainDescription: "禁用所有内部语法。" plainDescription: "禁用所有内部语法。"
crop: 裁剪
scale: 缩放
position: 位置
fade: 渐淡
advanced: 高级 MFM
background: 背景色
fadeDescription: 内容淡入和淡出。
warn: MFM 可能包含快速移动或华丽的动画
advancedDescription: 如果禁用,则仅允许基本标记,除非正在播放动态 MFM
foreground: 前景色
backgroundDescription: 更改文本的背景色。
play: 播放 MFM
alwaysPlay: 始终自动播放所有动态的 MFM
stop: 停止播放 MFM
positionDescription: 将内容移动指定的量。
cropDescription: 裁剪内容。
scaleDescription: 按指定量缩放内容。
foregroundDescription: 更改文本的前景色。
_instanceTicker: _instanceTicker:
none: "不显示" none: "不显示"
remote: "仅远程用户" remote: "仅远程用户"
@ -1059,6 +1081,7 @@ _serverDisconnectedBehavior:
reload: "自动重载" reload: "自动重载"
dialog: "对话框警告" dialog: "对话框警告"
quiet: "安静警告" quiet: "安静警告"
nothing: 什么也不做
_channel: _channel:
create: "创建频道" create: "创建频道"
edit: "编辑频道" edit: "编辑频道"
@ -1068,7 +1091,7 @@ _channel:
owned: "管理中" owned: "管理中"
following: "正在关注" following: "正在关注"
usersCount: "有{n}人参与" usersCount: "有{n}人参与"
notesCount: "有{n}个帖子" notesCount: "{n} 帖子"
nameAndDescription: "名称与描述" nameAndDescription: "名称与描述"
nameOnly: "仅名称" nameOnly: "仅名称"
_menuDisplay: _menuDisplay:
@ -1084,7 +1107,7 @@ _wordMute:
hardDescription: "防止将具有指定条件的帖子添加到时间线。 即使您更改条件,未添加的帖文也会被排除在外。" hardDescription: "防止将具有指定条件的帖子添加到时间线。 即使您更改条件,未添加的帖文也会被排除在外。"
soft: "软屏蔽" soft: "软屏蔽"
hard: "硬屏蔽" hard: "硬屏蔽"
mutedNotes: "被屏蔽的帖子" mutedNotes: "已静音的帖子"
_instanceMute: _instanceMute:
instanceMuteDescription: "屏蔽配置实例中的所有帖子和转帖,包括实例的用户回复。" instanceMuteDescription: "屏蔽配置实例中的所有帖子和转帖,包括实例的用户回复。"
instanceMuteDescription2: "设置时用换行符来分隔" instanceMuteDescription2: "设置时用换行符来分隔"
@ -1165,7 +1188,7 @@ _theme:
accentLighten: "强调色(浅)" accentLighten: "强调色(浅)"
fgHighlighted: "高亮显示文本" fgHighlighted: "高亮显示文本"
_sfx: _sfx:
note: "帖子" note: "新的帖子"
noteMy: "我的帖子" noteMy: "我的帖子"
notification: "通知" notification: "通知"
chat: "聊天" chat: "聊天"
@ -1178,7 +1201,7 @@ _ago:
secondsAgo: "{n}秒前" secondsAgo: "{n}秒前"
minutesAgo: "{n}分前" minutesAgo: "{n}分前"
hoursAgo: "{n}小时前" hoursAgo: "{n}小时前"
daysAgo: "{n}前" daysAgo: "{n}前"
weeksAgo: "{n}周前" weeksAgo: "{n}周前"
monthsAgo: "{n}月前" monthsAgo: "{n}月前"
yearsAgo: "{n}年前" yearsAgo: "{n}年前"
@ -1218,6 +1241,21 @@ _2fa:
step3: "输入您的应用提供的动态口令以完成设置。" step3: "输入您的应用提供的动态口令以完成设置。"
step4: "从现在开始,任何登录操作都将要求您提供动态口令。" step4: "从现在开始,任何登录操作都将要求您提供动态口令。"
securityKeyInfo: "您可以设置使用支持FIDO2的硬件安全密钥、设备上的指纹或PIN来保护您的登录过程。" securityKeyInfo: "您可以设置使用支持FIDO2的硬件安全密钥、设备上的指纹或PIN来保护您的登录过程。"
renewTOTPOk: 重新配置
renewTOTPCancel: 取消
token: 2FA 令牌
renewTOTP: 重新配置身份验证器应用程序
registerTOTPBeforeKey: 请设置一个认证器应用来注册一个安全或通行密钥。
renewTOTPConfirm: 这将导致您之前的应用程序中的验证码停止工作
step3Title: 输入验证码
step2Click: 点击此二维码将允许您在安全密钥或手机验证器应用中注册 2FA。
securityKeyNotSupported: 您的浏览器不支持安全密钥。
securityKeyName: 输入密钥名称
chromePasskeyNotSupported: 目前不支持 Chrome passkeys。
tapSecurityKey: 请按照您的浏览器的指示注册安全或通行密钥
removeKey: 移除安全密钥
removeKeyConfirm: 真的要删除 {name} 密钥吗?
whyTOTPOnlyRenew: 只要注册了安全密钥,就无法删除身份验证器应用程序。
_permissions: _permissions:
"read:account": "查看账户信息" "read:account": "查看账户信息"
"write:account": "更改帐户信息" "write:account": "更改帐户信息"
@ -1258,12 +1296,15 @@ _auth:
pleaseGoBack: "请返回到应用程序" pleaseGoBack: "请返回到应用程序"
callback: "回到应用程序" callback: "回到应用程序"
denied: "拒绝访问" denied: "拒绝访问"
allPermissions: 完全的账户访问权限
copyAsk: 请将以下授权码粘贴到应用程序中:
_antennaSources: _antennaSources:
all: "所有帖子" all: "所有帖子"
homeTimeline: "已关注用户的帖子" homeTimeline: "已关注用户的帖子"
users: "来自指定用户的帖子" users: "来自指定用户的帖子"
userList: "来自指定列表中的帖子" userList: "来自指定列表中的帖子"
userGroup: "来自指定群组中用户的帖子" userGroup: "来自指定群组中用户的帖子"
instances: 服务器上所有用户的帖子
_weekday: _weekday:
sunday: "星期日" sunday: "星期日"
monday: "星期一" monday: "星期一"
@ -1280,21 +1321,26 @@ _widgets:
trends: "趋势" trends: "趋势"
clock: "时钟" clock: "时钟"
rss: "RSS阅读器" rss: "RSS阅读器"
rssTicker: "RSS Ticker" rssTicker: "RSS滚动条"
activity: "活动" activity: "活动"
photos: "照片" photos: "照片"
digitalClock: "数字时钟" digitalClock: "数字时钟"
unixClock: "UNIX时钟" unixClock: "UNIX时钟"
federation: "联邦宇宙" federation: "联邦宇宙"
instanceCloud: "实例云" instanceCloud: "服务器云端"
postForm: "投稿窗口" postForm: "发布窗口"
slideshow: "幻灯片展示" slideshow: "幻灯片展示"
button: "按钮" button: "按钮"
onlineUsers: "在线用户" onlineUsers: "在线用户"
jobQueue: "作业队列" jobQueue: "作业队列"
serverMetric: "服务器监控" serverMetric: "服务器指标"
aiscript: "AiScript控制台" aiscript: "AiScript控制台"
aichan: "小蓝" aichan: "小蓝"
userList: 用户列表
meiliStatus: 服务器状态
meiliIndexCount: 已索引的帖子
meiliSize: 索引大小
serverInfo: 服务器信息
_cw: _cw:
hide: "隐藏" hide: "隐藏"
show: "查看更多" show: "查看更多"
@ -1325,7 +1371,7 @@ _poll:
_visibility: _visibility:
public: "公开" public: "公开"
publicDescription: "您的帖子将出现在全局时间线上" publicDescription: "您的帖子将出现在全局时间线上"
home: "首页" home: "不公开"
homeDescription: "仅发送至首页的时间线" homeDescription: "仅发送至首页的时间线"
followers: "仅关注者" followers: "仅关注者"
followersDescription: "仅发送至关注者" followersDescription: "仅发送至关注者"
@ -1395,6 +1441,7 @@ _timelines:
local: "本地" local: "本地"
social: "社交" social: "社交"
global: "全局" global: "全局"
recommended: 推荐
_pages: _pages:
newPage: "创建页面" newPage: "创建页面"
editPage: "编辑页面" editPage: "编辑页面"
@ -1733,9 +1780,9 @@ _deck:
stackLeft: "向左折叠" stackLeft: "向左折叠"
popRight: "向右弹出" popRight: "向右弹出"
profile: "配置文件" profile: "配置文件"
newProfile: "新建配置文件" newProfile: "新建工作区"
renameProfile: "重命名配置文件" renameProfile: "重命名配置文件"
deleteProfile: "删除配置文件" deleteProfile: "删除工作区"
nameAlreadyExists: "该配置文件名已存在。" nameAlreadyExists: "该配置文件名已存在。"
introduction: "将各列进行组合以创建您自己的界面!" introduction: "将各列进行组合以创建您自己的界面!"
introduction2: "您可以随时通过屏幕右侧的 + 来添加列" introduction2: "您可以随时通过屏幕右侧的 + 来添加列"
@ -1748,4 +1795,134 @@ _deck:
antenna: "天线" antenna: "天线"
list: "列表" list: "列表"
mentions: "提及" mentions: "提及"
direct: "指定用户" direct: "私信"
channel: 频道
apps: 应用
_messaging:
dms: 私信
groups: 群组
migration: 迁移
_experiments:
title: 实验性功能
license: 许可证
flagSpeakAsCatDescription: 在猫模式下你的帖子会喵化
allowedInstances: 白名单服务器
listsDesc: 列表可以让你创建含有指定用户的时间线,它们可以从时间线页面访问。
flagSpeakAsCat: 像猫一样说话
removeReaction: 移除你的回应
expandOnNoteClick: 点击打开帖子
expandOnNoteClickDesc: 如果禁用,你仍然可以在右键菜单中或通过点击时间戳打开帖子。
sendPushNotificationReadMessage: 删除已阅读的推送通知
customMOTD: 自定义 MOTD闪屏消息
sendPushNotificationReadMessageCaption: 短暂显示 "{emptyPushNotificationMessage}" 的通知,如果启用,可能会增加你的设备的耗电量。
adminCustomCssWarn: 仅当你知道此设置的作用时才应使用它。输入不正确的值可能会导致每个人的客户端停止正常运行。请在用户设置中进行测试来确保您的 CSS
正常工作。
customMOTDDescription: 自定义MOTD闪屏消息一行一个每次用户加载/刷新页面时都会随机显示。
customSplashIconsDescription: 用换行符隔开的自定义闪屏图标的URL在用户每次加载/重新加载页面时随机显示。请确保图片是在一个静态的
URL 上,最好全部调整为 192x192 的大小。
recommendedInstancesDescription: 推荐的服务器以换行符分隔,它们将出现在推荐的时间线中。不要添加 "https://",仅添加域名。
splash: 启动画面
showUpdates: Calckey 更新后显示弹出窗口
selectInstance: 选择一个服务器
silencedInstances: 静默的服务器
antennaInstancesDescription: 每行列出一个服务器主机
pushNotification: 推送通知
subscribePushNotification: 启用推送通知
showAdminUpdates: 提示新的 Calckey 版本可用(仅对于管理员)
searchPlaceholder: 搜索 Calckey
addInstance: 添加一个服务器
jumpToPrevious: 跳转至上一个
silenceThisInstance: 使此服务器静音
manageGroups: 管理群组
antennasDesc: "天线会显示符合您设置条件的新帖子!\n可以从时间线页面访问它们。"
channelFederationWarn: 频道还没有与其他服务器联合
seperateRenoteQuote: 单独的推荐和引用按钮
customSplashIcons: 自定义闪屏图标urls
alt: 替代文字
pushNotificationNotSupported: 你的浏览器或者服务器不支持推送通知
showAds: 显示广告
enterSendsMessage: 按回车键发送信息(关闭则是 Ctrl + Retun
recommendedInstances: 推荐服务器
updateAvailable: 可能有可用更新!
swipeOnMobile: 允许在页面之间滑动
swipeOnDesktop: 允许在桌面端以移动设备方式滑动
logoImageUrl: Logo 图像 URL
deleted: 已删除
editNote: 编辑帖子
edited: 于 {date} {time} 编辑
selectChannel: 选择一个频道
accountMoved: 用户已迁移至新账户:
silencedInstancesDescription: 列出你想静默的服务器的主机名。列出的服务器中的账户被视为 "静默",只能发出跟随请求,如果不被跟随,就不能提及本地账户。这不会影响被封锁的服务器。
hiddenTags: 隐藏的哈希标签
userSaysSomethingReason: '{name} 说 {reason}'
clipsDesc: 便签就像可共享的分类书签。您可以从各个帖子的菜单中创建便签。
privateModeInfo: 当启用时,只有白名单上的服务器可以与你的服务器联合,所有的帖子都会对公共时间线隐藏。
allowedInstancesDescription: 要列入联合白名单的服务器的主机名,一行一个(仅适用于私密模式)。
breakFollowConfirm: 你确定要移除关注者吗?
caption: 自动显示说明文字
newer: 更新的
older: 更老的
noInstances: 没有服务器
silenced: 静默的
accessibility: 无障碍
secureMode: 安全模式(仅允许授权的拉取)
replayTutorial: 重播教程
userSaysSomethingReasonReply: '{name} 回复了包含 {reason} 的帖子'
userSaysSomethingReasonQuote: '{name} 引用了一篇包含 {reason} 的帖子'
userSaysSomethingReasonRenote: '{name} 推荐了一个包含 {reason} 的帖子'
noThankYou: 不,谢谢
secureModeInfo: 当向其他服务器请求时,不要在没有验证的情况下发回。
privateMode: 私密模式
instanceSecurity: 服务器安全
image: 图像
video: 视频
audio: 音频
cannotUploadBecauseExceedsFileSizeLimit: 无法上传此文件,因为它超出了允许的最大大小。
unsubscribePushNotification: 禁用推送通知
pushNotificationAlreadySubscribed: 推送通知已启用
enableEmojiReactions: 启用 emoji 回应
cw: 内容警告
hiddenTagsDescription: 列出你想隐藏的话题标签(不带#)以避免在趋势和探索中显示。隐藏的标签仍然可以通过其他方式被发现。
enableRecommendedTimeline: 启用推荐时间线
_skinTones:
medium: 中等
light: 浅色
yellow: 黄色
dark: 深色
isModerator: 协作者
isAdmin: 管理员
findOtherInstance: 寻找其它服务器
moveFromDescription: 这将为您的旧帐户设置一个别名,以便您可以从该旧帐户转移到当前帐户。在从旧帐户转移之前执行此操作。请输入格式如@person@server.com
的帐户标签
indexPosts: 索引帖子
signupsDisabled: 该服务器目前关闭注册,但您随时可以在另一台服务器上注册!如果您有该服务器的邀请码,请在下面输入。
silencedWarning: 显示这个页面是因为这些用户来自你的管理员设置的静默服务器,所以他们有可能是垃圾信息。
isBot: 这个账户是一个机器人
moveAccountDescription: 这个过程是不可逆的。在移动之前,请确保您已在新帐户上为当前帐户设置了别名。请输入格式如 @person@server.com
帐户标签
moveFromLabel: 您要移出的旧帐户:
preventAiLearning: 阻止 AI 机器人抓取
preventAiLearningDescription: 请求第三方人工智能语言模型不要研究您上传的内容,例如帖子和图像。
noGraze: 请禁用 "Graze for Mastodon" 浏览器扩展,因为它会干扰 Calckey。
moveTo: 将当前帐户移至新帐户
moveToLabel: 你要迁移到的目标帐户:
moveAccount: 移动账户!
migrationConfirm: "你确实确定要将帐户迁移到 {account} 吗?此操作无法撤消,并且你将无法再次正常使用旧账户。\n另外请确保你已将此当前帐户设置为要移出的帐户。"
indexFromDescription: 留空以索引每个帖子
noteId: 帖子 ID
moveFrom: 从旧帐户移至此帐户
defaultReaction: 发出和收到的帖子的默认表情符号反应
indexNotice: 现在开始索引。这可能需要一段时间,请至少一个小时内不要重新启动服务器。
indexFrom: 从帖子 ID 开始的索引
sendModMail: 发送审核通知
isLocked: 该帐户设置了关注请求
_filters:
notesBefore: 在之前的帖子
followingOnly: 仅关注中
notesAfter: 在之后的帖子
fromDomain: 来自域名
withFile: 带有文件
fromUser: 来自用户
followersOnly: 仅关注者
reactionPickerSkinTone: 首选的表情符号肤色
isPatron: Calckey 赞助

View file

@ -1816,7 +1816,6 @@ silenceThisInstance: 靜音此伺服器
silencedInstances: 已靜音的伺服器 silencedInstances: 已靜音的伺服器
silenced: 已靜音 silenced: 已靜音
_experiments: _experiments:
enablePostEditing: 啟用帖子編輯
title: 試驗功能 title: 試驗功能
findOtherInstance: 找找另一個伺服器 findOtherInstance: 找找另一個伺服器
noGraze: 瀏覽器擴展 "Graze for Mastodon" 會與Calckey發生衝突請停用該擴展。 noGraze: 瀏覽器擴展 "Graze for Mastodon" 會與Calckey發生衝突請停用該擴展。

View file

@ -13,18 +13,19 @@ pub enum IdConvertType {
#[napi] #[napi]
pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result<String> { pub fn convert_id(in_id: String, id_convert_type: IdConvertType) -> napi::Result<String> {
println!("converting id: {}", in_id);
use IdConvertType::*; use IdConvertType::*;
match id_convert_type { match id_convert_type {
MastodonId => { MastodonId => {
let mut out: i64 = 0; let mut out: i128 = 0;
for (i, c) in in_id.to_lowercase().chars().rev().enumerate() { for (i, c) in in_id.to_lowercase().chars().rev().enumerate() {
out += num_from_char(c)? as i64 * 36_i64.pow(i as u32); out += num_from_char(c)? as i128 * 36_i128.pow(i as u32);
} }
Ok(out.to_string()) Ok(out.to_string())
} }
CalckeyId => { CalckeyId => {
let mut input: i64 = match in_id.parse() { let mut input: i128 = match in_id.parse() {
Ok(s) => s, Ok(s) => s,
Err(_) => { Err(_) => {
return Err(Error::new( return Err(Error::new(

View file

@ -43,7 +43,6 @@
"ajv": "8.12.0", "ajv": "8.12.0",
"archiver": "5.3.1", "archiver": "5.3.1",
"argon2": "^0.30.3", "argon2": "^0.30.3",
"async-mutex": "^0.4.0",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autolinker": "4.0.0", "autolinker": "4.0.0",
"autwh": "0.1.0", "autwh": "0.1.0",
@ -112,6 +111,7 @@
"ratelimiter": "3.4.1", "ratelimiter": "3.4.1",
"re2": "1.19.0", "re2": "1.19.0",
"redis-lock": "0.1.4", "redis-lock": "0.1.4",
"redis-semaphore": "5.3.1",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"rename": "1.0.4", "rename": "1.0.4",
"rndstr": "1.0.0", "rndstr": "1.0.0",

View file

@ -1,42 +1,48 @@
import probeImageSize from "probe-image-size"; import probeImageSize from "probe-image-size";
import { Mutex, withTimeout } from "async-mutex"; import { Mutex } from "redis-semaphore";
import { FILE_TYPE_BROWSERSAFE } from "@/const.js"; import { FILE_TYPE_BROWSERSAFE } from "@/const.js";
import Logger from "@/services/logger.js"; import Logger from "@/services/logger.js";
import { Cache } from "./cache.js"; import { redisClient } from "@/db/redis.js";
export type Size = { export type Size = {
width: number; width: number;
height: number; height: number;
}; };
const cache = new Cache<boolean>(1000 * 60 * 10); // once every 10 minutes for the same url const logger = new Logger("emoji");
const mutex = withTimeout(new Mutex(), 1000);
export async function getEmojiSize(url: string): Promise<Size> { export async function getEmojiSize(url: string): Promise<Size> {
const logger = new Logger("emoji"); let attempted = true;
await mutex.runExclusive(() => { const lock = new Mutex(redisClient, "getEmojiSize");
const attempted = cache.get(url); await lock.acquire();
try {
const key = `getEmojiSize:${url}`;
attempted = (await redisClient.get(key)) !== null;
if (!attempted) { if (!attempted) {
cache.set(url, true); await redisClient.set(key, "done", "EX", 60 * 10);
} else {
logger.warn(`Attempt limit exceeded: ${url}`);
throw new Error("Too many attempts");
} }
}); } finally {
await lock.release();
}
if (attempted) {
logger.warn(`Attempt limit exceeded: ${url}`);
throw new Error("attempt limit exceeded");
}
try { try {
logger.info(`Retrieving emoji size from ${url}`); logger.debug(`Retrieving emoji size from ${url}`);
const { width, height, mime } = await probeImageSize(url, { const { width, height, mime } = await probeImageSize(url, {
timeout: 5000, timeout: 5000,
}); });
if (!(mime.startsWith("image/") && FILE_TYPE_BROWSERSAFE.includes(mime))) { if (!(mime.startsWith("image/") && FILE_TYPE_BROWSERSAFE.includes(mime))) {
throw new Error("Unsupported image type"); throw new Error("unsupported image type");
} }
return { width, height }; return { width, height };
} catch (e) { } catch (e) {
throw new Error(`Unable to retrieve metadata: ${e}`); throw new Error(`unable to retrieve metadata: ${e}`);
} }
} }

View file

@ -482,7 +482,8 @@ export function createCleanRemoteFilesJob() {
export function createIndexAllNotesJob(data = {}) { export function createIndexAllNotesJob(data = {}) {
return backgroundQueue.add("indexAllNotes", data, { return backgroundQueue.add("indexAllNotes", data, {
removeOnComplete: true, removeOnComplete: true,
removeOnFail: true, removeOnFail: false,
timeout: 1000 * 60 * 60 * 24,
}); });
} }

View file

@ -20,7 +20,7 @@ export default async function indexAllNotes(
let total: number = (job.data.total as number) ?? 0; let total: number = (job.data.total as number) ?? 0;
let running = true; let running = true;
const take = 50000; const take = 100000;
const batch = 100; const batch = 100;
while (running) { while (running) {
logger.info( logger.info(

View file

@ -541,10 +541,6 @@ function notEmpty(partial: Partial<any>) {
export async function updateNote(value: string | IObject, resolver?: Resolver) { export async function updateNote(value: string | IObject, resolver?: Resolver) {
const uri = typeof value === "string" ? value : value.id; const uri = typeof value === "string" ? value : value.id;
if (!uri) throw new Error("Missing note uri"); if (!uri) throw new Error("Missing note uri");
const instanceMeta = await fetchMeta();
if (instanceMeta.experimentalFeatures?.postEdits === false) {
throw new Error("Post edits disabled.");
}
// Skip if URI points to this server // Skip if URI points to this server
if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local"); if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local");

View file

@ -476,9 +476,6 @@ export const meta = {
optional: true, optional: true,
nullable: true, nullable: true,
properties: { properties: {
postEditing: {
type: "boolean",
},
postImports: { postImports: {
type: "boolean", type: "boolean",
}, },

View file

@ -174,7 +174,6 @@ export const paramDef = {
type: "object", type: "object",
nullable: true, nullable: true,
properties: { properties: {
postEditing: { type: "boolean" },
postImports: { type: "boolean" }, postImports: { type: "boolean" },
}, },
}, },

View file

@ -529,7 +529,7 @@ export default define(meta, paramDef, async (ps, me) => {
github: instance.enableGithubIntegration, github: instance.enableGithubIntegration,
discord: instance.enableDiscordIntegration, discord: instance.enableDiscordIntegration,
serviceWorker: instance.enableServiceWorker, serviceWorker: instance.enableServiceWorker,
postEditing: instance.experimentalFeatures?.postEditing || false, postEditing: true,
postImports: instance.experimentalFeatures?.postImports || false, postImports: instance.experimentalFeatures?.postImports || false,
miauth: true, miauth: true,
}; };

View file

@ -140,12 +140,6 @@ export const meta = {
code: "NOT_LOCAL_USER", code: "NOT_LOCAL_USER",
id: "b907f407-2aa0-4283-800b-a2c56290b822", id: "b907f407-2aa0-4283-800b-a2c56290b822",
}, },
editsDisabled: {
message: "Post edits are disabled.",
code: "EDITS_DISABLED",
id: "99306f00-fb81-11ed-be56-0242ac120002",
},
}, },
} as const; } as const;
@ -244,11 +238,6 @@ export const paramDef = {
export default define(meta, paramDef, async (ps, user) => { export default define(meta, paramDef, async (ps, user) => {
if (user.movedToUri != null) throw new ApiError(meta.errors.accountLocked); if (user.movedToUri != null) throw new ApiError(meta.errors.accountLocked);
const instanceMeta = await fetchMeta();
if (instanceMeta.experimentalFeatures?.postEdits === false) {
throw new ApiError(meta.errors.editsDisabled);
}
if (!Users.isLocalUser(user)) { if (!Users.isLocalUser(user)) {
throw new ApiError(meta.errors.notLocalUser); throw new ApiError(meta.errors.notLocalUser);
} }

View file

@ -23,8 +23,15 @@ export default define(meta, paramDef, async (ps) => {
if (!ps.forceUpdate && cachedPatrons) { if (!ps.forceUpdate && cachedPatrons) {
patrons = JSON.parse(cachedPatrons); patrons = JSON.parse(cachedPatrons);
} else { } else {
AbortSignal.timeout ??= function timeout(ms) {
const ctrl = new AbortController()
setTimeout(() => ctrl.abort(), ms)
return ctrl.signal
}
patrons = await fetch( patrons = await fetch(
"https://codeberg.org/calckey/calckey/raw/branch/develop/patrons.json", "https://codeberg.org/calckey/calckey/raw/branch/develop/patrons.json",
{ signal: AbortSignal.timeout(2000) }
) )
.then((response) => response.json()) .then((response) => response.json())
.catch(() => { .catch(() => {

View file

@ -83,7 +83,7 @@ const nodeinfo2 = async () => {
disableGlobalTimeline: meta.disableGlobalTimeline, disableGlobalTimeline: meta.disableGlobalTimeline,
emailRequiredForSignup: meta.emailRequiredForSignup, emailRequiredForSignup: meta.emailRequiredForSignup,
searchFilters: config.meilisearch ? true : false, searchFilters: config.meilisearch ? true : false,
postEditing: meta.experimentalFeatures?.postEditing || false, postEditing: true,
postImports: meta.experimentalFeatures?.postImports || false, postImports: meta.experimentalFeatures?.postImports || false,
enableHcaptcha: meta.enableHcaptcha, enableHcaptcha: meta.enableHcaptcha,
enableRecaptcha: meta.enableRecaptcha, enableRecaptcha: meta.enableRecaptcha,

View file

@ -69,6 +69,7 @@ import { getActiveWebhooks } from "@/misc/webhook-cache.js";
import { shouldSilenceInstance } from "@/misc/should-block-instance.js"; import { shouldSilenceInstance } from "@/misc/should-block-instance.js";
import meilisearch from "../../db/meilisearch.js"; import meilisearch from "../../db/meilisearch.js";
import { redisClient } from "@/db/redis.js"; import { redisClient } from "@/db/redis.js";
import { Mutex } from "redis-semaphore";
const mutedWordsCache = new Cache< const mutedWordsCache = new Cache<
{ userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[] { userId: UserProfile["userId"]; mutedWords: UserProfile["mutedWords"] }[]
@ -461,58 +462,43 @@ export default async (
} }
if (!dontFederateInitially) { if (!dontFederateInitially) {
let publishKey: string;
let noteToPublish: Note;
const relays = await getCachedRelays(); const relays = await getCachedRelays();
// Some relays (e.g., aode-relay) deliver posts by boosting them as // Some relays (e.g., aode-relay) deliver posts by boosting them as
// Announce activities. In that case, user is the relay's actor. // Announce activities. In that case, user is the relay's actor.
const boostedByRelay = const boostedByRelay =
!!user.inbox && !!user.inbox &&
relays.map((relay) => relay.inbox).includes(user.inbox); relays.map((relay) => relay.inbox).includes(user.inbox);
if (!note.uri) { if (boostedByRelay && data.renote && data.renote.userHost) {
// Publish if the post is local publishKey = `publishedNote:${data.renote.id}`;
publishNotesStream(note); noteToPublish = data.renote;
} else if (boostedByRelay && data.renote?.uri) { } else {
// Use Redis transaction for atomicity publishKey = `publishedNote:${note.id}`;
await redisClient.watch(`publishedNote:${data.renote.uri}`); noteToPublish = note;
const exists = await redisClient.exists( }
`publishedNote:${data.renote.uri}`,
); const lock = new Mutex(redisClient, "publishedNote");
if (exists === 0) { await lock.acquire();
// Start the transaction try {
const transaction = redisClient.multi(); const published = (await redisClient.get(publishKey)) !== null;
const key = `publishedNote:${data.renote.uri}`; if (!published) {
transaction.set(key, 1, "EX", 30); await redisClient.set(publishKey, "done", "EX", 30);
// Execute the transaction if (noteToPublish.renoteId) {
transaction.exec((err, replies) => { // Prevents other threads from publishing the boosting post
// Publish after setting the key in Redis await redisClient.set(
if (!err && data.renote) { `publishedNote:${noteToPublish.renoteId}`,
publishNotesStream(data.renote); "done",
} "EX",
}); 30,
} else { );
// Abort the transaction }
redisClient.unwatch(); publishNotesStream(noteToPublish);
}
} else if (!boostedByRelay && note.uri) {
// Use Redis transaction for atomicity
await redisClient.watch(`publishedNote:${note.uri}`);
const exists = await redisClient.exists(`publishedNote:${note.uri}`);
if (exists === 0) {
// Start the transaction
const transaction = redisClient.multi();
const key = `publishedNote:${note.uri}`;
transaction.set(key, 1, "EX", 30);
// Execute the transaction
transaction.exec((err, replies) => {
// Publish after setting the key in Redis
if (!err) {
publishNotesStream(note);
}
});
} else {
// Abort the transaction
redisClient.unwatch();
} }
} finally {
await lock.release();
} }
} }
if (note.replyId != null) { if (note.replyId != null) {

View file

@ -67,9 +67,8 @@ function chosen(emoji: any) {
function opening() { function opening() {
try { try {
picker.value?.reset(); picker.value?.reset();
} } catch (e) {
catch (e) { console.error(`Something's wrong with restting the emoji picker: ${e}`);
console.error(`Something's wrong with restting the emoji picker: ${e}`)
} }
picker.value?.focus(); picker.value?.focus();
} }

View file

@ -337,9 +337,7 @@ let appearNote = $computed(() =>
const isMyRenote = $i && $i.id === note.userId; const isMyRenote = $i && $i.id === note.userId;
const showContent = ref(false); const showContent = ref(false);
const isDeleted = ref(false); const isDeleted = ref(false);
const muted = ref( const muted = ref(getWordSoftMute(note, $i, defaultStore.state.mutedWords));
getWordSoftMute(appearNote, $i, defaultStore.state.mutedWords)
);
const translation = ref(null); const translation = ref(null);
const translating = ref(false); const translating = ref(false);
const enableEmojiReactions = defaultStore.state.enableEmojiReactions; const enableEmojiReactions = defaultStore.state.enableEmojiReactions;

View file

@ -53,12 +53,12 @@ const props = defineProps<{
const pagingComponent = ref<InstanceType<typeof MkPagination>>(); const pagingComponent = ref<InstanceType<typeof MkPagination>>();
function scrollTop() { function scrollTop() {
scroll(tlEl.value, { top: 0, behavior: 'smooth' }) scroll(tlEl.value, { top: 0, behavior: "smooth" });
} }
defineExpose({ defineExpose({
pagingComponent, pagingComponent,
scrollTop scrollTop,
}); });
</script> </script>

View file

@ -23,7 +23,7 @@
ref="tlComponent" ref="tlComponent"
:no-gap="!$store.state.showGapBetweenNotesInTimeline" :no-gap="!$store.state.showGapBetweenNotesInTimeline"
:pagination="pagination" :pagination="pagination"
@queue="(x) => queue = x" @queue="(x) => (queue = x)"
/> />
</template> </template>

View file

@ -97,13 +97,16 @@
><Mfm ><Mfm
:text="'$[sparkle @kainoa@calckey.social] (Main developer)'" :text="'$[sparkle @kainoa@calckey.social] (Main developer)'"
/></FormLink> /></FormLink>
<FormLink to="/@april@calckey.social"
><Mfm :text="'@april@calckey.social (Backend)'"
/></FormLink>
<FormLink to="/@freeplay@calckey.social" <FormLink to="/@freeplay@calckey.social"
><Mfm ><Mfm
:text="'@freeplay@calckey.social (UI/UX)'" :text="'@freeplay@calckey.social (UI/UX)'"
/></FormLink> /></FormLink>
<FormLink to="/@nmkj@calckey.jp"
><Mfm :text="'@nmkj@calckey.jp (Backend)'"
/></FormLink>
<FormLink to="/@dev@post.naskya.net"
><Mfm :text="'@dev@post.naskya.net (Backend)'"
/></FormLink>
<FormLink to="/@panos@calckey.social" <FormLink to="/@panos@calckey.social"
><Mfm ><Mfm
:text="'@panos@calckey.social (Project Coordinator)'" :text="'@panos@calckey.social (Project Coordinator)'"
@ -128,6 +131,9 @@
><Mfm text="$[jelly ❤]" /> ><Mfm text="$[jelly ❤]" />
{{ i18n.ts._aboutMisskey.patrons }}</template {{ i18n.ts._aboutMisskey.patrons }}</template
> >
<p>
{{ i18n.ts._aboutMisskey.patronsList }}
</p>
<MkSparkle> <MkSparkle>
<span <span
v-for="patron in patrons" v-for="patron in patrons"
@ -164,7 +170,12 @@ import { defaultStore } from "@/store";
import * as os from "@/os"; import * as os from "@/os";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
const patrons = await os.api("patrons", { forceUpdate: true }); let patrons = [];
try {
patrons = await os.api("patrons", { forceUpdate: true });
} catch {
console.error("Codeberg's down.")
}
let easterEggReady = false; let easterEggReady = false;
let easterEggEmojis = $ref([]); let easterEggEmojis = $ref([]);

View file

@ -8,19 +8,6 @@
/></template> /></template>
<MkSpacer :content-max="700" :margin-min="16" :margin-max="32"> <MkSpacer :content-max="700" :margin-min="16" :margin-max="32">
<FormSuspense :p="init"> <FormSuspense :p="init">
<FormSwitch
v-model="enablePostEditing"
@update:modelValue="save"
class="_formBlock"
>
<template #label>
<i class="ph-pencil-line ph-bold ph-lg"></i>
{{ i18n.ts._experiments.enablePostEditing }}
</template>
<template #caption>{{
i18n.ts._experiments.postEditingCaption
}}</template>
</FormSwitch>
<FormSwitch <FormSwitch
v-model="enablePostImports" v-model="enablePostImports"
@update:modelValue="save" @update:modelValue="save"
@ -49,13 +36,11 @@ import { fetchInstance } from "@/instance";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
let enablePostEditing = $ref(false);
let enablePostImports = $ref(false); let enablePostImports = $ref(false);
let meta = $ref<MetaExperiments | null>(null); let meta = $ref<MetaExperiments | null>(null);
type MetaExperiments = { type MetaExperiments = {
experimentalFeatures?: { experimentalFeatures?: {
postEditing?: boolean;
postImports?: boolean; postImports?: boolean;
}; };
}; };
@ -64,14 +49,12 @@ async function init() {
meta = (await os.api("admin/meta")) as MetaExperiments; meta = (await os.api("admin/meta")) as MetaExperiments;
if (!meta) return; if (!meta) return;
enablePostEditing = meta.experimentalFeatures?.postEditing ?? false;
enablePostImports = meta.experimentalFeatures?.postImports ?? false; enablePostImports = meta.experimentalFeatures?.postImports ?? false;
} }
function save() { function save() {
const experiments: MetaExperiments = { const experiments: MetaExperiments = {
experimentalFeatures: { experimentalFeatures: {
postEditing: enablePostEditing,
postImports: enablePostImports, postImports: enablePostImports,
}, },
}; };

View file

@ -22,7 +22,7 @@
:value="usersComparedToThePrevDay" :value="usersComparedToThePrevDay"
></MkNumberDiff> ></MkNumberDiff>
</div> </div>
<div class="label">Users</div> <div class="label">{{ i18n.ts.users }}</div>
</div> </div>
</div> </div>
<div class="item _panel notes"> <div class="item _panel notes">
@ -41,7 +41,7 @@
:value="notesComparedToThePrevDay" :value="notesComparedToThePrevDay"
></MkNumberDiff> ></MkNumberDiff>
</div> </div>
<div class="label">Posts</div> <div class="label">{{ i18n.ts.notes }}</div>
</div> </div>
</div> </div>
<div class="item _panel instances"> <div class="item _panel instances">
@ -55,7 +55,7 @@
style="margin-right: 0.5em" style="margin-right: 0.5em"
/> />
</div> </div>
<div class="label">Instances</div> <div class="label">{{ i18n.ts.instances }}</div>
</div> </div>
</div> </div>
<div class="item _panel online"> <div class="item _panel online">
@ -69,10 +69,26 @@
style="margin-right: 0.5em" style="margin-right: 0.5em"
/> />
</div> </div>
<div class="label">Online</div> <div class="label">{{ i18n.ts.online }}</div>
</div>
</div>
<div class="item _panel emojis">
<div class="icon">
<i class="ph-smiley ph-bold ph-xl"></i>
</div>
<div class="body">
<div class="value">
<MkNumber
:value="emojiCount"
style="margin-right: 0.5em"
/>
</div>
<div class="label">{{ i18n.ts.emojis }}</div>
</div> </div>
</div> </div>
</div> </div>
<!-- TODO: Drive -->
</Transition> </Transition>
</div> </div>
</template> </template>
@ -90,6 +106,7 @@ let stats: any = $ref(null);
let usersComparedToThePrevDay = $ref<number>(); let usersComparedToThePrevDay = $ref<number>();
let notesComparedToThePrevDay = $ref<number>(); let notesComparedToThePrevDay = $ref<number>();
let onlineUsersCount = $ref(0); let onlineUsersCount = $ref(0);
let emojiCount = $ref(0);
let fetching = $ref(true); let fetching = $ref(true);
onMounted(async () => { onMounted(async () => {
@ -110,6 +127,10 @@ onMounted(async () => {
stats.originalNotesCount - chart.local.total[1]; stats.originalNotesCount - chart.local.total[1];
}); });
os.api("meta", { detail: false }).then((meta) => {
emojiCount = meta.emojis.length;
});
fetching = false; fetching = false;
}); });
</script> </script>
@ -172,6 +193,13 @@ onMounted(async () => {
} }
} }
&.drive {
> .icon {
background: #b4637a22;
color: #eb6f92;
}
}
> .body { > .body {
padding: 2px 0; padding: 2px 0;

View file

@ -126,7 +126,7 @@ definePageMetadata(
<style lang="scss" scoped> <style lang="scss" scoped>
.tqmomfks { .tqmomfks {
padding: var(--margin); padding: var(--margin);
> .tl { > .tl {
background: none; background: none;
border-radius: var(--radius); border-radius: var(--radius);

View file

@ -24,7 +24,9 @@
<div <div
ref="bannerEl" ref="bannerEl"
class="banner" class="banner"
:style="{ backgroundImage: `url('${user.bannerUrl}')` }" :style="{
backgroundImage: `url('${user.bannerUrl}')`,
}"
></div> ></div>
<div class="fade"></div> <div class="fade"></div>
<div class="title"> <div class="title">
@ -449,7 +451,12 @@ const timeForThem = $computed(() => {
return ""; return "";
}); });
const patrons = await os.api("patrons"); let patrons = [];
try {
patrons = await os.api("patrons");
} catch {
console.error("Codeberg's down.")
}
function parallaxLoop() { function parallaxLoop() {
parallaxAnimationId = window.requestAnimationFrame(parallaxLoop); parallaxAnimationId = window.requestAnimationFrame(parallaxLoop);
@ -510,7 +517,7 @@ onUnmounted(() => {
background-size: cover; background-size: cover;
background-position: center; background-position: center;
pointer-events: none; pointer-events: none;
filter: blur(12px) opacity(.1); filter: blur(12px) opacity(0.1);
} }
} }

View file

@ -408,7 +408,7 @@ export function getNoteMenu(props: {
}, },
} }
: undefined, : undefined,
instance.features.postEditing && isAppearAuthor isAppearAuthor
? { ? {
icon: "ph-pencil-line ph-bold ph-lg", icon: "ph-pencil-line ph-bold ph-lg",
text: i18n.ts.edit, text: i18n.ts.edit,

View file

@ -5,7 +5,7 @@
<span class="year">{{ i18n.t("yearX", { year }) }}</span> <span class="year">{{ i18n.t("yearX", { year }) }}</span>
<span class="month">{{ i18n.t("monthX", { month }) }}</span> <span class="month">{{ i18n.t("monthX", { month }) }}</span>
</p> </p>
<p v-if="month === 1 && day === 1" class="day"> <p v-if="(month === 1 && day === 1) || isBirthday" class="day">
🎉{{ i18n.t("dayX", { day }) 🎉{{ i18n.t("dayX", { day })
}}<span style="display: inline-block; transform: scaleX(-1)" }}<span style="display: inline-block; transform: scaleX(-1)"
>🎉</span >🎉</span
@ -55,6 +55,7 @@ import {
import { GetFormResultType } from "@/scripts/form"; import { GetFormResultType } from "@/scripts/form";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { useInterval } from "@/scripts/use-interval"; import { useInterval } from "@/scripts/use-interval";
import { $i } from "@/account";
const name = "calendar"; const name = "calendar";
@ -80,6 +81,8 @@ const { widgetProps, configure } = useWidgetPropsManager(
emit emit
); );
const hasBirthday = Boolean($i?.birthday);
const year = ref(0); const year = ref(0);
const month = ref(0); const month = ref(0);
const day = ref(0); const day = ref(0);
@ -88,6 +91,8 @@ const yearP = ref(0);
const monthP = ref(0); const monthP = ref(0);
const dayP = ref(0); const dayP = ref(0);
const isHoliday = ref(false); const isHoliday = ref(false);
const isBirthday = ref(false);
const tick = () => { const tick = () => {
const now = new Date(); const now = new Date();
const nd = now.getDate(); const nd = now.getDate();
@ -121,6 +126,13 @@ const tick = () => {
yearP.value = (yearNumer / yearDenom) * 100; yearP.value = (yearNumer / yearDenom) * 100;
isHoliday.value = now.getDay() === 0 || now.getDay() === 6; isHoliday.value = now.getDay() === 0 || now.getDay() === 6;
if (hasBirthday) {
const [bdayYear, bdayMonth, bdayDay] = $i.birthday.split("-");
if (month.value === +bdayMonth && day.value == +bdayDay) {
isBirthday.value = true;
}
}
}; };
useInterval(tick, 1000, { useInterval(tick, 1000, {

View file

@ -10,17 +10,15 @@
"@griff@stop.voring.me", "@griff@stop.voring.me",
"@cafkafk@ck.cafkafk.com", "@cafkafk@ck.cafkafk.com",
"@privateger@plasmatrap.com", "@privateger@plasmatrap.com",
"@self@neo.voidworks.cc", "@effye@toot.thoughtworks.com",
"@effy@social.effy.space",
"@Kio@kitsunes.club", "@Kio@kitsunes.club",
"@twann@tech.lgbt", "@twann@tech.lgbt",
"@surfbum@calckey.nz", "@surfbum@calckey.nz",
"@topher@mastodon.online", "@topher@mastodon.online",
"@hanicef@stop.voring.me", "@hanicef@stop.voring.me",
"@nmkj@calckey.jp", "@nmkj@calckey.jp",
"@trapezial@calckey.jp",
"@unattributed@calckey.social", "@unattributed@calckey.social",
"@cody@mk.codingneko.com", "@cody@misskey.codingneko.com",
"@kate@blahaj.zone", "@kate@blahaj.zone",
"@emtk@mkkey.net", "@emtk@mkkey.net",
"@jovikowi@calckey.social", "@jovikowi@calckey.social",
@ -35,13 +33,12 @@
"@box464@calckey.social", "@box464@calckey.social",
"@MariaTheMartian@calckey.social", "@MariaTheMartian@calckey.social",
"@nisemikol@calckey.social", "@nisemikol@calckey.social",
"@smallpatatas@calckey.patatas.ca", "@smallpatatas@blahaj.zone",
"@bayra@stop.voring.me", "@bayra@stop.voring.me",
"@frost@wolfdo.gg", "@frost@wolfdo.gg",
"@joebiden@fuckgov.org", "@joebiden@fuckgov.org",
"@nyaa@calckey.social", "@nyaa@calckey.social",
"@Dan@calckey.social", "@Dan@calckey.social",
"@testing@stop.voring.me",
"@dana@calckey.social", "@dana@calckey.social",
"@Jdreben@calckey.social", "@Jdreben@calckey.social",
"@natalie@prismst.one", "@natalie@prismst.one",
@ -77,6 +74,10 @@
"@jtbennett@noc.social", "@jtbennett@noc.social",
"@renere@distance.blue", "@renere@distance.blue",
"@theking@kitsunes.club", "@theking@kitsunes.club",
"@toof@fedi.toofie.net",
"@Punko@calckey.social",
"@joesbrat67@calckey.social",
"@arth@calckey.social",
"\nInterkosmos Link" "\nInterkosmos Link"
] ]
} }

View file

@ -132,9 +132,6 @@ importers:
argon2: argon2:
specifier: ^0.30.3 specifier: ^0.30.3
version: 0.30.3 version: 0.30.3
async-mutex:
specifier: ^0.4.0
version: 0.4.0
autobind-decorator: autobind-decorator:
specifier: 2.4.0 specifier: 2.4.0
version: 2.4.0 version: 2.4.0
@ -339,6 +336,9 @@ importers:
redis-lock: redis-lock:
specifier: 0.1.4 specifier: 0.1.4
version: 0.1.4 version: 0.1.4
redis-semaphore:
specifier: 5.3.1
version: 5.3.1(ioredis@5.3.2)
reflect-metadata: reflect-metadata:
specifier: 0.1.13 specifier: 0.1.13
version: 0.1.13 version: 0.1.13
@ -598,7 +598,7 @@ importers:
version: 5.1.3 version: 5.1.3
webpack: webpack:
specifier: ^5.85.1 specifier: ^5.85.1
version: 5.85.1(@swc/core@1.3.62)(webpack-cli@5.1.3) version: 5.85.1(@swc/core@1.3.62)
ws: ws:
specifier: 8.13.0 specifier: 8.13.0
version: 8.13.0 version: 8.13.0
@ -2666,6 +2666,7 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
requiresBuild: true
dependencies: dependencies:
'@swc/wasm': 1.2.130 '@swc/wasm': 1.2.130
@ -2772,6 +2773,7 @@ packages:
/@swc/wasm@1.2.130: /@swc/wasm@1.2.130:
resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==} resolution: {integrity: sha512-rNcJsBxS70+pv8YUWwf5fRlWX6JoY/HJc25HD/F8m6Kv7XhJdqPPMhyX6TKkUBPAG7TWlZYoxa+rHAjPy4Cj3Q==}
requiresBuild: true
/@syuilo/aiscript@0.11.1: /@syuilo/aiscript@0.11.1:
resolution: {integrity: sha512-chwOIA3yLUKvOB0G611hjLArKTeOWNmTm3lHERSaDW1d+dS6do56naX6Lkwy2UpnwWC0qzeNSgg35elk6t2gZg==} resolution: {integrity: sha512-chwOIA3yLUKvOB0G611hjLArKTeOWNmTm3lHERSaDW1d+dS6do56naX6Lkwy2UpnwWC0qzeNSgg35elk6t2gZg==}
@ -4491,12 +4493,6 @@ packages:
stream-exhaust: 1.0.2 stream-exhaust: 1.0.2
dev: true dev: true
/async-mutex@0.4.0:
resolution: {integrity: sha512-eJFZ1YhRR8UN8eBLoNzcDPcy/jqjsg6I1AP+KvWQX80BqOSW1oJPJXDylPUEeMr2ZQvHgnQ//Lp6f3RQ1zI7HA==}
dependencies:
tslib: 2.6.0
dev: false
/async-settle@1.0.0: /async-settle@1.0.0:
resolution: {integrity: sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==} resolution: {integrity: sha512-VPXfB4Vk49z1LHHodrEQ6Xf7W4gg1w0dAPROHngx7qgDjqmIQ+fXmwgGXTW/ITLai0YLSvWepJOP9EVpMnEAcw==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@ -4641,7 +4637,7 @@ packages:
/axios@0.24.0: /axios@0.24.0:
resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==} resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==}
dependencies: dependencies:
follow-redirects: 1.15.2(debug@4.3.4) follow-redirects: 1.15.2
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
dev: false dev: false
@ -4657,7 +4653,7 @@ packages:
/axios@1.2.2: /axios@1.2.2:
resolution: {integrity: sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==} resolution: {integrity: sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==}
dependencies: dependencies:
follow-redirects: 1.15.2(debug@4.3.4) follow-redirects: 1.15.2
form-data: 4.0.0 form-data: 4.0.0
proxy-from-env: 1.1.0 proxy-from-env: 1.1.0
transitivePeerDependencies: transitivePeerDependencies:
@ -4667,7 +4663,7 @@ packages:
/axios@1.4.0: /axios@1.4.0:
resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==} resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==}
dependencies: dependencies:
follow-redirects: 1.15.2(debug@4.3.4) follow-redirects: 1.15.2
form-data: 4.0.0 form-data: 4.0.0
proxy-from-env: 1.1.0 proxy-from-env: 1.1.0
transitivePeerDependencies: transitivePeerDependencies:
@ -6283,6 +6279,17 @@ packages:
dependencies: dependencies:
ms: 2.0.0 ms: 2.0.0
/debug@3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.3
dev: false
/debug@3.2.7(supports-color@8.1.1): /debug@3.2.7(supports-color@8.1.1):
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies: peerDependencies:
@ -6293,6 +6300,7 @@ packages:
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
supports-color: 8.1.1 supports-color: 8.1.1
dev: true
/debug@4.3.3: /debug@4.3.3:
resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==}
@ -7530,6 +7538,16 @@ packages:
tabbable: 6.2.0 tabbable: 6.2.0
dev: true dev: true
/follow-redirects@1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
/follow-redirects@1.15.2(debug@4.3.4): /follow-redirects@1.15.2(debug@4.3.4):
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
@ -7540,6 +7558,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
debug: 4.3.4(supports-color@8.1.1) debug: 4.3.4(supports-color@8.1.1)
dev: true
/for-each@0.3.3: /for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
@ -8450,7 +8469,7 @@ packages:
engines: {node: '>= 4.5.0'} engines: {node: '>= 4.5.0'}
dependencies: dependencies:
agent-base: 4.3.0 agent-base: 4.3.0
debug: 3.2.7(supports-color@8.1.1) debug: 3.2.7
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: false dev: false
@ -9849,7 +9868,7 @@ packages:
json5: 2.2.3 json5: 2.2.3
loader-utils: 2.0.4 loader-utils: 2.0.4
schema-utils: 3.3.0 schema-utils: 3.3.0
webpack: 5.85.1(@swc/core@1.3.62)(webpack-cli@5.1.3) webpack: 5.85.1(@swc/core@1.3.62)
dev: true dev: true
/json5@2.2.3: /json5@2.2.3:
@ -10092,7 +10111,7 @@ packages:
resolution: {integrity: sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==} resolution: {integrity: sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==}
engines: {node: '>= 7.6.0'} engines: {node: '>= 7.6.0'}
dependencies: dependencies:
debug: 3.2.7(supports-color@8.1.1) debug: 3.2.7
koa-send: 5.0.1 koa-send: 5.0.1
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -11086,7 +11105,7 @@ packages:
engines: {node: '>= 4.4.x'} engines: {node: '>= 4.4.x'}
hasBin: true hasBin: true
dependencies: dependencies:
debug: 3.2.7(supports-color@8.1.1) debug: 3.2.7
iconv-lite: 0.4.24 iconv-lite: 0.4.24
sax: 1.2.4 sax: 1.2.4
transitivePeerDependencies: transitivePeerDependencies:
@ -12831,6 +12850,18 @@ packages:
dependencies: dependencies:
redis-errors: 1.2.0 redis-errors: 1.2.0
/redis-semaphore@5.3.1(ioredis@5.3.2):
resolution: {integrity: sha512-oUpxxfxSbh5eT0mvVpz2d4Qlg2CsaoQkeo80/v6CU2l97zO0u6NPgc9/zQZa9KGR3/93b0igtSct3hEFh8Ei8w==}
engines: {node: '>= 14.17.0'}
peerDependencies:
ioredis: ^4.1.0 || ^5
dependencies:
debug: 4.3.4(supports-color@8.1.1)
ioredis: 5.3.2
transitivePeerDependencies:
- supports-color
dev: false
/redis@4.6.7: /redis@4.6.7:
resolution: {integrity: sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==} resolution: {integrity: sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==}
dependencies: dependencies:
@ -13980,7 +14011,7 @@ packages:
webpack: '>=2' webpack: '>=2'
dependencies: dependencies:
'@swc/core': 1.3.62 '@swc/core': 1.3.62
webpack: 5.85.1(@swc/core@1.3.62)(webpack-cli@5.1.3) webpack: 5.85.1(@swc/core@1.3.62)
dev: true dev: true
/swiper@9.3.2: /swiper@9.3.2:
@ -14101,7 +14132,7 @@ packages:
schema-utils: 3.3.0 schema-utils: 3.3.0
serialize-javascript: 6.0.1 serialize-javascript: 6.0.1
terser: 5.18.2 terser: 5.18.2
webpack: 5.85.1(@swc/core@1.3.62)(webpack-cli@5.1.3) webpack: 5.85.1(@swc/core@1.3.62)
dev: true dev: true
/terser@5.18.2: /terser@5.18.2:
@ -14401,7 +14432,7 @@ packages:
micromatch: 4.0.5 micromatch: 4.0.5
semver: 7.5.1 semver: 7.5.1
typescript: 5.1.3 typescript: 5.1.3
webpack: 5.85.1(@swc/core@1.3.62)(webpack-cli@5.1.3) webpack: 5.85.1(@swc/core@1.3.62)
dev: true dev: true
/ts-node@10.4.0(@swc/core@1.3.62)(@types/node@20.3.1)(typescript@5.1.3): /ts-node@10.4.0(@swc/core@1.3.62)(@types/node@20.3.1)(typescript@5.1.3):
@ -15235,6 +15266,46 @@ packages:
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
dev: true dev: true
/webpack@5.85.1(@swc/core@1.3.62):
resolution: {integrity: sha512-xTb7MRf4LY8Z5rzn7aIx4TDrwYJrjcHnIfU1TqtyZOoObyuGSpAUwIvVuqq5wPnv7WEgQr8UvO1q/dgoGG4HjA==}
engines: {node: '>=10.13.0'}
hasBin: true
peerDependencies:
webpack-cli: '*'
peerDependenciesMeta:
webpack-cli:
optional: true
dependencies:
'@types/eslint-scope': 3.7.4
'@types/estree': 1.0.1
'@webassemblyjs/ast': 1.11.6
'@webassemblyjs/wasm-edit': 1.11.6
'@webassemblyjs/wasm-parser': 1.11.6
acorn: 8.9.0
acorn-import-assertions: 1.9.0(acorn@8.9.0)
browserslist: 4.21.9
chrome-trace-event: 1.0.3
enhanced-resolve: 5.15.0
es-module-lexer: 1.3.0
eslint-scope: 5.1.1
events: 3.3.0
glob-to-regexp: 0.4.1
graceful-fs: 4.2.11
json-parse-even-better-errors: 2.3.1
loader-runner: 4.3.0
mime-types: 2.1.35
neo-async: 2.6.2
schema-utils: 3.3.0
tapable: 2.2.1
terser-webpack-plugin: 5.3.9(@swc/core@1.3.62)(webpack@5.85.1)
watchpack: 2.4.0
webpack-sources: 3.2.3
transitivePeerDependencies:
- '@swc/core'
- esbuild
- uglify-js
dev: true
/webpack@5.85.1(@swc/core@1.3.62)(webpack-cli@5.1.3): /webpack@5.85.1(@swc/core@1.3.62)(webpack-cli@5.1.3):
resolution: {integrity: sha512-xTb7MRf4LY8Z5rzn7aIx4TDrwYJrjcHnIfU1TqtyZOoObyuGSpAUwIvVuqq5wPnv7WEgQr8UvO1q/dgoGG4HjA==} resolution: {integrity: sha512-xTb7MRf4LY8Z5rzn7aIx4TDrwYJrjcHnIfU1TqtyZOoObyuGSpAUwIvVuqq5wPnv7WEgQr8UvO1q/dgoGG4HjA==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}