あに (aniy -iis, n.) の自分専用お一人様サーバー Meum proprium cubile :) / My own personal den. Re: Source code modifications (AGPL compliance matter)
I made modifications in Mastodon source codes (v4.3.1) as follow. For the purpose of AGPL compliance, I described below about the details of the changes I made in the codes.
1. Add a new trigger for re-fetching avatar and header 2. Change the default URL when you see limited instance page 3. Modify the aspect ratio of the server banner 4. Add "server name" above the domain name of "about" page 5. Remove "mailto:" scheme from the contact column of "about" page 6. Increase the number of fields for the profile metadata 7. Increase the maximum number of characters in a toot 8. "Really" hide your social graph 9. Reverse language filter 10. Minor layout adjustments 11. Show the first media file for OGP thumbnail, and fix a bug 12. Modify every page to be verified 13. Implementation of Latin locale 14. Eliminate those that are not needed 15. Implementation of anchor link smooth scroll within this page 16. Reduce file size of image file attachments 17. Increase the maximum number of pinned posts 18. Change the style for iframes to be embedded 19. Locate AbuseIPDB badge in "Moderated servers" section below 20. Suppress notifications to be filtered by user filters I'm quite unfamiliar with the github-things so I'm keeping this section updated instead and this is my best efforts for the license respect. Please educate me if there's any problem about license matter. Thanks.
1. Add a new trigger for re-fetching avatar and header
In "app/controllers/api/v1 /accounts_controller.rb",
30 - render json: @account, serializer: REST::AccountSerializer 30 + render json: @account.refresh!, serializer: REST::AccountSerializer This is to implement a local workaround for the non-re-fetching issue in both avatars and headers after the execution of "tootctl media remove --prune-profiles".
△ top 2. Change the default URL when you see limited instance page
In "config /navigation.rb",
54 - ...admin_instances_path(limited: limited_federation_mode? ? nil : '1'),... 54 + ...admin_instances_path(limited: nil),... This is to remove "?limited=1" suffix from the default URL given from clicking "Preferences > Moderation > Federation" not to show limited instances by default.
△ top 3. Modify the aspect ratio of the server banner
In "app/javascript/styles/mastodon /components.scss",
.server-banner &__hero 9261 - aspect-ratio: 1.9; 9261 + aspect-ratio: 3; .about &__header &__hero 9923 - aspect-ratio: 1.9; 9923 + aspect-ratio: 3; In "app/models /site_upload.rb",
42 - geometry: '1200x630#', 42 + geometry: '1500x500#', 52 - geometry: '2400x1260#', 52 + geometry: '3000x1000#', This is to modify the aspect ratio of the server banner to a specific size as shown above.
△ top 4. Add "server name" above the domain name of "about" page
In "app/javascript/mastodon/features /about/index.jsx",
125 - <h1>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</h1> 125 + <h1>{isLoading ? <Skeleton width='10ch' /> : server.get('title')}</h1> 126 + <p>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</p> As shown above, this is to change the layout of this page with the "server name" added above the domain name.
△ top 5. Remove "mailto:" scheme from the contact column of "about" page
In "app/javascript/mastodon/features /about/index.jsx",
142 - ...href={`mailto:${server.getIn(['contact', 'email'])}`}... 142 + ...href={`${server.getIn(['contact', 'email'])}`}... This is to remove "mailto:" scheme so that I can put URL into the contact column of this page instead of the mail address that tends to be scraped.
△ top 6. Increase the number of fields for the profile metadata
In "app/models /account.rb",
68 - DEFAULT_FIELDS_SIZE = 4 68 + DEFAULT_FIELDS_SIZE = 15 This is just to increase the number of fields for the
profile metadata up to 15 fields.
△ top 7. Increase the maximum number of characters in a toot
In "app/models/account.rb",
77 - NOTE_LENGTH_LIMIT = 500 77 + NOTE_LENGTH_LIMIT = 5000 In "app/validators /status_length_validator.rb",
4 - MAX_CHARS = 500 4 + MAX_CHARS = 5000 This is to increase the maximum number of the characters to 5,000 in a toot to be composed.
△ top 8. "Really" hide your social graph
In "app/models /account.rb",
441 + def public_statuses_count 442 + hide_collections? ? 0 : statuses_count 443 + end 444 + 445 + def public_followers_count 446 + hide_collections? ? 0 : followers_count 447 + end 448 + 449 + def public_following_count 450 + hide_collections? ? 0 : following_count 451 + end 452 + In "app/javascript/mastodon /api_types/accounts.ts",
47 - } 47 + public_statuses_count: number; 48 + public_followers_count: number; 49 + public_following_count: number; 50 + } *Thanks team, for your comment in account_serializer.rb :)
In "app/serializers/rest /account_serializer.rb",
11 - :followers_count, :following_count, :statuses_count, \ :last_status_at, :hide_collections 11 + :public_followers_count, :public_following_count, \ :public_statuses_count, 12 + :followers_count, :following_count, :statuses_count, \ :last_status_at, :hide_collections In "app/javascript/mastodon/features /account/components /header.jsx",
267 + 268 + const hideCollections = me !== account.get('id') && account.get('hide_collections'); 483 - ...title={intl.formatNumber(... 483 + ...title={hideCollections ? 0 : intl.formatNumber(... 485 - value={account.get('statuses_count')} 485 + value={hideCollections ? 0 : account.get('statuses_count')} 490 - ...title={intl.formatNumber(... 490 + ...title={hideCollections ? 0 : intl.formatNumber(... 492 - value={account.get('followings_count')} 492 + value={hideCollections ? 0 : account.get('following_count')} 497 - ...title={intl.formatNumber(... 497 + ...title={hideCollections ? 0 : intl.formatNumber(... 499 - value={account.get('followers_count')} 499 + value={hideCollections ? 0 : account.get('followers_count')} In "app/controllers/activitypub /outboxes_controller.rb",
37 - size: @account.statuses_count, 37 + size: @account.public_statuses_count, In "app/controllers /follower_accounts_controller.rb",
65 - size: @account.followers_count, 65 + size: @account.public_followers_count, 75 - size: @account.followers_count, 75 + size: @account.public_followers_count, In "app/controllers /following_accounts_controller.rb",
68 - size: @account.following_count, 68 + size: @account.public_following_count, 78 - size: @account.following_count, 78 + size: @account.public_following_count, In "app/helpers /accounts_helper.rb",
28 - [ 28 + account.hide_collections? ? nil : [ 29 - account_formatted_stat(account.statuses_count) 29 + account_formatted_stat(account.public_statuses_count) 30 - I18n.t('accounts.posts', count: account.statuses_count), 30 + I18n.t('accounts.posts', count: account.public_statuses_count), 33 - [ 33 + account.hide_collections? ? nil : [ 34 - account_formatted_stat(account.following_count), 34 + account_formatted_stat(account.public_following_count), 35 - I18n.t('accounts.posts', count: account.following_count), 35 + I18n.t('accounts.posts', count: account.public_following_count), 38 - [ 38 + account.hide_collections? ? nil : [ 39 - account_formatted_stat(account.followers_count), 39 + account_formatted_stat(account.public_followers_count), 40 - I18n.t('accounts.posts', count: account.followers_count), 40 + I18n.t('accounts.posts', count: account.public_followers_count), In "app/views/relationships /_account.html.haml",
12 - = friendly_number_to_human account.statuses_count 12 + = friendly_number_to_human account.public_statuses_count 13 - %small= t('accounts.posts', count: account.statuses_count).downcase 13 + %small= t('accounts.posts', count:\ account.public_statuses_count).downcase 15 - = friendly_number_to_human account.followers_count 15 + = friendly_number_to_human account.public_followers_count 16 - %small= t('accounts.followers', count:\ account.followers_count).downcase 16 + %small= t('accounts.followers', count:\ account.public_followers_count).downcase In "app/javascript/mastodon/features /directory/components /account_card.tsx",
110 + 111 + const hideCollections = me !== account.get('id') && account.get('hide_collections'); 200 - ...value={account.get('... 200 + ...value={hideCollections ? 0 : account.get('... 207 - ...value={account.get('... 207 + ...value={hideCollections ? 0 : account.get('... 217 - ...value={account.get('... 217 + ...value={hideCollections ? 0 : account.get('... In "app/javascript/mastodon/components /account.jsx",
126 + 127 + const hideCollections = me !== account.get('id') && account.get('hide_collections'); 145 - <ShortNumber value={account.get('followers_count')} 145 + <ShortNumber value={hideCollections ? 0 : account.get('followers_count')} This is to "really" hide the social graphs of the accounts with "Hide your social graph" option set, no matter from where you see the account profile pages.
△ top 9. Reverse language filter
In "app/models /public_feed.rb",
88 - Status.where(language: account.chosen_languages) 88 + Status.where.not(language: account.chosen_languages)\ .or(Status.where(language: nil)) In "streaming /index.js",
654 - ...indexOf(payload.language) === -1) { 654 + ...indexOf(payload.language) !== -1) { This is to reverse the functionality of the language filter as it "filters" checked languages.
△ top 10. Minor layout adjustments
In "app/javascript/mastodon /components/server_banner.jsx",
77 - <br /> 82 - <br /> 82 - ...aboutActiveUsers)}><FormattedMessage... 82 + ...aboutActiveUsers)}> <FormattedMessage... In "app/javascript/mastodon /locales/ja.json",
766 - "人のアクティブユーザー", 766 + "人のユーザー", *This is the Japanese environment specific modification.
In "app/javascript/styles/mastodon /components.scss",
.compose-form &__highlightable 554 + margin-top: -14px; .icon-with-badge &__badge 3199 - top: -13px; 3199 + top: -10px; .column-link 3847 - padding: 13px; 3847 + padding: 8px; .getting-started &__trends .trends__item 3943 - padding: 10px; 3943 + padding: 5px 10px; .search 5543 - margin-bottom: 32px; 5543 + margin-bottom: 18px; 5544 + margin-top: 3px; .server-banner &__introduction 9239 - margin-bottom: 20px; 9239 + margin-bottom: 17px; .server-banner &__hero 9262 - margin-bottom: 20px; 9262 + margin-bottom: 10px; .server-banner &__description 9273 - margin-bottom: 20px; 9273 + margin-bottom: 14px; 9274 + margin-top: 15px; .server-banner h4 9304 - margin-bottom: 10px; 9304 + margin-bottom: 5px; .server-banner .spacer 9318 - margin: 10px 0; 9318 + margin: 5px 0; .link-footer 9871 - padding-top: 20px; 9871 + padding-bottom: 25px; .link-footer p 9881 - margin-bottom: 20px; 9881 + margin-bottom: 10px; .about &__meta h4 9980 - margin-bottom: 20px; 9980 + margin-bottom: 10px; This is just for adjusting the layouts mainly for the left pane of non-logged-in page.
△ top 11. Show the first media file for OGP thumbnail, and fix a bug
In "app/views/statuses /_og_image.html.haml",
43 - - if player_card 43 + - break 44 + - if player_card 49 - = opengraph 'twitter:card', 'summary' 49 + = opengraph 'og:image', full_asset_url(account.avatar.url(:original)) 50 + = opengraph 'og:image:width', '400' 51 + = opengraph 'og:image:height','400' 52 + = opengraph 'twitter:card', 'summary' By default, mastodon shows the last media file among multiple attachments for OGP thumbnail but this modification changes it to the first one. Also fixed a bug came with v4.1.0 that it did not show OGP thumbnail for the toots without attachments.
△ top 12. Modify every page to be verified
In "app/views/shared /_web_app.html.haml",
14 - %noscript 14 + %a{ rel: 'me', href: 'https://aniy.jp/@aniy' } 15 + %a{ rel: 'me', href: 'https://aniy.jp/@aniyexmachina' } 16 + %noscript This is as described above to have every mastodon page of this server verified by Mastodon itself for my
profile metadata. Immediate verification snippet for server admin is also available
here.
△ top 13. Implementation of Latin locale
Additions and modifications of several files
mstdn_locale_la_temp.tar.gz This is a series of complement files so that Latin locale can be activated as it is set in Preferences settings screen avoiding Mastodon bug that makes application itself crash, and supplying Latin translations as much as possible (as of Dec. 4, 2024), and Roman date format functionality of my own (romandate.js).
In "app/javascript/mastodon/features /account/components /header.jsx",
37 + 38 + const DiesRomani = require("mastodon/locales/romandate.js"); 465 - <dd>{intl.formatDate(... 465 + <dd>{(intl.locale == "la") ? DiesRomani(account.get('created_at')) : intl.formatDate(... In "app/javascript/mastodon/features /status/components /detailed_status.tsx",
34 + 35 + const DiesRomani = require("mastodon/locales/romandate.js"); 365 - <FormattedDate 365 + {(document.documentElement.lang == "la") ? DiesRomani(status .get('created_at'), 1) : <FormattedDate 372 - /> 372 + />} In "app/javascript/mastodon /components /relative_timestamp.tsx",
5 + 6 + const DiesRomani = require("mastodon/locales/romandate.js"); 147 - relativeTime = intl.formatDate(... 147 + relativeTime = (intl.locale == "la") ? DiesRomani(date.toISOString(), 3) : intl.formatDate(... 149 - relativeTime = intl.formatDate(... 149 + relativeTime = (intl.locale == "la") ? DiesRomani(date.toISOString(), 3) : intl.formatDate(... 274 - title={intl.formatDate(... 274 + title={(intl.locale == "la") ? DiesRomani(date.toISOString(), 3) : intl.formatDate(... In "app/javascript/mastodon /components /status.jsx",
38 + 39 + const DiesRomani = require("mastodon/locales/romandate.js"); 557 - ...&& <abbr title={intl.formatMessage(... 557 + ...&& <abbr title={(intl.locale == "la") ? "Renovatum " + DiesRomani(status.get('created_at'), 3) : intl.formatMessage(... In "app/javascript/mastodon /components /edited_timestamp /index.jsx",
13 + 14 + const DiesRomani = require("mastodon/locales/romandate.js"); 70 - ...values={{ date: <span className='animated-number'> {intl.formatDate(... 70 + ...values={{ date: <span className='animated-number'> {(intl.locale == "la") ? DiesRomani(timestamp, 1) : intl.formatDate(... In "app/javascript/mastodon/features /privacy_policy /index.jsx"
11 + 12 + const DiesRomani = require("mastodon/locales/romandate.js"); 48 - : <FormattedDate value={lastUpdated}...day='2-digit' /> }} 48 + : (intl.locale == "la") ? DiesRomani(lastUpdated) : <FormattedDate value={lastUpdated}...day='2-digit' /> }} In "app/javascript/mastodon/features /about/index.jsx",
144 - ...target='_blank'>Mastodon</a> }} /></p> 144 + ...target='_blank'>Mastodo</a> }} /></p> 162 - <Section open title={intl.formatMessage(messages.title)}> 162 + <Section open title={intl.formatMessage(messages.title, { domain: server.get('domain') })}> In "app/javascript/mastodon/features /ui/components/link_footer.jsx",
41 - const { multiColumn } = this.props; 41 + const { multiColumn, intl } = this.props; 53 - ...undefined}><FormattedMessage id='footer.about' defaultMessage='About' /></Link> 53 + ...undefined}>{intl.formatMessage({ id: 'footer.about', defaultMessage: 'About' }, { domain: domain })}</Link> 79 - ..._blank'><FormattedMessage id='footer.about' defaultMessage='About' /></a> 79 + ..._blank'>{intl.formatMessage({ id: 'footer.about', defaultMessage: 'About' }, { domain: 'Mastodo' })}</a> In "app/views/about/show.html.haml",
2 - = t('about.title') 2 + = t('about.title', domain: site_hostname) In "app/helpers/languages_helper.rb",
95 - la: ['Latin', 'latine'].freeze, 95 + la: ['Latin', 'Latinum'].freeze, In "app/javascript/mastodon /components/badge.jsx",
9 + const latinroles = {1: "Moderator -trix", 2: "Administrator -trix", 3: "Dominus -a -um"}; 14 - {label} 14 + {(document.documentElement.lang == "la") && roleId ? latinroles[roleId]: label} Above are necessary code modifications that enables Roman date format functionality. Please see how they work at
this video.
△ top 14. Eliminate those that are not needed
In "app/javascript/mastodon /components /status_action_bar.jsx",
257 - if (publicStatus && isRemote) { 258 - menu.push({ text:... 259 - } 260 - 375 - ...counter={status.get('replies_count')}... 375 + ...counter={withCounters ? status.get('replies_count') : undefined}... In "app/javascript/mastodon/features /account/components /header.jsx"
321 - if (isRemote) { 322 - menu.push({ text:... 323 - menu.push(null); 324 - } 325 - In "app/javascript/mastodon/features /status/components /action_bar.jsx"
206 - if (publicStatus && isRemote) { 207 - menu.push({ text:... 208 - } 209 - In "app/javascript/mastodon /components /timeline_hint.tsx"
19 - <a href={url}... 20 - ... 21 - </a> In "app/javascript/mastodon/features /status/components /detailed_status.tsx",
388 - <div className='detailed-status__meta__line'> 389 - {reblogLink} 390 - {reblogLink && <> </>} 391 - {favouriteLink} 392 - </div> In "app/views/admin/accounts /_account.html.haml",
2 + -# As titled, this is to eliminate needless things.
△ top 15. Implementation of anchor link smooth scroll within this page
In "app/javascript/mastodon/features /about/index.jsx",
2 - import { PureComponent } from 'react'; 2 + import { PureComponent, createRef } from 'react'; 104 + 105 + constructor(props) { 106 + super(props); 107 + this.aboutref = createRef(); 108 + } 109 + 110 + smoothscroll = (e) => { 111 + e.preventDefault(); 112 + const id = e.currentTarget.getAttribute('href').slice(1) 113 + const $anchor = document.getElementById(id); 114 + const offsetTop = $anchor.getBoundingClientRect().top + window.pageYOffset; 115 + window.scroll({ 116 + top: offsetTop, 117 + behavior: 'smooth' 118 + }); 119 + }; 120 + 121 + async componentDidUpdate () { 122 + while (!this.aboutref.current) { 123 + await new Promise(r => setTimeout(r, 500)); 124 + } 125 + this.aboutref.current.querySelectorAll("a[href^='#']") .forEach(atag => { 126 + atag.addEventListener('click', this.smoothscroll); 127 + }); 128 + } 184 - className='prose' 184 + ref={this.aboutref} 185 + className='prose' Quit relying on 3rd party module, newly implemented own "anchor link smooth scroll" to deal with the inserted text by dangerouslySetInnerHTML (this "about" section), for the ease of both browsing and maintenance of this page. Please see how they work at
this video.
△ top 16. Reduce file size of image file attachments
In "app/models/media_attachment.rb",
73 - pixels: 8_294_400, # 3840x2160px 73 + pixels: 518_400, # 960x540px 174 - all: '-quality 90 +profile... 174 + all: '-quality 60 +profile... This is just to reduce the size of image file attachments to save the cost of the data transfer charged by Amazon (AWS) - of course disk space as well :)
△ top 17. Increase the maximum number of pinned posts
In "app/validators/status_pin_validator.rb",
4 - PIN_LIMIT = 5 4 + PIN_LIMIT = 10 Found this limitation and increased it up to 10 :)
△ top 18. Change the style for iframes to be embedded
In "app/views/layouts/embedded.html.haml",
14 - = theme_style_tags 'mastodon-light' 14 + = theme_style_tags 'default' Regarding "app/serializers/oembed_serializer.rb", restored it from the one of v4.2.12, and then made changes as follwos.
43 - style: 'max-width: 100%; border: 0', 43 + style: 'width: 550px; border: 0; border-radius: 12px; \ margin-top: 10px; margin-bottom: 10px;', This is just for my own preference.
△ top 19. Locate AbuseIPDB badge in "Moderated servers" section below
In "app/javascript/mastodon/features /about/index.jsx",
237 - </Section> 237 + <p> </p> 238 + <hr className="aniy" /> 239 + <iframe className="aniy" src={`abuseipdb.html?${Math.random()}`} scrolling="no"> </iframe> 232 + </Section> This is to locate the contributor badge of
AbuseIPDB in the bottom section of this page. Due to the loss of the backward compatibility in displaying SVG since v4.3.0, iframe bypass is used with
https://aniy.jp/abuseipdb.html.
△ top 20. Suppress notifications to be filtered by user filters
In "app/services/notify_service.rb",
121 - blocked_by_private_mentions_policy? 121 + blocked_by_private_mentions_policy? || 122 + filtered_by_custom_filter? 127 + def filtered_by_custom_filter? 128 + return false if @notification.target_status.nil? 129 + retflag = false 130 + t_status = @notification.target_status 131 + CustomFilter.cached_filters_for(@recipient.id)\ .filter_map do |filter, rules| 132 + match = rules[:keywords].match(t_status.proper\ .searchable_text) if rules[:keywords].present? 133 + keyword_matches = [match.to_s] unless match.nil? 134 + status_matches = [t_status.id, t_status.reblog_of_id]\ .compact & rules[:status_ids] if rules[:status_ids].present? 135 + if keyword_matches.blank? && status_matches.blank? 136 + next 137 + else 138 + retflag = true 139 + break 140 + end 141 + end 142 + return retflag 143 + end 144 + This is to suppress unwanted notifications that should be filtered out and muted by user filters. Due to the difference between the original filter algorithms of toots and notifications, no matter what options you set in Filter contexts section, no filtered notification will appear in the notification area. Please take a look at
this toot how it works.
△ top "
Using CSS to create a CRT" by Alec Lownes
https://aleclownes.com/