mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-20 20:21:20 -08:00
build all
Refactor utility functions for improved readability and consistency - Updated compatibility.js to use consistent line endings and formatting. - Refactored component.js for better readability and structure, including consistent use of arrow functions and binding. - Simplified dom.js functions with consistent formatting and improved readability. - Enhanced emitter.js with consistent formatting and arrow function usage. - Streamlined error.js for improved readability and consistency. - Refactored file.js to use consistent formatting and improved readability. - Improved format.js functions for better readability and consistency. - Updated index.js to maintain consistent export formatting. - Refactored property.js for improved readability and consistency. - Enhanced subtitle.js with consistent formatting and improved readability. - Refactored time.js for better readability and consistent formatting. fix: update lint script to target only source files for consistency Revert "fix: restore export statements for various plugins and update type definitions for better clarity" This reverts commit b5e969d81ec765cd8a34b06e6ef4f232ef25087f. fix: restore export statements for various plugins and update type definitions for better clarity Refactor type definitions to use interfaces instead of type aliases for better extensibility and clarity across i18n, icons, option, player, quality, setting, subtitle, template, and utils modules.
This commit is contained in:
1 parent
532dd67cfd
commit
35ad9883af
447 files changed
+18248
-17946
No files matched your search
@@ -1,66 +1,69 @@
|
||||
import { setStyle, addClass, removeClass, hasClass } from '../utils';
|
||||
import { addClass, hasClass, removeClass, setStyle } from '../utils'
|
||||
|
||||
export default function autoOrientation(art) {
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $video },
|
||||
} = art;
|
||||
const {
|
||||
constructor,
|
||||
template: { $player, $video },
|
||||
} = art
|
||||
|
||||
art.on('fullscreenWeb', (state) => {
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video;
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement;
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight) ||
|
||||
(videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
// There is a conflict with the fullscreen event, and it is changed to asynchronous execution
|
||||
setTimeout(() => {
|
||||
setStyle($player, 'width', `${viewHeight}px`);
|
||||
setStyle($player, 'height', `${viewWidth}px`);
|
||||
setStyle($player, 'transform-origin', '0 0');
|
||||
setStyle($player, 'transform', `rotate(90deg) translate(0, -${viewWidth}px)`);
|
||||
addClass($player, 'art-auto-orientation');
|
||||
art.isRotate = true;
|
||||
art.emit('resize');
|
||||
}, constructor.AUTO_ORIENTATION_TIME);
|
||||
}
|
||||
} else {
|
||||
if (hasClass($player, 'art-auto-orientation')) {
|
||||
removeClass($player, 'art-auto-orientation');
|
||||
art.isRotate = false;
|
||||
art.emit('resize');
|
||||
}
|
||||
}
|
||||
});
|
||||
art.on('fullscreenWeb', (state) => {
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight)
|
||||
|| (videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
// There is a conflict with the fullscreen event, and it is changed to asynchronous execution
|
||||
setTimeout(() => {
|
||||
setStyle($player, 'width', `${viewHeight}px`)
|
||||
setStyle($player, 'height', `${viewWidth}px`)
|
||||
setStyle($player, 'transform-origin', '0 0')
|
||||
setStyle($player, 'transform', `rotate(90deg) translate(0, -${viewWidth}px)`)
|
||||
addClass($player, 'art-auto-orientation')
|
||||
art.isRotate = true
|
||||
art.emit('resize')
|
||||
}, constructor.AUTO_ORIENTATION_TIME)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hasClass($player, 'art-auto-orientation')) {
|
||||
removeClass($player, 'art-auto-orientation')
|
||||
art.isRotate = false
|
||||
art.emit('resize')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
art.on('fullscreen', async (state) => {
|
||||
if (!screen?.orientation?.lock) return;
|
||||
art.on('fullscreen', async (state) => {
|
||||
if (!screen?.orientation?.lock)
|
||||
return
|
||||
|
||||
const lastOrientation = screen.orientation.type;
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video;
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement;
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight) ||
|
||||
(videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
const oppositeOrientation = lastOrientation.startsWith('portrait') ? 'landscape' : 'portrait';
|
||||
await screen.orientation.lock(oppositeOrientation);
|
||||
addClass($player, 'art-auto-orientation-fullscreen');
|
||||
}
|
||||
} else {
|
||||
if (hasClass($player, 'art-auto-orientation-fullscreen')) {
|
||||
await screen.orientation.lock(lastOrientation);
|
||||
removeClass($player, 'art-auto-orientation-fullscreen');
|
||||
}
|
||||
}
|
||||
});
|
||||
const lastOrientation = screen.orientation.type
|
||||
if (state) {
|
||||
const { videoWidth, videoHeight } = $video
|
||||
const { clientWidth: viewWidth, clientHeight: viewHeight } = document.documentElement
|
||||
if (
|
||||
(videoWidth > videoHeight && viewWidth < viewHeight)
|
||||
|| (videoWidth < videoHeight && viewWidth > viewHeight)
|
||||
) {
|
||||
const oppositeOrientation = lastOrientation.startsWith('portrait') ? 'landscape' : 'portrait'
|
||||
await screen.orientation.lock(oppositeOrientation)
|
||||
addClass($player, 'art-auto-orientation-fullscreen')
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hasClass($player, 'art-auto-orientation-fullscreen')) {
|
||||
await screen.orientation.lock(lastOrientation)
|
||||
removeClass($player, 'art-auto-orientation-fullscreen')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
name: 'autoOrientation',
|
||||
get state() {
|
||||
return hasClass($player, 'art-auto-orientation');
|
||||
},
|
||||
};
|
||||
return {
|
||||
name: 'autoOrientation',
|
||||
get state() {
|
||||
return hasClass($player, 'art-auto-orientation')
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,91 +1,91 @@
|
||||
import { secondToTime, setStyle, query, append } from '../utils';
|
||||
import { append, query, secondToTime, setStyle } from '../utils'
|
||||
|
||||
export default function autoPlayback(art) {
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
storage,
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $poster },
|
||||
} = art;
|
||||
const {
|
||||
i18n,
|
||||
icons,
|
||||
storage,
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $poster },
|
||||
} = art
|
||||
|
||||
const $autoPlayback = art.layers.add({
|
||||
name: 'auto-playback',
|
||||
html: `
|
||||
const $autoPlayback = art.layers.add({
|
||||
name: 'auto-playback',
|
||||
html: `
|
||||
<div class="art-auto-playback-close"></div>
|
||||
<div class="art-auto-playback-last"></div>
|
||||
<div class="art-auto-playback-jump"></div>
|
||||
`,
|
||||
});
|
||||
})
|
||||
|
||||
const $last = query('.art-auto-playback-last', $autoPlayback);
|
||||
const $jump = query('.art-auto-playback-jump', $autoPlayback);
|
||||
const $close = query('.art-auto-playback-close', $autoPlayback);
|
||||
append($close, icons.close);
|
||||
const $last = query('.art-auto-playback-last', $autoPlayback)
|
||||
const $jump = query('.art-auto-playback-jump', $autoPlayback)
|
||||
const $close = query('.art-auto-playback-close', $autoPlayback)
|
||||
append($close, icons.close)
|
||||
|
||||
let timer = null;
|
||||
let timer = null
|
||||
|
||||
art.on('video:timeupdate', () => {
|
||||
if (art.playing) {
|
||||
const times = storage.get('times') || {};
|
||||
const keys = Object.keys(times);
|
||||
if (keys.length > constructor.AUTO_PLAYBACK_MAX) {
|
||||
delete times[keys[0]];
|
||||
}
|
||||
times[art.option.id || art.option.url] = art.currentTime;
|
||||
storage.set('times', times);
|
||||
}
|
||||
});
|
||||
|
||||
function init() {
|
||||
const times = storage.get('times') || {};
|
||||
const currentTime = times[art.option.id || art.option.url];
|
||||
|
||||
clearTimeout(timer);
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
|
||||
if (currentTime && currentTime >= constructor.AUTO_PLAYBACK_MIN) {
|
||||
setStyle($autoPlayback, 'display', 'flex');
|
||||
|
||||
$last.innerText = `${i18n.get('Last Seen')} ${secondToTime(currentTime)}`;
|
||||
$jump.innerText = i18n.get('Jump Play');
|
||||
|
||||
proxy($close, 'click', () => {
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
});
|
||||
|
||||
proxy($jump, 'click', () => {
|
||||
art.seek = currentTime;
|
||||
art.play();
|
||||
setStyle($poster, 'display', 'none');
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
});
|
||||
|
||||
art.once('video:timeupdate', () => {
|
||||
timer = setTimeout(() => {
|
||||
setStyle($autoPlayback, 'display', 'none');
|
||||
}, constructor.AUTO_PLAYBACK_TIMEOUT);
|
||||
});
|
||||
}
|
||||
art.on('video:timeupdate', () => {
|
||||
if (art.playing) {
|
||||
const times = storage.get('times') || {}
|
||||
const keys = Object.keys(times)
|
||||
if (keys.length > constructor.AUTO_PLAYBACK_MAX) {
|
||||
delete times[keys[0]]
|
||||
}
|
||||
times[art.option.id || art.option.url] = art.currentTime
|
||||
storage.set('times', times)
|
||||
}
|
||||
})
|
||||
|
||||
art.on('ready', init);
|
||||
art.on('restart', init);
|
||||
function init() {
|
||||
const times = storage.get('times') || {}
|
||||
const currentTime = times[art.option.id || art.option.url]
|
||||
|
||||
return {
|
||||
name: 'auto-playback',
|
||||
get times() {
|
||||
return storage.get('times') || {};
|
||||
},
|
||||
clear() {
|
||||
return storage.del('times');
|
||||
},
|
||||
delete(id) {
|
||||
const times = storage.get('times') || {};
|
||||
delete times[id];
|
||||
storage.set('times', times);
|
||||
return times;
|
||||
},
|
||||
};
|
||||
clearTimeout(timer)
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
|
||||
if (currentTime && currentTime >= constructor.AUTO_PLAYBACK_MIN) {
|
||||
setStyle($autoPlayback, 'display', 'flex')
|
||||
|
||||
$last.textContent = `${i18n.get('Last Seen')} ${secondToTime(currentTime)}`
|
||||
$jump.textContent = i18n.get('Jump Play')
|
||||
|
||||
proxy($close, 'click', () => {
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
})
|
||||
|
||||
proxy($jump, 'click', () => {
|
||||
art.seek = currentTime
|
||||
art.play()
|
||||
setStyle($poster, 'display', 'none')
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
})
|
||||
|
||||
art.once('video:timeupdate', () => {
|
||||
timer = setTimeout(() => {
|
||||
setStyle($autoPlayback, 'display', 'none')
|
||||
}, constructor.AUTO_PLAYBACK_TIMEOUT)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
art.on('ready', init)
|
||||
art.on('restart', init)
|
||||
|
||||
return {
|
||||
name: 'auto-playback',
|
||||
get times() {
|
||||
return storage.get('times') || {}
|
||||
},
|
||||
clear() {
|
||||
return storage.del('times')
|
||||
},
|
||||
delete(id) {
|
||||
const times = storage.get('times') || {}
|
||||
delete times[id]
|
||||
storage.set('times', times)
|
||||
return times
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
import { hasClass, addClass, removeClass } from '../utils';
|
||||
import { addClass, hasClass, removeClass } from '../utils'
|
||||
|
||||
export default function fastForward(art) {
|
||||
const {
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $player, $video },
|
||||
} = art;
|
||||
const {
|
||||
constructor,
|
||||
proxy,
|
||||
template: { $player, $video },
|
||||
} = art
|
||||
|
||||
let timer = null;
|
||||
let isPress = false;
|
||||
let lastPlaybackRate = 1;
|
||||
let timer = null
|
||||
let isPress = false
|
||||
let lastPlaybackRate = 1
|
||||
|
||||
const onStart = (event) => {
|
||||
if (event.touches.length === 1 && art.playing && !art.isLock) {
|
||||
timer = setTimeout(() => {
|
||||
isPress = true;
|
||||
lastPlaybackRate = art.playbackRate;
|
||||
art.playbackRate = constructor.FAST_FORWARD_VALUE;
|
||||
addClass($player, 'art-fast-forward');
|
||||
}, constructor.FAST_FORWARD_TIME);
|
||||
}
|
||||
};
|
||||
const onStart = (event) => {
|
||||
if (event.touches.length === 1 && art.playing && !art.isLock) {
|
||||
timer = setTimeout(() => {
|
||||
isPress = true
|
||||
lastPlaybackRate = art.playbackRate
|
||||
art.playbackRate = constructor.FAST_FORWARD_VALUE
|
||||
addClass($player, 'art-fast-forward')
|
||||
}, constructor.FAST_FORWARD_TIME)
|
||||
}
|
||||
}
|
||||
|
||||
const onStop = () => {
|
||||
clearTimeout(timer);
|
||||
if (isPress) {
|
||||
isPress = false;
|
||||
art.playbackRate = lastPlaybackRate;
|
||||
removeClass($player, 'art-fast-forward');
|
||||
}
|
||||
};
|
||||
const onStop = () => {
|
||||
clearTimeout(timer)
|
||||
if (isPress) {
|
||||
isPress = false
|
||||
art.playbackRate = lastPlaybackRate
|
||||
removeClass($player, 'art-fast-forward')
|
||||
}
|
||||
}
|
||||
|
||||
proxy($video, 'touchstart', onStart);
|
||||
proxy(document, 'touchmove', onStop);
|
||||
proxy(document, 'touchend', onStop);
|
||||
proxy($video, 'touchstart', onStart)
|
||||
proxy(document, 'touchmove', onStop)
|
||||
proxy(document, 'touchend', onStop)
|
||||
|
||||
return {
|
||||
name: 'fastForward',
|
||||
get state() {
|
||||
return hasClass($player, 'art-fast-forward');
|
||||
},
|
||||
};
|
||||
return {
|
||||
name: 'fastForward',
|
||||
get state() {
|
||||
return hasClass($player, 'art-fast-forward')
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,59 @@
|
||||
import { errorHandle, isMobile, has, def } from '../utils';
|
||||
import miniProgressBar from './miniProgressBar';
|
||||
import autoOrientation from './autoOrientation';
|
||||
import autoPlayback from './autoPlayback';
|
||||
import fastForward from './fastForward';
|
||||
import lock from './lock';
|
||||
import { def, errorHandle, has, isMobile } from '../utils'
|
||||
import autoOrientation from './autoOrientation'
|
||||
import autoPlayback from './autoPlayback'
|
||||
import fastForward from './fastForward'
|
||||
import lock from './lock'
|
||||
import miniProgressBar from './miniProgressBar'
|
||||
|
||||
export default class Plugins {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.id = 0;
|
||||
constructor(art) {
|
||||
this.art = art
|
||||
this.id = 0
|
||||
|
||||
const { option } = art;
|
||||
const { option } = art
|
||||
|
||||
if (option.miniProgressBar && !option.isLive) {
|
||||
this.add(miniProgressBar);
|
||||
}
|
||||
|
||||
if (option.lock && isMobile) {
|
||||
this.add(lock);
|
||||
}
|
||||
|
||||
if (option.autoPlayback && !option.isLive) {
|
||||
this.add(autoPlayback);
|
||||
}
|
||||
|
||||
if (option.autoOrientation && isMobile) {
|
||||
this.add(autoOrientation);
|
||||
}
|
||||
|
||||
if (option.fastForward && isMobile && !option.isLive) {
|
||||
this.add(fastForward);
|
||||
}
|
||||
|
||||
for (let index = 0; index < option.plugins.length; index++) {
|
||||
this.add(option.plugins[index]);
|
||||
}
|
||||
if (option.miniProgressBar && !option.isLive) {
|
||||
this.add(miniProgressBar)
|
||||
}
|
||||
|
||||
add(plugin) {
|
||||
this.id += 1;
|
||||
const result = plugin.call(this.art, this.art);
|
||||
if (result instanceof Promise) {
|
||||
return result.then((res) => this.next(plugin, res));
|
||||
} else {
|
||||
return this.next(plugin, result);
|
||||
}
|
||||
if (option.lock && isMobile) {
|
||||
this.add(lock)
|
||||
}
|
||||
|
||||
next(plugin, result) {
|
||||
const pluginName = (result && result.name) || plugin.name || `plugin${this.id}`;
|
||||
errorHandle(!has(this, pluginName), `Cannot add a plugin that already has the same name: ${pluginName}`);
|
||||
def(this, pluginName, {
|
||||
value: result,
|
||||
});
|
||||
return this;
|
||||
if (option.autoPlayback && !option.isLive) {
|
||||
this.add(autoPlayback)
|
||||
}
|
||||
|
||||
if (option.autoOrientation && isMobile) {
|
||||
this.add(autoOrientation)
|
||||
}
|
||||
|
||||
if (option.fastForward && isMobile && !option.isLive) {
|
||||
this.add(fastForward)
|
||||
}
|
||||
|
||||
for (let index = 0; index < option.plugins.length; index++) {
|
||||
this.add(option.plugins[index])
|
||||
}
|
||||
}
|
||||
|
||||
add(plugin) {
|
||||
this.id += 1
|
||||
const result = plugin.call(this.art, this.art)
|
||||
if (result instanceof Promise) {
|
||||
return result.then(res => this.next(plugin, res))
|
||||
}
|
||||
else {
|
||||
return this.next(plugin, result)
|
||||
}
|
||||
}
|
||||
|
||||
next(plugin, result) {
|
||||
const pluginName = (result && result.name) || plugin.name || `plugin${this.id}`
|
||||
errorHandle(!has(this, pluginName), `Cannot add a plugin that already has the same name: ${pluginName}`)
|
||||
def(this, pluginName, {
|
||||
value: result,
|
||||
})
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -1,65 +1,68 @@
|
||||
import { append, setStyle, hasClass, addClass, removeClass } from '../utils';
|
||||
import { addClass, append, hasClass, removeClass, setStyle } from '../utils'
|
||||
|
||||
export default function lock(art) {
|
||||
const {
|
||||
layers,
|
||||
icons,
|
||||
template: { $player },
|
||||
} = art;
|
||||
const {
|
||||
layers,
|
||||
icons,
|
||||
template: { $player },
|
||||
} = art
|
||||
|
||||
function getState() {
|
||||
return hasClass($player, 'art-lock');
|
||||
}
|
||||
function getState() {
|
||||
return hasClass($player, 'art-lock')
|
||||
}
|
||||
|
||||
function setLock() {
|
||||
addClass($player, 'art-lock');
|
||||
art.isLock = true;
|
||||
art.emit('lock', true);
|
||||
}
|
||||
function setLock() {
|
||||
addClass($player, 'art-lock')
|
||||
art.isLock = true
|
||||
art.emit('lock', true)
|
||||
}
|
||||
|
||||
function setUnlock() {
|
||||
removeClass($player, 'art-lock');
|
||||
art.isLock = false;
|
||||
art.emit('lock', false);
|
||||
}
|
||||
function setUnlock() {
|
||||
removeClass($player, 'art-lock')
|
||||
art.isLock = false
|
||||
art.emit('lock', false)
|
||||
}
|
||||
|
||||
layers.add({
|
||||
name: 'lock',
|
||||
mounted($el) {
|
||||
const $lock = append($el, icons.lock);
|
||||
const $unlock = append($el, icons.unlock);
|
||||
setStyle($lock, 'display', 'none');
|
||||
layers.add({
|
||||
name: 'lock',
|
||||
mounted($el) {
|
||||
const $lock = append($el, icons.lock)
|
||||
const $unlock = append($el, icons.unlock)
|
||||
setStyle($lock, 'display', 'none')
|
||||
|
||||
art.on('lock', (state) => {
|
||||
if (state) {
|
||||
setStyle($lock, 'display', 'inline-flex');
|
||||
setStyle($unlock, 'display', 'none');
|
||||
} else {
|
||||
setStyle($lock, 'display', 'none');
|
||||
setStyle($unlock, 'display', 'inline-flex');
|
||||
}
|
||||
});
|
||||
},
|
||||
click() {
|
||||
if (getState()) {
|
||||
setUnlock();
|
||||
} else {
|
||||
setLock();
|
||||
}
|
||||
},
|
||||
});
|
||||
art.on('lock', (state) => {
|
||||
if (state) {
|
||||
setStyle($lock, 'display', 'inline-flex')
|
||||
setStyle($unlock, 'display', 'none')
|
||||
}
|
||||
else {
|
||||
setStyle($lock, 'display', 'none')
|
||||
setStyle($unlock, 'display', 'inline-flex')
|
||||
}
|
||||
})
|
||||
},
|
||||
click() {
|
||||
if (getState()) {
|
||||
setUnlock()
|
||||
}
|
||||
else {
|
||||
setLock()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
name: 'lock',
|
||||
get state() {
|
||||
return getState();
|
||||
},
|
||||
set state(value) {
|
||||
if (value) {
|
||||
setLock();
|
||||
} else {
|
||||
setUnlock();
|
||||
}
|
||||
},
|
||||
};
|
||||
return {
|
||||
name: 'lock',
|
||||
get state() {
|
||||
return getState()
|
||||
},
|
||||
set state(value) {
|
||||
if (value) {
|
||||
setLock()
|
||||
}
|
||||
else {
|
||||
setUnlock()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
import { addClass, removeClass } from '../utils';
|
||||
import { addClass, removeClass } from '../utils'
|
||||
|
||||
export default function miniProgressBar(art) {
|
||||
art.on('control', (state) => {
|
||||
if (state) {
|
||||
removeClass(art.template.$player, 'art-mini-progress-bar');
|
||||
} else {
|
||||
addClass(art.template.$player, 'art-mini-progress-bar');
|
||||
}
|
||||
});
|
||||
art.on('control', (state) => {
|
||||
if (state) {
|
||||
removeClass(art.template.$player, 'art-mini-progress-bar')
|
||||
}
|
||||
else {
|
||||
addClass(art.template.$player, 'art-mini-progress-bar')
|
||||
}
|
||||
})
|
||||
|
||||
return { name: 'mini-progress-bar' };
|
||||
return { name: 'mini-progress-bar' }
|
||||
}
|
||||
Reference in new issue
Block a user