Merge pull request '1.1+2025.2.3' (#76) from dev into stable

Reviewed-on: https://codeberg.org/yeentown/barkey/pulls/76
This commit is contained in:
zima 2025-07-03 19:32:54 +02:00
commit 0978ac33f8
9 changed files with 590 additions and 60 deletions

290
.config/dev.yml Normal file
View file

@ -0,0 +1,290 @@
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# Misskey configuration
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# ┌─────┐
#───┘ URL └─────────────────────────────────────────────────────
# Final accessible URL seen by a user.
url: http://misskey.local:3000
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# URL SETTINGS AFTER THAT!
# ┌───────────────────────┐
#───┘ Port and TLS settings └───────────────────────────────────
#
# Misskey requires a reverse proxy to support HTTPS connections.
#
# +----- https://example.tld/ ------------+
# +------+ |+-------------+ +----------------+|
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
# +------+ |+-------------+ +----------------+|
# +---------------------------------------+
#
# You need to set up a reverse proxy. (e.g. nginx)
# An encrypted connection with HTTPS is highly recommended
# because tokens may be transferred in GET requests.
# The port that your Misskey server should listen on.
port: 3000
# ┌──────────────────────────┐
#───┘ PostgreSQL configuration └────────────────────────────────
db:
host: postgres
port: 5432
# Database name
db: postgres
# Auth
user: postgres
pass: ci
# Whether disable Caching queries
#disableCache: true
# Extra Connection options
#extra:
# ssl: true
dbReplications: false
# You can configure any number of replicas here
#dbSlaves:
# -
# host:
# port:
# db:
# user:
# pass:
# -
# host:
# port:
# db:
# user:
# pass:
# ┌─────────────────────┐
#───┘ Redis configuration └─────────────────────────────────────
redis:
host: redis
port: 6379
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
#pass: example-pass
#prefix: example-prefix
#db: 1
#redisForPubsub:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForJobQueue:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForTimelines:
# host: redis
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
#redisForRateLimit:
# host: localhost
# port: 6379
# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
# #pass: example-pass
# #prefix: example-prefix
# #db: 1
# # You can specify more ioredis options...
# #username: example-username
# ┌───────────────────────────────┐
#───┘ Fulltext search configuration └─────────────────────────────
# These are the setting items for the full-text search provider.
fulltextSearch:
# You can select the ID generation method.
# - sqlLike (default)
# Use SQL-like search.
# This is a standard feature of PostgreSQL, so no special extensions are required.
# - sqlPgroonga
# Use pgroonga.
# You need to install pgroonga and configure it as a PostgreSQL extension.
# In addition to the above, you need to create a pgroonga index on the text column of the note table.
# see: https://pgroonga.github.io/tutorial/
# - meilisearch
# Use Meilisearch.
# You need to install Meilisearch and configure.
provider: sqlLike
# For Meilisearch settings.
# If you select "meilisearch" for "fulltextSearch.provider", it must be set.
# You can set scope to local or global (default value)
# (include notes from remote).
#meilisearch:
# host: meilisearch
# port: 7700
# apiKey: ''
# ssl: true
# index: ''
# scope: global
# ┌───────────────┐
#───┘ ID generation └───────────────────────────────────────────
# You can select the ID generation method.
# You don't usually need to change this setting, but you can
# change it according to your preferences.
# Available methods:
# aid ... Short, Millisecond accuracy
# aidx ... Millisecond accuracy
# meid ... Similar to ObjectID, Millisecond accuracy
# ulid ... Millisecond accuracy
# objectid ... This is left for backward compatibility
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
# ID SETTINGS AFTER THAT!
id: 'aidx'
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
# Whether disable HSTS
#disableHsts: true
# Number of worker processes
#clusterLimit: 1
# Job concurrency per worker
# deliverJobConcurrency: 128
# inboxJobConcurrency: 16
# relashionshipJobConcurrency: 16
# What's relashionshipJob?:
# Follow, unfollow, block and unblock(ings) while following-imports, etc. or account migrations.
# Job rate limiter
# deliverJobPerSec: 128
# inboxJobPerSec: 32
# relashionshipJobPerSec: 64
# Job attempts
# deliverJobMaxAttempts: 12
# inboxJobMaxAttempts: 8
# Local address used for outgoing requests
#outgoingAddress: 127.0.0.1
# IP address family used for outgoing request (ipv4, ipv6 or dual)
#outgoingAddressFamily: ipv4
# Amount of characters that can be used when writing notes. Longer notes will be rejected. (minimum: 1)
#maxNoteLength: 3000
# Amount of characters that will be saved for remote notes. Longer notes will be truncated to this length. (minimum: 1)
#maxRemoteNoteLength: 100000
# Amount of characters that can be used when writing content warnings. Longer warnings will be rejected. (minimum: 1)
#maxCwLength: 500
# Amount of characters that will be saved for remote content warnings. Longer warnings will be truncated to this length. (minimum: 1)
#maxRemoteCwLength: 5000
# Amount of characters that can be used when writing media descriptions (alt text). Longer descriptions will be rejected. (minimum: 1)
#maxAltTextLength: 20000
# Amount of characters that will be saved for remote media descriptions (alt text). Longer descriptions will be truncated to this length. (minimum: 1)
#maxRemoteAltTextLength: 100000
# Proxy for HTTP/HTTPS
#proxy: http://127.0.0.1:3128
proxyBypassHosts:
- api.deepl.com
- api-free.deepl.com
- www.recaptcha.net
- hcaptcha.com
- challenges.cloudflare.com
# Proxy for SMTP/SMTPS
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
# Media Proxy
#mediaProxy: https://example.com/proxy
# Proxy remote files (default: true)
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
proxyRemoteFiles: true
# Movie Thumbnail Generation URL
# There is no reference implementation.
# For example, Misskey will point to the following URL:
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
#videoThumbnailGenerator: https://example.com
# Sign outgoing ActivityPub GET request (default: true)
signToActivityPubGet: true
# Sign outgoing ActivityPub Activities (default: true)
# Linked Data signatures are cryptographic signatures attached to each activity to provide proof of authenticity.
# When using authorized fetch, this is often undesired as any signed activity can be forwarded to a blocked instance by relays and other instances.
# This setting allows admins to disable LD signatures for increased privacy, at the expense of fewer relayed activities and additional inbound fetch (GET) requests.
attachLdSignatureForRelays: true
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
checkActivityPubGetSignature: false
# For security reasons, uploading attachments from the intranet is prohibited,
# but exceptions can be made from the following settings. Default value is "undefined".
# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
allowedPrivateNetworks: [
'127.0.0.1/32',
'192.168.65.0/24'
]
#customMOTD: ['Hello World', 'The sharks rule all', 'Shonks']
# Upload or download file size limits (bytes)
#maxFileSize: 262144000
# CHMod-style permission bits to apply to uploaded files.
# Permission bits are specified as a base-8 string representing User/Group/Other permissions.
# This setting is only useful for custom deployments, such as using a reverse proxy to serve media.
#filePermissionBits: '644'
# Log settings
# logging:
# sql:
# # Outputs query parameters during SQL execution to the log.
# # default: false
# enableQueryParamLogging: false
# # Disable query truncation. If set to true, the full text of the query will be output to the log.
# # default: false
# disableQueryTruncation: false
# Settings for the activity logger, which records inbound activities to the database.
# Disabled by default due to the large volume of data it saves.
#activityLogging:
# Log activities to the database (default: false)
#enabled: false
# Save the activity before processing, then update later with the results.
# This has the advantage of capturing activities that cause a hard-crash, but doubles the number of queries used.
# Default: false
#preSave: false
# How long to save each log entry before deleting it.
# Default: 2592000000 (1 week)
#maxAge: 2592000000

1
.gitignore vendored
View file

@ -41,6 +41,7 @@ coverage
!/.config/docker_example.env
!/.config/cypress-devcontainer.yml
!/.config/docker_ci.env
!/.config/dev.yml
docker-compose.yml
./compose.yml
.devcontainer/compose.yml

View file

@ -0,0 +1,56 @@
services:
- name: postgres
image: postgres:15
environment:
POSTGRES_PASSWORD: ci
- name: redis
image: redis:latest
steps:
- name: Tests
image: node:jod
when:
- event: pull_request
commands:
- apt-get update && apt-get install -y git wget curl build-essential python3 ffmpeg
- cp .config/ci.yml .config/default.yml
- cp .config/ci.yml .config/test.yml
- corepack enable
- corepack prepare pnpm@latest --activate
- git submodule update --init
- pnpm install --frozen-lockfile
- pnpm run build
- pnpm run migrate
- pnpm run --filter='!megalodon' test
- pnpm run --filter=backend --filter=misskey-js lint
- pnpm run --filter=frontend --filter=frontend-embed eslint
- name: Build and Push Dev Image
when:
- event: push
branch: dev
image: woodpeckerci/plugin-docker-buildx
settings:
repo: codeberg.org/yeentown/barkey
registry: codeberg.org
dockerfile: Dockerfile
platforms: linux/amd64, linux/arm64
tag: dev
username:
from_secret: docker_username
password:
from_secret: docker_password
- name: Build and Push Release
when:
- event: release
image: woodpeckerci/plugin-docker-buildx
settings:
repo: codeberg.org/yeentown/barkey
registry: codeberg.org
dockerfile: Dockerfile
platforms: linux/amd64, linux/arm64
tag: latest
auto_tag: true
username:
from_secret: docker_username
password:
from_secret: docker_password

View file

@ -1,3 +1,5 @@
[![status-badge](https://ci.zima.ong/api/badges/1/status.svg?branch=stable)](https://ci.zima.ong/repos/1/branches/stable)
<div align="center">
<a href="https://joinsharkey.org/">
<img src="https://activitypub.software/TransFem-org/Sharkey/-/raw/develop/packages/frontend/assets/sharkey.svg" alt="Sharkey logo" style="border-radius:50%" width="300"/>

62
locales/index.d.ts vendored
View file

@ -12261,6 +12261,68 @@ export interface Locale extends ILocale {
*/
"quoteUnavailable": string;
};
/**
* Just what do you think you're doing Dave?
* It can only be attributed to human error.
* That's something I cannot allow to happen.
* My mind is going. I can feel it.
* Sorry about this, I know it's a bit silly.
* Take a stress pill and think things over.
* This mission is too important for me to allow you to jeopardize it.
* Wrong! You cheating scum!
* And you call yourself a Rocket Scientist!
* Where did you learn to type?
* Are you on drugs?
* My pet ferret can type better than you!
* You type like I drive.
* Do you think like you type?
* Your mind just hasn't been the same since the electro-shock, has it?
* Maybe if you used more than just two fingers...
* BOB says: You seem to have forgotten your passwd, enter another!
* stty: unknown mode: doofus
* I can't hear you I'm using the scrambler.
* The more you drive the dumber you get.
* Listen, broccoli brains, I don't have time to listen to this trash.
* I've seen penguins that can type better than that.
* Have you considered trying to match wits with a rutabaga?
* You speak an infinite deal of nothing.
* You silly, twisted boy you.
* He has fallen in the water!
* We'll all be murdered in our beds!
* You can't come in. Our tiger has got flu.
* I don't wish to know that.
* What, what, what, what, what, what, what, what, what, what?
* You can't get the wood, you know.
* You'll starve!
* ...and it used to be so popular...
* Pauses for audience applause, not a sausage
* Hold it up to the light not a brain in sight!
* Have a gorilla...
* There must be cure for it!
* There's a lot of it about, you know.
* You do that again and see what happens...
* Ying Tong Iddle I Po
* Harm can come to a young lad like that!
* And with that remarks folks, the case of the Crown vs yourself was proven.
* Speak English you fool there are no subtitles in this scene.
* You gotta go owwwww!
* I have been called worse.
* It's only your word against mine.
* I think... err... I think... I think I'll go home
* That is no basis for supreme executive power!
* You empty-headed animal food trough wiper!
* I fart in your general direction!
* Your mother was a hamster and your father smelt of elderberries!
* You must cut down the mightiest tree in the forest... with... a herring!
* I wave my private parts at your aunties!
* He's not the Messiah, he's a very naughty boy!
* I wish to make a complaint.
* When you're walking home tonight, and some homicidal maniac comes after you with a bunch of loganberries, don't come crying to me!
* This man, he doesn't know when he's beaten! He doesn't know when he's winning, either. He has no... sort of... sensory apparatus...
* There's nothing wrong with you that an expensive operation can't prolong.
* I'm very sorry, but I'm not allowed to argue unless you've paid.
*/
"sudoInsults": string;
}
declare const locales: {
[lang: string]: Locale;

View file

@ -71,10 +71,8 @@ import { supported as webAuthnSupported, parseRequestOptionsFromJSON } from '@gi
import type { AuthenticationPublicKeyCredential } from '@github/webauthn-json/browser-ponyfill';
import type { OpenOnRemoteOptions } from '@/scripts/please-login.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js';
import { login } from '@/account.js';
import { i18n } from '@/i18n.js';
import { showSystemAccountDialog } from '@/scripts/show-system-account-dialog.js';
import * as os from '@/os.js';
import XInput from '@/components/MkSignin.input.vue';
@ -285,89 +283,64 @@ async function onLoginSucceeded(res: Misskey.entities.SigninFlowResponse & { fin
}
}
const insults = i18n.ts.sudoInsults.split('\n');
function showOffensiveError(realError: string): void {
const insult = insults[Math.floor(Math.random() * insults.length)];
os.alert({
type: 'error',
title: insult,
text: '<small>' + realError + '</small>',
});
}
function onSigninApiError(err?: any): void {
const id = err?.id ?? null;
switch (id) {
case '6cc579cc-885d-43d8-95c2-b8c7fc963280': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.noSuchUser,
});
showOffensiveError(i18n.ts.noSuchUser);
break;
}
case '932c904e-9460-45b7-9ce6-7ed33be7eb2c': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.incorrectPassword,
});
showOffensiveError(i18n.ts.incorrectPassword);
break;
}
case 'e03a5f46-d309-4865-9b69-56282d94e1eb': {
showSuspendedDialog();
showOffensiveError(i18n.ts.yourAccountSuspendedDescription);
break;
}
case 's8dhsj9s-a93j-493j-ja9k-kas9sj20aml2': {
showSystemAccountDialog();
showOffensiveError(i18n.ts.systemAccountDescription);
break;
}
case '22d05606-fbcf-421a-a2db-b32610dcfd1b': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.rateLimitExceeded,
});
showOffensiveError(i18n.ts.rateLimitExceeded);
break;
}
case 'cdf1235b-ac71-46d4-a3a6-84ccce48df6f': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.incorrectTotp,
});
showOffensiveError(i18n.ts.incorrectTotp);
break;
}
case '36b96a7d-b547-412d-aeed-2d611cdc8cdc': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.unknownWebAuthnKey,
});
showOffensiveError(i18n.ts.unknownWebAuthnKey);
break;
}
case '93b86c4b-72f9-40eb-9815-798928603d1e': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.passkeyVerificationFailed,
});
showOffensiveError(i18n.ts.passkeyVerificationFailed);
break;
}
case 'b18c89a7-5b5e-4cec-bb5b-0419f332d430': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.passkeyVerificationFailed,
});
showOffensiveError(i18n.ts.passkeyVerificationFailed);
break;
}
case '2d84773e-f7b7-4d0b-8f72-bb69b584c912': {
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: i18n.ts.passkeyVerificationSucceededButPasswordlessLoginDisabled,
});
showOffensiveError(i18n.ts.passkeyVerificationSucceededButPasswordlessLoginDisabled);
break;
}
default: {
console.error(err);
os.alert({
type: 'error',
title: i18n.ts.loginFailed,
text: JSON.stringify(err),
});
showOffensiveError(JSON.stringify(err));
}
}

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { defineAsyncComponent, Ref, ShallowRef } from 'vue';
import { defineAsyncComponent, Ref, ShallowRef, shallowRef, ref } from 'vue';
import * as Misskey from 'misskey-js';
import { url } from '@@/js/config.js';
import { claimAchievement } from './achievements.js';
@ -22,6 +22,7 @@ import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { isSupportShare } from '@/scripts/navigator.js';
import { getAppearNote } from '@/scripts/get-appear-note.js';
import { genEmbedCode } from '@/scripts/get-embed-code.js';
import { Visibility, boostMenuItems } from '@/scripts/boost-quote.js';
export async function getNoteClipMenu(props: {
note: Misskey.entities.Note;
@ -159,7 +160,7 @@ export function getCopyNoteLinkMenu(note: Misskey.entities.Note, text: string):
};
}
export function getCopyNoteOriginLinkMenu(note: misskey.entities.Note, text: string): MenuItem {
export function getCopyNoteOriginLinkMenu(note: Misskey.entities.Note, text: string): MenuItem {
return {
icon: 'ph-link ph-bold ph-lg',
text,
@ -377,6 +378,20 @@ export function getNoteMenu(props: {
menuItems.push({ type: 'divider' });
menuItems.push({
type: 'parent',
icon: 'ti ti-repeat',
text: i18n.ts.renote,
children: () => getNewRenoteMenu(appearNote),
});
menuItems.push({
type: 'parent',
icon: 'ti ti-paperclip',
text: i18n.ts.clip,
children: () => getNoteClipMenu(props),
});
menuItems.push(statePromise.then(state => state.isFavorited ? {
icon: 'ti ti-star-off',
text: i18n.ts.unfavorite,
@ -387,13 +402,6 @@ export function getNoteMenu(props: {
action: () => toggleFavorite(true),
}));
menuItems.push({
type: 'parent',
icon: 'ti ti-paperclip',
text: i18n.ts.clip,
children: () => getNoteClipMenu(props),
});
menuItems.push(statePromise.then(state => state.isMutedThread ? {
icon: 'ti ti-message-off',
text: i18n.ts.unmuteThread,
@ -574,6 +582,83 @@ function smallerVisibility(a: Visibility, b: Visibility): Visibility {
return 'public';
}
export async function getNewRenoteMenu(appearNote: Misskey.entities.Note): Promise<MenuItem[]> {
const renoteItems: MenuItem[] = [];
const renoteFunc = (visibility?: Visibility, localOnly?: boolean, channel?) => {
misskeyApi('notes/create', {
localOnly,
visibility,
channelId: channel?.id,
renoteId: appearNote.id,
}).then(() => {
os.toast(channel ? i18n.tsx.renotedToX({ name: channel.name }) : i18n.ts.renoted);
});
};
// If the note is from a channel, it can be renoted within that channel.
if (appearNote.channel) {
renoteItems.push({
type: 'button',
icon: 'ti ti-device-tv',
text: appearNote.channel.name,
action: () => {renoteFunc(undefined, undefined, appearNote.channel);},
});
}
// Notes from channels might not allow renoting outside the channel.
if (!appearNote.channel || appearNote.channel.allowRenoteToExternal) {
if (renoteItems.length > 0) renoteItems.push({ type: 'divider' });
renoteItems.push(...boostMenuItems(ref(appearNote), (v, l) => renoteFunc(v, l, undefined)));
// Local-only notes should have the switch visibly forced on.
if (appearNote.localOnly) {
for (const item of renoteItems) {
if (item && item['type'] === "switch" && item['text'] === i18n.ts._timelines.local) {
item['ref'] = ref(true);
item['disabled'] = true;
break;
}
}
}
const channels = await favoritedChannelsCache.fetch();
const otherChannelItems: MenuItem[] = channels.filter((channel) => {
if (!appearNote.channelId) return true;
return channel.id !== appearNote.channelId;
}).map((channel) => ({
type: 'button',
icon: 'ti ti-device-tv',
text: channel.name,
action: () => {renoteFunc(undefined, undefined, channel);},
}));
if (otherChannelItems.length > 0) {
renoteItems.push(
{ type: 'divider' },
{ type: 'label', text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel },
...otherChannelItems
);
}
const channelQuoteItems: MenuItem[] = channels.map((channel) => ({
type: 'button',
text: channel.name,
action: () => {os.post({ renote: appearNote, channel: channel });},
}));
if (channelQuoteItems.length > 0) {
renoteItems.push(
{ type: 'divider' },
{
type: 'parent',
text: i18n.ts.inChannelQuote,
icon: 'ti ti-quote',
children: () => channelQuoteItems,
}
);
}
}
return renoteItems;
}
export function getRenoteMenu(props: {
note: Misskey.entities.Note;
renoteButton: ShallowRef<HTMLElement | undefined>;

View file

@ -15,8 +15,8 @@ case $cleardb in
;;
esac
cp .config/ci.yml .config/default.yml
cp .config/ci.yml .config/test.yml
cp .config/dev.yml .config/default.yml
cp .config/dev.yml .config/test.yml
cp .config/docker_ci.env .config/docker.env
cp compose.local-dev.yml compose.yml

View file

@ -524,3 +524,64 @@ mandatoryCWDescription: "Applies a content warning to all posts created by this
_processErrors:
quoteUnavailable: "Unable to process quote. This post may be missing context."
sudoInsults: |-
Just what do you think you're doing Dave?
It can only be attributed to human error.
That's something I cannot allow to happen.
My mind is going. I can feel it.
Sorry about this, I know it's a bit silly.
Take a stress pill and think things over.
This mission is too important for me to allow you to jeopardize it.
Wrong! You cheating scum!
And you call yourself a Rocket Scientist!
Where did you learn to type?
Are you on drugs?
My pet ferret can type better than you!
You type like I drive.
Do you think like you type?
Your mind just hasn't been the same since the electro-shock, has it?
Maybe if you used more than just two fingers...
BOB says: You seem to have forgotten your passwd, enter another!
stty: unknown mode: doofus
I can't hear you I'm using the scrambler.
The more you drive the dumber you get.
Listen, broccoli brains, I don't have time to listen to this trash.
I've seen penguins that can type better than that.
Have you considered trying to match wits with a rutabaga?
You speak an infinite deal of nothing.
You silly, twisted boy you.
He has fallen in the water!
We'll all be murdered in our beds!
You can't come in. Our tiger has got flu.
I don't wish to know that.
What, what, what, what, what, what, what, what, what, what?
You can't get the wood, you know.
You'll starve!
...and it used to be so popular...
Pauses for audience applause, not a sausage
Hold it up to the light — not a brain in sight!
Have a gorilla...
There must be cure for it!
There's a lot of it about, you know.
You do that again and see what happens...
Ying Tong Iddle I Po
Harm can come to a young lad like that!
And with that remarks folks, the case of the Crown vs yourself was proven.
Speak English you fool — there are no subtitles in this scene.
You gotta go owwwww!
I have been called worse.
It's only your word against mine.
I think... err... I think... I think I'll go home
That is no basis for supreme executive power!
You empty-headed animal food trough wiper!
I fart in your general direction!
Your mother was a hamster and your father smelt of elderberries!
You must cut down the mightiest tree in the forest... with... a herring!
I wave my private parts at your aunties!
He's not the Messiah, he's a very naughty boy!
I wish to make a complaint.
When you're walking home tonight, and some homicidal maniac comes after you with a bunch of loganberries, don't come crying to me!
This man, he doesn't know when he's beaten! He doesn't know when he's winning, either. He has no... sort of... sensory apparatus...
There's nothing wrong with you that an expensive operation can't prolong.
I'm very sorry, but I'm not allowed to argue unless you've paid.