Add a domain timeline
This commit is contained in:
parent
92a9a23eb6
commit
3d6eaf638d
20 changed files with 319 additions and 12 deletions
|
@ -39,6 +39,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
|||
current_account,
|
||||
local: truthy_param?(:local),
|
||||
remote: truthy_param?(:remote),
|
||||
domain: params[:domain],
|
||||
only_media: truthy_param?(:only_media)
|
||||
)
|
||||
end
|
||||
|
@ -48,7 +49,7 @@ class Api::V1::Timelines::PublicController < Api::BaseController
|
|||
end
|
||||
|
||||
def pagination_params(core_params)
|
||||
params.slice(:local, :remote, :limit, :only_media).permit(:local, :remote, :limit, :only_media).merge(core_params)
|
||||
params.slice(:local, :remote, :domain, :limit, :only_media).permit(:local, :remote, :domain, :limit, :only_media).merge(core_params)
|
||||
end
|
||||
|
||||
def next_path
|
||||
|
|
|
@ -126,9 +126,18 @@ export const connectCommunityStream = ({ onlyMedia } = {}) =>
|
|||
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
|
||||
|
||||
/**
|
||||
* @param {string} domain
|
||||
* @param {Object} options
|
||||
* @param {boolean} [options.onlyMedia]
|
||||
* @return {function(): void}
|
||||
*/
|
||||
export const connectDomainStream = (domain, { onlyMedia } = {}) =>
|
||||
connectTimelineStream(`domain${onlyMedia ? ':media' : ''}:${domain}`, `public:domain${onlyMedia ? ':media' : ''}`, { domain: domain });
|
||||
|
||||
/**
|
||||
* @param {Object} options
|
||||
* @param {boolean} [options.onlyRemote]
|
||||
* @param {boolean} [options.onlyMedia]
|
||||
* @return {function(): void}
|
||||
*/
|
||||
export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) =>
|
||||
|
|
|
@ -131,6 +131,7 @@ 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, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, 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 expandDomainTimeline = (domain, { maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`domain${onlyMedia ? ':media' : ''}:${domain}`, '/api/v1/timelines/public', { local: false, domain: domain, max_id: maxId, only_media: !!onlyMedia }, 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 });
|
||||
export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 });
|
||||
|
|
|
@ -41,6 +41,7 @@ const messages = defineMessages({
|
|||
copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
|
||||
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
||||
openDomainTimeline: { id: 'account.open_domain_timeline', defaultMessage: 'Open {domain} timeline' },
|
||||
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
});
|
||||
|
@ -192,6 +193,13 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
onUnblockDomain(account.get('acct').split('@')[1]);
|
||||
}
|
||||
|
||||
handleOpenDomainTimeline = () => {
|
||||
const { status } = this.props;
|
||||
const account = status.get('account');
|
||||
|
||||
this.context.router.history.push(`/timelines/public/domain/${account.get('acct').split('@')[1]}`);
|
||||
}
|
||||
|
||||
handleOpen = () => {
|
||||
this.context.router.history.push(`/statuses/${this.props.status.get('id')}`);
|
||||
}
|
||||
|
@ -292,6 +300,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
|||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.blockDomain, { domain }), action: this.handleBlockDomain });
|
||||
}
|
||||
menu.push({ text: intl.formatMessage(messages.openDomainTimeline, { domain }), action: this.handleOpenDomainTimeline });
|
||||
}
|
||||
|
||||
if (isStaff) {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
import SettingToggle from '../../notifications/components/setting_toggle';
|
||||
|
||||
export default @injectIntl
|
||||
class ColumnSettings extends React.PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
};
|
||||
|
||||
render () {
|
||||
const { settings, onChange } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='column-settings__row'>
|
||||
<SettingToggle settings={settings} settingPath={['other', 'onlyMedia']} onChange={onChange} label={<FormattedMessage id='community.column_settings.media_only' defaultMessage='Media only' />} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { connect } from 'react-redux';
|
||||
import ColumnSettings from '../components/column_settings';
|
||||
import { changeSetting } from '../../../actions/settings';
|
||||
import { changeColumnParams } from '../../../actions/columns';
|
||||
|
||||
const mapStateToProps = (state, { columnId }) => {
|
||||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
|
||||
return {
|
||||
settings: (uuid && index >= 0) ? columns.get(index).get('params') : state.getIn(['settings', 'domain']),
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { columnId }) => {
|
||||
return {
|
||||
onChange (key, checked) {
|
||||
if (columnId) {
|
||||
dispatch(changeColumnParams(columnId, key, checked));
|
||||
} else {
|
||||
dispatch(changeSetting(['domain', ...key], checked));
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings);
|
136
app/javascript/mastodon/features/domain_timeline/index.js
Normal file
136
app/javascript/mastodon/features/domain_timeline/index.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { injectIntl, FormattedMessage } from 'react-intl';
|
||||
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 { expandDomainTimeline } from '../../actions/timelines';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
import { connectDomainStream } from '../../actions/streaming';
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
const uuid = props.columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const onlyMedia = (props.columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'domain', 'other', 'onlyMedia']);
|
||||
const timelineState = state.getIn(['timelines', `domain${onlyMedia ? ':media' : ''}:${domain}`]);
|
||||
const domain = props.params.domain;
|
||||
|
||||
return {
|
||||
hasUnread: !!timelineState && timelineState.get('unread') > 0,
|
||||
onlyMedia,
|
||||
domain: domain,
|
||||
};
|
||||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class DomainTimeline extends React.PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
router: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
onlyMedia: PropTypes.bool,
|
||||
domain: PropTypes.string,
|
||||
};
|
||||
|
||||
handlePin = () => {
|
||||
const { columnId, dispatch, onlyMedia, domain } = this.props;
|
||||
|
||||
if (columnId) {
|
||||
dispatch(removeColumn(columnId));
|
||||
} else {
|
||||
dispatch(addColumn('DOMAIN', { domain, other: { onlyMedia } }));
|
||||
}
|
||||
}
|
||||
|
||||
handleMove = (dir) => {
|
||||
const { columnId, dispatch } = this.props;
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia, domain } = this.props;
|
||||
|
||||
dispatch(expandDomainTimeline(domain, { onlyMedia }));
|
||||
this.disconnect = dispatch(connectDomainStream(domain, { onlyMedia }));
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.domain !== this.props.domain) {
|
||||
const { dispatch, onlyMedia, domain } = this.props;
|
||||
|
||||
this.disconnect();
|
||||
dispatch(expandDomainTimeline(domain, { onlyMedia }));
|
||||
this.disconnect = dispatch(connectDomainStream(domain, { onlyMedia }));
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
if (this.disconnect) {
|
||||
this.disconnect();
|
||||
this.disconnect = null;
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
}
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
const { dispatch, onlyMedia, domain } = this.props;
|
||||
|
||||
dispatch(expandDomainTimeline(domain, { maxId, onlyMedia }));
|
||||
}
|
||||
|
||||
render () {
|
||||
const { hasUnread, columnId, multiColumn, onlyMedia, domain } = this.props;
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={domain}>
|
||||
<ColumnHeader
|
||||
icon='users'
|
||||
active={hasUnread}
|
||||
title={domain}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
>
|
||||
<ColumnSettingsContainer columnId={columnId} />
|
||||
</ColumnHeader>
|
||||
|
||||
<StatusListContainer
|
||||
trackScroll={!pinned}
|
||||
scrollKey={`domain_timeline-${columnId}`}
|
||||
timelineId={`domain${onlyMedia ? ':media' : ''}:${domain}`}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
emptyMessage={<FormattedMessage id='empty_column.domain' defaultMessage='There is nothing here! Manually follow users from other servers to fill it up' />}
|
||||
bindToDocument={!multiColumn}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -37,6 +37,7 @@ const messages = defineMessages({
|
|||
copy: { id: 'status.copy', defaultMessage: 'Copy link to status' },
|
||||
blockDomain: { id: 'account.block_domain', defaultMessage: 'Block domain {domain}' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
|
||||
openDomainTimeline: { id: 'account.open_domain_timeline', defaultMessage: 'Open {domain} timeline' },
|
||||
unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
});
|
||||
|
@ -149,6 +150,13 @@ class ActionBar extends React.PureComponent {
|
|||
onUnblockDomain(account.get('acct').split('@')[1]);
|
||||
}
|
||||
|
||||
handleOpenDomainTimeline = () => {
|
||||
const { status } = this.props;
|
||||
const account = status.get('account');
|
||||
|
||||
this.context.router.history.push(`/timelines/public/domain/${account.get('acct').split('@')[1]}`);
|
||||
}
|
||||
|
||||
handleConversationMuteClick = () => {
|
||||
this.props.onMuteConversation(this.props.status);
|
||||
}
|
||||
|
@ -246,6 +254,7 @@ class ActionBar extends React.PureComponent {
|
|||
} else {
|
||||
menu.push({ text: intl.formatMessage(messages.blockDomain, { domain }), action: this.handleBlockDomain });
|
||||
}
|
||||
menu.push({ text: intl.formatMessage(messages.openDomainTimeline, { domain }), action: this.handleOpenDomainTimeline });
|
||||
}
|
||||
|
||||
if (isStaff) {
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
HomeTimeline,
|
||||
CommunityTimeline,
|
||||
PublicTimeline,
|
||||
DomainTimeline,
|
||||
HashtagTimeline,
|
||||
DirectTimeline,
|
||||
FavouritedStatuses,
|
||||
|
@ -41,6 +42,7 @@ const componentMap = {
|
|||
'PUBLIC': PublicTimeline,
|
||||
'REMOTE': PublicTimeline,
|
||||
'COMMUNITY': CommunityTimeline,
|
||||
'DOMAIN': DomainTimeline,
|
||||
'HASHTAG': HashtagTimeline,
|
||||
'DIRECT': DirectTimeline,
|
||||
'FAVOURITES': FavouritedStatuses,
|
||||
|
|
|
@ -29,6 +29,7 @@ import {
|
|||
KeyboardShortcuts,
|
||||
PublicTimeline,
|
||||
CommunityTimeline,
|
||||
DomainTimeline,
|
||||
AccountTimeline,
|
||||
AccountGallery,
|
||||
HomeTimeline,
|
||||
|
@ -155,6 +156,7 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
<WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public/local' exact component={CommunityTimeline} content={children} />
|
||||
<WrappedRoute path='/timelines/public/domain/:domain' exact component={DomainTimeline} content={children} />
|
||||
<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} />
|
||||
|
|
|
@ -22,6 +22,10 @@ export function CommunityTimeline () {
|
|||
return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline');
|
||||
}
|
||||
|
||||
export function DomainTimeline () {
|
||||
return import(/* webpackChunkName: "features/domain_timeline" */'../../domain_timeline');
|
||||
}
|
||||
|
||||
export function HashtagTimeline () {
|
||||
return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline');
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
"account.mute_notifications": "Mute notifications from @{name}",
|
||||
"account.muted": "Muted",
|
||||
"account.never_active": "Never",
|
||||
"account.open_domain_timeline": "Open {domain} timeline",
|
||||
"account.posts": "Posts",
|
||||
"account.posts_with_replies": "Posts and replies",
|
||||
"account.report": "Report @{name}",
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
"account.mute_notifications": "@{name}さんからの通知を受け取らない",
|
||||
"account.muted": "ミュート済み",
|
||||
"account.never_active": "活動なし",
|
||||
"account.open_domain_timeline": "{domain}タイムラインを表示",
|
||||
"account.posts": "投稿",
|
||||
"account.posts_with_replies": "投稿と返信",
|
||||
"account.report": "@{name}さんを通報",
|
||||
|
|
|
@ -74,6 +74,12 @@ const initialState = ImmutableMap({
|
|||
}),
|
||||
}),
|
||||
|
||||
domain: ImmutableMap({
|
||||
regex: ImmutableMap({
|
||||
body: '',
|
||||
}),
|
||||
}),
|
||||
|
||||
public: ImmutableMap({
|
||||
regex: ImmutableMap({
|
||||
body: '',
|
||||
|
|
|
@ -103,6 +103,8 @@ const sharedCallbacks = {
|
|||
return channelName === streamChannelName && params.tag === streamIdentifier;
|
||||
} else if (channelName === 'list') {
|
||||
return channelName === streamChannelName && params.list === streamIdentifier;
|
||||
} else if (['public:domain', 'public:domain:media'].includes(channelName)) {
|
||||
return channelName === streamChannelName && params.domain === streamIdentifier;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -25,6 +25,7 @@ class PublicFeed
|
|||
scope.merge!(without_reblogs_scope) unless with_reblogs?
|
||||
scope.merge!(local_only_scope) if local_only?
|
||||
scope.merge!(remote_only_scope) if remote_only?
|
||||
scope.merge!(domain_only_scope) if domain_only?
|
||||
scope.merge!(account_filters_scope) if account?
|
||||
scope.merge!(media_only_scope) if media_only?
|
||||
|
||||
|
@ -51,6 +52,10 @@ class PublicFeed
|
|||
options[:remote]
|
||||
end
|
||||
|
||||
def domain_only?
|
||||
@options[:domain].present?
|
||||
end
|
||||
|
||||
def account?
|
||||
account.present?
|
||||
end
|
||||
|
@ -59,6 +64,10 @@ class PublicFeed
|
|||
options[:only_media]
|
||||
end
|
||||
|
||||
def domain
|
||||
@options[:domain]
|
||||
end
|
||||
|
||||
def public_scope
|
||||
Status.with_public_visibility.joins(:account).merge(Account.without_suspended.without_silenced)
|
||||
end
|
||||
|
@ -71,6 +80,10 @@ class PublicFeed
|
|||
Status.remote
|
||||
end
|
||||
|
||||
def domain_only_scope
|
||||
Status.joins(:account).merge(Account.where(domain: domain))
|
||||
end
|
||||
|
||||
def without_replies_scope
|
||||
Status.without_replies
|
||||
end
|
||||
|
|
|
@ -76,18 +76,31 @@ class BatchedRemoveStatusService < BaseService
|
|||
return unless status.public_visibility? && status.id > @status_id_cutoff
|
||||
|
||||
payload = Oj.dump(event: :delete, payload: status.id.to_s)
|
||||
domain = status.account.domain.mb_chars.downcase
|
||||
|
||||
redis.publish('timeline:public', payload)
|
||||
redis.publish(status.local? ? 'timeline:public:local' : 'timeline:public:remote', payload)
|
||||
redis.pipelined do
|
||||
redis.publish('timeline:public', payload)
|
||||
if status.local?
|
||||
redis.publish('timeline:public:local', payload)
|
||||
else
|
||||
redis.publish('timeline:public:remote', payload)
|
||||
redis.publish("timeline:public:domain:#{domain}", payload)
|
||||
end
|
||||
|
||||
if status.media_attachments.any?
|
||||
redis.publish('timeline:public:media', payload)
|
||||
redis.publish(status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', payload)
|
||||
end
|
||||
if status.media_attachments.any?
|
||||
redis.publish('timeline:public:media', payload)
|
||||
if status.local?
|
||||
redis.publish('timeline:public:local:media', payload)
|
||||
else
|
||||
redis.publish('timeline:public:remote:media', payload)
|
||||
redis.publish("timeline:public:domain:media:#{domain}", payload)
|
||||
end
|
||||
end
|
||||
|
||||
status.tags.map { |tag| tag.name.mb_chars.downcase }.each do |hashtag|
|
||||
redis.publish("timeline:hashtag:#{hashtag}", payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
|
||||
status.tags.map { |tag| tag.name.mb_chars.downcase }.each do |hashtag|
|
||||
redis.publish("timeline:hashtag:#{hashtag}", payload)
|
||||
redis.publish("timeline:hashtag:#{hashtag}:local", payload) if status.local?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -170,6 +170,7 @@ class FanOutOnWriteService < BaseService
|
|||
Redis.current.publish('timeline:public:local', @payload)
|
||||
else
|
||||
Redis.current.publish('timeline:public:remote', @payload)
|
||||
Redis.current.publish("timeline:public:domain:#{status.account.domain.mb_chars.downcase}", @payload)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -181,6 +182,7 @@ class FanOutOnWriteService < BaseService
|
|||
Redis.current.publish('timeline:public:local:media', @payload)
|
||||
else
|
||||
Redis.current.publish('timeline:public:remote:media', @payload)
|
||||
Redis.current.publish("timeline:public:domain:media:#{status.account.domain.mb_chars.downcase}", @payload)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -124,14 +124,24 @@ class RemoveStatusService < BaseService
|
|||
return unless @status.public_visibility?
|
||||
|
||||
redis.publish('timeline:public', @payload)
|
||||
redis.publish(@status.local? ? 'timeline:public:local' : 'timeline:public:remote', @payload)
|
||||
if @status.local?
|
||||
redis.publish('timeline:public:local', @payload)
|
||||
else
|
||||
redis.publish('timeline:public:remote', @payload)
|
||||
redis.publish("timeline:public:domain:#{@account.domain.mb_chars.downcase}", @payload)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_from_media
|
||||
return unless @status.public_visibility?
|
||||
|
||||
redis.publish('timeline:public:media', @payload)
|
||||
redis.publish(@status.local? ? 'timeline:public:local:media' : 'timeline:public:remote:media', @payload)
|
||||
if @status.local?
|
||||
redis.publish('timeline:public:local:media', @payload)
|
||||
else
|
||||
redis.publish('timeline:public:remote:media', @payload)
|
||||
redis.publish("timeline:public:domain:media:#{@account.domain.mb_chars.downcase}", @payload)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_media
|
||||
|
|
|
@ -369,6 +369,8 @@ const startWorker = (workerId) => {
|
|||
return onlyMedia ? 'public:local:media' : 'public:local';
|
||||
case '/api/v1/streaming/public/remote':
|
||||
return onlyMedia ? 'public:remote:media' : 'public:remote';
|
||||
case '/api/v1/streaming/public/domain':
|
||||
return onlyMedia ? 'public:domain:media' : 'public:domain';
|
||||
case '/api/v1/streaming/hashtag':
|
||||
return 'hashtag';
|
||||
case '/api/v1/streaming/hashtag/local':
|
||||
|
@ -389,6 +391,8 @@ const startWorker = (workerId) => {
|
|||
'public:local:media',
|
||||
'public:remote',
|
||||
'public:remote:media',
|
||||
'public:domain',
|
||||
'public:domain:media',
|
||||
'hashtag',
|
||||
'hashtag:local',
|
||||
];
|
||||
|
@ -772,6 +776,7 @@ const startWorker = (workerId) => {
|
|||
* @typedef StreamParams
|
||||
* @property {string} [tag]
|
||||
* @property {string} [list]
|
||||
* @property {string} [domain]
|
||||
* @property {string} [only_media]
|
||||
*/
|
||||
|
||||
|
@ -817,6 +822,17 @@ const startWorker = (workerId) => {
|
|||
options: { needsFiltering: true, notificationOnly: false },
|
||||
});
|
||||
|
||||
break;
|
||||
case 'public:domain':
|
||||
if (!params.domain || params.domain.length === 0) {
|
||||
reject('No domain for stream provided');
|
||||
} else {
|
||||
resolve({
|
||||
channelIds: [`timeline:public:domain:${params.domain.toLowerCase()}`],
|
||||
options: { needsFiltering: true, notificationOnly: false },
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case 'public:media':
|
||||
resolve({
|
||||
|
@ -838,6 +854,17 @@ const startWorker = (workerId) => {
|
|||
options: { needsFiltering: true, notificationOnly: false },
|
||||
});
|
||||
|
||||
break;
|
||||
case 'public:domain:media':
|
||||
if (!params.domain || params.domain.length === 0) {
|
||||
reject('No domain for stream provided');
|
||||
} else {
|
||||
resolve({
|
||||
channelIds: [`timeline:public:domain:media:${params.domain.toLowerCase()}`],
|
||||
options: { needsFiltering: true, notificationOnly: false },
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case 'direct':
|
||||
resolve({
|
||||
|
@ -894,6 +921,8 @@ const startWorker = (workerId) => {
|
|||
return [channelName, params.list];
|
||||
} else if (['hashtag', 'hashtag:local'].includes(channelName)) {
|
||||
return [channelName, params.tag];
|
||||
} else if (['public:domain', 'public:domain:media'].includes(channelName)) {
|
||||
return [channelName, params.domain];
|
||||
} else {
|
||||
return [channelName];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue