vuepress-plugin-md-power 1.0.0-rc.121 → 1.0.0-rc.122

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,160 @@
1
+ <script setup lang="ts">
2
+ import type ArtPlayer from 'artplayer'
3
+ import type { Option as ArtPlayerInitOptions } from 'artplayer/types/option.js'
4
+ import { isLinkHttp } from '@vuepress/helper/client'
5
+ import { useCssVar } from '@vueuse/core'
6
+ import { onMounted, onUnmounted, ref, toRefs } from 'vue'
7
+ import { usePageLang, withBase } from 'vuepress/client'
8
+ import { useSize } from '../composables/size.js'
9
+ import { ART_PLAYER_SUPPORTED_VIDEO_TYPES, installed } from '../options.js'
10
+ import Loading from './icons/Loading.vue'
11
+
12
+ type CustomType = Record<string, (this: ArtPlayer, video: HTMLVideoElement, url: string, art: ArtPlayer) => any>
13
+
14
+ const props = withDefaults(defineProps<{
15
+ src: string
16
+ type?: string
17
+ width?: string
18
+ height?: string
19
+ ratio?: string
20
+ } & Omit<ArtPlayerInitOptions, 'container' | 'url' | 'type'>>(), {
21
+ hotkey: true,
22
+ mutex: true,
23
+ playsInline: true,
24
+ })
25
+
26
+ const loaded = ref(false)
27
+ const lang = usePageLang()
28
+ const brandColor = useCssVar('--vp-c-brand-1')
29
+ const { el, width, height, resize } = useSize<HTMLDivElement>(toRefs(props))
30
+
31
+ let player: ArtPlayer | null = null
32
+
33
+ async function createPlayer() {
34
+ if (!el.value)
35
+ return
36
+
37
+ loaded.value = false
38
+ const { default: ArtPlayer } = await import(
39
+ /* webpackChunkName: "artplayer" */ 'artplayer'
40
+ )
41
+ loaded.value = true
42
+ const { src, type: _t, width: _w, height: _h, ratio: _r, ...opt } = props
43
+ const { customType = {}, ...options } = opt
44
+ Object.keys(options).forEach((key) => {
45
+ if (typeof options[key] === 'undefined') {
46
+ delete options[key]
47
+ }
48
+ })
49
+ const type = props.type ?? src.split('.').pop() ?? ''
50
+ const url = isLinkHttp(src) ? src : withBase(src)
51
+
52
+ if (!ART_PLAYER_SUPPORTED_VIDEO_TYPES.includes(type)) {
53
+ console.error(`Unsupported video type: ${type}`)
54
+ return
55
+ }
56
+
57
+ player = new ArtPlayer({
58
+ container: el.value,
59
+ url,
60
+ type,
61
+ ...{
62
+ lang: lang.value.split('-')[0] === 'zh' ? 'zh-cn' : 'en',
63
+ volume: 0.75,
64
+ useSSR: false,
65
+ theme: brandColor.value ?? '#5086a1',
66
+ },
67
+ ...options,
68
+ customType: {
69
+ ...initCustomType(type),
70
+ ...customType,
71
+ },
72
+ })
73
+ }
74
+
75
+ function initCustomType(type: string): CustomType {
76
+ const customType: CustomType = {}
77
+
78
+ if ((type === 'mpd' || type === 'dash') && installed.dashjs) {
79
+ customType[type] = async function (video, url, art) {
80
+ const dashjs = (await import(/* webpackChunkName: "dashjs" */ 'dashjs')).default
81
+ if (dashjs.supportsMediaSource()) {
82
+ const dashPlayer = dashjs.MediaPlayer().create()
83
+ dashPlayer.initialize(video, url, props.autoplay, 0)
84
+ art.on('destroy', () => dashPlayer.destroy())
85
+ }
86
+ }
87
+ }
88
+
89
+ if (type === 'm3u8' || type === 'hls') {
90
+ customType[type] = async function (video, url, art) {
91
+ if (video.canPlayType('application/x-mpegURL')
92
+ || video.canPlayType('application/vnd.apple.mpegURL')) {
93
+ video.src = url
94
+ return
95
+ }
96
+ if (!installed.hlsjs)
97
+ return
98
+
99
+ const Hls = (await import(/* webpackChunkName: "hls.js" */ 'hls.js')).default
100
+ if (Hls.isSupported()) {
101
+ const hls = new Hls()
102
+ hls.attachMedia(video)
103
+ hls.on(Hls.Events.MEDIA_ATTACHED, () => hls.loadSource(url))
104
+ art.on('destroy', () => hls.destroy())
105
+ }
106
+ }
107
+ }
108
+
109
+ if ((type === 'ts' || type === 'flv') && installed.mpegtsjs) {
110
+ customType[type] = async function (video, url, art) {
111
+ const mpegts = (await import(/* webpackChunkName: "mpegts.js" */ 'mpegts.js/dist/mpegts.js')).default
112
+ if (mpegts.isSupported()) {
113
+ const flv = mpegts.createPlayer({ type: 'flv', url })
114
+
115
+ flv.attachMediaElement(video)
116
+ flv.load()
117
+ art.on('destroy', () => flv.destroy())
118
+ }
119
+ }
120
+ }
121
+
122
+ return customType
123
+ }
124
+
125
+ onMounted(async () => {
126
+ await createPlayer()
127
+ resize()
128
+ })
129
+
130
+ onUnmounted(() => {
131
+ player?.destroy()
132
+ player = null
133
+ })
134
+ </script>
135
+
136
+ <template>
137
+ <div class="vp-artplayer-wrapper">
138
+ <div ref="el" class="vp-artplayer" :style="{ width, height }" />
139
+ <Loading v-if="!loaded" absolute />
140
+ </div>
141
+ </template>
142
+
143
+ <style>
144
+ .vp-artplayer-wrapper {
145
+ position: relative;
146
+ }
147
+
148
+ .vp-artplayer {
149
+ margin: 16px 0;
150
+ }
151
+
152
+ @media (min-width: 768px) {
153
+ .vp-artplayer {
154
+ overflow: hidden;
155
+ border-radius: 8px;
156
+ box-shadow: var(--vp-shadow-2);
157
+ transition: box-shadow var(--vp-t-color);
158
+ }
159
+ }
160
+ </style>
@@ -1,5 +1,11 @@
1
1
  import { MarkdownPowerPluginOptions } from '../shared/index.js';
2
2
 
3
3
  declare const pluginOptions: MarkdownPowerPluginOptions;
4
+ declare const installed: {
5
+ dashjs: boolean;
6
+ hlsjs: boolean;
7
+ mpegtsjs: boolean;
8
+ };
9
+ declare const ART_PLAYER_SUPPORTED_VIDEO_TYPES: string[];
4
10
 
5
- export { pluginOptions };
11
+ export { ART_PLAYER_SUPPORTED_VIDEO_TYPES, installed, pluginOptions };
@@ -1,5 +1,22 @@
1
1
  // src/client/options.ts
2
2
  var pluginOptions = __MD_POWER_INJECT_OPTIONS__;
3
+ var installed = {
4
+ dashjs: __MD_POWER_DASHJS_INSTALLED__,
5
+ hlsjs: __MD_POWER_HLSJS_INSTALLED__,
6
+ mpegtsjs: __MD_POWER_MPEGTSJS_INSTALLED__
7
+ };
8
+ var ART_PLAYER_SUPPORTED_VIDEO_TYPES = ["mp4", "mp3", "webm", "ogg"];
9
+ if (installed.dashjs) {
10
+ ART_PLAYER_SUPPORTED_VIDEO_TYPES.push("mpd", "dash");
11
+ }
12
+ if (installed.hlsjs) {
13
+ ART_PLAYER_SUPPORTED_VIDEO_TYPES.push("m3u8", "hls");
14
+ }
15
+ if (installed.mpegtsjs) {
16
+ ART_PLAYER_SUPPORTED_VIDEO_TYPES.push("ts", "flv");
17
+ }
3
18
  export {
19
+ ART_PLAYER_SUPPORTED_VIDEO_TYPES,
20
+ installed,
4
21
  pluginOptions
5
22
  };
@@ -200,6 +200,12 @@ interface MarkdownPowerPluginOptions {
200
200
  * @default false
201
201
  */
202
202
  youtube?: boolean;
203
+ /**
204
+ * 是否启用 artPlayer 视频嵌入
205
+ *
206
+ * `@[artPlayer](url)`
207
+ */
208
+ artPlayer?: boolean;
203
209
  /**
204
210
  * 是否启用 codepen 嵌入
205
211
  *
@@ -295,6 +301,16 @@ interface YoutubeTokenMeta extends SizeOptions {
295
301
  start?: string | number;
296
302
  end?: string | number;
297
303
  }
304
+ interface ArtPlayerTokenMeta extends SizeOptions {
305
+ muted?: boolean;
306
+ autoplay?: boolean;
307
+ autoMini?: boolean;
308
+ loop?: boolean;
309
+ volume?: number;
310
+ poster?: string;
311
+ url: string;
312
+ type?: string;
313
+ }
298
314
 
299
315
  interface ImgSize {
300
316
  width: number;
@@ -304,4 +320,4 @@ declare function resolveImageSize(app: App, url: string, remote?: boolean): Prom
304
320
 
305
321
  declare function markdownPowerPlugin(options?: MarkdownPowerPluginOptions): Plugin;
306
322
 
307
- export { type BilibiliTokenMeta, type CanIUseMode, type CanIUseOptions, type CanIUseTokenMeta, type CodeSandboxTokenMeta, type CodeTabsOptions, type CodepenTokenMeta, type FileTreeIconMode, type FileTreeOptions, type IconsOptions, type JSFiddleTokenMeta, type MarkdownPowerPluginOptions, type NpmToOptions, type NpmToPackageManager, type PDFEmbedType, type PDFOptions, type PDFTokenMeta, type PlotOptions, type ReplEditorData, type ReplOptions, type ReplitTokenMeta, type SizeOptions, type ThemeOptions, type VideoOptions, type YoutubeTokenMeta, markdownPowerPlugin, resolveImageSize };
323
+ export { type ArtPlayerTokenMeta, type BilibiliTokenMeta, type CanIUseMode, type CanIUseOptions, type CanIUseTokenMeta, type CodeSandboxTokenMeta, type CodeTabsOptions, type CodepenTokenMeta, type FileTreeIconMode, type FileTreeOptions, type IconsOptions, type JSFiddleTokenMeta, type MarkdownPowerPluginOptions, type NpmToOptions, type NpmToPackageManager, type PDFEmbedType, type PDFOptions, type PDFTokenMeta, type PlotOptions, type ReplEditorData, type ReplOptions, type ReplitTokenMeta, type SizeOptions, type ThemeOptions, type VideoOptions, type YoutubeTokenMeta, markdownPowerPlugin, resolveImageSize };
package/lib/node/index.js CHANGED
@@ -212,6 +212,7 @@ async function resolveImageSize(app, url, remote = false) {
212
212
 
213
213
  // src/node/plugin.ts
214
214
  import { addViteOptimizeDepsInclude } from "@vuepress/helper";
215
+ import { isPackageExists as isPackageExists2 } from "local-pkg";
215
216
 
216
217
  // src/node/container/index.ts
217
218
  import { isPlainObject as isPlainObject2 } from "@vuepress/helper";
@@ -2007,8 +2008,8 @@ var codeSandboxPlugin = (md) => {
2007
2008
  filepath: filepath2
2008
2009
  };
2009
2010
  },
2010
- content({ title, height, width, user, id, type: type2, filepath: filepath2, console, navbar, layout }) {
2011
- return `<CodeSandboxViewer title="${title}" height="${height}" width="${width}" user="${user}" id="${id}" type="${type2}" filepath="${filepath2}" :console=${console} :navbar=${navbar} layout="${layout}" />`;
2011
+ content({ title, height, width, user, id, type: type2, filepath: filepath2, console: console2, navbar, layout }) {
2012
+ return `<CodeSandboxViewer title="${title}" height="${height}" width="${width}" user="${user}" id="${id}" type="${type2}" filepath="${filepath2}" :console=${console2} :navbar=${navbar} layout="${layout}" />`;
2012
2013
  }
2013
2014
  });
2014
2015
  };
@@ -2087,6 +2088,71 @@ var pdfPlugin = (md) => {
2087
2088
  });
2088
2089
  };
2089
2090
 
2091
+ // src/node/embed/video/artPlayer.ts
2092
+ import { isPackageExists } from "local-pkg";
2093
+ import { colors } from "vuepress/utils";
2094
+ var installed = {
2095
+ dashjs: isPackageExists("dashjs"),
2096
+ hlsjs: isPackageExists("hls.js"),
2097
+ mpegtsjs: isPackageExists("mpegts.js")
2098
+ };
2099
+ var SUPPORTED_VIDEO_TYPES = ["mp4", "mp3", "webm", "ogg", "mpd", "dash", "m3u8", "hls", "ts", "flv"];
2100
+ var artPlayerPlugin = (md) => {
2101
+ createEmbedRuleBlock(md, {
2102
+ type: "artPlayer",
2103
+ name: "video_artPlayer",
2104
+ syntaxPattern: /^@\[artPlayer([^\]]*)\]\(([^)]*)\)/,
2105
+ meta([, info, source]) {
2106
+ const { attrs: attrs2 } = resolveAttrs(info);
2107
+ const url = source.trim();
2108
+ checkSupportType(attrs2.type ?? url.split(".").pop());
2109
+ return {
2110
+ autoplay: attrs2.autoplay ?? false,
2111
+ muted: attrs2.muted ?? attrs2.autoplay ?? false,
2112
+ autoMini: attrs2.autoMini ?? false,
2113
+ loop: attrs2.loop ?? false,
2114
+ volume: typeof attrs2.volume !== "undefined" ? Number(attrs2.volume) : 0.75,
2115
+ poster: attrs2.poster,
2116
+ width: attrs2.width ? parseRect(attrs2.width) : "100%",
2117
+ height: attrs2.height ? parseRect(attrs2.height) : "",
2118
+ ratio: attrs2.ratio ? parseRect(`${attrs2.ratio}`) : "",
2119
+ type: attrs2.type,
2120
+ url
2121
+ };
2122
+ },
2123
+ content({ autoMini, autoplay, loop, muted, poster, url, type: type2, volume, width, height, ratio }) {
2124
+ return `<ArtPlayer src="${url}" fullscreen flip playback-rate aspect-ratio setting pip ${loop ? " loop" : ""}${type2 ? ` type="${type2}"` : ""}${autoMini ? " auto-min" : ""}${autoplay ? " autoplay" : ""}${muted || autoplay ? " muted" : ""}${poster ? ` poster="${poster}"` : ""} :volume="${volume}" width="${width}"${height ? ` height="${height}"` : ""}${ratio ? ` ratio="${ratio}"` : ""}/>`;
2125
+ }
2126
+ });
2127
+ };
2128
+ function checkSupportType(type2) {
2129
+ if (!type2)
2130
+ return;
2131
+ if (SUPPORTED_VIDEO_TYPES.includes(type2)) {
2132
+ let name = "";
2133
+ switch (type2.toLowerCase()) {
2134
+ case "m3u8":
2135
+ case "hls":
2136
+ name = !installed.hlsjs ? "hls.js" : "";
2137
+ break;
2138
+ case "flv":
2139
+ case "ts": {
2140
+ name = !installed.mpegtsjs ? "mpegts.js" : "";
2141
+ break;
2142
+ }
2143
+ case "mpd":
2144
+ case "dash":
2145
+ name = !installed.dashjs ? "dashjs" : "";
2146
+ break;
2147
+ }
2148
+ if (name) {
2149
+ console.warn(`${colors.yellow("[vuepress-plugin-md-power] artPlayer: ")} ${colors.cyan(name)} is not installed, please install it via npm or yarn or pnpm`);
2150
+ }
2151
+ } else {
2152
+ console.warn(`${colors.yellow("[vuepress-plugin-md-power] artPlayer: ")} unsupported video type: ${colors.cyan(type2)}`);
2153
+ }
2154
+ }
2155
+
2090
2156
  // src/node/embed/video/bilibili.ts
2091
2157
  import { URLSearchParams as URLSearchParams2 } from "node:url";
2092
2158
 
@@ -2208,6 +2274,9 @@ function embedSyntaxPlugin(md, options) {
2208
2274
  if (options.youtube) {
2209
2275
  md.use(youtubePlugin);
2210
2276
  }
2277
+ if (options.artPlayer) {
2278
+ md.use(artPlayerPlugin);
2279
+ }
2211
2280
  if (options.codepen) {
2212
2281
  md.use(codepenPlugin);
2213
2282
  }
@@ -2431,6 +2500,10 @@ async function prepareConfigFile(app, options) {
2431
2500
  imports.add(`import FileTreeItem from '${CLIENT_FOLDER}components/FileTreeItem.vue'`);
2432
2501
  enhances.add(`app.component('FileTreeItem', FileTreeItem)`);
2433
2502
  }
2503
+ if (options.artPlayer) {
2504
+ imports.add(`import ArtPlayer from '${CLIENT_FOLDER}components/ArtPlayer.vue'`);
2505
+ enhances.add(`app.component('ArtPlayer', ArtPlayer)`);
2506
+ }
2434
2507
  return app.writeTemp(
2435
2508
  "md-power/config.js",
2436
2509
  `import { defineClientConfig } from 'vuepress/client'
@@ -2453,7 +2526,10 @@ function markdownPowerPlugin(options = {}) {
2453
2526
  name: "vuepress-plugin-md-power",
2454
2527
  clientConfigFile: (app) => prepareConfigFile(app, options),
2455
2528
  define: {
2456
- __MD_POWER_INJECT_OPTIONS__: options
2529
+ __MD_POWER_INJECT_OPTIONS__: options,
2530
+ __MD_POWER_DASHJS_INSTALLED__: isPackageExists2("dashjs"),
2531
+ __MD_POWER_HLSJS_INSTALLED__: isPackageExists2("hls.js"),
2532
+ __MD_POWER_MPEGTSJS_INSTALLED__: isPackageExists2("mpegts.js")
2457
2533
  },
2458
2534
  extendsBundlerOptions(bundlerOptions, app) {
2459
2535
  if (options.repl) {
@@ -2463,6 +2539,13 @@ function markdownPowerPlugin(options = {}) {
2463
2539
  ["shiki/core", "shiki/wasm", "shiki/engine/oniguruma"]
2464
2540
  );
2465
2541
  }
2542
+ if (options.artPlayer) {
2543
+ addViteOptimizeDepsInclude(
2544
+ bundlerOptions,
2545
+ app,
2546
+ ["artplayer", "dashjs", "hls.js", "mpegts.js"]
2547
+ );
2548
+ }
2466
2549
  },
2467
2550
  extendsMarkdown: async (md, app) => {
2468
2551
  docsTitlePlugin(md);
@@ -2478,3 +2561,4 @@ export {
2478
2561
  resolveImageSize
2479
2562
  };
2480
2563
  /* istanbul ignore if -- @preserve */
2564
+ /* istanbul ignore next -- @preserve */
@@ -198,6 +198,12 @@ interface MarkdownPowerPluginOptions {
198
198
  * @default false
199
199
  */
200
200
  youtube?: boolean;
201
+ /**
202
+ * 是否启用 artPlayer 视频嵌入
203
+ *
204
+ * `@[artPlayer](url)`
205
+ */
206
+ artPlayer?: boolean;
201
207
  /**
202
208
  * 是否启用 codepen 嵌入
203
209
  *
@@ -293,5 +299,15 @@ interface YoutubeTokenMeta extends SizeOptions {
293
299
  start?: string | number;
294
300
  end?: string | number;
295
301
  }
302
+ interface ArtPlayerTokenMeta extends SizeOptions {
303
+ muted?: boolean;
304
+ autoplay?: boolean;
305
+ autoMini?: boolean;
306
+ loop?: boolean;
307
+ volume?: number;
308
+ poster?: string;
309
+ url: string;
310
+ type?: string;
311
+ }
296
312
 
297
- export type { BilibiliTokenMeta, CanIUseMode, CanIUseOptions, CanIUseTokenMeta, CodeSandboxTokenMeta, CodeTabsOptions, CodepenTokenMeta, FileTreeIconMode, FileTreeOptions, IconsOptions, JSFiddleTokenMeta, MarkdownPowerPluginOptions, NpmToOptions, NpmToPackageManager, PDFEmbedType, PDFOptions, PDFTokenMeta, PlotOptions, ReplEditorData, ReplOptions, ReplitTokenMeta, SizeOptions, ThemeOptions, VideoOptions, YoutubeTokenMeta };
313
+ export type { ArtPlayerTokenMeta, BilibiliTokenMeta, CanIUseMode, CanIUseOptions, CanIUseTokenMeta, CodeSandboxTokenMeta, CodeTabsOptions, CodepenTokenMeta, FileTreeIconMode, FileTreeOptions, IconsOptions, JSFiddleTokenMeta, MarkdownPowerPluginOptions, NpmToOptions, NpmToPackageManager, PDFEmbedType, PDFOptions, PDFTokenMeta, PlotOptions, ReplEditorData, ReplOptions, ReplitTokenMeta, SizeOptions, ThemeOptions, VideoOptions, YoutubeTokenMeta };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vuepress-plugin-md-power",
3
3
  "type": "module",
4
- "version": "1.0.0-rc.121",
4
+ "version": "1.0.0-rc.122",
5
5
  "description": "The Plugin for VuePress 2 - markdown power",
6
6
  "author": "pengzhanbo <volodymyr@foxmail.com>",
7
7
  "license": "MIT",
@@ -31,12 +31,28 @@
31
31
  "lib"
32
32
  ],
33
33
  "peerDependencies": {
34
+ "artplayer": "^5.2.0",
35
+ "dashjs": "^4.7.4",
36
+ "hls.js": "^1.5.18",
34
37
  "markdown-it": "^14.0.0",
38
+ "mpegts.js": "^1.7.3",
35
39
  "vuepress": "2.0.0-rc.19"
36
40
  },
37
41
  "peerDependenciesMeta": {
42
+ "artplayer": {
43
+ "optional": true
44
+ },
45
+ "dashjs": {
46
+ "optional": true
47
+ },
48
+ "hls.js": {
49
+ "optional": true
50
+ },
38
51
  "markdown-it": {
39
52
  "optional": true
53
+ },
54
+ "mpegts.js": {
55
+ "optional": true
40
56
  }
41
57
  },
42
58
  "dependencies": {
@@ -49,17 +65,21 @@
49
65
  "@mdit/plugin-tasklist": "^0.14.0",
50
66
  "@vuepress/helper": "2.0.0-rc.66",
51
67
  "@vueuse/core": "^12.0.0",
52
- "image-size": "^1.1.1",
68
+ "image-size": "^1.2.0",
53
69
  "local-pkg": "^0.5.1",
54
70
  "markdown-it-container": "^4.0.0",
55
71
  "nanoid": "^5.0.9",
56
- "shiki": "^1.24.2",
57
- "tm-grammars": "^1.21.4",
72
+ "shiki": "^1.24.4",
73
+ "tm-grammars": "^1.21.9",
58
74
  "tm-themes": "^1.9.5",
59
75
  "vue": "^3.5.13"
60
76
  },
61
77
  "devDependencies": {
62
- "@types/markdown-it": "^14.1.2"
78
+ "@types/markdown-it": "^14.1.2",
79
+ "artplayer": "^5.2.1",
80
+ "dashjs": "^4.7.4",
81
+ "hls.js": "^1.5.18",
82
+ "mpegts.js": "^1.7.3"
63
83
  },
64
84
  "publishConfig": {
65
85
  "access": "public"