完成gif插件

This commit is contained in:
Harvey Zack committed 2018-12-06 15:39:47 +08:00
1 parent d535423dd8
commit c9dfc883ab
11 files changed
+352 -54

No files matched your search

+61 -1
View File
@@ -1,3 +1,63 @@
# artplayer-plugin-gif
Gif plugin for ArtPlayer
Gif plugin for ArtPlayer, use [gifshot](https://github.com/yahoo/gifshot) as a dependency
## Demo
[Checkout the demo](https://artplayer.org/gif/) from Github Pages
## Install
Install with `npm`
```
$ npm install artplayer-plugin-gif
```
Or install with `yarn`
```
$ yarn add artplayer-plugin-gif
```
```js
import artplayerPluginGif from 'artplayer-plugin-gif';
```
Or umd builds are also available
```html
<script src="artplayer-plugin-gif"></script>
```
Will expose the global variable to `window.artplayerPluginGif`.
## Usage
This will add a button called "GIF" in the bottom control bar.
```js
var art = new Artplayer({
container: '.artplayer-app',
url: 'path/to/video.mp4',
plugins: [artplayerPluginGif],
});
```
Or can be called via api
```js
art.plugins.artplayerPluginGif.create(
{
// some configuration
// https://github.com/yahoo/gifshot#options
},
function(imageUrl) {
console.log(imageUrl);
},
);
```
## License
MIT © [Harvey Zack](https://www.zhw-island.com/)
+125 -7
View File
@@ -1,22 +1,140 @@
import gifshot from 'gifshot';
function i18nMix(i18n) {
i18n.update({
'zh-cn': {
'Long press, gif length is between 1 second and 5 seconds': '长按,gif 长度为 1 ~ 5 秒',
'Gif time is too short': 'Gif 时间太短',
'Start creating gif, please wait': '开始创建 gif,请稍等',
'Create gif successfully': '创建 gif 成功',
'There is another gif in the processing': '正有另一个 gif 在创建中',
},
'zh-tw': {
'Long press, gif length is between 1 second and 5 seconds': '長按,gif 長度為 1 ~ 5 秒',
'Gif time is too short': 'Gif 時間太短',
'Start creating gif, please wait': '開始創建 gif,請稍等',
'Create gif successfully': '創建 gif 成功',
'There is another gif in the processing': '正有另一個 gif 在創建中',
},
});
}
function artplayerPluginGif(art) {
const { errorHandle, clamp, downloadImage } = art.constructor.utils;
const {
i18n,
notice,
layers,
controls,
player,
option: { theme, title },
events: { proxy },
template: { $video },
} = art;
i18nMix(i18n);
layers.add({
name: 'artplayer-plugin-gif-progress',
html: '<div class="artplayer-plugin-gif-progress"></div>',
style: {
position: 'absolute',
top: '0',
left: '0',
height: '3px',
width: '0%',
'background-color': theme,
},
});
const $progress = layers['artplayer-plugin-gif-progress'].$ref;
let isProcessing = false;
let pressStartTime = 0;
let progressTimer = null;
function cleanTimer() {
$progress.style.width = '0%';
clearTimeout(progressTimer);
progressTimer = null;
}
function createGif() {
cleanTimer();
const pressTime = new Date() - pressStartTime;
if (isProcessing) {
notice.show(i18n.get('There is another gif in the processing'));
} else if (pressTime < 1000) {
notice.show(i18n.get('Gif time is too short'));
} else {
const numFrames = Math.floor(clamp(pressTime, 1000, 5000) / 100);
const { videoWidth, videoHeight } = $video;
art.plugins.artplayerPluginGif.create(
{
numFrames,
gifHeight: 200,
gifWidth: (videoWidth / videoHeight) * 200,
},
image => {
downloadImage(image, `${title || 'unnamed'}.gif`);
},
);
}
}
controls.add({
name: 'artplayer-plugin-gif',
position: 'right',
html: 'GIF',
mounted: $gif => {
proxy($gif, 'mousedown', () => {
cleanTimer();
pressStartTime = new Date();
notice.show(i18n.get('Long press, gif length is between 1 second and 5 seconds'));
(function loop() {
progressTimer = setTimeout(() => {
const width = parseInt($progress.style.width, 10);
if (width <= 100) {
$progress.style.width = `${width + 1}%`;
loop();
} else {
createGif();
}
}, 50);
})();
});
proxy($gif, 'mouseup', () => {
createGif();
});
},
});
return {
name: 'artplayerPluginGif',
isProcessing,
create(config = {}, callback) {
isProcessing = true;
art.emit('artplayerPluginGif:create:start');
notice.show(`${i18n.get('Start creating gif, please wait')}: ${config.numFrames / 10 || 1} s`, false, 5000);
gifshot.createGIF(
{
...config,
video: [art.template.$video.src],
offset: player.currentTime,
video: [$video.src],
},
obj => {
if (!obj.error) {
if (callback) {
callback(obj.image);
}
} else {
console.log(obj.error);
if (obj.error) {
notice.show(obj.errorMsg);
errorHandle(false, obj.errorMsg);
} else if (typeof callback === 'function') {
callback(obj.image);
notice.show(i18n.get('Create gif successfully'));
}
isProcessing = false;
art.emit('artplayerPluginGif:create:end');
},
);
},
@@ -1,4 +1,4 @@
import { setStyle, secondToTime } from '../utils';
import { secondToTime, downloadImage } from '../utils';
export default function screenshotMix(art, player) {
const {
@@ -13,13 +13,7 @@ export default function screenshotMix(art, player) {
canvas.height = $video.videoHeight;
canvas.getContext('2d').drawImage($video, 0, 0);
const dataUri = canvas.toDataURL('image/png');
const elink = document.createElement('a');
setStyle(elink, 'display', 'none');
elink.href = dataUri;
elink.download = `${option.title || 'artplayer'}_${secondToTime($video.currentTime)}.png`;
document.body.appendChild(elink);
elink.click();
document.body.removeChild(elink);
downloadImage(dataUri, `${option.title || 'artplayer'}_${secondToTime($video.currentTime)}.png`);
return dataUri;
}
+2
View File
@@ -136,7 +136,9 @@
opacity: .9;
font-size: 12px;
height: 36px;
min-width: 36px;
line-height: 36px;
text-align: center;
cursor: pointer;
.art-icon {
display: flex;
+10
View File
@@ -170,3 +170,13 @@ export function vttToBlob(vttText) {
}),
);
}
export function downloadImage(url, name) {
const elink = document.createElement('a');
setStyle(elink, 'display', 'none');
elink.href = url;
elink.download = name;
document.body.appendChild(elink);
elink.click();
document.body.removeChild(elink);
}