mirror of
https://github.com/mastodon/mastodon.git
synced 2024-12-22 16:25:19 +01:00
Add media timeline (#6631)
This commit is contained in:
parent
05f8c375a2
commit
7403e5d306
53 changed files with 205 additions and 35 deletions
|
@ -41,9 +41,8 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => {
|
|||
};
|
||||
|
||||
export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
|
||||
export const connectCommunityStream = () => connectTimelineStream('community', 'public:local');
|
||||
export const connectMediaStream = () => connectTimelineStream('community', 'public:local');
|
||||
export const connectPublicStream = () => connectTimelineStream('public', 'public');
|
||||
export const connectHashtagStream = (tag) => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`);
|
||||
export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
|
||||
export const connectPublicStream = ({ onlyMedia } = {}) => connectTimelineStream(`public${onlyMedia ? ':media' : ''}`, `public${onlyMedia ? ':media' : ''}`);
|
||||
export const connectHashtagStream = tag => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`);
|
||||
export const connectDirectStream = () => connectTimelineStream('direct', 'direct');
|
||||
export const connectListStream = (id) => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
||||
export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`);
|
||||
|
|
|
@ -94,8 +94,8 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
|
|||
};
|
||||
|
||||
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done);
|
||||
export const expandPublicTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('public', '/api/v1/timelines/public', { max_id: maxId }, done);
|
||||
export const expandCommunityTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('community', '/api/v1/timelines/public', { local: true, max_id: maxId }, done);
|
||||
export const expandPublicTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`public${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||
export const expandDirectTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('direct', '/api/v1/timelines/direct', { max_id: maxId }, done);
|
||||
export const expandAccountTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, max_id: maxId });
|
||||
export const expandAccountFeaturedTimeline = accountId => expandTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { expandCommunityTimeline } from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import { connectCommunityStream } from '../../actions/streaming';
|
||||
|
||||
|
@ -14,20 +15,25 @@ const messages = defineMessages({
|
|||
title: { id: 'column.community', defaultMessage: 'Local timeline' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'community', 'unread']) > 0,
|
||||
const mapStateToProps = (state, { onlyMedia }) => ({
|
||||
hasUnread: state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`, 'unread']) > 0,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class CommunityTimeline extends React.PureComponent {
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
onlyMedia: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
|
@ -50,10 +56,10 @@ export default class CommunityTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandCommunityTimeline());
|
||||
this.disconnect = dispatch(connectCommunityStream());
|
||||
dispatch(expandCommunityTimeline({ onlyMedia }));
|
||||
this.disconnect = dispatch(connectCommunityStream({ onlyMedia }));
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -68,13 +74,22 @@ export default class CommunityTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
this.props.dispatch(expandCommunityTimeline({ maxId }));
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandCommunityTimeline({ maxId, onlyMedia }));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, hasUnread, columnId, multiColumn } = this.props;
|
||||
const { intl, hasUnread, columnId, multiColumn, onlyMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
const headline = (
|
||||
<div className='community-timeline__section-headline'>
|
||||
<NavLink exact to='/timelines/public/local' replace><FormattedMessage id='timeline.posts' defaultMessage='Toots' /></NavLink>
|
||||
<NavLink exact to='/timelines/public/local/media' replace><FormattedMessage id='timeline.media' defaultMessage='Media' /></NavLink>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
|
@ -91,9 +106,10 @@ export default class CommunityTimeline extends React.PureComponent {
|
|||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
prepend={headline}
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`community_timeline-${columnId}`}
|
||||
timelineId='community'
|
||||
timelineId={`community${onlyMedia ? ':media' : ''}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
|
||||
/>
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { expandPublicTimeline } from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import { connectPublicStream } from '../../actions/streaming';
|
||||
|
||||
|
@ -14,20 +15,25 @@ const messages = defineMessages({
|
|||
title: { id: 'column.public', defaultMessage: 'Federated timeline' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hasUnread: state.getIn(['timelines', 'public', 'unread']) > 0,
|
||||
const mapStateToProps = (state, { onlyMedia }) => ({
|
||||
hasUnread: state.getIn(['timelines', `public${onlyMedia ? ':media' : ''}`, 'unread']) > 0,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class PublicTimeline extends React.PureComponent {
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
multiColumn: PropTypes.bool,
|
||||
hasUnread: PropTypes.bool,
|
||||
onlyMedia: PropTypes.bool,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
|
@ -50,10 +56,10 @@ export default class PublicTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandPublicTimeline());
|
||||
this.disconnect = dispatch(connectPublicStream());
|
||||
dispatch(expandPublicTimeline({ onlyMedia }));
|
||||
this.disconnect = dispatch(connectPublicStream({ onlyMedia }));
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -68,13 +74,22 @@ export default class PublicTimeline extends React.PureComponent {
|
|||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
this.props.dispatch(expandPublicTimeline({ maxId }));
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
dispatch(expandPublicTimeline({ maxId, onlyMedia }));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { intl, columnId, hasUnread, multiColumn } = this.props;
|
||||
const { intl, columnId, hasUnread, multiColumn, onlyMedia } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
const headline = (
|
||||
<div className='public-timeline__section-headline'>
|
||||
<NavLink exact to='/timelines/public' replace><FormattedMessage id='timeline.posts' defaultMessage='Toots' /></NavLink>
|
||||
<NavLink exact to='/timelines/public/media' replace><FormattedMessage id='timeline.media' defaultMessage='Media' /></NavLink>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Column ref={this.setRef}>
|
||||
<ColumnHeader
|
||||
|
@ -91,7 +106,8 @@ export default class PublicTimeline extends React.PureComponent {
|
|||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
timelineId='public'
|
||||
prepend={headline}
|
||||
timelineId={`public${onlyMedia ? ':media' : ''}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`public_timeline-${columnId}`}
|
||||
|
|
|
@ -141,7 +141,9 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
<WrappedRoute path='/keyboard-shortcuts' component={KeyboardShortcuts} content={children} />
|
||||
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public/media' extract component={PublicTimeline} content={children} componentParams={{ onlyMedia: true }} />
|
||||
<WrappedRoute path='/timelines/public/local' component={CommunityTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public/local/media' component={CommunityTimeline} content={children} componentParams={{ onlyMedia: true }} />
|
||||
<WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/list/:id' component={ListTimeline} content={children} />
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "المحلي",
|
||||
"tabs_bar.notifications": "الإخطارات",
|
||||
"tabs_bar.search": "البحث",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "سوف تفقد مسودتك إن تركت ماستدون.",
|
||||
"upload_area.title": "إسحب ثم أفلت للرفع",
|
||||
"upload_button.label": "إضافة وسائط",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Известия",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Добави медия",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificacions",
|
||||
"tabs_bar.search": "Cerca",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "El vostre esborrany es perdrà si sortiu de Mastodon.",
|
||||
"upload_area.title": "Arrossega i deixa anar per carregar",
|
||||
"upload_button.label": "Afegir multimèdia",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lucale",
|
||||
"tabs_bar.notifications": "Nutificazione",
|
||||
"tabs_bar.search": "Cercà",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "A bruttacopia sarà persa s'ellu hè chjosu Mastodon.",
|
||||
"upload_area.title": "Drag & drop per caricà un fugliale",
|
||||
"upload_button.label": "Aghjunghje un media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokal",
|
||||
"tabs_bar.notifications": "Mitteilungen",
|
||||
"tabs_bar.search": "Suchen",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Dein Entwurf geht verloren, wenn du Mastodon verlässt.",
|
||||
"upload_area.title": "Zum Hochladen hereinziehen",
|
||||
"upload_button.label": "Mediendatei hinzufügen",
|
||||
|
|
|
@ -596,6 +596,14 @@
|
|||
"defaultMessage": "Local timeline",
|
||||
"id": "column.community"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Toots",
|
||||
"id": "timeline.posts"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Media",
|
||||
"id": "timeline.media"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||
"id": "empty_column.community"
|
||||
|
@ -1393,6 +1401,14 @@
|
|||
"defaultMessage": "Federated timeline",
|
||||
"id": "column.public"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Toots",
|
||||
"id": "timeline.posts"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Media",
|
||||
"id": "timeline.media"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
|
||||
"id": "empty_column.public"
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Loka tempolinio",
|
||||
"tabs_bar.notifications": "Sciigoj",
|
||||
"tabs_bar.search": "Serĉi",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Via malneto perdiĝos se vi eliras de Mastodon.",
|
||||
"upload_area.title": "Altreni kaj lasi por alŝuti",
|
||||
"upload_button.label": "Aldoni aŭdovidaĵon",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificaciones",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Tu borrador se perderá si sales de Mastodon.",
|
||||
"upload_area.title": "Arrastra y suelta para subir",
|
||||
"upload_button.label": "Subir multimedia",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "محلی",
|
||||
"tabs_bar.notifications": "اعلانها",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "اگر از ماستدون خارج شوید پیشنویس شما پاک خواهد شد.",
|
||||
"upload_area.title": "برای بارگذاری به اینجا بکشید",
|
||||
"upload_button.label": "افزودن تصویر",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Paikallinen",
|
||||
"tabs_bar.notifications": "Ilmoitukset",
|
||||
"tabs_bar.search": "Hae",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Luonnos häviää, jos poistut Mastodonista.",
|
||||
"upload_area.title": "Lataa raahaamalla ja pudottamalla tähän",
|
||||
"upload_button.label": "Lisää mediaa",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Fil public local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Chercher",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Votre brouillon sera perdu si vous quittez Mastodon.",
|
||||
"upload_area.title": "Glissez et déposez pour envoyer",
|
||||
"upload_button.label": "Joindre un média",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificacións",
|
||||
"tabs_bar.search": "Buscar",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "O borrador perderase se sae de Mastodon.",
|
||||
"upload_area.title": "Arrastre e solte para subir",
|
||||
"upload_button.label": "Engadir medios",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "ציר זמן מקומי",
|
||||
"tabs_bar.notifications": "התראות",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "הטיוטא תאבד אם תעזבו את מסטודון.",
|
||||
"upload_area.title": "ניתן להעלות על ידי Drag & drop",
|
||||
"upload_button.label": "הוספת מדיה",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokalno",
|
||||
"tabs_bar.notifications": "Notifikacije",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Povuci i spusti kako bi uploadao",
|
||||
"upload_button.label": "Dodaj media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Értesítések",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "A piszkozata el fog vesztődni ha elhagyja Mastodon-t.",
|
||||
"upload_area.title": "Húzza ide a feltöltéshez",
|
||||
"upload_button.label": "Média hozzáadása",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Տեղական",
|
||||
"tabs_bar.notifications": "Ծանուցումներ",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Քո սեւագիրը կկորի, եթե լքես Մաստոդոնը։",
|
||||
"upload_area.title": "Քաշիր ու նետիր՝ վերբեռնելու համար",
|
||||
"upload_button.label": "Ավելացնել մեդիա",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokal",
|
||||
"tabs_bar.notifications": "Notifikasi",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Naskah anda akan hilang jika anda keluar dari Mastodon.",
|
||||
"upload_area.title": "Seret & lepaskan untuk mengunggah",
|
||||
"upload_button.label": "Tambahkan media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokala",
|
||||
"tabs_bar.notifications": "Savigi",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Tranar faligar por kargar",
|
||||
"upload_button.label": "Adjuntar kontenajo",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Locale",
|
||||
"tabs_bar.notifications": "Notifiche",
|
||||
"tabs_bar.search": "Cerca",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "La bozza andrà persa se esci da Mastodon.",
|
||||
"upload_area.title": "Trascina per caricare",
|
||||
"upload_button.label": "Aggiungi file multimediale",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "ローカル",
|
||||
"tabs_bar.notifications": "通知",
|
||||
"tabs_bar.search": "検索",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Mastodonから離れると送信前の投稿は失われます。",
|
||||
"upload_area.title": "ドラッグ&ドロップでアップロード",
|
||||
"upload_button.label": "メディアを追加",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "로컬",
|
||||
"tabs_bar.notifications": "알림",
|
||||
"tabs_bar.search": "검색",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "지금 나가면 저장되지 않은 항목을 잃게 됩니다.",
|
||||
"upload_area.title": "드래그 & 드롭으로 업로드",
|
||||
"upload_button.label": "미디어 추가",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokaal",
|
||||
"tabs_bar.notifications": "Meldingen",
|
||||
"tabs_bar.search": "Zoeken",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Je concept zal verloren gaan als je Mastodon verlaat.",
|
||||
"upload_area.title": "Hierin slepen om te uploaden",
|
||||
"upload_button.label": "Media toevoegen",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokal",
|
||||
"tabs_bar.notifications": "Varslinger",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Din kladd vil bli forkastet om du forlater Mastodon.",
|
||||
"upload_area.title": "Dra og slipp for å laste opp",
|
||||
"upload_button.label": "Legg til media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Flux public local",
|
||||
"tabs_bar.notifications": "Notificacions",
|
||||
"tabs_bar.search": "Recèrcas",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Vòstre brolhon serà perdut se quitatz Mastodon.",
|
||||
"upload_area.title": "Lisatz e depausatz per mandar",
|
||||
"upload_button.label": "Ajustar un mèdia",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokalne",
|
||||
"tabs_bar.notifications": "Powiadomienia",
|
||||
"tabs_bar.search": "Szukaj",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Utracisz tworzony wpis, jeżeli opuścisz Mastodona.",
|
||||
"upload_area.title": "Przeciągnij i upuść aby wysłać",
|
||||
"upload_button.label": "Dodaj zawartość multimedialną",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificações",
|
||||
"tabs_bar.search": "Buscar",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Seu rascunho será perdido se você sair do Mastodon.",
|
||||
"upload_area.title": "Arraste e solte para enviar",
|
||||
"upload_button.label": "Adicionar mídia",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notificações",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "O teu rascunho vai ser perdido se abandonares o Mastodon.",
|
||||
"upload_area.title": "Arraste e solte para enviar",
|
||||
"upload_button.label": "Adicionar media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Локальная",
|
||||
"tabs_bar.notifications": "Уведомления",
|
||||
"tabs_bar.search": "Поиск",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Ваш черновик будет утерян, если вы покинете Mastodon.",
|
||||
"upload_area.title": "Перетащите сюда, чтобы загрузить",
|
||||
"upload_button.label": "Добавить медиаконтент",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokálna",
|
||||
"tabs_bar.notifications": "Notifikácie",
|
||||
"tabs_bar.search": "Hľadaj",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Čo máte rozpísané sa stratí, ak opustíte Mastodon.",
|
||||
"upload_area.title": "Ťahaj a pusti pre nahratie",
|
||||
"upload_button.label": "Pridať médiá",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokalno",
|
||||
"tabs_bar.notifications": "Obvestila",
|
||||
"tabs_bar.search": "Poišči",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Vaš osnutek bo izgubljen, če zapustite Mastodona.",
|
||||
"upload_area.title": "Povlecite in spustite za pošiljanje",
|
||||
"upload_button.label": "Dodaj medij",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokalno",
|
||||
"tabs_bar.notifications": "Obaveštenja",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Ako napustite Mastodont, izgubićete napisani nacrt.",
|
||||
"upload_area.title": "Prevucite ovde da otpremite",
|
||||
"upload_button.label": "Dodaj multimediju",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Локално",
|
||||
"tabs_bar.notifications": "Обавештења",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Ако напустите Мастодонт, изгубићете написани нацрт.",
|
||||
"upload_area.title": "Превуците овде да отпремите",
|
||||
"upload_button.label": "Додај мултимедију",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Lokal",
|
||||
"tabs_bar.notifications": "Meddelanden",
|
||||
"tabs_bar.search": "Sök",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Ditt utkast kommer att förloras om du lämnar Mastodon.",
|
||||
"upload_area.title": "Dra & släpp för att ladda upp",
|
||||
"upload_button.label": "Lägg till media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Yerel",
|
||||
"tabs_bar.notifications": "Bildirimler",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Upload için sürükle bırak yapınız",
|
||||
"upload_button.label": "Görsel ekle",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "Локальна",
|
||||
"tabs_bar.notifications": "Сповіщення",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Перетягніть сюди, щоб завантажити",
|
||||
"upload_button.label": "Додати медіаконтент",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "本站",
|
||||
"tabs_bar.notifications": "通知",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "如果你现在离开 Mastodon,你的草稿内容将会被丢弃。",
|
||||
"upload_area.title": "将文件拖放到此处开始上传",
|
||||
"upload_button.label": "上传媒体文件",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "本站",
|
||||
"tabs_bar.notifications": "通知",
|
||||
"tabs_bar.search": "搜尋",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "如果你現在離開 Mastodon,你的草稿內容將會被丟棄。",
|
||||
"upload_area.title": "將檔案拖放至此上載",
|
||||
"upload_button.label": "上載媒體檔案",
|
||||
|
|
|
@ -280,6 +280,8 @@
|
|||
"tabs_bar.local_timeline": "本地",
|
||||
"tabs_bar.notifications": "通知",
|
||||
"tabs_bar.search": "Search",
|
||||
"timeline.media": "Media",
|
||||
"timeline.posts": "Toots",
|
||||
"ui.beforeunload": "如果離開 Mastodon,你的草稿將會不見。",
|
||||
"upload_area.title": "拖放來上傳",
|
||||
"upload_button.label": "增加媒體",
|
||||
|
|
|
@ -4737,6 +4737,8 @@ a.status-card {
|
|||
}
|
||||
}
|
||||
|
||||
.community-timeline__section-headline,
|
||||
.public-timeline__section-headline,
|
||||
.account__section-headline {
|
||||
background: darken($ui-base-color, 4%);
|
||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||
|
|
|
@ -81,6 +81,11 @@ class BatchedRemoveStatusService < BaseService
|
|||
redis.publish('timeline:public', payload)
|
||||
redis.publish('timeline:public:local', payload) if status.local?
|
||||
|
||||
if status.media_attachments.exists?
|
||||
redis.publish('timeline:public:media', payload)
|
||||
redis.publish('timeline:public:local:media', payload) if status.local?
|
||||
end
|
||||
|
||||
@tags[status.id].each do |hashtag|
|
||||
redis.publish("timeline:hashtag:#{hashtag}", payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
|
||||
|
|
|
@ -25,6 +25,7 @@ class FanOutOnWriteService < BaseService
|
|||
return if status.reply? && status.in_reply_to_account_id != status.account_id
|
||||
|
||||
deliver_to_public(status)
|
||||
deliver_to_media(status) if status.media_attachments.exists?
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -85,6 +86,13 @@ class FanOutOnWriteService < BaseService
|
|||
Redis.current.publish('timeline:public:local', @payload) if status.local?
|
||||
end
|
||||
|
||||
def deliver_to_media(status)
|
||||
Rails.logger.debug "Delivering status #{status.id} to media timeline"
|
||||
|
||||
Redis.current.publish('timeline:public:media', @payload)
|
||||
Redis.current.publish('timeline:public:local:media', @payload) if status.local?
|
||||
end
|
||||
|
||||
def deliver_to_direct_timelines(status)
|
||||
Rails.logger.debug "Delivering status #{status.id} to direct timelines"
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ class RemoveStatusService < BaseService
|
|||
remove_reblogs
|
||||
remove_from_hashtags
|
||||
remove_from_public
|
||||
remove_from_media if status.media_attachments.exists?
|
||||
remove_from_direct if status.direct_visibility?
|
||||
|
||||
@status.destroy!
|
||||
|
@ -131,6 +132,13 @@ class RemoveStatusService < BaseService
|
|||
Redis.current.publish('timeline:public:local', @payload) if @status.local?
|
||||
end
|
||||
|
||||
def remove_from_media
|
||||
return unless @status.public_visibility?
|
||||
|
||||
Redis.current.publish('timeline:public:media', @payload)
|
||||
Redis.current.publish('timeline:public:local:media', @payload) if @status.local?
|
||||
end
|
||||
|
||||
def remove_from_direct
|
||||
@mentions.each do |mention|
|
||||
Redis.current.publish("timeline:direct:#{mention.account.id}", @payload) if mention.account.local?
|
||||
|
|
|
@ -241,7 +241,9 @@ const startWorker = (workerId) => {
|
|||
|
||||
const PUBLIC_STREAMS = [
|
||||
'public',
|
||||
'public:media',
|
||||
'public:local',
|
||||
'public:local:media',
|
||||
'hashtag',
|
||||
'hashtag:local',
|
||||
];
|
||||
|
@ -459,11 +461,17 @@ const startWorker = (workerId) => {
|
|||
});
|
||||
|
||||
app.get('/api/v1/streaming/public', (req, res) => {
|
||||
streamFrom('timeline:public', req, streamToHttp(req, res), streamHttpEnd(req), true);
|
||||
const onlyMedia = req.query.only_media === '1' || req.query.only_media === 'true';
|
||||
const channel = onlyMedia ? 'timeline:public:media' : 'timeline:public';
|
||||
|
||||
streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req), true);
|
||||
});
|
||||
|
||||
app.get('/api/v1/streaming/public/local', (req, res) => {
|
||||
streamFrom('timeline:public:local', req, streamToHttp(req, res), streamHttpEnd(req), true);
|
||||
const onlyMedia = req.query.only_media === '1' || req.query.only_media === 'true';
|
||||
const channel = onlyMedia ? 'timeline:public:local:media' : 'timeline:public:local';
|
||||
|
||||
streamFrom(channel, req, streamToHttp(req, res), streamHttpEnd(req), true);
|
||||
});
|
||||
|
||||
app.get('/api/v1/streaming/direct', (req, res) => {
|
||||
|
@ -521,6 +529,12 @@ const startWorker = (workerId) => {
|
|||
case 'public:local':
|
||||
streamFrom('timeline:public:local', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
|
||||
break;
|
||||
case 'public:media':
|
||||
streamFrom('timeline:public:media', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
|
||||
break;
|
||||
case 'public:local:media':
|
||||
streamFrom('timeline:public:local:media', req, streamToWs(req, ws), streamWsEnd(req, ws), true);
|
||||
break;
|
||||
case 'direct':
|
||||
streamFrom(`timeline:direct:${req.accountId}`, req, streamToWs(req, ws), streamWsEnd(req, ws), true);
|
||||
break;
|
||||
|
|
Loading…
Reference in a new issue