Skip to content

Commit

Permalink
Opt: subtitle
Browse files Browse the repository at this point in the history
  • Loading branch information
zijiren233 committed Dec 10, 2023
1 parent 5a3242a commit 1b4c36f
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 109 deletions.
1 change: 0 additions & 1 deletion components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ declare module 'vue' {
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
Github: typeof import('./src/components/icons/Github.vue')['default']
Header: typeof import('./src/components/Header.vue')['default']
Hot: typeof import('./src/components/Hot.vue')['default']
Moon: typeof import('./src/components/icons/Moon.vue')['default']
Expand Down
93 changes: 43 additions & 50 deletions src/components/Player.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
<script setup lang="ts">
import { roomStore } from "@/stores/room";
import Artplayer from "artplayer";
import type { Option } from "artplayer/types/option";
import { onMounted, onBeforeUnmount, ref, watch, computed } from "vue";
import type { PropType, WatchStopHandle } from "vue";
import { deepEqualObject } from "@/utils";
const room = roomStore();
import { newSubtitle } from "@/plugins/subtitle";
const watchers: WatchStopHandle[] = [];
Expand All @@ -15,16 +13,15 @@ onBeforeUnmount(() => {
Artplayer.DBCLICK_FULLSCREEN = false;
const artplayer = ref<HTMLDivElement>();
let art: Artplayer;
interface options {
export interface options {
url: string;
isLive: boolean;
type?: string;
headers: { [key: string]: string };
plugins: ((art: Artplayer) => unknown)[];
subtitles?: { [key: string]: { type: string; url: string } };
}
const Props = defineProps({
Expand All @@ -36,17 +33,6 @@ const Props = defineProps({
const Emits = defineEmits(["get-instance"]);
// 监听弹幕变化
watchers.push(
watch(
() => room.danmuku,
() => {
if (!art || !art.plugins.artplayerPluginDanmuku) return;
art.plugins.artplayerPluginDanmuku.emit(room.danmuku);
}
)
);
const playMpd = (player: HTMLMediaElement, url: string, art: any) => {
import("@/utils/dash").then((dash) => {
if (dash.isSupported()) {
Expand Down Expand Up @@ -160,9 +146,11 @@ const playM3u8 = (player: HTMLMediaElement, url: string, art: any) => {
});
};
const playerOption = computed<Option>(() => {
return {
container: artplayer.value!,
const newPlayerOption = (html: HTMLDivElement): Option => {
const opts: Option = {
url: Props.options.url,
isLive: Props.options.isLive,
container: html,
volume: 0, // 音量
autoSize: false, // 隐藏黑边
autoMini: false,
Expand All @@ -186,14 +174,8 @@ const playerOption = computed<Option>(() => {
autoPlayback: false, // 使用自动回放功能
autoOrientation: true, // 移动端的网页全屏时,根据视频尺寸和视口尺寸,旋转播放器
airplay: false, // 隔空播放
...Props.options,
type: Props.options.type,
subtitle: {
type: room.currentMovie.base.subtitles
? room.currentMovie.base.subtitles[Object.keys(room.currentMovie.base.subtitles!)[0]].type
: "srt",
encoding: "utf-8"
},
plugins: Props.options.plugins,
customType: {
flv: playFlv,
m3u8: playM3u8,
Expand All @@ -205,45 +187,58 @@ const playerOption = computed<Option>(() => {
mts: playM2ts
}
};
});
if (Props.options.subtitles) {
opts.subtitle = {
type: Props.options.subtitles[Object.keys(Props.options.subtitles)[0]].type,
encoding: "utf-8",
escape: true
};
opts.plugins!.push(newSubtitle(Props.options.subtitles));
}
return opts;
};
console.log(Props.options);
const father = ref<HTMLDivElement>();
onMounted(() => {
art = new Artplayer(playerOption.value);
const euqalRecord = <T extends Record<string, unknown>>(a: T, b: T) => {
return Object.keys(a).every((key) => {
return a[key] === b[key];
});
};
const mountPlayer = () => {
const newDiv = document.createElement("div");
newDiv.setAttribute("class", "artplayer-app");
while (father.value!.firstChild) {
father.value!.removeChild(father.value!.firstChild);
}
father.value!.appendChild(newDiv);
art = new Artplayer(newPlayerOption(newDiv));
console.log(art);
Emits("get-instance", art);
};
onMounted(() => {
mountPlayer();
const needDestroy = (oldOption: options, newOption: options) => {
return (
oldOption.isLive !== newOption.isLive ||
oldOption.type !== newOption.type ||
oldOption.url !== newOption.url ||
!deepEqualObject(oldOption.headers, newOption.headers)
!euqalRecord(oldOption.headers, newOption.headers)
);
};
watchers.push(
watch(
() => Props.options,
(old, current) => {
if (needDestroy(old, current)) {
console.log("destroy");
art.destroy();
const newDiv = document.createElement("div");
newDiv.setAttribute("class", "artplayer-app");
newDiv.setAttribute("ref", "artplayer");
while (father.value!.firstChild) {
father.value!.removeChild(father.value!.firstChild);
}
father.value!.appendChild(newDiv);
artplayer.value = newDiv;
art = new Artplayer(playerOption.value);
Emits("get-instance", art);
} else {
//
}
if (!needDestroy(old, current)) return;
console.log("destroy");
if (art) art.destroy();
mountPlayer();
}
)
);
Expand All @@ -255,9 +250,7 @@ onBeforeUnmount(() => {
</script>

<template>
<div ref="father">
<div class="artplayer-app" ref="artplayer"></div>
</div>
<div ref="father"></div>
</template>

<style></style>
85 changes: 56 additions & 29 deletions src/plugins/subtitle.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,63 @@
import { roomStore } from "@/stores/room";
import type Artplayer from "artplayer";
import type { ComponentOption } from "artplayer/types/component";

const room = roomStore();
const SubtitleHtml =
"<span style='background-color:#fff;color:#000;padding:2px 6px;border-radius:5px;font-size:14px;'>字幕</span>";
const newSubtitleHtml = (name: string): HTMLElement => {
const SubtitleHtml = document.createElement("span");
SubtitleHtml.style.backgroundColor = "#fff";
SubtitleHtml.style.color = "#000";
SubtitleHtml.style.padding = "2px 6px";
SubtitleHtml.style.borderRadius = "5px";
SubtitleHtml.style.fontSize = "14px";
SubtitleHtml.innerText = name;
return SubtitleHtml;
};

export const subtitle = (art: Artplayer) => {
if (room.currentMovie.base.subtitles) {
art.controls.add({
name: "subtitle",
html: SubtitleHtml,
position: "right",
selector: Object.keys(room.currentMovie.base.subtitles).map((key) => {
return {
html: key,
url: room.currentMovie.base.subtitles![key].url
};
}),
onSelect: function (item: { html: string; url: string }, $dom: any) {
art.subtitle.switch(item.url);
console.info(item, $dom);
console.log(art.subtitle);
const newSubtitleControl = (
subtitles: Record<
string,
{
url: string;
type: string;
}
>
): ComponentOption => {
return {
name: "subtitle",
html: newSubtitleHtml("字幕"),
position: "right",
selector: Object.keys(subtitles).map((key) => {
return {
html: key,
url: subtitles[key].url
};
}),
onSelect(this: Artplayer, selector: any, element: HTMLElement, event: Event): void {
console.log("切换字幕:", selector.url);
this.subtitle.switch(selector.url);
console.log(element);
}
};
};

return SubtitleHtml;
export const newSubtitle = (
subtitles: Record<
string,
{
url: string;
type: string;
}
>
): ((art: Artplayer) => unknown) => {
return (art: Artplayer) => {
if (!subtitles) return;
art.once("ready", () => {
if (art.controls["subtitle"]) {
art.controls.remove("subtitle");
}
art.controls.add(newSubtitleControl(subtitles));
return {
name: "subtitles"
};
});
}

art.on("destroy", () => {
if (art.controls["subtitle"]) art.controls.remove("subtitle");
});

return {
name: "subtitles"
};
};
3 changes: 0 additions & 3 deletions src/stores/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,13 @@ export const roomStore = defineStore("roomStore", () => {
// 在线人数
const peopleNum = ref(1);

const danmuku = ref({});

return {
isDarkMode,
movies,
totalMovies,
currentMovie,
currentMovieStatus,
play,
danmuku,
peopleNum,
login
};
Expand Down
3 changes: 2 additions & 1 deletion src/types/Movie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export interface BaseMovieInfo {
subtitles?: Record<
string,
{
[prop: string]: string;
url: string;
type: string;
}
>;
}
Expand Down
19 changes: 0 additions & 19 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,6 @@ export const debounces = (delay: number): Function => {
return add;
};

export const deepEqualObject = (obj1: any, obj2: any) => {
if (obj1 === obj2) {
return true;
} else if (
typeof obj1 === "object" &&
typeof obj2 === "object" &&
Object.keys(obj1).length === Object.keys(obj2).length
) {
for (const key in obj1) {
if (!deepEqualObject(obj1[key], obj2[key])) {
return false;
}
}
return true;
} else {
return false;
}
};

export const strLengthLimit = (str: any, num: number) => {
if (typeof str !== "string") return;
if (str.length > num)
Expand Down
13 changes: 7 additions & 6 deletions src/views/Cinema.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ import {
} from "@/services/apis/movie";
import type { EditMovieInfo, MovieInfo } from "@/types/Movie";
import { sync } from "@/plugins/sync";
import { subtitle } from "@/plugins/subtitle";
import artplayerPluginDanmuku from "artplayer-plugin-danmuku";
import { strLengthLimit, blobToUin8Array } from "@/utils";
import MoviePush from "@/components/MoviePush.vue";
import { ElementMessage, ElementMessageType } from "@/proto/message";
import customHeaders from "@/components/dialogs/customHeaders.vue";
import { useRouteParams } from "@vueuse/router";
import type { options } from "@/components/Player.vue";
const Player = defineAsyncComponent(() => import("@/components/Player.vue"));
Expand Down Expand Up @@ -158,13 +158,14 @@ const playerUrl = computed(() => {
}
});
const playerOption = computed(() => {
let option = {
const playerOption = computed<options>(() => {
let option: options = {
url: playerUrl.value,
type: room.currentMovie.base?.type || "",
isLive: room.currentMovie.base!.live,
headers: room.currentMovie.base!.headers,
plugins: [subtitle, danmukuPlugin, syncPlugin?.plugin]
plugins: [danmukuPlugin, syncPlugin?.plugin],
subtitles: room.currentMovie.base?.subtitles
};
if (option.url.startsWith(window.location.origin)) {
option.headers = {
Expand Down Expand Up @@ -377,13 +378,13 @@ const handleElementMessage = (msg: ElementMessage) => {
case ElementMessageType.CHAT_MESSAGE: {
msgList.value.push(`${msg.sender}:${msg.message}`);
// jsonData.message.split(":")[0] !== "PLAYER" &&
room.danmuku = {
player?.plugins.artplayerPluginDanmuku.emit({
text: msg.message, // 弹幕文本
//time: Date.now(), // 发送时间,单位秒
color: "#fff", // 弹幕局部颜色
border: false // 是否显示描边
//mode: 0, // 弹幕模式: 0表示滚动, 1静止
};
});
// 自动滚动到最底部
if (chatArea.value) chatArea.value.scrollTop = chatArea.value.scrollHeight;
Expand Down

0 comments on commit 1b4c36f

Please sign in to comment.