Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40fcda6a37 | ||
|
|
bb82f899ff | ||
|
|
59d3c9f50c | ||
|
|
37cbb6f600 | ||
|
|
72cf3551e2 | ||
|
|
cb69e4ad66 | ||
|
|
42c4ca735d | ||
|
|
0f47e11d63 | ||
|
|
0b9c31a8cf | ||
|
|
02d1ded7b8 | ||
|
|
014b21566c | ||
|
|
4c7d0aa9fa | ||
|
|
fc90d4a0df | ||
|
|
26841c5b1c | ||
|
|
d6c1e5d25b | ||
|
|
63c8966ed7 | ||
|
|
23c8f46878 | ||
|
|
4b75df286a | ||
|
|
7e0b84ba7c | ||
|
|
6aa6f9ad53 | ||
|
|
4501ec2907 | ||
|
|
6c79148da5 | ||
|
|
65e51751cd | ||
|
|
daf133b226 | ||
|
|
740ac4cb24 | ||
|
|
b11f0eb99a | ||
|
|
89a28e91fe | ||
|
|
92f09a4290 | ||
|
|
3adff76edf | ||
|
|
562cfe18db | ||
|
|
5ce29ac190 | ||
|
|
39a1fb1abd | ||
|
|
bd43b6638d | ||
|
|
dc850dd2d2 | ||
|
|
9f5070b523 | ||
|
|
1c75731ca9 | ||
|
|
78e9cc74f8 | ||
|
|
1dc8e9a4ff | ||
|
|
1e60637b74 | ||
|
|
2622b2c6ae | ||
|
|
9cb7d6dc9f | ||
|
|
0f752260a4 | ||
|
|
7bfee6c6dc | ||
|
|
5cc8d14454 | ||
|
|
3bf0707faa | ||
|
|
699bf09577 | ||
|
|
ddb78cf850 | ||
|
|
3ae89ab349 | ||
|
|
e112b33f97 | ||
|
|
bad7892660 | ||
|
|
88de2ae9e6 | ||
|
|
9c819676bd | ||
|
|
7a4b429672 | ||
|
|
f07e51c071 | ||
|
|
9a73b85fc7 | ||
|
|
150d14907e | ||
|
|
d2e59f7d6b | ||
|
|
1f0ffbfa17 | ||
|
|
0c00074f6a | ||
|
|
6b66029c54 | ||
|
|
9db9cd1f1e | ||
|
|
14ce165f50 | ||
|
|
edc2b6c9f9 | ||
|
|
cea2859b40 | ||
|
|
f28b809a67 | ||
|
|
f750e77e4f | ||
|
|
1841f754dc | ||
|
|
0bdc59e446 | ||
|
|
cfaaea6a5c | ||
|
|
687a34c6b3 | ||
|
|
14807e2633 | ||
|
|
210eb94b75 | ||
|
|
17042867fc | ||
|
|
7dffd99cfd | ||
|
|
07a5b0c0f0 | ||
|
|
8b5b366da3 | ||
|
|
441909f8ac | ||
|
|
486231f04b | ||
|
|
4a980971f7 | ||
|
|
a3416fcb33 | ||
|
|
9378aa21ee | ||
|
|
23a20d5d6d | ||
|
|
ece55c5747 | ||
|
|
ca34b47180 | ||
|
|
c321d40cc3 | ||
|
|
b36f88db5f | ||
|
|
6370f607f8 | ||
|
|
d9ac20b3f1 | ||
|
|
c655f073ae | ||
|
|
c88aa97c0a | ||
|
|
24352e01c4 | ||
|
|
cf01186977 | ||
|
|
fb7eddf433 | ||
|
|
b69d020c5a | ||
|
|
0d032f685b | ||
|
|
f4d99eb09e | ||
|
|
c977790602 | ||
|
|
fa2c69e83d | ||
|
|
62b4be9d82 | ||
|
|
e559d3bc6f | ||
|
|
a8d36a38ad | ||
|
|
ae03670f9a | ||
|
|
ce35026cb4 | ||
|
|
7968495416 | ||
|
|
fce3b33909 | ||
|
|
0bb4e1acdb | ||
|
|
4a0fbda3c4 | ||
|
|
d892685a25 | ||
|
|
9d760a2f59 | ||
|
|
be44c1f8dd | ||
|
|
59e9a32ecb | ||
|
|
51d49f857a | ||
|
|
a93967d518 | ||
|
|
8cb9cd480c | ||
|
|
911c88d95f | ||
|
|
7d8034ca18 | ||
|
|
e45bc1ef20 | ||
|
|
bd6ce34420 | ||
|
|
dbeaba78e6 | ||
|
|
01d8dc680c | ||
|
|
ef537ecfbf | ||
|
|
b7d94558b2 | ||
|
|
efa757ca2d | ||
|
|
e27581b800 | ||
|
|
48b3f76151 | ||
|
|
b84b0af2ec | ||
|
|
99ad0d7b93 | ||
|
|
529ade25d5 | ||
|
|
04b955f455 | ||
|
|
7b4ca85844 | ||
|
|
2f42f85f90 | ||
|
|
140674b511 | ||
|
|
a3fd5d9343 | ||
|
|
86bbc95722 | ||
|
|
47085d1275 | ||
|
|
4681a8bc7a | ||
|
|
f5f3800449 | ||
|
|
3f47356d2c | ||
|
|
b6d0c07f8c | ||
|
|
0044053348 | ||
|
|
a516c0b204 | ||
|
|
0a9aadf543 | ||
|
|
987795503b | ||
|
|
b5b52bbf17 | ||
|
|
8041de8411 | ||
|
|
e28be64026 | ||
|
|
630b6b9d93 | ||
|
|
12d6781bf5 | ||
|
|
714c81e6c3 | ||
|
|
8d1ebc4393 | ||
|
|
eb015c7fac | ||
|
|
92ff80d285 | ||
|
|
23da290357 | ||
|
|
5b1cebb334 | ||
|
|
18475f08fd | ||
|
|
fd9aeddbed | ||
|
|
811d83f463 | ||
|
|
736a6c1973 | ||
|
|
6be0ea9542 | ||
|
|
474383853b | ||
|
|
649963f07c | ||
|
|
013fa21e7c | ||
|
|
ea903dcf4c | ||
|
|
cc7e7576ab | ||
|
|
14451c7221 | ||
|
|
2a69147c8b | ||
|
|
9bfd535e57 | ||
|
|
cb3d391c34 | ||
|
|
06c00906c2 | ||
|
|
ddbcdbd459 | ||
|
|
745d2b4848 | ||
|
|
cf5057fa89 | ||
|
|
fb8975272c | ||
|
|
68b40de93c | ||
|
|
eccea444b0 | ||
|
|
e8b01c357f | ||
|
|
40b66b4b68 | ||
|
|
9e73b0aec9 | ||
|
|
79358663eb | ||
|
|
043947c9af | ||
|
|
1b856ae681 | ||
|
|
48b78d0ad7 | ||
|
|
e7633ed49d | ||
|
|
abbecff472 | ||
|
|
50320bad5d | ||
|
|
241b4f3ee3 | ||
|
|
5cc6724f54 | ||
|
|
0eed9c114b | ||
|
|
4b55b97e9e | ||
|
|
0c0bcecb9e | ||
|
|
09aab497ac | ||
|
|
41040e5ac1 | ||
|
|
c911928166 | ||
|
|
012dde8da4 | ||
|
|
8b32f050a0 | ||
|
|
ea34eda07b | ||
|
|
6344a0bef9 | ||
|
|
ada6afca69 | ||
|
|
52b38a48b2 | ||
|
|
34fe45fa2d | ||
|
|
fa0961a9f9 | ||
|
|
e834246641 | ||
|
|
3a2dcdb226 | ||
|
|
3cfc1c031c | ||
|
|
8af6f7c322 | ||
|
|
abd64e11f2 | ||
|
|
84c118855d | ||
|
|
1f142ced9f | ||
|
|
596269bf3f | ||
|
|
657dd7e77c | ||
|
|
a7d77f4f70 | ||
|
|
571a4c8e1d | ||
|
|
7d4175efbc | ||
|
|
c23520a4a6 | ||
|
|
bd071b2d63 | ||
|
|
f1fcbd75fe | ||
|
|
4fa1730242 | ||
|
|
8460959a7f | ||
|
|
d9c84d2dbc | ||
|
|
8a87de6df3 | ||
|
|
6f3363014f | ||
|
|
fa755b5f61 | ||
|
|
3540cd0cce | ||
|
|
e947be8a8e | ||
|
|
9d966bf696 | ||
|
|
f3c0a9a77d | ||
|
|
35ad9883af | ||
|
|
532dd67cfd | ||
|
|
46ad399b2f | ||
|
|
05ce97c6fd | ||
|
|
603151af84 | ||
|
|
412b8e7fa7 | ||
|
|
8d912c6c99 | ||
|
|
ea392e0d60 | ||
|
|
5337f9b075 | ||
|
|
c1fe0e2b03 | ||
|
|
11b59da2cf | ||
|
|
9932551352 | ||
|
|
84bc5a85bc | ||
|
|
6d640062c9 | ||
|
|
012c73c202 | ||
|
|
e8a7e050c4 | ||
|
|
e2e8e83e63 | ||
|
|
1374d530a4 | ||
|
|
7e7bd8c0ad | ||
|
|
da94223721 | ||
|
|
3715a36cde | ||
|
|
68d00e0166 | ||
|
|
c81b1ec83b | ||
|
|
bf5a186375 | ||
|
|
20b62ad3e3 | ||
|
|
1941da46d9 | ||
|
|
078b595819 | ||
|
|
169c6a318a | ||
|
|
77eaba8de9 | ||
|
|
db58d759b5 | ||
|
|
1ae4d17372 | ||
|
|
e773e2c44f | ||
|
|
19756e8224 | ||
|
|
826abd8c7d | ||
|
|
d02740bd94 | ||
|
|
5602ac315c | ||
|
|
b2f88cdd94 | ||
|
|
15067279e3 | ||
|
|
0d0a6f5516 | ||
|
|
10337ddb1d | ||
|
|
62835bb042 | ||
|
|
3f0a1bd433 | ||
|
|
1ece90c582 | ||
|
|
4bdad1675b | ||
|
|
9fdbdabd7c | ||
|
|
5d7710979d | ||
|
|
6c4e9f7e78 | ||
|
|
dd57cc2a03 | ||
|
|
ab06749c15 | ||
|
|
c3343ad74f | ||
|
|
2a7e3d5e03 | ||
|
|
a64e13c9c1 | ||
|
|
674c6420e9 | ||
|
|
9bdaaa3b7d | ||
|
|
0aabb42db3 | ||
|
|
17ece4c0c8 | ||
|
|
2aaef7db45 | ||
|
|
bc401159b6 | ||
|
|
36865f1e7e | ||
|
|
dd0fba6eb4 | ||
|
|
db5e9fc810 | ||
|
|
4987579d92 | ||
|
|
b4e5c712f5 | ||
|
|
518bc45af0 | ||
|
|
b52ea6b146 | ||
|
|
ff10f4f0a6 | ||
|
|
a8458b050b | ||
|
|
4b4973eeb3 |
No files matched your search
@@ -1,20 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "19:00"
|
||||
open-pull-requests-limit: 10
|
||||
ignore:
|
||||
- dependency-name: cssnano
|
||||
versions:
|
||||
- 5.0.0
|
||||
- 5.0.1
|
||||
- dependency-name: autoprefixer
|
||||
versions:
|
||||
- 10.2.4
|
||||
- 10.2.5
|
||||
- dependency-name: eslint-config-prettier
|
||||
versions:
|
||||
- 8.0.0
|
||||
@@ -15,27 +15,29 @@ jobs:
|
||||
node-version: [20.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: npm install, lint, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm run lint
|
||||
npm run build:all
|
||||
env:
|
||||
CI: true
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: install, lint, build, and test
|
||||
run: |
|
||||
yarn
|
||||
yarn test:playback
|
||||
yarn lint
|
||||
yarn build:all
|
||||
yarn test:dash-control
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
if: success()
|
||||
run: |
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add -f docs
|
||||
git commit -m 'Deploy to GitHub Pages'
|
||||
git subtree split --prefix docs master -b gh-pages-temp
|
||||
git push origin gh-pages-temp:refs/heads/gh-pages --force
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Deploy to GitHub Pages
|
||||
if: success()
|
||||
run: |
|
||||
git config --global user.name 'github-actions[bot]'
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
git add -f docs
|
||||
git commit -m 'Deploy to GitHub Pages'
|
||||
git subtree split --prefix docs master -b gh-pages-temp
|
||||
git push origin gh-pages-temp:refs/heads/gh-pages --force
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,7 +1,6 @@
|
||||
.env
|
||||
.vscode
|
||||
.DS_Store
|
||||
.parcel-cache
|
||||
node_modules
|
||||
package-lock.json
|
||||
lerna-debug.log
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
docs
|
||||
.github
|
||||
.docusaurus
|
||||
node_modules
|
||||
.parcel-cache
|
||||
packages/*/dist
|
||||
packages/*/node_modules
|
||||
packages/*/.parcel-cache
|
||||
packages/artplayer-template/*/.next
|
||||
packages/artplayer-template/*/.nuxt
|
||||
scripts/plugin/template
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"useTabs": false,
|
||||
"tabWidth": 4,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all",
|
||||
"printWidth": 120,
|
||||
"semi": true,
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf",
|
||||
"quoteProps": "as-needed"
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Project Summary
|
||||
|
||||
ArtPlayer is a monorepo for a modern HTML5 video player and its ecosystem packages.
|
||||
|
||||
- Homepage: `https://artplayer.org`
|
||||
- Local dev site: `http://localhost:8082`
|
||||
- API docs: `https://artplayer.org/document`
|
||||
- Packaging model: workspace monorepo with per-package versioning and per-package build output
|
||||
|
||||
The repository contains:
|
||||
|
||||
- `packages/artplayer`: the core player
|
||||
- `packages/artplayer-plugin-*`: UI and playback plugins
|
||||
- `packages/artplayer-proxy-*`: proxy renderers and playback adapters
|
||||
- `packages/artplayer-tool-*`: helper tools
|
||||
- `packages/artplayer-vitepress`: docs site package
|
||||
- `docs/`: local demo site, examples, compiled assets, generated docs
|
||||
- `scripts/`: custom build/dev/doc tooling
|
||||
|
||||
## Working Style For This Repo
|
||||
|
||||
- Verify the real implementation before editing docs or examples.
|
||||
- Prefer changing the source package first, then regenerate build artifacts only when needed.
|
||||
- Keep package APIs small and consistent with existing ArtPlayer plugin conventions.
|
||||
- Preserve the existing visual and API style of sibling packages instead of inventing a new pattern.
|
||||
- When touching demo examples, make sure the example still works in `http://localhost:8082`.
|
||||
- Do not hand-edit `dist/`, `docs/compiled/`, or `docs/uncompiled/` unless a build step generated them.
|
||||
|
||||
## Primary Commands
|
||||
|
||||
Use the repo scripts rather than ad hoc bundler commands.
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Starts the local dev site on port `8082` and interactively selects a package to watch. The selected package is built into:
|
||||
|
||||
- `docs/uncompiled/<package>/`
|
||||
|
||||
### Production Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
Interactive build for one package. Outputs:
|
||||
|
||||
- `packages/<name>/dist/*.js|*.legacy.js|*.mjs`
|
||||
- copied artifacts into `docs/compiled/`
|
||||
|
||||
Build all packages:
|
||||
|
||||
```bash
|
||||
npm run build all
|
||||
```
|
||||
|
||||
### Other Project Scripts
|
||||
|
||||
```bash
|
||||
npm run build:i18n
|
||||
npm run build:ts
|
||||
npm run build:docs
|
||||
npm run build:llm
|
||||
npm run build:test
|
||||
npm run lint
|
||||
npm run build:all
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `npm run lint` targets package source/types plus scripts and TypeScript demo assets.
|
||||
- `npm run build:all` is expensive; use it when a change truly spans builds/docs/types/lint together.
|
||||
|
||||
## Useful Local URLs
|
||||
|
||||
- Root demo index: `http://localhost:8082`
|
||||
- Demo by package/example:
|
||||
- `http://localhost:8082/?libs=./uncompiled/<package>/index.js&example=<example>`
|
||||
- Docs: `http://localhost:8082/document/`
|
||||
|
||||
For proxy/plugin work, prefer validating on the local demo page rather than reasoning only from source.
|
||||
|
||||
## Repository Layout
|
||||
|
||||
### Core package
|
||||
|
||||
- `packages/artplayer/src/index.js`: player entry
|
||||
- `packages/artplayer/src/player/`: playback mixins and player-facing behavior
|
||||
- `packages/artplayer/src/control/`: bottom controls
|
||||
- `packages/artplayer/src/setting/`: settings panel
|
||||
- `packages/artplayer/src/contextmenu/`: context menu items
|
||||
- `packages/artplayer/src/plugins/`: built-in plugins
|
||||
- `packages/artplayer/src/utils/`: shared helpers, component base classes, DOM utilities
|
||||
- `packages/artplayer/types/`: public TS declarations
|
||||
|
||||
### Ecosystem packages
|
||||
|
||||
Most ecosystem packages follow this pattern:
|
||||
|
||||
```text
|
||||
packages/<package>/
|
||||
src/index.js
|
||||
src/*.less # optional
|
||||
types/*.d.ts # optional but preferred for public APIs
|
||||
README.md
|
||||
package.json
|
||||
dist/*
|
||||
```
|
||||
|
||||
### Demo and docs assets
|
||||
|
||||
- `docs/assets/example/*.js`: runnable browser examples
|
||||
- `docs/assets/ts/*.js`: TypeScript demo assets targeted by lint/docs flows
|
||||
- `docs/uncompiled/`: dev output
|
||||
- `docs/compiled/`: production-copied output
|
||||
- `docs/document/`: generated docs content
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
### Core player
|
||||
|
||||
ArtPlayer composes many subsystems during construction. Common integration points:
|
||||
|
||||
- `art.template`
|
||||
- `art.events`
|
||||
- `art.controls`
|
||||
- `art.setting`
|
||||
- `art.contextmenu`
|
||||
- `art.layers`
|
||||
- `art.plugins`
|
||||
- `art.player`
|
||||
|
||||
When extending behavior, prefer integrating with these existing systems rather than bypassing them.
|
||||
|
||||
### Control and setting components
|
||||
|
||||
Controls and setting entries are managed through component registries.
|
||||
|
||||
Relevant implementation:
|
||||
|
||||
- `packages/artplayer/src/control/index.js`
|
||||
- `packages/artplayer/src/setting/index.js`
|
||||
- `packages/artplayer/src/utils/component.js`
|
||||
|
||||
Important behavior:
|
||||
|
||||
- `art.controls.update(...)` and `art.setting.update(...)` replace existing entries by `name`
|
||||
- `art.controls.remove(name)` and `art.setting.remove(name)` are the correct cleanup APIs
|
||||
- selector-style controls rely on `default` flags to determine highlighted items
|
||||
|
||||
If a plugin conditionally shows UI, it must also clean that UI up when the condition no longer holds.
|
||||
|
||||
### Plugin shape
|
||||
|
||||
Standard plugin/export shape:
|
||||
|
||||
```js
|
||||
export default function somePlugin(option = {}) {
|
||||
return (art) => {
|
||||
return {
|
||||
name: 'somePlugin',
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Naming conventions:
|
||||
|
||||
- package: `artplayer-plugin-<name>`
|
||||
- global: `artplayerPlugin<Name>`
|
||||
- exported function name should match the global naming convention
|
||||
|
||||
### Proxy packages
|
||||
|
||||
Proxy packages usually return a non-video element or video-like shim and emulate media element behavior for ArtPlayer.
|
||||
|
||||
Examples:
|
||||
|
||||
- `packages/artplayer-proxy-canvas`
|
||||
- `packages/artplayer-proxy-mediabunny`
|
||||
|
||||
When editing proxy packages:
|
||||
|
||||
- keep the HTMLMediaElement-like surface coherent
|
||||
- keep event ordering stable
|
||||
- treat `loadedmetadata`, `loadeddata`, `canplay`, `seeked`, `waiting`, and `pause/play` semantics carefully
|
||||
- ensure UI state is updated and cleaned up when source topology changes
|
||||
|
||||
### HLS / adaptive playback controls
|
||||
|
||||
The reference implementation for adaptive selector UI is:
|
||||
|
||||
- `packages/artplayer-plugin-hls-control/src/index.js`
|
||||
|
||||
If adding HLS-like quality/audio selection elsewhere:
|
||||
|
||||
- follow the selector format used there
|
||||
- derive highlighted items from actual current tracks, not only from mode flags
|
||||
- avoid stale selectors when changing to streams without the same topology
|
||||
|
||||
## Build and Artifact Rules
|
||||
|
||||
- Always edit `src/` and `types/` first.
|
||||
- Rebuild package artifacts after source changes that should ship.
|
||||
- Do not treat `dist/` as source of truth.
|
||||
- If a change affects demo behavior, also verify the matching file in `docs/assets/example/`.
|
||||
|
||||
For package-specific builds, the normal flow is:
|
||||
|
||||
1. `npm run dev` and pick the package for fast local iteration
|
||||
2. validate in `http://localhost:8082`
|
||||
3. `npm run build` and pick the package when ready to update shippable artifacts
|
||||
|
||||
## Documentation Expectations
|
||||
|
||||
If a public package API changes, check whether these also need updates:
|
||||
|
||||
- the package `README.md`
|
||||
- `docs/assets/example/<name>.js`
|
||||
- `types/<name>.d.ts`
|
||||
- any generated compiled outputs if you built the package
|
||||
|
||||
Keep examples realistic and runnable. Prefer local demo URLs or stable public sample streams.
|
||||
|
||||
## Code Quality Expectations
|
||||
|
||||
- Follow existing plain JavaScript style in the repo.
|
||||
- Use ASCII unless a file already requires otherwise.
|
||||
- Match the minimal-comment style of neighboring files.
|
||||
- Avoid unnecessary abstraction; this codebase generally prefers direct implementation.
|
||||
- Respect current browser targets:
|
||||
- modern build: `es2020`
|
||||
- legacy build: `es2015`
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
For most package changes, validate as many of these as apply:
|
||||
|
||||
- source file lint passes
|
||||
- local demo page loads
|
||||
- expected events fire once and in the correct order
|
||||
- controls/settings render correctly
|
||||
- cleanup works after restart, source switch, or destroy
|
||||
- package build succeeds
|
||||
|
||||
For playback/proxy changes specifically:
|
||||
|
||||
- test initial load
|
||||
- test play/pause
|
||||
- test seek
|
||||
- test switching source or track topology
|
||||
- test whether UI reflects the actual selected track/quality
|
||||
|
||||
## Notes Specific To `artplayer-proxy-mediabunny`
|
||||
|
||||
This package now depends on modern `mediabunny` and supports HLS through `mediabunny` input handling.
|
||||
|
||||
Files to understand first:
|
||||
|
||||
- `packages/artplayer-proxy-mediabunny/src/index.js`
|
||||
- `packages/artplayer-proxy-mediabunny/src/VideoShim.js`
|
||||
- `packages/artplayer-proxy-mediabunny/src/MediaBunnyEngine.js`
|
||||
- `packages/artplayer-proxy-mediabunny/src/input.js`
|
||||
- `packages/artplayer-proxy-mediabunny/src/m3u8.js`
|
||||
|
||||
Key expectations:
|
||||
|
||||
- HLS source detection should happen in `input.js`
|
||||
- track selection should use actual pairable audio/video relationships
|
||||
- selector UI should mirror the behavior of `artplayer-plugin-hls-control`
|
||||
- selector cleanup is required when a later source no longer supports the same controls
|
||||
- avoid duplicate readiness events during load and track switches
|
||||
|
||||
## When Unsure
|
||||
|
||||
Start with the nearest sibling implementation instead of inventing a new pattern:
|
||||
|
||||
- control/setting UI: `artplayer-plugin-hls-control`, `artplayer-plugin-dash-control`
|
||||
- proxy behavior: `artplayer-proxy-canvas`, `artplayer-proxy-mediabunny`
|
||||
- component lifecycle: `packages/artplayer/src/utils/component.js`
|
||||
|
||||
If a change spans source, examples, and packaging, make all three consistent in the same pass.
|
||||
@@ -0,0 +1,435 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Fix safe area issue when enter web fullscreen [#1033](https://github.com/zhw2590582/ArtPlayer/issues/1033)
|
||||
|
||||
## [5.4.0] - 2026-03-12
|
||||
|
||||
- Refactor `Parcel` to `Vite`
|
||||
- Change `Artplayer.FULLSCREEN_WEB_IN_BODY` defaults to `true`
|
||||
- The `reset` method is used to reset video request
|
||||
- Fix [#1014](https://github.com/zhw2590582/ArtPlayer/issues/1014)
|
||||
- Fix [#1023](https://github.com/zhw2590582/ArtPlayer/issues/1023)
|
||||
- Fix [#1028](https://github.com/zhw2590582/ArtPlayer/issues/1028)
|
||||
- Add `artplayer-plugin-jassub` plugin
|
||||
- Add `artplayer-proxy-mediabunny` plugin
|
||||
- Add `artplayer-plugin-audio-track` plugin
|
||||
- Add `artplayer-plugin-asr` plugin
|
||||
- Add `artplayer-plugin-danmuku-mask` plugin
|
||||
- Deprecate `artplayer-plugin-libass` plugin
|
||||
- Prevent `Hint.css` from polluting global styles
|
||||
|
||||
## [5.3.0] - 2025-09-06
|
||||
|
||||
- Rename `.esm.js` to `.mjs`
|
||||
- Remove the default `fill` color value of `svg`
|
||||
- Optimize the `autoOrientation` logic
|
||||
- Add `Artplayer.REMOVE_SRC_WHEN_DESTROY`
|
||||
- Add `artplayer-plugin-document-pip` plugin
|
||||
- Add `art.events.bindGlobalEvents` method for rebinding global methods
|
||||
- Optimize `artplayer.d.ts`, now you can directly import `Option`
|
||||
|
||||
```ts
|
||||
import type { Option } from 'artplayer'
|
||||
|
||||
const option: Option = {
|
||||
container: '.artplayer-app',
|
||||
url: './assets/sample/video.mp4',
|
||||
}
|
||||
```
|
||||
|
||||
- Simplify `i18n` import
|
||||
|
||||
```ts
|
||||
import fr from 'artplayer/i18n/fr'
|
||||
import id from 'artplayer/i18n/id'
|
||||
|
||||
const option = {
|
||||
container: '.artplayer-app',
|
||||
url: './assets/sample/video.mp4',
|
||||
i18n: { id, fr },
|
||||
lang: 'fr',
|
||||
}
|
||||
```
|
||||
|
||||
## [5.2.5] - 2025-08-01
|
||||
|
||||
- Add `ESM` version for all packages, such as `artplayer/dist/artplayer.esm.js`
|
||||
- Recognize `globalThis.CUSTOM_USER_AGENT` global variable for customizing `navigator.userAgent`
|
||||
- Fix missing `mount` parameter when initializing `artplayer-plugin-danmuku`
|
||||
|
||||
## [5.2.3] - 2025-04-20
|
||||
|
||||
- Add Vietnamese `vi`
|
||||
- Clear the `video.src` property on destroy
|
||||
- Add `onClick` option for `Setting`
|
||||
- Fix style loading failure of danmuku and chapter plugins when the page has no head tag
|
||||
- Add `gesture` option to enable or disable gesture events on mobile `video` element
|
||||
|
||||
## [5.2.2] - 2025-01-19
|
||||
|
||||
- Fix thumbnail crossover issue
|
||||
- Fix style loading failure when the page has no head tag
|
||||
- Add slider support in subtitle plugin settings panel for mobile dragging
|
||||
- Fix positioning error of settings panel when rotating screen
|
||||
- Fix classname switching error when fullscreen state changes
|
||||
|
||||
## [5.2.1] - 2024-10-26
|
||||
|
||||
- Refactor `Setting` component, fix state loss issue
|
||||
- For `Setting` of type `range`, callback now returns an array of numbers instead of a single number
|
||||
- Remove `isStringOrNumber` utility function
|
||||
- Fix inconsistent state issue in `artplayer-plugin-hls-control`
|
||||
- Deprecate `artplayer-plugin-dash-quality` plugin
|
||||
- Add new `artplayer-plugin-dash-control` plugin
|
||||
- Use `code` instead of deprecated `keyCode` for keyboard events
|
||||
- Add `keydown` event to listen for `keydown` from `document`
|
||||
|
||||
## [5.2.0] - 2024-10-19
|
||||
|
||||
- Add `option.proxy` for proxying third-party `video` and `canvas`
|
||||
- Add `artplayer-proxy-canvas` proxy, enabling video playback via `canvas`
|
||||
- Add `option.thumbnails.scale` for preview image scaling
|
||||
- Fix bug where changing `art.url` didn’t trigger `autoPlayback`: [#797](https://github.com/zhw2590582/ArtPlayer/issues/797)
|
||||
- Add `art.subtitle.cues` property for retrieving all subtitle list
|
||||
- Add `art.subtitle.activeCues` property for retrieving active subtitles
|
||||
- Add `subtitleBeforeUpdate` event triggered before subtitle element rendering
|
||||
- Change `subtitleUpdate` event to `subtitleAfterUpdate`, triggered after subtitle element rendering
|
||||
- Optimize trigger timing and callback parameters of `subtitleLoad` event
|
||||
- Remove `subtitleSwitch` event; use `subtitleLoad` instead
|
||||
- Upgrade `artplayer-plugin-hls-quality` to `artplayer-plugin-hls-control`
|
||||
- Add `artplayer-plugin-ambilight` plugin
|
||||
- Fix `thumbnails` display bug
|
||||
|
||||
## [5.1.7] - 2024-08-15
|
||||
|
||||
- Add `Artplayer.STYLE` property to return player style text
|
||||
- `art.screenshot('your-name')` now supports custom file names
|
||||
- When `Artplayer.CONTEXTMENU` is `false`, default context menu is no longer hidden
|
||||
- Add `art.thumbnails` property for dynamically setting `thumbnails`
|
||||
|
||||
## [5.1.6] - 2024-06-15
|
||||
|
||||
- Optimize `setBar` event
|
||||
- Add `artplayerPluginChapter` plugin
|
||||
- Add `art.plugins.artplayerPluginDanmuku.load(target)` parameter for appending danmuku library
|
||||
- Add `width` option to danmuku plugin; when player width is smaller than this, danmuku sender is placed at the bottom
|
||||
- Fix `artplayerPluginVttThumbnail` not displaying on mobile
|
||||
- Fix danmuku plugin style and percentage font-size bug
|
||||
- `thumbnails` are now visible on mobile too
|
||||
- Restore `screen.orientation.lock` functionality
|
||||
|
||||
## [5.1.5] - 2024-06-01
|
||||
|
||||
- Refactor `artplayerPluginDanmuku` plugin
|
||||
- Add `artplayerPluginChromecast` plugin
|
||||
- Add `fullscreenError` event
|
||||
- Optimize double-click event: [#728](https://github.com/zhw2590582/ArtPlayer/pull/728)
|
||||
- Fix delayed display of `thumbnails`
|
||||
- Add `art.plugins.lock.state = true/false` for manually controlling `lock` state
|
||||
- Control bar no longer auto-hides when mouse is on it or when settings panel is open
|
||||
- Remove `screen.orientation.lock` due to compatibility issues
|
||||
- Fix `fullscreen` bug on mobile
|
||||
|
||||
## [5.1.1] - 2024-01-11
|
||||
|
||||
- Plugin functions now support both synchronous and asynchronous returns
|
||||
|
||||
## [5.1.0] - 2023-12-23
|
||||
|
||||
- Plugin functions now support async return
|
||||
- Player will no longer be destroyed after reaching error limit for playback address
|
||||
- Split language files, core no longer bundles multiple languages [Language Settings](https://artplayer.org/document/start/i18n.html)
|
||||
- Updating components now supports updating only specified fields [pull/549](https://github.com/zhw2590582/ArtPlayer/pull/549)
|
||||
- Add `muted` event triggered when mute state changes
|
||||
- Add `Artplayer.LOG_VERSION` global config to control whether to print player version (default `true`)
|
||||
- Add `Artplayer.USE_RAF` global config to control whether to use `requestAnimationFrame` (default `false`), currently for smooth progress bar effect
|
||||
- Remove default styles `margin:0;padding:0;` to avoid conflicts with third-party libraries
|
||||
- Subtitle line changed from `p` to `div` tag, with classname `art-subtitle-line`
|
||||
- On mobile, tapping video toggles control bar display
|
||||
- Remove `art.loop` interval playback feature (not commonly used)
|
||||
- Subtitle track now has `label` attribute to display subtitle names on mobile
|
||||
- Add utility functions `unescape`, `isBrowser`, `setStyleText`
|
||||
- Add `artplayerPluginMultipleSubtitles` plugin for merged subtitle files: [demo](https://www.artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles)
|
||||
- Modify mini progress bar display
|
||||
|
||||
## [5.0.9] - 2023-05-14
|
||||
|
||||
- Fix `art.autoOrientation` style bug
|
||||
- Remove animation effect of player container
|
||||
|
||||
## [5.0.8] - 2023-05-13
|
||||
|
||||
- Fix conflict of `art.mini`
|
||||
- Fix animation bug of `art.aspectRatio`
|
||||
|
||||
## [5.0.7] - 2023-05-13
|
||||
|
||||
- Switching via `switchUrl` or `switchQuality` preserves existing adjustments such as `aspectRatio`, `playbackRate`, `flip`, `autoSize`
|
||||
- Remove the second `name` parameter from `switchUrl` and `switchQuality`
|
||||
- Add `isIOS13` utility to fix inaccurate `isMobile` detection on iOS 13+
|
||||
- `art.autoSize` and `art.autoHeight` are now methods: `art.autoSize()` and `art.autoHeight()`
|
||||
- Add new property `art.quality` for dynamically updating quality list
|
||||
- Fix incorrect `art.aspectRatio` property
|
||||
- Add `art.switch` setter property, same as `art.switchUrl` method
|
||||
|
||||
## [5.0.6] - 2023-05-03
|
||||
|
||||
- Fix style bug of settings panel
|
||||
|
||||
## [5.0.5] - 2023-05-03
|
||||
|
||||
- Add `heatmap` option to danmuku plugin for enabling heatmap (default: off)
|
||||
- Fix English subtitle line break style bug
|
||||
- Fix settings panel style bug
|
||||
- Remove unnecessary global properties
|
||||
- Remove `title` option (not useful now)
|
||||
- Remove `whitelist` option (not useful now)
|
||||
|
||||
## [5.0.4] - 2023-04-27
|
||||
|
||||
- Fix controller dropdown list style bug
|
||||
|
||||
## [5.0.3] - 2023-04-26
|
||||
|
||||
- Fix `event.pageY` value error in volume controller
|
||||
- Update build config, `artplayer.legacy.js` now compatible with IE 11
|
||||
|
||||
## [5.0.2] - 2023-04-24
|
||||
|
||||
- Fix style compatibility issue of control bar position
|
||||
|
||||
## [5.0.1] - 2023-04-24
|
||||
|
||||
- Fix web fullscreen style bug
|
||||
- Fix built-in settings text error
|
||||
|
||||
## [5.0.0] - 2023-04-23
|
||||
|
||||
- Rewrite volume controller
|
||||
- Fix incorrect progress drag angle on mobile
|
||||
- Rewrite `mini` mode, now video detaches from original container
|
||||
- All components (layers, controller, contextmenu, settings panel) support dynamic deletion and updating
|
||||
- Subtitle option adds `onVttLoad` for modifying vtt text before output
|
||||
- Rewrite all styles, add many `css` variables
|
||||
- Add `cssVar` option for initializing `css` variables
|
||||
- Add `cssVar` method for getting/setting `css` variables
|
||||
- `artplayer-plugin-hls-quality` adds `getResolution` function option for getting resolution text from level
|
||||
- Add `artplayer-plugin-dash-quality` plugin for adding Dash quality list to player
|
||||
- Fix `lock` and `loop` event issues
|
||||
- Add Russian `ru` and Indonesian `id` languages
|
||||
- Update `artplayer-plugin-control` for `artplayer@5.0.0`
|
||||
- Update `artplayer-plugin-dash-quality` for `artplayer@5.0.0`
|
||||
- Update `artplayer-plugin-hls-quality` for `artplayer@5.0.0`
|
||||
- Update `artplayer-plugin-danmuku` for `artplayer@5.0.0`
|
||||
|
||||
## [4.6.2] - 2023-01-26
|
||||
|
||||
- Default `Artplayer.PROGRESS_HEIGHT` changed to `6`
|
||||
- Add `artplayer-plugin-vtt-thumbnail` to generate video preview images from vtt subtitle files
|
||||
- Add `Artplayer.FULLSCREEN_WEB_IN_BODY` for whether to mount player to `document.body` in web fullscreen (default `false`)
|
||||
- Change subtitle offset adjustment to slider
|
||||
- Subtitle option adds `escape` (default `true`) for HTML escaping
|
||||
|
||||
## [4.6.1] - 2023-01-11
|
||||
|
||||
- Write brand new docs
|
||||
- Optimize `d.ts`
|
||||
- Remove redundant events
|
||||
- Optimize some styles
|
||||
- Add `i18n` option
|
||||
|
||||
## [4.6.0] - 2022-12-31
|
||||
|
||||
- Optimize style effects of control bar icons
|
||||
- Optimize style effects of settings panel
|
||||
- Fix incorrect `art.fullscreen` state detection
|
||||
- Add `artplayer-plugin-control` plugin to change control bar style
|
||||
|
||||
## [4.5.12] - 2022-11-20
|
||||
|
||||
- Fix `art.loop = []` display bug
|
||||
|
||||
## [4.5.11] - 2022-11-06
|
||||
|
||||
- Add `Artplayer.CONTEXTMENU` for controlling whether to show contextmenu (default `true`)
|
||||
- Whitelist function default `true` on mobile, all devices use player UI
|
||||
|
||||
## [4.5.10] - 2022-11-05
|
||||
|
||||
- Fix subtitle not showing in Firefox: [#pull/415](https://github.com/zhw2590582/ArtPlayer/pull/415)
|
||||
- Info popup supports clicking to select video property text
|
||||
|
||||
## [4.5.9] - 2022-11-05
|
||||
|
||||
- Add `art.type` property to get/set video type
|
||||
- Add `art.video` property to get video element
|
||||
- Add `artplayer-tool-iframe` plugin to control player inside iframe
|
||||
- Add `artplayer-plugin-hls-quality` plugin for adding Hls quality list
|
||||
- Add `Artplayer.PLAYBACK_RATE` for default playback rates `[0.5, 0.75, 1, 1.25, 1.5, 2]`
|
||||
- Add `Artplayer.ASPECT_RATIO` for default ratios `['default','4:3','16:9']`
|
||||
- Add `Artplayer.FLIP` for default flip options `['normal','horizontal','vertical']`
|
||||
- Add `Artplayer.PROGRESS_HEIGHT` (default: `4`)
|
||||
- Add `legacy.js` version for older browsers (larger size)
|
||||
- Remove `examples` dir, no longer provide Vue/React examples
|
||||
|
||||
## [4.5.8] - 2022-10-09
|
||||
|
||||
- Add Farsi language
|
||||
- Add `Artplayer.DEBUG` (default `false`) for debug logs
|
||||
- Add `art.setting.update()` for dynamic settings update
|
||||
- Optimize `artplayer.d.ts`
|
||||
|
||||
## [4.5.7] - 2022-09-28
|
||||
|
||||
- Add `Artplayer.VOLUME_STEP` for controlling volume step (default `0.1`)
|
||||
- Add `Artplayer.SEEK_STEP` for controlling seek step (default `5s`)
|
||||
- Fix some svg icons not showing on mobile
|
||||
- Fix desktop progress bar cannot click+drag simultaneously
|
||||
- Fix mobile progress bar cannot click+drag
|
||||
- Add `art.isRotate` property for detecting auto fullscreen rotation
|
||||
- Settings panel `range` adds `onChange` option for real-time values
|
||||
|
||||
```js
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
setting: true,
|
||||
settings: [
|
||||
{
|
||||
html: 'Slider',
|
||||
tooltip: '5x',
|
||||
range: [5, 1, 10, 0.1],
|
||||
onChange: function (item) {
|
||||
return item.range + 'x';
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## [4.5.6] - 2022-09-19
|
||||
|
||||
- Fix hls.js not working in Safari
|
||||
|
||||
## [4.5.5] - 2022-09-19
|
||||
|
||||
- Ad plugin adds `option.muted` for autoplay muted ads
|
||||
- Danmuku plugin exposes `art.plugins.artplayerPluginDanmuku.reset()` to clear display
|
||||
- Danmuku plugin exposes `art.plugins.artplayerPluginDanmuku.option` for current config
|
||||
- Fix subtitle bug in iOS fullscreen
|
||||
- Add Spanish `es`
|
||||
|
||||
## [4.5.4] - 2022-08-01
|
||||
|
||||
### Added
|
||||
|
||||
- Add `Artplayer.AUTO_PLAYBACK_MIN` for min playback memory value (default `5s`)
|
||||
- Add `Artplayer.TOUCH_MOVE_RATIO` for mobile progress drag ratio (default `0.5`)
|
||||
- `option.thumbnails` adds optional `width`/`height`
|
||||
- Add `option.id` for unique playback memory identifier
|
||||
|
||||
## [4.5.3] - 2022-07-13
|
||||
|
||||
### Added
|
||||
|
||||
- `url` option allows empty string for async `art.url`
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '',
|
||||
container: '.artplayer-app',
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
art.url = '/assets/sample/video.mp4';
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
- `art.play()` always returns Promise; `play` event is async
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '/assets/sample/video.mp4',
|
||||
container: '.artplayer-app',
|
||||
});
|
||||
|
||||
art.on('ready', async () => {
|
||||
try {
|
||||
await art.play();
|
||||
console.log('Play success');
|
||||
} catch (error) {
|
||||
console.log('Play failed', error.message);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
- Add `airplay` (only Safari)
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '/assets/sample/video.mp4',
|
||||
container: '.artplayer-app',
|
||||
airplay: true,
|
||||
});
|
||||
```
|
||||
|
||||
## [4.5.2] - 2022-06-22
|
||||
|
||||
- Optimize auto-playback to allow user choice
|
||||
|
||||
## [4.5.0] - 2022-06-21
|
||||
|
||||
- Remove built-in ads
|
||||
- Add ad plugin
|
||||
|
||||
## [4.4.7] - 2022-06-13
|
||||
|
||||
- Support danmuku lib d.ts
|
||||
- Update deps
|
||||
|
||||
## [4.4.6] - 2022-06-11
|
||||
|
||||
- Add danmuku lib d.ts
|
||||
- Adjust subtitle font-size param
|
||||
- Optimize regex parsing of xml danmuku
|
||||
|
||||
## [4.4.5] - 2022-06-02
|
||||
|
||||
- Fix theme color missing in mini mode
|
||||
|
||||
## [4.4.3] - 2022-05-26
|
||||
|
||||
- Fix custom mounted input residual on danmuku destroy
|
||||
- Fix mini mode size calculation error
|
||||
|
||||
## [4.4.2] - 2022-05-20
|
||||
|
||||
- Remove UI init `video:loadedmetadata` event
|
||||
- Danmuku exposes `load` for switching sources
|
||||
- Add error icon after video load error limit
|
||||
- Fix multiple init of setting panel bug
|
||||
|
||||
## [4.4.1] - 2022-05-17
|
||||
|
||||
- Add `art.isInput`, when true control bar won’t auto-hide (e.g. typing danmuku)
|
||||
- Add `art.isLock`, when true on mobile prevents seek/play/pause
|
||||
- Fix fixed width bug of danmuku input box
|
||||
- Settings panel supports `range` and `onRange`
|
||||
- Add `isAndroid` and `isIOS` utils
|
||||
- Danmuku adds `lockTime`, `maxLength`, `minWidth`, `maxWidth`, `mount`, `beforeEmit`, `theme`
|
||||
|
||||
## [4.4.0] - 2022-05-15
|
||||
|
||||
- Settings panel supports `switch` and `onSwitch`
|
||||
- Danmuku plugin adds settings panel and send
|
||||
- Danmuku adds default mode and font-size
|
||||
- Danmuku font-size supports percentage of player
|
||||
- Fix flip icon missing
|
||||
- Player with focus won’t auto-hide control bar
|
||||
- Remove subtitle toggle button (manual config required)
|
||||
@@ -1,395 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [5.2.2] - 2025-01-19
|
||||
|
||||
- 修复缩略图跨越问题
|
||||
- 修复当网页没有head时引起的样式加载失败问题
|
||||
- 新增字幕插件的设置面板的滑块支持移动端拖动
|
||||
- 修复设置面板在旋屏时的定位错误
|
||||
- 修复全屏状态变化时类名切换错误问题
|
||||
|
||||
## [5.2.1] - 2024-10-26
|
||||
|
||||
- 重构 `Setting` 组件,修复状态丢失的问题
|
||||
- 类型是 `range` 的 `Setting`,现在回调函数返回的 `range` 是数字的数组,不再是单一数字
|
||||
- 删除 `isStringOrNumber` 工具函数
|
||||
- 修复 `artplayer-plugin-hls-control` 状态不统一的问题
|
||||
- 废弃 `artplayer-plugin-dash-quality` 插件
|
||||
- 新增 `artplayer-plugin-dash-control` 插件
|
||||
- 使用 `code` 替代已废弃的`keyCode` 监听键盘事件
|
||||
- 新增 `keydown` 事件,监听来自 `document` 的 `keydown` 事件
|
||||
|
||||
## [5.2.0] - 2024-10-19
|
||||
|
||||
- 新增 `option.proxy` 选项,用于代理第三方的 `video` 和 `canvas`
|
||||
- 新增 `artplayer-proxy-canvas` 代理,可以使用 `canvas` 播放视频
|
||||
- 新增 `artplayer-proxy-webav` 代理,来自 [bilibili/WebAV](https://github.com/bilibili/WebAV)
|
||||
- 新增 `option.thumbnails.scale`, 用于预览图缩放
|
||||
- 修复 `art.url` 更改不能触发 `autoPlayBack` 的 `bug`: [#797](https://github.com/zhw2590582/ArtPlayer/issues/797)
|
||||
- 新增 `art.subtitle.cues` 属性, 获取整体的字幕列表
|
||||
- 新增 `art.subtitle.activeCues` 属性, 获取活跃的字幕列表
|
||||
- 新增 `subtitleBeforeUpdate` 事件, 在字幕元素渲染前触发
|
||||
- 修改 `subtitleUpdate` 事件为 `subtitleAfterUpdate`, 在字幕元素渲染后触发
|
||||
- 优化 `subtitleLoad` 事件的触发时机和回调参数
|
||||
- 删除 `subtitleSwitch` 事件,请使用 `subtitleLoad` 代替
|
||||
- 升级 `artplayer-plugin-hls-quality` 为 `artplayer-plugin-hls-control`
|
||||
- 新增 `artplayer-plugin-ambilight` 插件
|
||||
- 修复 `thumbnails` 显示 bug
|
||||
|
||||
## [5.1.7] - 2024-8-15
|
||||
|
||||
- 新增 `Artplayer.STYLE` 属性,返回播放器样式文本
|
||||
- `art.screenshot('your-name')` 截图功能支持自定义文件名字
|
||||
- `Artplayer.CONTEXTMENU` 为 `false` 时,不再隐藏默认右键菜单
|
||||
- 新增 `art.thumbnails` 属性,用于动态设置 `thumbnails`
|
||||
|
||||
## [5.1.6] - 2024-6-15
|
||||
|
||||
- 优化 `setBar` 事件
|
||||
- 新增 `artplayerPluginChapter` 插件
|
||||
- 新增 `art.plugins.artplayerPluginDanmuku.load(target)` 参数,用于追加弹幕库
|
||||
- 新增弹幕插件的 `width` 选项参数,当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
- 修复 `artplayerPluginVttThumbnail` 在移动端不显示的问题
|
||||
- 修复弹幕插件样式,和字号百分比显示的 `bug`
|
||||
- 移动端也可以看到 `thumbnails` 了
|
||||
- 恢复 `screen.orientation.lock` 功能
|
||||
|
||||
## [5.1.5] - 2024-6-1
|
||||
|
||||
- 重构 `artplayerPluginDanmuku` 插件
|
||||
- 新增 `artplayerPluginChromecast` 插件
|
||||
- 添加 `fullscreenError` 事件
|
||||
- 优化双击事件: [#728](https://github.com/zhw2590582/ArtPlayer/pull/728)
|
||||
- 修复 `thumbnails` 延迟显示问题
|
||||
- 新增 `art.plugins.lock.state = true/false`, 用于手动控制 `lock` 状态
|
||||
- 当鼠标在控制栏上,或者打开了设置面板,控制栏不再自动隐藏
|
||||
- 由于兼容性不足,删除 `screen.orientation.lock` 功能
|
||||
- 修复移动端的 `fullscreen` bug
|
||||
|
||||
## [5.1.1] - 2024-1-11
|
||||
|
||||
- 插件函数支持同步和异步返回
|
||||
|
||||
## [5.1.0] - 2023-12-23
|
||||
|
||||
- 插件函数改为支持异步返回
|
||||
- 当播放地址发生错误到达上限后,不会再主动销毁播放器
|
||||
- 分离语言文件,核心代码不再捆绑多国语言 [语言设置](https://artplayer.org/document/start/i18n.html)
|
||||
- 更新组件时,支持填写只更新的字段 [pull/549](https://github.com/zhw2590582/ArtPlayer/pull/549)
|
||||
- 添加 `muted` 事件,当静音的状态变化时触发
|
||||
- 添加 `Artplayer.LOG_VERSION` 全局配置,设置是否打印播放器版本,默认为 `true`
|
||||
- 添加 `Artplayer.USE_RAF` 全局配置,设置是否使用 `requestAnimationFrame` ,默认为 `false`,目前主要用于进度条的平滑效果
|
||||
- 移除默认样式 `margin:0;padding:0;`,因为容易与第三方库起样式冲突,导致难以覆写
|
||||
- 字幕行从 `p` 标签改为 `div` 标签,并且添加类名 `art-subtitle-line`
|
||||
- 在移动端,点击视频会切换控制栏的显示与隐藏
|
||||
- 由于功能不常用,删除 `art.loop` 区间播放功能
|
||||
- 字幕轨添加 `label` 属性,用于在移动设备上显示字幕名字
|
||||
- 添加 `unescape`, `isBrowser`, `setStyleText` 工具函数
|
||||
- 添加 `artplayerPluginMultipleSubtitles` 插件,用于显示合并后的字幕文件: [demo](https://www.artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles)
|
||||
- 修改迷你进度条的显示方式
|
||||
|
||||
## [5.0.9] - 2023-5-14
|
||||
|
||||
- 修复 `art.autoOrientation` 样式错误问题
|
||||
- 移除播放器容器的动画效果
|
||||
|
||||
## [5.0.8] - 2023-5-13
|
||||
|
||||
- 修复 `art.mini` 的互斥关系
|
||||
- 修复 `art.aspectRatio` 动画效果问题
|
||||
|
||||
## [5.0.7] - 2023-5-13
|
||||
|
||||
- 使用 `switchUrl` 或者 `switchQuality` 方法切换地址后会保持原有的调整如:`aspectRatio`, `playbackRate`, `flip`, `autoSize`
|
||||
- 删除 `switchUrl` 方法和 `switchQuality` 方法的第二个 `name` 参数
|
||||
- 添加 `isIOS13` 工具,用于修复在 `IOS13` 以上版本的设备上的 `isMobile` 判断不准确的问题
|
||||
- `art.autoSize` 和 `art.autoHeight` 改为方法的形式调用,即 `art.autoSize()` 和 `art.autoHeight()`
|
||||
- 添加新的属性 `art.quality`,用于动态更新画质列表
|
||||
- 修复 `art.aspectRatio` 属性不正确的问题
|
||||
- 添加 `art.switch` Setter 属性, 功能和 `art.switchUrl` 方法一样
|
||||
|
||||
## [5.0.6] - 2023-5-3
|
||||
|
||||
- 修复设置面板的样式错误
|
||||
|
||||
## [5.0.5] - 2023-5-3
|
||||
|
||||
- 弹幕插件添加 `heatmap` 选项,用于是否开启热度图,默认为关闭
|
||||
- 修复英文字幕换行的样式错误
|
||||
- 修复设置面板的样式错误
|
||||
- 移除多余的全局属性
|
||||
- 移除 `title` 选项,因为目前用处不大
|
||||
- 移除 `whitelist` 选项,因为目前用处不大
|
||||
|
||||
## [5.0.4] - 2023-4-27
|
||||
|
||||
- 修复控制器的上拉列表的样式 bug
|
||||
|
||||
## [5.0.3] - 2023-4-26
|
||||
|
||||
- 修复音量控制器 `event.pageY` 取值错误
|
||||
- 修改构建配置,`artplayer.legacy.js` 可以兼容到 `IE 11`
|
||||
|
||||
## [5.0.2] - 2023-4-24
|
||||
|
||||
- 修复控制栏位置的样式兼容问题
|
||||
|
||||
## [5.0.1] - 2023-4-24
|
||||
|
||||
- 修复网页全屏的样式错误
|
||||
- 修改内置设置项的文本错误
|
||||
|
||||
## [5.0.0] - 2023-4-23
|
||||
|
||||
- 重写了音量控制器
|
||||
- 修复在移动端下,进度拖动的角度不正确的问题
|
||||
- 重写了 `mini` 模式,现在这个模式下,视频会脱离原来的容器
|
||||
- 全部组件(层,控制器,右键菜单,设置面板)支持动态删除和动态更新
|
||||
- 字幕选项添加了 `onVttLoad` 方法,用于在字幕输出前修改 `vtt` 文本
|
||||
- 重写了全部样式,添加了许多 `css` 变量
|
||||
- 添加 `cssVar` 选项,用于初始化 `css` 变量
|
||||
- 添加 `cssVar` 方法,用于设置和获取 `css` 变量
|
||||
- 插件 `artplayer-plugin-hls-quality` 添加 `getResolution` 函数选项,用于获取从 `level` 中分辨率的文本
|
||||
- 新增 `artplayer-plugin-dash-quality` 插件,用于添加 `Dash` 画质列表到播放器
|
||||
- 修复 `lock` 和 `loop` 事件失效问题
|
||||
- 添加俄语 `ru` 和印度尼西亚 `id` 语言
|
||||
- 更新 `artplayer-plugin-control`,用于兼容`artplayer@5.0.0`
|
||||
- 更新 `artplayer-plugin-dash-quality`,用于兼容`artplayer@5.0.0`
|
||||
- 更新 `artplayer-plugin-hls-quality`,用于兼容`artplayer@5.0.0`
|
||||
- 更新 `artplayer-plugin-danmuku`,用于兼容`artplayer@5.0.0`
|
||||
|
||||
## [4.6.2] - 2023-1-26
|
||||
|
||||
- `Artplayer.PROGRESS_HEIGHT` 默认值改为 `6`
|
||||
- 添加 `artplayer-plugin-vtt-thumbnail` 用于使用 `vtt` 字幕文件生成视频预览图
|
||||
- 添加 `Artplayer.FULLSCREEN_WEB_IN_BODY` 用于网页全屏时,是否把播放器挂载于 `document.body` 上,默认为 `false`
|
||||
- 修改字幕偏移的方式为滑块
|
||||
- 字幕选项添加 `escape`,用于是否转义 `html` 标签,默认为 `true`
|
||||
|
||||
## [4.6.1] - 2023-1-11
|
||||
|
||||
- 编写全新的文档
|
||||
- 优化`d.ts`
|
||||
- 移除多余的事件
|
||||
- 优化部分样式
|
||||
- 添加`i18n`选项
|
||||
|
||||
## [4.6.0] - 2022-12-31
|
||||
|
||||
- 优化控制栏图标的样式效果
|
||||
- 优化设置面板的样式效果
|
||||
- 修复 `art.fullscreen` 监听状态错误的问题
|
||||
- 添加 `artplayer-plugin-control` 插件,用于改变控制栏样式
|
||||
|
||||
## [4.5.12] - 2022-11-20
|
||||
|
||||
- 修复 `art.loop = []` 的显示 `bug`
|
||||
|
||||
## [4.5.11] - 2022-11-6
|
||||
|
||||
- 新增 `Artplayer.CONTEXTMENU` 用于设置是否显示右键菜单,默认为 `true`
|
||||
- 移动设备 `Whitelist` 功能默认为 `true`,即全部移动设备都使用播放器 `UI`
|
||||
|
||||
## [4.5.10] - 2022-11-5
|
||||
|
||||
- 修复字幕在 `firefox` 不显示的问题:[#pull/415](https://github.com/zhw2590582/ArtPlayer/pull/415)
|
||||
- 信息弹窗支持点击选中视频属性文本值
|
||||
|
||||
## [4.5.9] - 2022-11-5
|
||||
|
||||
- 添加 `art.type` 属性,用于获取和设置视频类型
|
||||
- 添加 `art.video` 属性,用于获取 `video` 元素
|
||||
- 添加 `artplayer-plugin-iframe` 插件,用于控制 `iframe` 里的播放器
|
||||
- 添加 `artplayer-plugin-hls-quality` 插件,用于添加 `Hls` 画质列表到播放器
|
||||
- 新增 `Artplayer.PLAYBACK_RATE` 用于设置默认播放速度,默认 `[0.5, 0.75, 1, 1.25, 1.5, 2]`
|
||||
- 新增 `Artplayer.ASPECT_RATIO` 用于设置默认长宽比,默认 `['default', '4:3', '16:9']`
|
||||
- 新增 `Artplayer.FLIP` 用于设置默认翻转功能,默认 `['normal', 'horizontal', 'vertical']`
|
||||
- 新增 `Artplayer.PROGRESS_HEIGHT` 用于设置进度条高度,默认为 `4`
|
||||
- 添加 `legacy.js` 版本,用于兼容更老的浏览器,但相对体积较大
|
||||
- 移除 `examples` 目录,不再提供 `vue.js` 和 `react.js` 的例子文件
|
||||
|
||||
## [4.5.8] - 2022-10-9
|
||||
|
||||
- 添加 `farsi` 语言
|
||||
- 新增 `Artplayer.DEBUG` 用于打印 `debug` 信息,默认为 `false`
|
||||
- 新增 `art.setting.update()` 用于动态更新设置面板
|
||||
- 优化 `artplayer.d.ts`
|
||||
|
||||
## [4.5.7] - 2022-9-28
|
||||
|
||||
- 新增 `Artplayer.VOLUME_STEP` 用于控制调整 `音量` 的步长,默认为 `0.1`
|
||||
- 新增 `Artplayer.SEEK_STEP` 用于控制调整 `快进/快退` 的步长,默认为 `5` 秒
|
||||
- 修复部分 `svg` 图标在移动端不显示的问题
|
||||
- 修复在桌面端进度条不能同时点击和拖动的问题
|
||||
- 修复在移动端进度条不能点击和拖动的问题
|
||||
- 新增 `art.isRotate` 属性,用于识别是否自动全屏旋转
|
||||
- 设置面板 `range` 添加 `onChange` 选项,可以实时获取当前值
|
||||
|
||||
```js
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
setting: true,
|
||||
settings: [
|
||||
{
|
||||
html: 'Slider',
|
||||
tooltip: '5x',
|
||||
range: [5, 1, 10, 0.1],
|
||||
onChange: function (item) {
|
||||
return item.range + 'x';
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## [4.5.6] - 2022-9-19
|
||||
|
||||
- 修复 `hls.js` 在 `Safari` 播放失效的问题
|
||||
|
||||
## [4.5.5] - 2022-9-19
|
||||
|
||||
- 广告插件添加 `option.muted` 选项,用于静音自动播放广告
|
||||
- 弹幕库插件暴露 `art.plugins.artplayerPluginDanmuku.reset()` 方法,用于清空当前弹幕显示
|
||||
- 弹幕库插件暴露 `art.plugins.artplayerPluginDanmuku.option` 属性,用于获取当前弹幕配置
|
||||
- 修复在 `IOS` 全屏模式下,字幕失效的问题
|
||||
- 添加 `es` 语言
|
||||
|
||||
## [4.5.4] - 2022-8-1
|
||||
|
||||
### Added
|
||||
|
||||
- 新增 `Artplayer.AUTO_PLAYBACK_MIN` 用于控制最小可以记忆播放的进度值,默认为 `5` 秒
|
||||
- 新增 `Artplayer.TOUCH_MOVE_RATIO` 用于控制移动端进度条拖放比例,默认为 `0.5`
|
||||
- `option.thumbnails` 添加可选的 `width` 和 `height`
|
||||
- 新增播放器编号选项 `option.id`,可用于记忆播放时的唯一标识
|
||||
|
||||
## [4.5.3] - 2022-7-13
|
||||
|
||||
### Added
|
||||
|
||||
- `url` 选项允许传空字符串,可用于异步设置 `art.url`
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '',
|
||||
container: '.artplayer-app',
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
art.url = '/assets/sample/video.mp4';
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
- `art.play()` 方法统一返回 `Promise`, `play` 事件也改为异步触发
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '/assets/sample/video.mp4',
|
||||
container: '.artplayer-app',
|
||||
});
|
||||
|
||||
art.on('ready', async () => {
|
||||
try {
|
||||
await art.play();
|
||||
console.log('播放成功');
|
||||
} catch (error) {
|
||||
console.log('播放失败', error.message);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
- 新增 `airplay` (隔空播放) 功能,当前只在 Safari 下可用
|
||||
|
||||
```js
|
||||
const art = new Artplayer({
|
||||
url: '/assets/sample/video.mp4',
|
||||
container: '.artplayer-app',
|
||||
airplay: true,
|
||||
});
|
||||
```
|
||||
|
||||
## [4.5.2] - 2022-6-22
|
||||
|
||||
### Added
|
||||
|
||||
- 优化自动回放功能,让用户自行选择
|
||||
|
||||
## [4.5.0] - 2022-6-21
|
||||
|
||||
### Added
|
||||
|
||||
- 移除内置广告功能
|
||||
- 新增广告插件
|
||||
|
||||
## [4.4.7] - 2022-6-13
|
||||
|
||||
### Added
|
||||
|
||||
- 兼容弹幕库 d.ts
|
||||
- 更新依赖库
|
||||
|
||||
## [4.4.6] - 2022-6-11
|
||||
|
||||
### Added
|
||||
|
||||
- 添加弹幕库 d.ts
|
||||
- 调整字幕字体大小参数
|
||||
- 优化正则解析 xml 弹幕
|
||||
|
||||
## [4.4.5] - 2022-6-2
|
||||
|
||||
### Added
|
||||
|
||||
- 修复迷你模式时,主题色缺失的 bug
|
||||
|
||||
## [4.4.3] - 2022-05-26
|
||||
|
||||
### Added
|
||||
|
||||
- 修复弹幕库销毁时,自定义挂载输入框的残留
|
||||
- 修复迷你模式的尺寸计算错误
|
||||
|
||||
## [4.4.2] - 2022-05-20
|
||||
|
||||
### Added
|
||||
|
||||
- 移除播放器 UI 初始化的 video:loadedmetadata 事件
|
||||
- 弹幕库暴露 load 方法,用于切换弹幕源
|
||||
- 添加 error 图标,出现于视频加载错误达到上限后
|
||||
- 修复 setting 多次初始化时产生的 bug
|
||||
|
||||
## [4.4.1] - 2022-05-17
|
||||
|
||||
### Added
|
||||
|
||||
- 添加 art.isInput 属性,当为 true 的时候不自动隐藏控制栏,如弹幕正在输入时
|
||||
- 添加 art.isLock 属性,在移动端当为 true 的时候不能操作快进、开始和暂停
|
||||
- 修复弹幕输入框的固定宽度 bug
|
||||
- 设置面板支持 range 和 onRange 选项
|
||||
- 添加 isAndroid 和 isIOS 工具函数
|
||||
- 弹幕库添加 lockTime 选项,可自定义输入框的锁定时间
|
||||
- 弹幕库添加 maxLength 选项,控制输入最大可输入字数
|
||||
- 弹幕库添加 minWidth 选项,控制输入框最小宽度
|
||||
- 弹幕库添加 maxWidth 选项,控制输入框最大宽度
|
||||
- 弹幕库添加 mount 选项,控制输入框自定义挂载位置
|
||||
- 弹幕库添加 beforeEmit 选项,控制弹幕发送前的校验
|
||||
- 弹幕库添加 theme 选项,控制输入框自定义挂载的主题色
|
||||
|
||||
## [4.4.0] - 2022-05-15
|
||||
|
||||
### Added
|
||||
|
||||
- 设置面板支持 switch 和 onSwitch 选项
|
||||
- 弹幕库插件添加设置面板和弹幕发送
|
||||
- 弹幕库的选项添加默认模式和默认字号
|
||||
- 弹幕库字号支持按播放器的百分百
|
||||
- 修复翻转设置的图标缺失
|
||||
- 默认播放器获取了焦点后,不会自动隐藏控制栏
|
||||
- 删除字幕开关按钮,需要自行配置字幕开关
|
||||
@@ -0,0 +1,202 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
ArtPlayer.js is a modern, full-featured HTML5 video player. It's organized as a monorepo using Lerna with independent versioning.
|
||||
|
||||
- **Homepage**: https://artplayer.org
|
||||
- **Online Editor**: https://artplayer.org (for testing examples)
|
||||
- **API Docs**: https://artplayer.org/document
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
packages/
|
||||
artplayer/ # Core player package
|
||||
artplayer-plugin-*/ # 17+ plugins (danmuku, ads, chromecast, etc.)
|
||||
artplayer-proxy-*/ # Canvas, Mediabunny proxies
|
||||
artplayer-tool-*/ # iframe, thumbnail tools
|
||||
artplayer-vitepress/ # Documentation site
|
||||
|
||||
docs/ # Documentation and demo site
|
||||
assets/ # Example assets and TypeScript demos
|
||||
compiled/ # Built packages output
|
||||
document/ # Generated API documentation
|
||||
uncompiled/ # Development build output
|
||||
test/ # Browser test files
|
||||
|
||||
scripts/ # Build tooling
|
||||
build.js # Production build
|
||||
dev.js # Development server
|
||||
build-i18n.js # I18n bundle builder
|
||||
build-docs.js # Documentation generator
|
||||
build-llm.js # LLMs.txt generator
|
||||
plugin/create.js # New plugin scaffolding
|
||||
```
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Development
|
||||
```bash
|
||||
# Start dev server on port 8082 with hot reload
|
||||
npm run dev
|
||||
|
||||
# Build for production (interactive prompt to select package)
|
||||
npm run build
|
||||
|
||||
# Build all packages
|
||||
npm run build all
|
||||
|
||||
# Build everything (packages, i18n, types, docs) + lint
|
||||
npm run build:all
|
||||
```
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
# Lint with auto-fix (covers packages, scripts, tests, docs assets)
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Plugin Development
|
||||
```bash
|
||||
# Create new plugin from template
|
||||
npm run create:plugin <kebab-case-name>
|
||||
|
||||
# Example:
|
||||
npm run create:plugin my-feature
|
||||
```
|
||||
|
||||
### I18n
|
||||
```bash
|
||||
# Build i18n bundles for all languages
|
||||
npm run build:i18n
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
```bash
|
||||
# Generate TypeScript declaration files
|
||||
npm run build:ts
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Player (`packages/artplayer`)
|
||||
|
||||
The main `Artplayer` class extends `Emitter` and initializes sub-components:
|
||||
|
||||
```javascript
|
||||
// Key components instantiated in constructor:
|
||||
this.template = new Template(this) // DOM structure
|
||||
this.events = new Events(this) // Event handling
|
||||
this.player = new Player(this) // Video playback
|
||||
this.controls = new Control(this) // Control bar
|
||||
this.layers = new Layer(this) // Custom layers
|
||||
this.contextmenu = new Contextmenu(this)
|
||||
this.subtitle = new Subtitle(this)
|
||||
this.setting = new Setting(this)
|
||||
this.plugins = new Plugins(this) // Plugin manager
|
||||
// ... and more
|
||||
```
|
||||
|
||||
Source organization in `src/`:
|
||||
- `config/` - Default configuration values
|
||||
- `control/` - UI controls (play, progress, volume, etc.)
|
||||
- `events/` - Event handling (click, hover, resize, etc.)
|
||||
- `i18n/` - Localization files
|
||||
- `icons/` - SVG icons
|
||||
- `player/` - Video playback logic (hls, flv, dash, etc.)
|
||||
- `plugins/` - Built-in plugins
|
||||
- `setting/` - Settings panel components
|
||||
- `style/` - LESS stylesheets
|
||||
- `template.js` - HTML template generation
|
||||
- `utils/` - Utility functions
|
||||
|
||||
### Plugin Architecture
|
||||
|
||||
Plugins are functions that receive the player instance and options:
|
||||
|
||||
```javascript
|
||||
// Template from scripts/plugin/template/src/index.js
|
||||
export default function artplayerPluginTemplate(option = {}) {
|
||||
return (art) => {
|
||||
// Plugin initialization
|
||||
// Access: art.player, art.controls, art.template, etc.
|
||||
|
||||
return {
|
||||
name: 'artplayerPluginTemplate',
|
||||
// Expose methods to art.plugins['artplayerPluginTemplate']
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Plugin naming convention:
|
||||
- Package: `artplayer-plugin-<name>`
|
||||
- Global variable: `artplayerPlugin<Name>` (camelCase)
|
||||
- Exported function uses same name as global
|
||||
|
||||
### Styling
|
||||
|
||||
Uses LESS with inline imports:
|
||||
```javascript
|
||||
import style from './style/index.less?inline'
|
||||
```
|
||||
|
||||
Styles are injected at runtime via `utils.setStyleText()`.
|
||||
|
||||
### Build System
|
||||
|
||||
Uses Vite via custom Node.js scripts:
|
||||
|
||||
**Development** (`scripts/dev.js`):
|
||||
- Builds IIFE bundle to `docs/uncompiled/<package>/`
|
||||
- Serves `docs/` directory on port 8082
|
||||
- Watches source files for changes
|
||||
|
||||
**Production** (`scripts/build.js`):
|
||||
- Builds 3 formats: UMD (`.js`), UMD legacy (`.legacy.js`), ESM (`.mjs`)
|
||||
- Outputs to `packages/<name>/dist/`
|
||||
- Copies to `docs/compiled/`
|
||||
|
||||
### I18n System
|
||||
|
||||
Language files in `packages/artplayer/src/i18n/`:
|
||||
- Base language: `zh-cn.js`
|
||||
- Additional languages: `en.js`, `fr.js`, etc.
|
||||
- Built as separate UMD/ESM bundles via `build-i18n.js`
|
||||
- Global naming: `artplayerI18n<Language>` (e.g., `artplayerI18nEn`)
|
||||
|
||||
### Creating New Plugins
|
||||
|
||||
The `npm run create:plugin <name>` command:
|
||||
1. Copies `scripts/plugin/template/` to `packages/artplayer-plugin-<name>/`
|
||||
2. Replaces placeholders in filenames and content
|
||||
3. Creates example file at `docs/assets/example/<name>.js`
|
||||
|
||||
Plugin template structure:
|
||||
```
|
||||
src/
|
||||
index.js # Main plugin code
|
||||
style.less # Plugin styles
|
||||
package.json
|
||||
README.md
|
||||
types/
|
||||
<name>.d.ts # TypeScript declarations (optional)
|
||||
```
|
||||
|
||||
### Utility Functions
|
||||
|
||||
Core utilities in `packages/artplayer/src/utils/`:
|
||||
- `utils.js` - Common helpers (isMobile, isSafari, query, etc.)
|
||||
- `emitter.js` - Event emitter base class
|
||||
- `scheme.js` - Option validation schema
|
||||
|
||||
## Development Notes
|
||||
|
||||
- **Package manager**: Uses Yarn with Lerna
|
||||
- **Node version**: >= 20.0.0
|
||||
- **ESLint**: Uses @antfu/eslint-config
|
||||
- **Browser support**: Last 1 Chrome version (ES2020), legacy builds target ES2015
|
||||
- **UMD builds**: Always expose global even in AMD/RequireJS environments
|
||||
@@ -1,4 +1,4 @@
|
||||
This project uses `parcel` as a development and packaging tool, so there are few overall configuration options
|
||||
This project uses `vite` as a development and packaging tool, so there are few overall configuration options
|
||||
|
||||
## 1. Install dependencies
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Harvey Zack
|
||||
Copyright (c) 2018 Harvey Zhao
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/artplayer" alt="Size">
|
||||
<img src="https://img.shields.io/npm/dm/artplayer.svg?sanitize=true" alt="Downloads">
|
||||
<img src="https://img.shields.io/npm/v/artplayer.svg?sanitize=true" alt="Version">
|
||||
<img src="https://img.shields.io/npm/l/artplayer.svg?sanitize=true" alt="License">
|
||||
<a href="https://www.npmjs.com/package/artplayer">
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/artplayer" alt="Size">
|
||||
<img src="https://img.shields.io/npm/dm/artplayer.svg?sanitize=true" alt="Downloads">
|
||||
<img src="https://img.shields.io/npm/v/artplayer.svg?sanitize=true" alt="Version">
|
||||
<img src="https://img.shields.io/npm/l/artplayer.svg?sanitize=true" alt="License">
|
||||
<img src="https://data.jsdelivr.com/v1/package/npm/artplayer/badge?style=rounded" alt="jsdelivr">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -20,15 +23,17 @@
|
||||
<span>・</span>
|
||||
<a href="https://artplayer.org/document">API Document</a>
|
||||
<span>・</span>
|
||||
<a href="https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku">弹幕演示</a>
|
||||
<a href="https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku">Danmuku</a>
|
||||
<span>・</span>
|
||||
<a href="./CHANGELOG_CN.md">更新记录</a>
|
||||
<a href="./CHANGELOG.md">Changelog</a>
|
||||
<span>・</span>
|
||||
<a href="https://artplayer.org/llms.txt">🤖LLMs</a>
|
||||
<span>・</span>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://artplayer.org">
|
||||
<img src="./images/screenshot.png" alt="screenshot">
|
||||
<img src="./images/screenshot.png" alt="screenshot" width="720">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -58,8 +63,20 @@ Or install with `yarn`:
|
||||
$ yarn add artplayer
|
||||
```
|
||||
|
||||
Or install with `pnpm`:
|
||||
|
||||
```bash
|
||||
$ pnpm add artplayer
|
||||
```
|
||||
|
||||
Or install with `bun`:
|
||||
|
||||
```bash
|
||||
$ bun add artplayer
|
||||
```
|
||||
|
||||
```js
|
||||
import Artplayer from 'artplayer';
|
||||
import Artplayer from 'artplayer'
|
||||
```
|
||||
|
||||
Or umd build also available:
|
||||
@@ -87,45 +104,53 @@ Will expose the global variable to `window.Artplayer`.
|
||||
```
|
||||
|
||||
```js
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'path/to/video.mp4',
|
||||
});
|
||||
let art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'path/to/video.mp4',
|
||||
})
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
- [artplayer-plugin-danmuku](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku)
|
||||
- [artplayer-plugin-danmuku-mask](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js%0A./uncompiled/artplayer-plugin-danmuku-mask/index.js&example=danmuku.mask) (WIP)
|
||||
- [artplayer-plugin-ads](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ads/index.js&example=ads) (WIP)
|
||||
- [artplayer-plugin-iframe](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-iframe/index.js&example=iframe)
|
||||
- [artplayer-plugin-hls-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js%0A./uncompiled/artplayer-plugin-hls-control/index.js&example=hls.control)
|
||||
- [artplayer-plugin-dash-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.5.2/dash.all.min.js%0A./uncompiled/artplayer-plugin-dash-control/index.js&example=dash.control)
|
||||
- [artplayer-plugin-vtt-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail)
|
||||
- [artplayer-plugin-multiple-subtitles](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles)
|
||||
- [artplayer-plugin-libass](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-libass/index.js&example=libass)
|
||||
- [artplayer-plugin-chromecast](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chromecast/index.js&example=chromecast)
|
||||
- [artplayer-plugin-vast](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vast/index.js&example=vast)
|
||||
- [artplayer-plugin-chapter](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chapter/index.js&example=chapter)
|
||||
- [artplayer-plugin-auto-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-auto-thumbnail/index.js&example=auto.thumbnail)
|
||||
- [artplayer-plugin-ambilight](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ambilight/index.js&example=ambilight)
|
||||
| Name | Describe | State |
|
||||
| :--- | :--- | :--- |
|
||||
| [artplayer-plugin-danmuku](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku) | Danmuku (bullet comment) system | <img src="https://img.shields.io/npm/v/artplayer-plugin-danmuku.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-danmuku.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-hls-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js%0A./uncompiled/artplayer-plugin-hls-control/index.js&example=hls.control) | HLS quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-hls-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-hls-control.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-dash-control](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js%0A./uncompiled/artplayer-plugin-dash-control/index.js&example=dash.control) | DASH quality control | <img src="https://img.shields.io/npm/v/artplayer-plugin-dash-control.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-dash-control.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-vtt-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vtt-thumbnail/index.js&example=vtt.thumbnail) | VTT thumbnail preview | <img src="https://img.shields.io/npm/v/artplayer-plugin-vtt-thumbnail.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-vtt-thumbnail.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-multiple-subtitles](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-multiple-subtitles/index.js&example=multiple.subtitles) | Multiple subtitles support | <img src="https://img.shields.io/npm/v/artplayer-plugin-multiple-subtitles.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-multiple-subtitles.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-chromecast](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chromecast/index.js&example=chromecast) | Google Chromecast support | <img src="https://img.shields.io/npm/v/artplayer-plugin-chromecast.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-chromecast.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-vast](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-vast/index.js&example=vast) | VAST/VPAID advertising | <img src="https://img.shields.io/npm/v/artplayer-plugin-vast.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-vast.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-chapter](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-chapter/index.js&example=chapter) | Video chapters support | <img src="https://img.shields.io/npm/v/artplayer-plugin-chapter.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-chapter.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-auto-thumbnail](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-auto-thumbnail/index.js&example=auto.thumbnail) | Auto-generated thumbnails | <img src="https://img.shields.io/npm/v/artplayer-plugin-auto-thumbnail.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-auto-thumbnail.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-ambilight](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ambilight/index.js&example=ambilight) | Ambilight effect | <img src="https://img.shields.io/npm/v/artplayer-plugin-ambilight.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-ambilight.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-document-pip](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-document-pip/index.js&example=document.pip) | Document Picture-in-Picture | <img src="https://img.shields.io/npm/v/artplayer-plugin-document-pip.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-document-pip.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-audio-track](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-audio-track/index.js&example=audio.track) | Independent audio track playback | <img src="https://img.shields.io/npm/v/artplayer-plugin-audio-track.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-audio-track.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-jassub](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-jassub/index.js&example=jassub) | ASS/SSA subtitle support | <img src="https://img.shields.io/npm/v/artplayer-plugin-jassub.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-jassub.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-danmuku-mask](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js%0A./uncompiled/artplayer-plugin-danmuku-mask/index.js&example=danmuku.mask) | Danmuku masking (smart blocking) | <img src="https://img.shields.io/npm/v/artplayer-plugin-danmuku-mask.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-danmuku-mask.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-asr](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-asr/index.js&example=asr) | Automatic Speech Recognition | <img src="https://img.shields.io/npm/v/artplayer-plugin-asr.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-plugin-asr.svg?sanitize=true"> |
|
||||
| [artplayer-plugin-ads](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ads/index.js&example=ads) | Video advertising plugin | WIP |
|
||||
|
||||
## Libraries
|
||||
|
||||
- [hls.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js&example=hls)
|
||||
- [dash.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/4.5.2/dash.all.min.js&example=dash)
|
||||
- [flv.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.6.2/flv.min.js&example=flv)
|
||||
- [mpegts.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/mpegts.js@1.7.3/dist/mpegts.min.js&example=mpegts)
|
||||
- [webtorrent.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/webtorrent@1/webtorrent.min.js&example=webtorrent)
|
||||
| Name | Describe | State |
|
||||
| :--- | :--- | :--- |
|
||||
| [hls.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js&example=hls) | HLS client | <img src="https://img.shields.io/npm/v/hls.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/hls.js.svg?sanitize=true"> |
|
||||
| [dash.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/dashjs/5.2.1/modern/umd/dash.all.min.js&example=dash) | MPEG DASH player | <img src="https://img.shields.io/npm/v/dashjs.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/dashjs.svg?sanitize=true"> |
|
||||
| [flv.js](https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/flv.js/1.6.2/flv.min.js&example=flv) | HTML5 FLV Player | <img src="https://img.shields.io/npm/v/flv.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/flv.js.svg?sanitize=true"> |
|
||||
| [mpegts.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/mpegts.js@1.7.3/dist/mpegts.min.js&example=mpegts) | MPEG-TS/FLV Player | <img src="https://img.shields.io/npm/v/mpegts.js.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/mpegts.js.svg?sanitize=true"> |
|
||||
| [webtorrent.js](https://artplayer.org/?libs=https://cdn.jsdelivr.net/npm/webtorrent@1/webtorrent.min.js&example=webtorrent) | Streaming torrent client | <img src="https://img.shields.io/npm/v/webtorrent.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/webtorrent.svg?sanitize=true"> |
|
||||
|
||||
## Proxys
|
||||
|
||||
- [Canvas](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-canvas/index.js&example=canvas)
|
||||
- [WebAV](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-webav/index.js&example=webav) (WIP)
|
||||
| Name | Describe | State |
|
||||
| :--- | :--- | :--- |
|
||||
| [Canvas](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-canvas/index.js&example=canvas) | Proxy video to canvas | <img src="https://img.shields.io/npm/v/artplayer-proxy-canvas.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-proxy-canvas.svg?sanitize=true"> |
|
||||
| [Mediabunny](https://artplayer.org/?libs=./uncompiled/artplayer-proxy-mediabunny/index.js&example=mediabunny) | Mediabunny proxy | <img src="https://img.shields.io/npm/v/artplayer-proxy-mediabunny.svg?sanitize=true"><br><img src="https://img.shields.io/npm/dm/artplayer-proxy-mediabunny.svg?sanitize=true"> |
|
||||
|
||||
## Changelog
|
||||
|
||||
[CHANGELOG_CN.md](./CHANGELOG_CN.md)
|
||||
[CHANGELOG.md](./CHANGELOG.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
@@ -137,8 +162,8 @@ We accept donations through these channels:
|
||||
|
||||

|
||||
|
||||
- [Patreon](https://www.patreon.com/artplayer)
|
||||
- [Paypal](https://www.paypal.me/harveyzack)
|
||||
- [Patreon](https://www.patreon.com/artplayer)
|
||||
- [Paypal](https://www.paypal.me/harveyzack)
|
||||
|
||||
## QQ Group
|
||||
|
||||
@@ -146,4 +171,4 @@ We accept donations through these channels:
|
||||
|
||||
## License
|
||||
|
||||
MIT © Harvey Zack
|
||||
MIT © Harvey Zhao
|
||||
@@ -1 +1 @@
|
||||
artplayer.org
|
||||
github.artplayer.org
|
||||
@@ -1,48 +1,48 @@
|
||||
// npm i artplayer-plugin-ads
|
||||
// import artplayerPluginAds from 'artplayer-plugin-ads';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
plugins: [
|
||||
artplayerPluginAds({
|
||||
// html广告,假如是视频广告则忽略该值
|
||||
html: '<img src="/assets/sample/poster.jpg">',
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
plugins: [
|
||||
artplayerPluginAds({
|
||||
// html广告,假如是视频广告则忽略该值
|
||||
html: '<img src="/assets/sample/poster.jpg">',
|
||||
|
||||
// 视频广告的地址
|
||||
video: '/assets/sample/test1.mp4',
|
||||
// 视频广告的地址
|
||||
video: '/assets/sample/test1.mp4',
|
||||
|
||||
// 广告跳转网址,为空则不跳转
|
||||
url: 'http://artplayer.org',
|
||||
// 广告跳转网址,为空则不跳转
|
||||
url: 'http://artplayer.org',
|
||||
|
||||
// 必须观看的时长,期间不能被跳过,单位为秒
|
||||
// 当该值大于或等于totalDuration时,不能提前关闭广告
|
||||
// 当该值等于或小于0时,则随时都可以关闭广告
|
||||
playDuration: 5,
|
||||
// 必须观看的时长,期间不能被跳过,单位为秒
|
||||
// 当该值大于或等于totalDuration时,不能提前关闭广告
|
||||
// 当该值等于或小于0时,则随时都可以关闭广告
|
||||
playDuration: 5,
|
||||
|
||||
// 广告总时长,单位为秒
|
||||
totalDuration: 10,
|
||||
// 广告总时长,单位为秒
|
||||
totalDuration: 10,
|
||||
|
||||
// 多语言支持
|
||||
i18n: {
|
||||
close: '关闭广告',
|
||||
countdown: '%s秒',
|
||||
detail: '查看详情',
|
||||
canBeClosed: '%s秒后可关闭广告',
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
// 多语言支持
|
||||
i18n: {
|
||||
close: '关闭广告',
|
||||
countdown: '%s秒',
|
||||
detail: '查看详情',
|
||||
canBeClosed: '%s秒后可关闭广告',
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
// 广告被点击
|
||||
art.on('artplayerPluginAds:click', (ads) => {
|
||||
console.info('广告被点击', ads);
|
||||
});
|
||||
console.info('广告被点击', ads)
|
||||
})
|
||||
|
||||
// 广告被跳过
|
||||
art.on('artplayerPluginAds:skip', (ads) => {
|
||||
console.info('广告被跳过', ads);
|
||||
});
|
||||
console.info('广告被跳过', ads)
|
||||
})
|
||||
@@ -1,16 +1,16 @@
|
||||
// npm i artplayer-plugin-ambilight
|
||||
// import artplayerPluginAmbilight from 'artplayer-plugin-ambilight';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
plugins: [
|
||||
artplayerPluginAmbilight({
|
||||
blur: '50px',
|
||||
opacity: 1,
|
||||
frequency: 10,
|
||||
duration: 0.3,
|
||||
}),
|
||||
],
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
plugins: [
|
||||
artplayerPluginAmbilight({
|
||||
blur: '50px',
|
||||
opacity: 1,
|
||||
frequency: 10,
|
||||
duration: 0.3,
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -0,0 +1,61 @@
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/steve-jobs.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
moreVideoAttr: {
|
||||
// crossOrigin: 'anonymous',
|
||||
},
|
||||
plugins: [
|
||||
artplayerPluginAsr({
|
||||
length: 2,
|
||||
interval: 40,
|
||||
sampleRate: 16000,
|
||||
autoHideTimeout: 10000,
|
||||
// Use your AI tool to convert pcm into subtitles
|
||||
onAudioChunk: ({ pcm }) => startAsr(pcm),
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
let ws = null
|
||||
let loading = false
|
||||
|
||||
function stopAsr() {
|
||||
try {
|
||||
ws.send(JSON.stringify({ type: 'end' }))
|
||||
ws.close()
|
||||
}
|
||||
catch {}
|
||||
ws = null
|
||||
loading = false
|
||||
}
|
||||
|
||||
async function startAsr(buffer) {
|
||||
if (loading)
|
||||
return
|
||||
if (!ws) {
|
||||
loading = true
|
||||
const api = 'https://api.aimu.app/asr/tencent?engine_model_type=16k_en'
|
||||
const { url } = await (await fetch(api)).json()
|
||||
ws = new WebSocket(url)
|
||||
ws.binaryType = 'arraybuffer'
|
||||
ws.onmessage = (event) => {
|
||||
const { code, result, message } = JSON.parse(event.data)
|
||||
if (code === 0) {
|
||||
art.plugins.artplayerPluginAsr.append(result?.voice_text_str)
|
||||
}
|
||||
else {
|
||||
console.error(code, message)
|
||||
stopAsr()
|
||||
}
|
||||
}
|
||||
loading = false
|
||||
}
|
||||
if (ws?.readyState === WebSocket.OPEN) {
|
||||
ws.send(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
art.on('destroy', stopAsr)
|
||||
@@ -0,0 +1,14 @@
|
||||
// npm i artplayer-plugin-audio-track
|
||||
// import artplayerPluginAudioTrack from 'artplayer-plugin-audio-track';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/sprite-fight.mp4',
|
||||
plugins: [
|
||||
artplayerPluginAudioTrack({
|
||||
url: '/assets/sample/sprite-fight.aac',
|
||||
offset: 0,
|
||||
sync: 0.3,
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -1,12 +1,12 @@
|
||||
// npm i artplayer-plugin-auto-thumbnail
|
||||
// import artplayerPluginAutoThumbnail from 'artplayer-plugin-auto-thumbnail';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
plugins: [
|
||||
artplayerPluginAutoThumbnail({
|
||||
//
|
||||
}),
|
||||
],
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
plugins: [
|
||||
artplayerPluginAutoThumbnail({
|
||||
//
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -1,30 +1,30 @@
|
||||
// npm i artplayer-proxy-canvas
|
||||
// import artplayerProxyCanvas from 'artplayer-proxy-canvas';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
poster: '/assets/sample/poster.jpg',
|
||||
volume: 0.5,
|
||||
autoplay: false,
|
||||
autoSize: false,
|
||||
screenshot: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
pip: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
autoOrientation: true,
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
scale: 0.85,
|
||||
},
|
||||
proxy: artplayerProxyCanvas(),
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
poster: '/assets/sample/poster.jpg',
|
||||
volume: 0.5,
|
||||
autoplay: false,
|
||||
autoSize: false,
|
||||
screenshot: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
pip: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
autoOrientation: true,
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
scale: 0.85,
|
||||
},
|
||||
proxy: artplayerProxyCanvas(),
|
||||
})
|
||||
@@ -1,28 +1,28 @@
|
||||
// npm i artplayer-plugin-chapter
|
||||
// import artplayerPluginChapter from 'artplayer-plugin-chapter';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoOrientation: true,
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
},
|
||||
plugins: [
|
||||
artplayerPluginChapter({
|
||||
chapters: [
|
||||
{ start: 0, end: 18, title: 'One more chance' },
|
||||
{ start: 18, end: 36, title: '谁でもいいはずなのに' },
|
||||
{ start: 36, end: 54, title: '夏の想い出がまわる' },
|
||||
{ start: 54, end: 72, title: 'こんなとこにあるはずもないのに' },
|
||||
{ start: 72, end: Infinity, title: '终わり' },
|
||||
]
|
||||
}),
|
||||
],
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoOrientation: true,
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
},
|
||||
plugins: [
|
||||
artplayerPluginChapter({
|
||||
chapters: [
|
||||
{ start: 0, end: 18, title: 'One more chance' },
|
||||
{ start: 18, end: 36, title: '谁でもいいはずなのに' },
|
||||
{ start: 36, end: 54, title: '夏の想い出がまわる' },
|
||||
{ start: 54, end: 72, title: 'こんなとこにあるはずもないのに' },
|
||||
{ start: 72, end: Infinity, title: '终わり' },
|
||||
],
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -1,15 +1,15 @@
|
||||
// npm i artplayer-plugin-chromecast
|
||||
// import artplayerPluginChromecast from 'artplayer-plugin-chromecast';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
plugins: [
|
||||
artplayerPluginChromecast({
|
||||
// sdk: '', // The URL of the Cast SDK
|
||||
// mimeType: '', // The MIME type of the media
|
||||
}),
|
||||
],
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
plugins: [
|
||||
artplayerPluginChromecast({
|
||||
// sdk: '', // The URL of the Cast SDK
|
||||
// mimeType: '', // The MIME type of the media
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -2,53 +2,53 @@
|
||||
// import artplayerPluginDanmuku from 'artplayer-plugin-danmuku';
|
||||
// 使用文档 https://artplayer.org/document/plugin/danmuku.html
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
autoOrientation: true,
|
||||
plugins: [
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: '/assets/sample/danmuku.xml',
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
autoOrientation: true,
|
||||
plugins: [
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: '/assets/sample/danmuku.xml',
|
||||
|
||||
// 以下为非必填
|
||||
speed: 5, // 弹幕持续时间,范围在[1 ~ 10]
|
||||
margin: [10, '25%'], // 弹幕上下边距,支持像素数字和百分比
|
||||
opacity: 1, // 弹幕透明度,范围在[0 ~ 1]
|
||||
color: '#FFFFFF', // 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
mode: 0, // 默认弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
modes: [0, 1, 2], // 弹幕可见的模式
|
||||
fontSize: 25, // 弹幕字体大小,支持像素数字和百分比
|
||||
antiOverlap: true, // 弹幕是否防重叠
|
||||
synchronousPlayback: false, // 是否同步播放速度
|
||||
mount: undefined, // 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
heatmap: true, // 是否开启热力图
|
||||
width: 512, // 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
points: [], // 热力图数据
|
||||
filter: (danmu) => danmu.text.length <= 100, // 弹幕载入前的过滤器
|
||||
beforeVisible: () => true, // 弹幕显示前的过滤器,返回 true 则可以发送
|
||||
visible: true, // 弹幕层是否可见
|
||||
emitter: true, // 是否开启弹幕发射器
|
||||
maxLength: 200, // 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
lockTime: 5, // 输入框锁定时间,范围在[1 ~ 60]
|
||||
theme: 'dark', // 弹幕主题,支持 dark 和 light,只在自定义挂载时生效
|
||||
OPACITY: {}, // 不透明度配置项
|
||||
FONT_SIZE: {}, // 弹幕字号配置项
|
||||
MARGIN: {}, // 显示区域配置项
|
||||
SPEED: {}, // 弹幕速度配置项
|
||||
COLOR: [], // 颜色列表配置项
|
||||
// 以下为非必填
|
||||
speed: 5, // 弹幕持续时间,范围在[1 ~ 10]
|
||||
margin: [10, '25%'], // 弹幕上下边距,支持像素数字和百分比
|
||||
opacity: 1, // 弹幕透明度,范围在[0 ~ 1]
|
||||
color: '#FFFFFF', // 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
mode: 0, // 默认弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
modes: [0, 1, 2], // 弹幕可见的模式
|
||||
fontSize: 25, // 弹幕字体大小,支持像素数字和百分比
|
||||
antiOverlap: true, // 弹幕是否防重叠
|
||||
synchronousPlayback: false, // 是否同步播放速度
|
||||
mount: undefined, // 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
heatmap: true, // 是否开启热力图
|
||||
width: 512, // 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
points: [], // 热力图数据
|
||||
filter: danmu => danmu.text.length <= 100, // 弹幕载入前的过滤器
|
||||
beforeVisible: () => true, // 弹幕显示前的过滤器,返回 true 则可以发送
|
||||
visible: true, // 弹幕层是否可见
|
||||
emitter: true, // 是否开启弹幕发射器
|
||||
maxLength: 200, // 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
lockTime: 5, // 输入框锁定时间,范围在[1 ~ 60]
|
||||
theme: 'dark', // 弹幕主题,支持 dark 和 light,只在自定义挂载时生效
|
||||
OPACITY: {}, // 不透明度配置项
|
||||
FONT_SIZE: {}, // 弹幕字号配置项
|
||||
MARGIN: {}, // 显示区域配置项
|
||||
SPEED: {}, // 弹幕速度配置项
|
||||
COLOR: [], // 颜色列表配置项
|
||||
|
||||
// 手动发送弹幕前的过滤器,返回 true 则可以发送,可以做存库处理
|
||||
beforeEmit(danmu) {
|
||||
return new Promise((resolve) => {
|
||||
console.log(danmu);
|
||||
setTimeout(() => {
|
||||
resolve(true);
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
// 手动发送弹幕前的过滤器,返回 true 则可以发送,可以做存库处理
|
||||
beforeEmit(danmu) {
|
||||
return new Promise((resolve) => {
|
||||
console.log(danmu)
|
||||
setTimeout(() => {
|
||||
resolve(true)
|
||||
}, 1000)
|
||||
})
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -4,19 +4,19 @@
|
||||
// npm i @mediapipe/selfie_segmentation
|
||||
// 把 node_modules/@mediapipe/selfie_segmentation 目录复制到你的项目下
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
autoOrientation: true,
|
||||
plugins: [
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: '/assets/sample/danmuku.xml'
|
||||
}),
|
||||
artplayerPluginDanmukuMask({
|
||||
solutionPath: '/assets/@mediapipe/selfie_segmentation',
|
||||
}),
|
||||
],
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/steve-jobs.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
autoOrientation: true,
|
||||
plugins: [
|
||||
artplayerPluginDanmuku({
|
||||
danmuku: '/assets/sample/danmuku.xml',
|
||||
}),
|
||||
artplayerPluginDanmukuMask({
|
||||
solutionPath: '/assets/@mediapipe/selfie_segmentation',
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -4,47 +4,49 @@
|
||||
// import dashjs from 'dashjs';
|
||||
// import artplayerPluginDashControl from 'artplayer-plugin-dash-control';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginDashControl({
|
||||
quality: {
|
||||
// Show qualitys in control
|
||||
control: true,
|
||||
// Show qualitys in setting
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: (level) => level.height + 'P',
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: (track) => track.lang.toUpperCase(),
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
}
|
||||
}),
|
||||
],
|
||||
customType: {
|
||||
mpd: function playMpd(video, url, art) {
|
||||
if (dashjs.supportsMediaSource()) {
|
||||
if (art.dash) art.dash.destroy();
|
||||
const dash = dashjs.MediaPlayer().create();
|
||||
dash.initialize(video, url, art.option.autoplay);
|
||||
art.dash = dash;
|
||||
art.on('destroy', () => dash.destroy());
|
||||
} else {
|
||||
art.notice.show = 'Unsupported playback format: mpd';
|
||||
}
|
||||
}
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://media.axprod.net/TestVectors/v7-Clear/Manifest_1080p.mpd',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginDashControl({
|
||||
quality: {
|
||||
// Show qualitys in control
|
||||
control: true,
|
||||
// Show qualitys in setting
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: level => `${level.height}P`,
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: track => track.lang.toUpperCase(),
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
}),
|
||||
],
|
||||
customType: {
|
||||
mpd: function playMpd(video, url, art) {
|
||||
if (dashjs.supportsMediaSource()) {
|
||||
if (art.dash)
|
||||
art.dash.destroy()
|
||||
const dash = dashjs.MediaPlayer().create()
|
||||
dash.initialize(video, url, art.option.autoplay)
|
||||
art.dash = dash
|
||||
art.on('destroy', () => dash.destroy())
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: mpd'
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
})
|
||||
@@ -2,26 +2,28 @@
|
||||
// import dashjs from 'dashjs';
|
||||
|
||||
function playMpd(video, url, art) {
|
||||
if (dashjs.supportsMediaSource()) {
|
||||
if (art.dash) art.dash.destroy();
|
||||
const dash = dashjs.MediaPlayer().create();
|
||||
dash.initialize(video, url, art.option.autoplay);
|
||||
art.dash = dash;
|
||||
art.on('destroy', () => dash.destroy());
|
||||
} else {
|
||||
art.notice.show = 'Unsupported playback format: mpd';
|
||||
}
|
||||
if (dashjs.supportsMediaSource()) {
|
||||
if (art.dash)
|
||||
art.dash.destroy()
|
||||
const dash = dashjs.MediaPlayer().create()
|
||||
dash.initialize(video, url, art.option.autoplay)
|
||||
art.dash = dash
|
||||
art.on('destroy', () => dash.destroy())
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: mpd'
|
||||
}
|
||||
}
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd',
|
||||
type: 'mpd',
|
||||
customType: {
|
||||
mpd: playMpd
|
||||
},
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd',
|
||||
type: 'mpd',
|
||||
customType: {
|
||||
mpd: playMpd,
|
||||
},
|
||||
})
|
||||
|
||||
art.on('ready', () => {
|
||||
console.info(art.dash);
|
||||
});
|
||||
console.info(art.dash)
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
// npm i artplayer-plugin-document-pip
|
||||
// import artplayerPluginDocumentPip from 'artplayer-plugin-document-pip';
|
||||
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
plugins: [
|
||||
artplayerPluginDocumentPip({
|
||||
width: 480,
|
||||
height: 270,
|
||||
fallbackToVideoPiP: true,
|
||||
placeholder: `Playing in Document Picture-in-Picture`,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
art.on('document-pip', (state) => {
|
||||
console.log('Document Picture-in-Picture', state)
|
||||
})
|
||||
@@ -2,27 +2,29 @@
|
||||
// import flvjs from 'flv.js';
|
||||
|
||||
function playFlv(video, url, art) {
|
||||
if (flvjs.isSupported()) {
|
||||
if (art.flv) art.flv.destroy();
|
||||
const flv = flvjs.createPlayer({ type: 'flv', url });
|
||||
flv.attachMediaElement(video);
|
||||
flv.load();
|
||||
art.flv = flv;
|
||||
art.on('destroy', () => flv.destroy());
|
||||
} else {
|
||||
art.notice.show = 'Unsupported playback format: flv';
|
||||
}
|
||||
if (flvjs.isSupported()) {
|
||||
if (art.flv)
|
||||
art.flv.destroy()
|
||||
const flv = flvjs.createPlayer({ type: 'flv', url })
|
||||
flv.attachMediaElement(video)
|
||||
flv.load()
|
||||
art.flv = flv
|
||||
art.on('destroy', () => flv.destroy())
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: flv'
|
||||
}
|
||||
}
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.flv',
|
||||
type: 'flv',
|
||||
customType: {
|
||||
flv: playFlv,
|
||||
},
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.flv',
|
||||
type: 'flv',
|
||||
customType: {
|
||||
flv: playFlv,
|
||||
},
|
||||
})
|
||||
|
||||
art.on('ready', () => {
|
||||
console.info(art.flv);
|
||||
});
|
||||
console.info(art.flv)
|
||||
})
|
||||
@@ -4,50 +4,53 @@
|
||||
// import Hls from 'hls.js';
|
||||
// import artplayerPluginHlsControl from 'artplayer-plugin-hls-control';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginHlsControl({
|
||||
quality: {
|
||||
// Show qualitys in control
|
||||
control: true,
|
||||
// Show qualitys in setting
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: (level) => level.height + 'P',
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: (track) => track.name,
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
}
|
||||
}),
|
||||
],
|
||||
customType: {
|
||||
m3u8: function playM3u8(video, url, art) {
|
||||
if (Hls.isSupported()) {
|
||||
if (art.hls) art.hls.destroy();
|
||||
const hls = new Hls();
|
||||
hls.loadSource(url);
|
||||
hls.attachMedia(video);
|
||||
art.hls = hls;
|
||||
art.on('destroy', () => hls.destroy());
|
||||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
video.src = url;
|
||||
} else {
|
||||
art.notice.show = 'Unsupported playback format: m3u8';
|
||||
}
|
||||
}
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://playertest.longtailvideo.com/adaptive/elephants_dream_v4/index.m3u8',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginHlsControl({
|
||||
quality: {
|
||||
// Show qualitys in control
|
||||
control: true,
|
||||
// Show qualitys in setting
|
||||
setting: true,
|
||||
// Get the quality name from level
|
||||
getName: level => `${level.height}P`,
|
||||
// I18n
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
// Show audios in control
|
||||
control: true,
|
||||
// Show audios in setting
|
||||
setting: true,
|
||||
// Get the audio name from track
|
||||
getName: track => track.name,
|
||||
// I18n
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
}),
|
||||
],
|
||||
customType: {
|
||||
m3u8: function playM3u8(video, url, art) {
|
||||
if (Hls.isSupported()) {
|
||||
if (art.hls)
|
||||
art.hls.destroy()
|
||||
const hls = new Hls()
|
||||
hls.loadSource(url)
|
||||
hls.attachMedia(video)
|
||||
art.hls = hls
|
||||
art.on('destroy', () => hls.destroy())
|
||||
}
|
||||
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
video.src = url
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: m3u8'
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
})
|
||||
@@ -2,29 +2,32 @@
|
||||
// import Hls from 'hls.js';
|
||||
|
||||
function playM3u8(video, url, art) {
|
||||
if (Hls.isSupported()) {
|
||||
if (art.hls) art.hls.destroy();
|
||||
const hls = new Hls();
|
||||
hls.loadSource(url);
|
||||
hls.attachMedia(video);
|
||||
art.hls = hls;
|
||||
art.on('destroy', () => hls.destroy());
|
||||
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
video.src = url;
|
||||
} else {
|
||||
art.notice.show = 'Unsupported playback format: m3u8';
|
||||
}
|
||||
if (Hls.isSupported()) {
|
||||
if (art.hls)
|
||||
art.hls.destroy()
|
||||
const hls = new Hls()
|
||||
hls.loadSource(url)
|
||||
hls.attachMedia(video)
|
||||
art.hls = hls
|
||||
art.on('destroy', () => hls.destroy())
|
||||
}
|
||||
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||
video.src = url
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: m3u8'
|
||||
}
|
||||
}
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
||||
type: 'm3u8',
|
||||
customType: {
|
||||
m3u8: playM3u8,
|
||||
},
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
||||
type: 'm3u8',
|
||||
customType: {
|
||||
m3u8: playM3u8,
|
||||
},
|
||||
})
|
||||
|
||||
art.on('ready', () => {
|
||||
console.info(art.hls);
|
||||
});
|
||||
console.info(art.hls)
|
||||
})
|
||||
@@ -1,46 +1,47 @@
|
||||
// npm i artplayer-plugin-iframe
|
||||
// import ArtplayerPluginIframe from 'artplayer-plugin-iframe';
|
||||
// npm i artplayer-tool-iframe
|
||||
// import ArtplayerToolIframe from 'artplayer-tool-iframe';
|
||||
|
||||
const $iframe = document.createElement('iframe');
|
||||
$iframe.allowFullscreen = true;
|
||||
$iframe.width = '100%';
|
||||
$iframe.height = '100%';
|
||||
const $iframe = document.createElement('iframe')
|
||||
$iframe.allowFullscreen = true
|
||||
$iframe.width = '100%'
|
||||
$iframe.height = '100%'
|
||||
|
||||
const $container = document.querySelector('.artplayer-app');
|
||||
$container.innerHTML = '';
|
||||
$container.appendChild($iframe);
|
||||
const $container = document.querySelector('.artplayer-app')
|
||||
$container.innerHTML = ''
|
||||
$container.appendChild($iframe)
|
||||
|
||||
const iframe = new ArtplayerPluginIframe({
|
||||
iframe: $iframe,
|
||||
url: '/iframe.html',
|
||||
});
|
||||
const iframe = new ArtplayerToolIframe({
|
||||
iframe: $iframe,
|
||||
url: '/iframe.html',
|
||||
})
|
||||
|
||||
iframe.message(({ type, data }) => {
|
||||
switch (type) {
|
||||
case 'fullscreenWeb':
|
||||
if (data) {
|
||||
$iframe.classList.add('fullscreenWeb');
|
||||
} else {
|
||||
$iframe.classList.remove('fullscreenWeb');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
switch (type) {
|
||||
case 'fullscreenWeb':
|
||||
if (data) {
|
||||
$iframe.classList.add('fullscreenWeb')
|
||||
}
|
||||
else {
|
||||
$iframe.classList.remove('fullscreenWeb')
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
iframe.commit(() => {
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
})
|
||||
|
||||
art.on('fullscreenWeb', (state) => {
|
||||
ArtplayerPluginIframe.postMessage({
|
||||
type: 'fullscreenWeb',
|
||||
data: state,
|
||||
});
|
||||
});
|
||||
});
|
||||
art.on('fullscreenWeb', (state) => {
|
||||
ArtplayerToolIframe.postMessage({
|
||||
type: 'fullscreenWeb',
|
||||
data: state,
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,182 +1,190 @@
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
poster: '/assets/sample/poster.jpg',
|
||||
volume: 0.5,
|
||||
isLive: false,
|
||||
muted: false,
|
||||
autoplay: false,
|
||||
pip: true,
|
||||
autoSize: true,
|
||||
autoMini: true,
|
||||
screenshot: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
subtitleOffset: true,
|
||||
miniProgressBar: true,
|
||||
mutex: true,
|
||||
backdrop: true,
|
||||
playsInline: true,
|
||||
autoPlayback: true,
|
||||
airplay: true,
|
||||
theme: '#23ade5',
|
||||
lang: navigator.language.toLowerCase(),
|
||||
moreVideoAttr: {
|
||||
crossOrigin: 'anonymous',
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
poster: '/assets/sample/poster.jpg',
|
||||
volume: 0.5,
|
||||
isLive: false,
|
||||
muted: false,
|
||||
autoplay: false,
|
||||
pip: true,
|
||||
autoSize: true,
|
||||
autoMini: true,
|
||||
screenshot: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
subtitleOffset: true,
|
||||
miniProgressBar: true,
|
||||
mutex: true,
|
||||
backdrop: true,
|
||||
playsInline: true,
|
||||
autoPlayback: true,
|
||||
airplay: true,
|
||||
theme: '#23ade5',
|
||||
lang: navigator.language.toLowerCase(),
|
||||
moreVideoAttr: {
|
||||
crossOrigin: 'anonymous',
|
||||
},
|
||||
settings: [
|
||||
{
|
||||
width: 200,
|
||||
html: 'Subtitle',
|
||||
tooltip: 'Bilingual',
|
||||
icon: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
html: 'Display',
|
||||
tooltip: 'Show',
|
||||
switch: true,
|
||||
onSwitch(item) {
|
||||
item.tooltip = item.switch ? 'Hide' : 'Show'
|
||||
art.subtitle.show = !item.switch
|
||||
return !item.switch
|
||||
},
|
||||
},
|
||||
{
|
||||
default: true,
|
||||
html: 'Bilingual',
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
},
|
||||
{
|
||||
html: 'Chinese',
|
||||
url: '/assets/sample/subtitle.cn.srt',
|
||||
},
|
||||
{
|
||||
html: 'Japanese',
|
||||
url: '/assets/sample/subtitle.jp.srt',
|
||||
},
|
||||
],
|
||||
onSelect(item) {
|
||||
art.subtitle.switch(item.url, {
|
||||
name: item.html,
|
||||
})
|
||||
return item.html
|
||||
},
|
||||
},
|
||||
settings: [
|
||||
{
|
||||
width: 200,
|
||||
html: 'Subtitle',
|
||||
tooltip: 'Bilingual',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
html: 'Display',
|
||||
tooltip: 'Show',
|
||||
switch: true,
|
||||
onSwitch: function (item) {
|
||||
item.tooltip = item.switch ? 'Hide' : 'Show';
|
||||
art.subtitle.show = !item.switch;
|
||||
return !item.switch;
|
||||
},
|
||||
},
|
||||
{
|
||||
default: true,
|
||||
html: 'Bilingual',
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
},
|
||||
{
|
||||
html: 'Chinese',
|
||||
url: '/assets/sample/subtitle.cn.srt',
|
||||
},
|
||||
{
|
||||
html: 'Japanese',
|
||||
url: '/assets/sample/subtitle.jp.srt',
|
||||
},
|
||||
],
|
||||
onSelect: function (item) {
|
||||
art.subtitle.switch(item.url, {
|
||||
name: item.html,
|
||||
});
|
||||
return item.html;
|
||||
},
|
||||
},
|
||||
{
|
||||
html: 'Switcher',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/state.svg">',
|
||||
tooltip: 'OFF',
|
||||
switch: false,
|
||||
onSwitch: function (item) {
|
||||
item.tooltip = item.switch ? 'OFF' : 'ON';
|
||||
console.info('You clicked on the custom switch', item.switch);
|
||||
return !item.switch;
|
||||
},
|
||||
},
|
||||
{
|
||||
html: 'Slider',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/state.svg">',
|
||||
tooltip: '5x',
|
||||
range: [5, 1, 10, 0.1],
|
||||
onRange: function (item) {
|
||||
return item.range[0] + 'x';
|
||||
},
|
||||
},
|
||||
],
|
||||
contextmenu: [
|
||||
{
|
||||
html: 'Custom menu',
|
||||
click: function (contextmenu) {
|
||||
console.info('You clicked on the custom menu');
|
||||
contextmenu.show = false;
|
||||
},
|
||||
},
|
||||
],
|
||||
layers: [
|
||||
{
|
||||
html: '<img width="100" src="/assets/sample/layer.png">',
|
||||
click: function () {
|
||||
window.open('https://aimu.app');
|
||||
console.info('You clicked on the custom layer');
|
||||
},
|
||||
style: {
|
||||
position: 'absolute',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
opacity: '.9',
|
||||
},
|
||||
},
|
||||
],
|
||||
quality: [
|
||||
{
|
||||
default: true,
|
||||
html: 'SD 480P',
|
||||
url: '/assets/sample/video.mp4?q=480',
|
||||
},
|
||||
{
|
||||
html: 'HD 720P',
|
||||
url: '/assets/sample/video.mp4?q=720',
|
||||
},
|
||||
],
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
scale: 0.85,
|
||||
{
|
||||
html: 'Switcher',
|
||||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||||
tooltip: 'OFF',
|
||||
switch: false,
|
||||
onSwitch(item) {
|
||||
item.tooltip = item.switch ? 'OFF' : 'ON'
|
||||
console.info('You clicked on the custom switch', item.switch)
|
||||
return !item.switch
|
||||
},
|
||||
},
|
||||
subtitle: {
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
type: 'srt',
|
||||
style: {
|
||||
color: '#fe9200',
|
||||
fontSize: '20px',
|
||||
},
|
||||
encoding: 'utf-8',
|
||||
{
|
||||
html: 'Slider',
|
||||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||||
tooltip: '5x',
|
||||
range: [5, 1, 10, 0.1],
|
||||
onRange(item) {
|
||||
return `${item.range[0]}x`
|
||||
},
|
||||
},
|
||||
highlight: [
|
||||
{
|
||||
time: 15,
|
||||
text: 'One more chance',
|
||||
},
|
||||
{
|
||||
time: 30,
|
||||
text: '谁でもいいはずなのに',
|
||||
},
|
||||
{
|
||||
time: 45,
|
||||
text: '夏の想い出がまわる',
|
||||
},
|
||||
{
|
||||
time: 60,
|
||||
text: 'こんなとこにあるはずもないのに',
|
||||
},
|
||||
{
|
||||
time: 75,
|
||||
text: '终わり',
|
||||
},
|
||||
],
|
||||
controls: [
|
||||
{
|
||||
position: 'right',
|
||||
html: 'Control',
|
||||
index: 1,
|
||||
tooltip: 'Control Tooltip',
|
||||
style: {
|
||||
marginRight: '20px',
|
||||
},
|
||||
click: function () {
|
||||
console.info('You clicked on the custom control');
|
||||
},
|
||||
},
|
||||
],
|
||||
icons: {
|
||||
loading: '<img src="/assets/img/ploading.gif">',
|
||||
state: '<img width="150" heigth="150" src="/assets/img/state.svg">',
|
||||
indicator: '<img width="16" heigth="16" src="/assets/img/indicator.svg">',
|
||||
{
|
||||
html: 'Button',
|
||||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||||
tooltip: 'tooltip',
|
||||
onClick() {
|
||||
return 'Button clicked'
|
||||
},
|
||||
},
|
||||
});
|
||||
],
|
||||
contextmenu: [
|
||||
{
|
||||
html: 'Custom menu',
|
||||
click(contextmenu) {
|
||||
console.info('You clicked on the custom menu')
|
||||
contextmenu.show = false
|
||||
},
|
||||
},
|
||||
],
|
||||
layers: [
|
||||
{
|
||||
html: '<img width="100" src="/assets/sample/layer.png">',
|
||||
click() {
|
||||
window.open('https://aimu.app')
|
||||
console.info('You clicked on the custom layer')
|
||||
},
|
||||
style: {
|
||||
position: 'absolute',
|
||||
top: '20px',
|
||||
right: '20px',
|
||||
opacity: '.9',
|
||||
},
|
||||
},
|
||||
],
|
||||
quality: [
|
||||
{
|
||||
default: true,
|
||||
html: 'SD 480P',
|
||||
url: '/assets/sample/video.mp4?q=480',
|
||||
},
|
||||
{
|
||||
html: 'HD 720P',
|
||||
url: '/assets/sample/video.mp4?q=720',
|
||||
},
|
||||
],
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
scale: 0.85,
|
||||
},
|
||||
subtitle: {
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
type: 'srt',
|
||||
style: {
|
||||
color: '#fe9200',
|
||||
fontSize: '20px',
|
||||
},
|
||||
encoding: 'utf-8',
|
||||
},
|
||||
highlight: [
|
||||
{
|
||||
time: 15,
|
||||
text: 'One more chance',
|
||||
},
|
||||
{
|
||||
time: 30,
|
||||
text: '谁でもいいはずなのに',
|
||||
},
|
||||
{
|
||||
time: 45,
|
||||
text: '夏の想い出がまわる',
|
||||
},
|
||||
{
|
||||
time: 60,
|
||||
text: 'こんなとこにあるはずもないのに',
|
||||
},
|
||||
{
|
||||
time: 75,
|
||||
text: '终わり',
|
||||
},
|
||||
],
|
||||
controls: [
|
||||
{
|
||||
position: 'right',
|
||||
html: 'Control',
|
||||
index: 1,
|
||||
tooltip: 'Control Tooltip',
|
||||
style: {
|
||||
marginRight: '20px',
|
||||
},
|
||||
click() {
|
||||
console.info('You clicked on the custom control')
|
||||
},
|
||||
},
|
||||
],
|
||||
icons: {
|
||||
loading: '<img src="/assets/img/ploading.gif">',
|
||||
state: '<img width="150" height="150" src="/assets/img/state.svg">',
|
||||
indicator: '<img width="16" height="16" src="/assets/img/indicator.svg">',
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,28 @@
|
||||
// https://github.com/ThaUnknown/jassub
|
||||
// npm i artplayer-plugin-jassub
|
||||
// import artplayerPluginJassub from 'artplayer-plugin-jassub';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/jassub/FGOBD.mp4',
|
||||
autoSize: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
plugins: [
|
||||
artplayerPluginJassub({
|
||||
subUrl: '/assets/jassub/FGOBD.ass',
|
||||
workerUrl: '/assets/jassub/jassub-worker.js',
|
||||
wasmUrl: '/assets/jassub/jassub-worker.wasm',
|
||||
modernWasmUrl: '/assets/jassub/jassub-worker-modern.wasm',
|
||||
availableFonts: {
|
||||
'liberation sans': '/assets/jassub/default.woff2'
|
||||
},
|
||||
fonts: [
|
||||
'/assets/jassub/fonts/Averia Sans Libre Light.ttf',
|
||||
'/assets/jassub/fonts/Averia Serif Simple Light.ttf',
|
||||
'/assets/jassub/fonts/Gramond.ttf'
|
||||
],
|
||||
timeOffset: -0.041
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -1,44 +0,0 @@
|
||||
// npm i artplayer-plugin-libass
|
||||
// import artplayerPluginLibass from 'artplayer-plugin-libass';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
fullscreenWeb: true,
|
||||
subtitle: {
|
||||
url: '/assets/sample/style-test.ass',
|
||||
},
|
||||
plugins: [
|
||||
artplayerPluginLibass({
|
||||
// debug: true,
|
||||
workerUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.js',
|
||||
// wasmUrl: 'https://unpkg.com/libass-wasm@4.1.0/dist/js/subtitles-octopus-worker.wasm',
|
||||
fallbackFont: '/assets/misc/SourceHanSansCN-Bold.woff2'
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// init
|
||||
art.on('artplayerPluginLibass:init', (adapter) => {
|
||||
console.info('artplayerPluginLibass:init', adapter);
|
||||
});
|
||||
|
||||
// subtitle switch
|
||||
art.on('artplayerPluginLibass:switch', (url) => {
|
||||
console.info('artplayerPluginLibass:switch', url);
|
||||
})
|
||||
|
||||
// subtitle visible
|
||||
art.on('artplayerPluginLibass:visible', (visible) => {
|
||||
console.info('artplayerPluginLibass:visible', visible);
|
||||
})
|
||||
|
||||
// subtitle timeOffset
|
||||
art.on('artplayerPluginLibass:timeOffset', (timeOffset) => {
|
||||
console.info('artplayerPluginLibass:timeOffset', timeOffset);
|
||||
})
|
||||
|
||||
// destroy
|
||||
art.on('artplayerPluginLibass:destroy', () => {
|
||||
console.info('artplayerPluginLibass:destroy');
|
||||
})
|
||||
@@ -0,0 +1,35 @@
|
||||
// npm i artplayer-proxy-mediabunny
|
||||
// import artplayerProxyMediabunny from 'artplayer-proxy-mediabunny';
|
||||
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8',
|
||||
autoSize: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
autoOrientation: true,
|
||||
proxy: artplayerProxyMediabunny({
|
||||
m3u8: {
|
||||
quality: {
|
||||
control: true,
|
||||
setting: true,
|
||||
getName: level => level.height ? `${level.height}P` : level.name,
|
||||
title: 'Quality',
|
||||
auto: 'Auto',
|
||||
},
|
||||
audio: {
|
||||
control: true,
|
||||
setting: true,
|
||||
getName: track => track.name || track.language,
|
||||
title: 'Audio',
|
||||
auto: 'Auto',
|
||||
},
|
||||
},
|
||||
}),
|
||||
})
|
||||
@@ -1,98 +1,98 @@
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
poster: '/assets/sample/poster.jpg',
|
||||
autoSize: true,
|
||||
loop: true,
|
||||
mutex: true,
|
||||
setting: true,
|
||||
flip: true,
|
||||
lock: true,
|
||||
fastForward: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
theme: '#ff0057',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoOrientation: true,
|
||||
airplay: true,
|
||||
moreVideoAttr: {
|
||||
'x5-video-player-type': 'h5',
|
||||
'x5-video-player-fullscreen': false,
|
||||
'x5-video-orientation': 'portraint',
|
||||
preload: "metadata"
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
poster: '/assets/sample/poster.jpg',
|
||||
autoSize: true,
|
||||
loop: true,
|
||||
mutex: true,
|
||||
setting: true,
|
||||
flip: true,
|
||||
lock: true,
|
||||
fastForward: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
theme: '#ff0057',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoOrientation: true,
|
||||
airplay: true,
|
||||
moreVideoAttr: {
|
||||
'x5-video-player-type': 'h5',
|
||||
'x5-video-player-fullscreen': false,
|
||||
'x5-video-orientation': 'portraint',
|
||||
'preload': 'metadata',
|
||||
},
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
scale: 0.6,
|
||||
},
|
||||
subtitle: {
|
||||
name: '中日双语',
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
style: {
|
||||
color: '#48aff0',
|
||||
fontSize: '16px',
|
||||
},
|
||||
thumbnails: {
|
||||
url: '/assets/sample/thumbnails.png',
|
||||
number: 60,
|
||||
column: 10,
|
||||
scale: 0.6
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
html: `<img width="50" src="/assets/sample/layer.png">`,
|
||||
click() {
|
||||
art.notice.show = '你点击了自定义层'
|
||||
},
|
||||
style: {
|
||||
position: 'absolute',
|
||||
top: '10px',
|
||||
right: '10px',
|
||||
opacity: '.9',
|
||||
},
|
||||
},
|
||||
subtitle: {
|
||||
name: '中日双语',
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
style: {
|
||||
color: '#48aff0',
|
||||
fontSize: '16px',
|
||||
},
|
||||
},
|
||||
layers: [
|
||||
],
|
||||
icons: {
|
||||
loading: '<img src="/assets/img/ploading.gif">',
|
||||
state: '<img width="150" height="150" src="/assets/img/state.svg">',
|
||||
indicator: '<img width="16" height="16" src="/assets/img/indicator.svg">',
|
||||
},
|
||||
settings: [
|
||||
{
|
||||
width: 200,
|
||||
html: '切换字幕',
|
||||
tooltip: '双语',
|
||||
icon: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
html: `<img width="50" src="/assets/sample/layer.png">`,
|
||||
click: function () {
|
||||
art.notice.show = "你点击了自定义层";
|
||||
},
|
||||
style: {
|
||||
position: 'absolute',
|
||||
top: '10px',
|
||||
right: '10px',
|
||||
opacity: '.9',
|
||||
},
|
||||
html: '开关',
|
||||
switch: true,
|
||||
tooltip: '显示',
|
||||
onSwitch(item) {
|
||||
item.tooltip = item.switch ? '隐藏' : '显示'
|
||||
art.subtitle.show = !item.switch
|
||||
return !item.switch
|
||||
},
|
||||
},
|
||||
],
|
||||
icons: {
|
||||
loading: '<img src="/assets/img/ploading.gif">',
|
||||
state: '<img width="150" heigth="150" src="/assets/img/state.svg">',
|
||||
indicator: '<img width="16" heigth="16" src="/assets/img/indicator.svg">',
|
||||
},
|
||||
settings: [
|
||||
{
|
||||
width: 200,
|
||||
html: '切换字幕',
|
||||
tooltip: '双语',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
html: '开关',
|
||||
switch: true,
|
||||
tooltip: '显示',
|
||||
onSwitch: function (item) {
|
||||
item.tooltip = item.switch ? '隐藏' : '显示';
|
||||
art.subtitle.show = !item.switch;
|
||||
return !item.switch;
|
||||
},
|
||||
},
|
||||
{
|
||||
default: true,
|
||||
html: '双语',
|
||||
url: '/assets/sample/subtitle.srt'
|
||||
},
|
||||
{
|
||||
html: '中文',
|
||||
url: '/assets/sample/subtitle.cn.srt'
|
||||
},
|
||||
{
|
||||
html: '日文',
|
||||
url: '/assets/sample/subtitle.jp.srt'
|
||||
},
|
||||
],
|
||||
onSelect: function (item) {
|
||||
art.subtitle.switch(item.url, {
|
||||
name: item.html
|
||||
});
|
||||
return item.html;
|
||||
},
|
||||
default: true,
|
||||
html: '双语',
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
},
|
||||
],
|
||||
});
|
||||
{
|
||||
html: '中文',
|
||||
url: '/assets/sample/subtitle.cn.srt',
|
||||
},
|
||||
{
|
||||
html: '日文',
|
||||
url: '/assets/sample/subtitle.jp.srt',
|
||||
},
|
||||
],
|
||||
onSelect(item) {
|
||||
art.subtitle.switch(item.url, {
|
||||
name: item.html,
|
||||
})
|
||||
return item.html
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
@@ -2,33 +2,35 @@
|
||||
// import mpegts from 'mpegts';
|
||||
|
||||
function playFlv(video, url, art) {
|
||||
if (mpegts.isSupported()) {
|
||||
if (art.flv) art.flv.destroy();
|
||||
if (mpegts.isSupported()) {
|
||||
if (art.flv)
|
||||
art.flv.destroy()
|
||||
|
||||
const flv = mpegts.createPlayer({
|
||||
type: 'flv',
|
||||
url: url
|
||||
});
|
||||
flv.attachMediaElement(video);
|
||||
flv.load();
|
||||
flv.play();
|
||||
const flv = mpegts.createPlayer({
|
||||
type: 'flv',
|
||||
url,
|
||||
})
|
||||
flv.attachMediaElement(video)
|
||||
flv.load()
|
||||
flv.play()
|
||||
|
||||
art.flv = flv;
|
||||
art.on('destroy', () => flv.destroy());
|
||||
} else {
|
||||
art.notice.show = 'Unsupported playback format: flv';
|
||||
}
|
||||
art.flv = flv
|
||||
art.on('destroy', () => flv.destroy())
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: flv'
|
||||
}
|
||||
}
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.flv',
|
||||
type: 'flv',
|
||||
customType: {
|
||||
flv: playFlv,
|
||||
},
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.flv',
|
||||
type: 'flv',
|
||||
customType: {
|
||||
flv: playFlv,
|
||||
},
|
||||
})
|
||||
|
||||
art.on('ready', () => {
|
||||
console.info(art.flv);
|
||||
});
|
||||
console.info(art.flv)
|
||||
})
|
||||
@@ -2,88 +2,89 @@
|
||||
// import artplayerPluginMultipleSubtitles from 'artplayer-plugin-multiple-subtitles';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginMultipleSubtitles({
|
||||
subtitles: [
|
||||
{
|
||||
name: 'chinese',
|
||||
url: '/assets/sample/subtitle.cn.srt',
|
||||
},
|
||||
{
|
||||
name: 'japanese',
|
||||
url: '/assets/sample/subtitle.jp.srt',
|
||||
}
|
||||
],
|
||||
})
|
||||
],
|
||||
settings: [
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
setting: true,
|
||||
plugins: [
|
||||
artplayerPluginMultipleSubtitles({
|
||||
subtitles: [
|
||||
{
|
||||
width: 200,
|
||||
html: 'Subtitle',
|
||||
tooltip: 'Double',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
html: 'Display',
|
||||
tooltip: 'Show',
|
||||
switch: true,
|
||||
onSwitch: function (item) {
|
||||
item.tooltip = item.switch ? 'Hide' : 'Show';
|
||||
// 显示/隐藏字幕
|
||||
// Show/hide subtitles
|
||||
art.subtitle.show = !item.switch;
|
||||
return !item.switch;
|
||||
},
|
||||
},
|
||||
{
|
||||
html: 'Reverse',
|
||||
tooltip: 'Off',
|
||||
switch: false,
|
||||
onSwitch: function (item) {
|
||||
item.tooltip = item.switch ? 'Off' : 'On';
|
||||
// 修改字幕顺序
|
||||
// Change the order of subtitles
|
||||
if (item.switch) {
|
||||
art.plugins.multipleSubtitles.tracks(['chinese', 'japanese']);
|
||||
} else {
|
||||
art.plugins.multipleSubtitles.tracks(['japanese', 'chinese']);
|
||||
|
||||
}
|
||||
return !item.switch;
|
||||
},
|
||||
},
|
||||
{
|
||||
default: true,
|
||||
html: 'Double',
|
||||
name: 'double',
|
||||
},
|
||||
{
|
||||
html: 'Chinese',
|
||||
name: 'chinese',
|
||||
},
|
||||
{
|
||||
html: 'Japanese',
|
||||
name: 'japanese',
|
||||
},
|
||||
],
|
||||
onSelect: function (item) {
|
||||
if (item.name === 'double') {
|
||||
// 重置字幕
|
||||
// Reset subtitles
|
||||
art.plugins.multipleSubtitles.reset();
|
||||
} else {
|
||||
// 显示单个字幕
|
||||
// Show single subtitle
|
||||
art.plugins.multipleSubtitles.tracks([item.name]);
|
||||
}
|
||||
return item.html;
|
||||
},
|
||||
name: 'chinese',
|
||||
url: '/assets/sample/subtitle.cn.srt',
|
||||
},
|
||||
],
|
||||
});
|
||||
{
|
||||
name: 'japanese',
|
||||
url: '/assets/sample/subtitle.jp.srt',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
settings: [
|
||||
{
|
||||
width: 200,
|
||||
html: 'Subtitle',
|
||||
tooltip: 'Double',
|
||||
icon: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
html: 'Display',
|
||||
tooltip: 'Show',
|
||||
switch: true,
|
||||
onSwitch(item) {
|
||||
item.tooltip = item.switch ? 'Hide' : 'Show'
|
||||
// 显示/隐藏字幕
|
||||
// Show/hide subtitles
|
||||
art.subtitle.show = !item.switch
|
||||
return !item.switch
|
||||
},
|
||||
},
|
||||
{
|
||||
html: 'Reverse',
|
||||
tooltip: 'Off',
|
||||
switch: false,
|
||||
onSwitch(item) {
|
||||
item.tooltip = item.switch ? 'Off' : 'On'
|
||||
// 修改字幕顺序
|
||||
// Change the order of subtitles
|
||||
if (item.switch) {
|
||||
art.plugins.multipleSubtitles.tracks(['chinese', 'japanese'])
|
||||
}
|
||||
else {
|
||||
art.plugins.multipleSubtitles.tracks(['japanese', 'chinese'])
|
||||
}
|
||||
return !item.switch
|
||||
},
|
||||
},
|
||||
{
|
||||
default: true,
|
||||
html: 'Double',
|
||||
name: 'double',
|
||||
},
|
||||
{
|
||||
html: 'Chinese',
|
||||
name: 'chinese',
|
||||
},
|
||||
{
|
||||
html: 'Japanese',
|
||||
name: 'japanese',
|
||||
},
|
||||
],
|
||||
onSelect(item) {
|
||||
if (item.name === 'double') {
|
||||
// 重置字幕
|
||||
// Reset subtitles
|
||||
art.plugins.multipleSubtitles.reset()
|
||||
}
|
||||
else {
|
||||
// 显示单个字幕
|
||||
// Show single subtitle
|
||||
art.plugins.multipleSubtitles.tracks([item.name])
|
||||
}
|
||||
return item.html
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
// 自定义你自己的样式,请勿复制以下代码
|
||||
// Customize your own style, please do not copy the following code
|
||||
@@ -98,14 +99,15 @@ const style = `
|
||||
color: yellow;
|
||||
font-size: 12px;
|
||||
}
|
||||
`;
|
||||
`
|
||||
|
||||
const $style = document.getElementById('artplayer-subtitle-style');
|
||||
const $style = document.getElementById('artplayer-subtitle-style')
|
||||
if ($style) {
|
||||
$style.textContent = style;
|
||||
} else {
|
||||
const $style = document.createElement('style');
|
||||
$style.id = 'artplayer-subtitle-style';
|
||||
$style.textContent = style;
|
||||
document.head.appendChild($style);
|
||||
}
|
||||
$style.textContent = style
|
||||
}
|
||||
else {
|
||||
const $style = document.createElement('style')
|
||||
$style.id = 'artplayer-subtitle-style'
|
||||
$style.textContent = style
|
||||
document.head.appendChild($style)
|
||||
}
|
||||
@@ -1,138 +1,140 @@
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
setting: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
subtitleOffset: true,
|
||||
settings: [
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
setting: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
subtitleOffset: true,
|
||||
settings: [
|
||||
{
|
||||
width: 200,
|
||||
html: 'Subtitle',
|
||||
name: 'subtitle',
|
||||
tooltip: 'Bilingual',
|
||||
icon: '<img width="22" height="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
width: 200,
|
||||
html: 'Subtitle',
|
||||
name: 'subtitle',
|
||||
tooltip: 'Bilingual',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/subtitle.svg">',
|
||||
selector: [
|
||||
{
|
||||
html: 'Display',
|
||||
tooltip: 'Show',
|
||||
switch: true,
|
||||
onSwitch: function (item) {
|
||||
item.tooltip = item.switch ? 'Hide' : 'Show';
|
||||
art.subtitle.show = !item.switch;
|
||||
return !item.switch;
|
||||
},
|
||||
},
|
||||
{
|
||||
default: true,
|
||||
html: 'Bilingual',
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
},
|
||||
{
|
||||
html: 'Chinese',
|
||||
url: '/assets/sample/subtitle.cn.srt',
|
||||
},
|
||||
{
|
||||
html: 'Japanese',
|
||||
url: '/assets/sample/subtitle.jp.srt',
|
||||
},
|
||||
],
|
||||
onSelect: function (item) {
|
||||
art.subtitle.switch(item.url, {
|
||||
name: item.html,
|
||||
});
|
||||
return item.html;
|
||||
},
|
||||
mounted: function (...args) {
|
||||
console.info(args);
|
||||
},
|
||||
html: 'Display',
|
||||
tooltip: 'Show',
|
||||
switch: true,
|
||||
onSwitch(item) {
|
||||
item.tooltip = item.switch ? 'Hide' : 'Show'
|
||||
art.subtitle.show = !item.switch
|
||||
return !item.switch
|
||||
},
|
||||
},
|
||||
{
|
||||
html: 'Switcher',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/state.svg">',
|
||||
tooltip: 'OFF',
|
||||
switch: false,
|
||||
onSwitch: function (item) {
|
||||
item.tooltip = item.switch ? 'OFF' : 'ON';
|
||||
console.info('You clicked on the custom switch', item.switch);
|
||||
return !item.switch;
|
||||
},
|
||||
mounted: function (...args) {
|
||||
console.info(args);
|
||||
},
|
||||
default: true,
|
||||
html: 'Bilingual',
|
||||
url: '/assets/sample/subtitle.srt',
|
||||
},
|
||||
{
|
||||
html: 'Slider',
|
||||
icon: '<img width="22" heigth="22" src="/assets/img/state.svg">',
|
||||
tooltip: '5x',
|
||||
range: [5, 1, 10, 0.1],
|
||||
onRange: function (item) {
|
||||
return item.range[0] + 'x';
|
||||
},
|
||||
mounted: function (...args) {
|
||||
console.info(args);
|
||||
},
|
||||
html: 'Chinese',
|
||||
url: '/assets/sample/subtitle.cn.srt',
|
||||
},
|
||||
],
|
||||
{
|
||||
html: 'Japanese',
|
||||
url: '/assets/sample/subtitle.jp.srt',
|
||||
},
|
||||
],
|
||||
onSelect(item) {
|
||||
art.subtitle.switch(item.url, {
|
||||
name: item.html,
|
||||
})
|
||||
return item.html
|
||||
},
|
||||
mounted(...args) {
|
||||
console.info(args)
|
||||
},
|
||||
},
|
||||
{
|
||||
html: 'Switcher',
|
||||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||||
tooltip: 'OFF',
|
||||
switch: false,
|
||||
onSwitch(item) {
|
||||
item.tooltip = item.switch ? 'OFF' : 'ON'
|
||||
console.info('You clicked on the custom switch', item.switch)
|
||||
return !item.switch
|
||||
},
|
||||
mounted(...args) {
|
||||
console.info(args)
|
||||
},
|
||||
},
|
||||
{
|
||||
html: 'Slider',
|
||||
icon: '<img width="22" height="22" src="/assets/img/state.svg">',
|
||||
tooltip: '5x',
|
||||
range: [5, 1, 10, 0.1],
|
||||
onRange(item) {
|
||||
return `${item.range[0]}x`
|
||||
},
|
||||
mounted(...args) {
|
||||
console.info(args)
|
||||
},
|
||||
},
|
||||
],
|
||||
}, async () => {
|
||||
const { sleep } = Artplayer.utils;
|
||||
art.setting.show = true;
|
||||
console.log(art.setting.builtin);
|
||||
console.log(art.setting.find('aspect-ratio'));
|
||||
console.log(art.setting.find('aspect-ratio2'));
|
||||
await sleep(1000);
|
||||
art.setting.resize();
|
||||
await sleep(1000);
|
||||
art.setting.inactivate(art.setting.find('subtitle'));
|
||||
art.setting.remove('aspect-ratio');
|
||||
try {
|
||||
art.setting.remove('aspect-ratio2');
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
}
|
||||
await sleep(1000);
|
||||
art.setting.update({
|
||||
name: 'subtitle-offset',
|
||||
html: 'new offset',
|
||||
range: [5, -11, 11, 1],
|
||||
});
|
||||
await sleep(1000);
|
||||
art.setting.find('subtitle-offset').range = [0, -0, 10, 1];
|
||||
await sleep(1000);
|
||||
art.setting.update({
|
||||
name: 'subtitle-offset2',
|
||||
html: 'new offset 2',
|
||||
range: [5, -11, 11, 1],
|
||||
onChange(item) {
|
||||
return item.range[0] + 's';
|
||||
},
|
||||
});
|
||||
await sleep(1000);
|
||||
art.setting.update({
|
||||
name: 'flip',
|
||||
html: 'new flip',
|
||||
tooltip: 'OFF',
|
||||
switch: false,
|
||||
});
|
||||
await sleep(1000);
|
||||
art.setting.find('flip').switch = true;
|
||||
await sleep(1000);
|
||||
art.setting.update({
|
||||
name: 'flip2',
|
||||
html: 'new flip2',
|
||||
tooltip: 'OFF',
|
||||
switch: true,
|
||||
});
|
||||
await sleep(1000);
|
||||
try {
|
||||
art.setting.add({
|
||||
name: 'flip2',
|
||||
html: 'new flip2',
|
||||
tooltip: 'OFF',
|
||||
switch: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
}
|
||||
});
|
||||
const { sleep } = Artplayer.utils
|
||||
art.setting.show = true
|
||||
console.log(art.setting.builtin)
|
||||
console.log(art.setting.find('aspect-ratio'))
|
||||
console.log(art.setting.find('aspect-ratio2'))
|
||||
await sleep(1000)
|
||||
art.setting.resize()
|
||||
await sleep(1000)
|
||||
art.setting.inactivate(art.setting.find('subtitle'))
|
||||
art.setting.remove('aspect-ratio')
|
||||
try {
|
||||
art.setting.remove('aspect-ratio2')
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error.message)
|
||||
}
|
||||
await sleep(1000)
|
||||
art.setting.update({
|
||||
name: 'subtitle-offset',
|
||||
html: 'new offset',
|
||||
range: [5, -11, 11, 1],
|
||||
})
|
||||
await sleep(1000)
|
||||
art.setting.find('subtitle-offset').range = [0, -0, 10, 1]
|
||||
await sleep(1000)
|
||||
art.setting.update({
|
||||
name: 'subtitle-offset2',
|
||||
html: 'new offset 2',
|
||||
range: [5, -11, 11, 1],
|
||||
onChange(item) {
|
||||
return `${item.range[0]}s`
|
||||
},
|
||||
})
|
||||
await sleep(1000)
|
||||
art.setting.update({
|
||||
name: 'flip',
|
||||
html: 'new flip',
|
||||
tooltip: 'OFF',
|
||||
switch: false,
|
||||
})
|
||||
await sleep(1000)
|
||||
art.setting.find('flip').switch = true
|
||||
await sleep(1000)
|
||||
art.setting.update({
|
||||
name: 'flip2',
|
||||
html: 'new flip2',
|
||||
tooltip: 'OFF',
|
||||
switch: true,
|
||||
})
|
||||
await sleep(1000)
|
||||
try {
|
||||
art.setting.add({
|
||||
name: 'flip2',
|
||||
html: 'new flip2',
|
||||
tooltip: 'OFF',
|
||||
switch: true,
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error.message)
|
||||
}
|
||||
})
|
||||
@@ -1,14 +1,14 @@
|
||||
// npm i artplayer-plugin-thumbnail
|
||||
// import artplayerPluginThumbnail from 'artplayer-plugin-thumbnail';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
plugins: [
|
||||
artplayerPluginThumbnail({
|
||||
width: 160,
|
||||
number: 100,
|
||||
scale: 1,
|
||||
}),
|
||||
],
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
plugins: [
|
||||
artplayerPluginThumbnail({
|
||||
width: 160,
|
||||
number: 100,
|
||||
scale: 1,
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -0,0 +1,69 @@
|
||||
if (window.lastThumbnail) {
|
||||
window.lastThumbnail.destroy();
|
||||
}
|
||||
|
||||
var $popups = document.querySelector('.popups');
|
||||
var $popinner = document.querySelector('.popinner');
|
||||
var $artplayer = document.querySelector('.artplayer-app');
|
||||
|
||||
$artplayer.innerHTML = 'Drop video file here or click to upload.';
|
||||
var thumbnail = new ArtplayerToolThumbnail({
|
||||
fileInput: $artplayer,
|
||||
number: 60, // 数量
|
||||
width: 160, // 宽度
|
||||
column: 10, // 列数
|
||||
begin: 0, // 开始
|
||||
end: NaN, // 结束
|
||||
});
|
||||
|
||||
window.lastThumbnail = thumbnail;
|
||||
|
||||
thumbnail.on('file', function (file) {
|
||||
console.log('Read video successfully: ' + file.name);
|
||||
});
|
||||
|
||||
thumbnail.on('video', function (video) {
|
||||
console.log('Video size: ' + video.videoWidth + ' x ' + video.videoHeight);
|
||||
console.log('Video duration: ' + video.duration + 's');
|
||||
thumbnail.start();
|
||||
});
|
||||
|
||||
thumbnail.on('canvas', function (canvas) {
|
||||
console.log('Build canvas successfully');
|
||||
console.log('Canvas size: ' + canvas.width + ' x ' + canvas.height);
|
||||
console.log('Preview density: ' + thumbnail.density + ' p/s');
|
||||
});
|
||||
|
||||
thumbnail.on('update', function (url, percentage) {
|
||||
console.log('Processing: ' + Math.floor(percentage.toFixed(2) * 100) + '%');
|
||||
$popups.style.display = 'flex';
|
||||
$popinner.style.backgroundImage = 'url(' + url + ')';
|
||||
});
|
||||
|
||||
thumbnail.on('download', function (name) {
|
||||
console.log('Start download preview: ' + name);
|
||||
});
|
||||
|
||||
thumbnail.on('done', function () {
|
||||
$popups.style.display = 'none';
|
||||
thumbnail.download();
|
||||
console.log('Build preview image complete');
|
||||
|
||||
[...Artplayer.instances].forEach(function (art) {
|
||||
art.destroy(true);
|
||||
});
|
||||
|
||||
new Artplayer({
|
||||
container: $artplayer,
|
||||
url: thumbnail.videoUrl,
|
||||
autoSize: true,
|
||||
poster: thumbnail.thumbnailUrl,
|
||||
thumbnails: {
|
||||
url: thumbnail.thumbnailUrl,
|
||||
number: thumbnail.option.number,
|
||||
column: thumbnail.option.column,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('Build player complete');
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
// Depends on:
|
||||
// Depends on:
|
||||
// https://glomex.github.io/vast-ima-player/
|
||||
// https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side
|
||||
|
||||
@@ -9,16 +9,16 @@
|
||||
// import artplayerPluginVast from 'artplayer-plugin-vast';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
plugins: [
|
||||
artplayerPluginVast(({ playUrl, imaPlayer, ima }) => {
|
||||
// Play the ad when the video is played
|
||||
art.once('play', () => {
|
||||
playUrl('https://artplayer.org/assets/vast/linear-ad.xml');
|
||||
});
|
||||
}),
|
||||
],
|
||||
});
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/video.mp4',
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
plugins: [
|
||||
artplayerPluginVast(({ playUrl, imaPlayer, ima }) => {
|
||||
// Play the ad when the video is played
|
||||
art.once('play', () => {
|
||||
playUrl('https://artplayer.org/assets/vast/linear-ad.xml')
|
||||
})
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -1,12 +1,12 @@
|
||||
// npm i artplayer-plugin-vtt-thumbnail
|
||||
// import artplayerPluginVttThumbnail from 'artplayer-plugin-vtt-thumbnail';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/bbb-video.mp4',
|
||||
plugins: [
|
||||
artplayerPluginVttThumbnail({
|
||||
vtt: '/assets/sample/bbb-thumbnails.vtt',
|
||||
})
|
||||
]
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/bbb-video.mp4',
|
||||
plugins: [
|
||||
artplayerPluginVttThumbnail({
|
||||
vtt: '/assets/sample/bbb-thumbnails.vtt',
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -1,31 +0,0 @@
|
||||
// From: https://github.com/bilibili/WebAV
|
||||
// npm i artplayer-proxy-webav
|
||||
// import artplayerProxyWebAV from 'artplayer-proxy-webav';
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: '/assets/sample/bbb-video.mp4',
|
||||
volume: 0.5,
|
||||
autoplay: false,
|
||||
autoSize: false,
|
||||
screenshot: true,
|
||||
setting: true,
|
||||
loop: true,
|
||||
flip: true,
|
||||
playbackRate: true,
|
||||
aspectRatio: true,
|
||||
fullscreen: true,
|
||||
fullscreenWeb: true,
|
||||
miniProgressBar: true,
|
||||
autoPlayback: true,
|
||||
thumbnails: {
|
||||
url: '/assets/sample/bbb-sprite.jpg',
|
||||
number: 121,
|
||||
column: 11,
|
||||
width: 128,
|
||||
height: 72,
|
||||
},
|
||||
proxy: artplayerProxyWebAV({
|
||||
//
|
||||
}),
|
||||
});
|
||||
@@ -2,35 +2,37 @@
|
||||
// import WebTorrent from 'webtorrent';
|
||||
|
||||
async function playTorrent(video, url, art) {
|
||||
if (WebTorrent.WEBRTC_SUPPORT) {
|
||||
if (art.torrent) art.torrent.destroy();
|
||||
art.torrent = new WebTorrent();
|
||||
if (WebTorrent.WEBRTC_SUPPORT) {
|
||||
if (art.torrent)
|
||||
art.torrent.destroy()
|
||||
art.torrent = new WebTorrent()
|
||||
|
||||
await navigator.serviceWorker.register('/webtorrent.sw.min.js');
|
||||
art.torrent.loadWorker(navigator.serviceWorker.controller);
|
||||
await navigator.serviceWorker.register('/webtorrent.sw.min.js')
|
||||
art.torrent.loadWorker(navigator.serviceWorker.controller)
|
||||
|
||||
art.torrent.add(url, (torrent) => {
|
||||
const file = torrent.files.find((file) => {
|
||||
return file.name.endsWith('.mp4');
|
||||
});
|
||||
file.streamTo(video);
|
||||
});
|
||||
art.torrent.add(url, (torrent) => {
|
||||
const file = torrent.files.find((file) => {
|
||||
return file.name.endsWith('.mp4')
|
||||
})
|
||||
file.streamTo(video)
|
||||
})
|
||||
|
||||
art.on('destroy', () => art.torrent.destroy());
|
||||
} else {
|
||||
art.notice.show = 'Unsupported playback format: torrent';
|
||||
}
|
||||
art.on('destroy', () => art.torrent.destroy())
|
||||
}
|
||||
else {
|
||||
art.notice.show = 'Unsupported playback format: torrent'
|
||||
}
|
||||
}
|
||||
|
||||
var art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent',
|
||||
type: 'torrent',
|
||||
customType: {
|
||||
torrent: playTorrent,
|
||||
},
|
||||
});
|
||||
const art = new Artplayer({
|
||||
container: '.artplayer-app',
|
||||
url: 'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent',
|
||||
type: 'torrent',
|
||||
customType: {
|
||||
torrent: playTorrent,
|
||||
},
|
||||
})
|
||||
|
||||
art.on('ready', () => {
|
||||
console.info(art.torrent);
|
||||
});
|
||||
console.info(art.torrent)
|
||||
})
|
||||
|
Before Width: | Height: | Size: 248 KiB |
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg class="icon" viewBox="0 0 1152 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#fff" d="M311.296 661.504c0 4.096-4.096 8.704-8.704 12.8 0 4.096 0 4.096-4.096 8.704h-12.8c-4.096 0-8.704-4.096-16.896-8.704-8.704-8.704-16.896-8.704-25.6-8.704s-12.8 4.096-16.896 12.8c-4.096 12.8-8.704 21.504-4.096 29.696 4.096 8.704 12.8 16.896 25.6 21.504 16.896 8.704 34.304 16.896 47.104 16.896 12.8 0 21.504-4.096 34.304-8.704 8.704-4.096 16.896-16.896 25.6-29.696 8.704-12.8 12.8-34.304 16.896-55.296 4.096-21.504 4.096-51.2 4.096-85.504 0-12.8 0-21.504-4.096-29.696 0-8.704-4.096-12.8-8.704-16.896-4.096-4.096-8.704-8.704-12.8-8.704s-12.8-4.096-21.504-4.096H272.896s-4.096-4.096 0-8.704l4.096-38.4c0-4.096 0-8.704 4.096-8.704h47.104c16.896 0 25.6-4.096 34.304-12.8 8.704-8.704 12.8-21.504 12.8-42.496V324.096c0-16.896-4.096-34.304-8.704-42.496-12.8-12.8-25.6-16.896-42.496-16.896H243.2c-8.704 0-16.896 0-21.504 4.096-4.096 8.704-4.096 12.8-4.096 25.6 0 8.704 0 16.896 4.096 21.504 4.096 4.096 12.8 8.704 21.504 8.704H307.2c4.096 0 8.704 0 8.704 4.096v34.304c0 8.704 0 12.8-4.096 12.8 0 0-4.096 4.096-8.704 4.096h-34.304c-8.704 0-12.8 0-21.504 4.096-4.096 0-8.704 4.096-8.704 4.096-4.096 4.096-8.704 12.8-8.704 16.896 0 8.704-4.096 16.896-4.096 25.6l-8.704 72.704v29.696c0 8.704 4.096 12.8 8.704 16.896s8.704 4.096 16.896 8.704h68.096c4.096 0 8.704 0 8.704 4.096s4.096 8.704 4.096 16.896c0 21.504 0 42.496-4.096 55.296 0.512 9.216-3.584 22.016-8.192 26.624zM896 486.4c-93.696 0-175.104 51.2-217.6 123.904h-106.496v-34.304H640c21.504 0 34.304-4.096 42.496-12.8 8.704-8.704 12.8-21.504 12.8-42.496V358.4c0-21.504-4.096-34.304-12.8-42.496-8.704-8.704-21.504-12.8-42.496-12.8 0-4.096 4.096-4.096 4.096-8.704-4.096 0-4.096-4.096-4.096-4.096 4.096-12.8 8.704-21.504 4.096-25.6 0-8.704-4.096-12.8-12.8-21.504-8.704-4.096-16.896-4.096-21.504-4.096-8.704 4.096-12.8 8.704-21.504 21.504-4.096 8.704-8.704 12.8-12.8 21.504-4.096 8.704-8.704 12.8-12.8 21.504h-51.2c-4.096-8.704-8.704-16.896-8.704-21.504-4.096-8.704-8.704-12.8-12.8-21.504-4.096-12.8-12.8-16.896-21.504-16.896s-16.896 0-25.6 8.704C434.176 261.12 430.08 265.216 430.08 273.92c0 8.704 0 16.896 8.704 25.6l4.096 4.096 4.096 4.096c-16.896 0-29.696 4.096-38.4 12.8-8.704 4.096-12.8 21.504-12.8 38.4v157.696c0 21.504 4.096 34.304 12.8 42.496 8.704 8.704 21.504 12.8 42.496 12.8H512v34.304H413.696c-12.8 0-21.504 0-25.6 4.096-4.096 4.096-8.704 8.704-8.704 21.504v16.896c0 4.096 4.096 8.704 4.096 8.704 4.096 0 4.096 4.096 8.704 4.096H512V716.8c0 12.8 4.096 21.504 8.704 25.6 4.096 4.096 12.8 8.704 21.504 8.704 12.8 0 21.504-4.096 25.6-8.704 4.096-4.096 4.096-12.8 4.096-25.6v-55.296h80.896c-8.704 25.6-12.8 51.2-12.8 76.8 0 140.8 115.2 256 256 256s256-115.2 256-256S1036.8 486.4 896 486.4z m-328.704-128h55.296c4.096 0 4.096 0 4.096 4.096V409.6h-59.904V358.4z m0 102.4h59.904v51.2h-55.296V460.8h-4.608zM512 516.096H456.704v-51.2H512v51.2z m0-102.4H452.096v-51.2H512v51.2z m384 499.2c-93.696 0-170.496-76.8-170.496-170.496s76.8-170.496 170.496-170.496 170.496 76.8 170.496 170.496-76.8 170.496-170.496 170.496z" />
|
||||
<path fill="#fff" d="M580.096 879.104H213.504c-72.704 0-128-55.296-128-119.296V230.4c0-64 55.296-119.296 128-119.296h512c72.704 0 128 55.296 128 119.296v140.8c0 25.6 16.896 42.496 42.496 42.496s42.496-16.896 42.496-42.496V230.4c0-115.2-93.696-204.8-213.504-204.8h-512C93.696 25.6 0 119.296 0 230.4v528.896c0 115.2 93.696 204.8 213.504 204.8h367.104c25.6 0 42.496-16.896 42.496-42.496 0-25.6-21.504-42.496-43.008-42.496z m171.52 10.752c-15.36-15.36-15.36-40.96 0-56.32l237.568-237.568c15.36-15.36 40.96-15.36 56.32 0s15.36 40.96 0 56.32l-237.568 237.568c-15.36 15.36-40.448 15.36-56.32 0z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.7 KiB |
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg class="icon" viewBox="0 0 1152 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#fff" d="M311.466667 661.333333c0 4.266667-4.266667 8.533333-8.533334 12.8 0 4.266667 0 4.266667-4.266666 8.533334h-12.8c-4.266667 0-8.533333-4.266667-17.066667-8.533334-8.533333-8.533333-17.066667-8.533333-25.6-8.533333-8.533333 0-12.8 4.266667-17.066667 12.8-4.266667 12.8-8.533333 21.333333-4.266666 29.866667 4.266667 8.533333 12.8 17.066667 25.6 21.333333 17.066667 8.533333 34.133333 17.066667 46.933333 17.066667 12.8 0 21.333333-4.266667 34.133333-8.533334 8.533333-4.266667 17.066667-17.066667 25.6-29.866666 8.533333-12.8 12.8-34.133333 17.066667-55.466667 4.266667-21.333333 4.266667-51.2 4.266667-85.333333 0-12.8 0-21.333333-4.266667-29.866667 0-8.533333-4.266667-12.8-8.533333-17.066667-4.266667-4.266667-8.533333-8.533333-12.8-8.533333-4.266667 0-12.8-4.266667-21.333334-4.266667H273.066667s-4.266667-4.266667 0-8.533333l4.266666-38.4c0-4.266667 0-8.533333 4.266667-8.533333h46.933333c17.066667 0 25.6-4.266667 34.133334-12.8 8.533333-8.533333 12.8-21.333333 12.8-42.666667V324.266667c0-17.066667-4.266667-34.133333-8.533334-42.666667-12.8-12.8-25.6-17.066667-42.666666-17.066667H243.2c-8.533333 0-17.066667 0-21.333333 4.266667-4.266667 8.533333-4.266667 12.8-4.266667 25.6 0 8.533333 0 17.066667 4.266667 21.333333 4.266667 4.266667 12.8 8.533333 21.333333 8.533334h64c4.266667 0 8.533333 0 8.533333 4.266666v34.133334c0 8.533333 0 12.8-4.266666 12.8 0 0-4.266667 4.266667-8.533334 4.266666h-34.133333c-8.533333 0-12.8 0-21.333333 4.266667-4.266667 0-8.533333 4.266667-8.533334 4.266667-4.266667 4.266667-8.533333 12.8-8.533333 17.066666 0 8.533333-4.266667 17.066667-4.266667 25.6l-8.533333 72.533334v29.866666c0 8.533333 4.266667 12.8 8.533333 17.066667 4.266667 4.266667 8.533333 4.266667 17.066667 8.533333h68.266667c4.266667 0 8.533333 0 8.533333 4.266667s4.266667 8.533333 4.266667 17.066667c0 21.333333 0 42.666667-4.266667 55.466666 0 8.533333-4.266667 21.333333-8.533333 25.6zM896 486.4c-93.866667 0-174.933333 51.2-217.6 123.733333h-106.666667v-34.133333H640c21.333333 0 34.133333-4.266667 42.666667-12.8 8.533333-8.533333 12.8-21.333333 12.8-42.666667V358.4c0-21.333333-4.266667-34.133333-12.8-42.666667-8.533333-8.533333-21.333333-12.8-42.666667-12.8 0-4.266667 4.266667-4.266667 4.266667-8.533333-4.266667 0-4.266667-4.266667-4.266667-4.266667 4.266667-12.8 8.533333-21.333333 4.266667-25.6 0-8.533333-4.266667-12.8-12.8-21.333333-8.533333-4.266667-17.066667-4.266667-21.333334-4.266667-8.533333 4.266667-12.8 8.533333-21.333333 21.333334-4.266667 8.533333-8.533333 12.8-12.8 21.333333-4.266667 8.533333-8.533333 12.8-12.8 21.333333H512c-4.266667-8.533333-8.533333-17.066667-8.533333-21.333333-4.266667-8.533333-8.533333-12.8-12.8-21.333333-4.266667-12.8-12.8-17.066667-21.333334-17.066667s-17.066667 0-25.6 8.533333c-8.533333 8.533333-12.8 12.8-12.8 21.333334s0 17.066667 8.533334 25.6l4.266666 4.266666 4.266667 4.266667c-17.066667 0-29.866667 4.266667-38.4 12.8-8.533333 4.266667-12.8 21.333333-12.8 38.4v157.866667c0 21.333333 4.266667 34.133333 12.8 42.666666 8.533333 8.533333 21.333333 12.8 42.666667 12.8H512v34.133334H413.866667c-12.8 0-21.333333 0-25.6 4.266666-4.266667 4.266667-8.533333 8.533333-8.533334 21.333334v17.066666c0 4.266667 4.266667 8.533333 4.266667 8.533334 4.266667 0 4.266667 4.266667 8.533333 4.266666H512v55.466667c0 12.8 4.266667 21.333333 8.533333 25.6 4.266667 4.266667 12.8 8.533333 21.333334 8.533333 12.8 0 21.333333-4.266667 25.6-8.533333 4.266667-4.266667 4.266667-12.8 4.266666-25.6v-55.466667h81.066667c-8.533333 25.6-12.8 51.2-12.8 76.8 0 140.8 115.2 256 256 256s256-115.2 256-256-115.2-251.733333-256-251.733333z m-328.533333-128h55.466666c4.266667 0 4.266667 0 4.266667 4.266667v46.933333h-59.733333V358.4z m0 102.4h59.733333V512h-55.466667v-51.2zM512 516.266667h-55.466667V465.066667H512v51.2z m0-102.4h-59.733333V366.933333v-4.266666H512v51.2z m384 499.2c-93.866667 0-170.666667-76.8-170.666667-170.666667s76.8-170.666667 170.666667-170.666667 170.666667 76.8 170.666667 170.666667-76.8 170.666667-170.666667 170.666667z" />
|
||||
<path fill="#fff" d="M951.466667 669.866667l-72.533334 72.533333-29.866666-25.6c-17.066667-17.066667-42.666667-12.8-59.733334 4.266667-17.066667 17.066667-12.8 42.666667 4.266667 59.733333l59.733333 51.2c8.533333 8.533333 17.066667 8.533333 29.866667 8.533333 12.8 0 21.333333-4.266667 29.866667-12.8l102.4-102.4c17.066667-17.066667 17.066667-42.666667 0-59.733333-21.333333-12.8-46.933333-12.8-64 4.266667zM580.266667 878.933333H213.333333c-72.533333 0-128-55.466667-128-119.466666V230.4c0-64 55.466667-119.466667 128-119.466667h512c72.533333 0 128 55.466667 128 119.466667v140.8c0 25.6 17.066667 42.666667 42.666667 42.666667s42.666667-17.066667 42.666667-42.666667V230.4c0-115.2-93.866667-204.8-213.333334-204.8H213.333333C93.866667 25.6 0 119.466667 0 230.4v529.066667c0 115.2 93.866667 204.8 213.333333 204.8h366.933334c25.6 0 42.666667-17.066667 42.666666-42.666667s-21.333333-42.666667-42.666666-42.666667z" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.0 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 74" height="54"><g fill="none" fill-rule="evenodd"><rect width="199" height="73" x="0.5" y="0.5" fill="#FFF" fill-opacity="0.889" stroke="#979797" stroke-opacity="0.207" rx="8"></rect><path fill="#003087" fill-rule="nonzero" d="M77.5599861,42.672 C82.5421299,42.6678941 86.7787401,39.0351801 87.5429861,34.112 C88.3229861,29.145 84.4419861,24.8089419 78.9429861,24.8089419 L70.0799861,24.8089419 C69.7362553,24.8045668 69.4418457,25.054175 69.3899861,25.394 L65.4399861,50.466 C65.411103,50.6513547 65.4646051,50.8400802 65.5864664,50.9827001 C65.7083276,51.1253201 65.8863949,51.2076112 66.0739861,51.2080349 L70.7639861,51.2080349 C71.1069609,51.2114294 71.4002308,50.9620648 71.4519861,50.623 L72.6139861,43.258 C72.665345,42.9181575 72.9593063,42.6681411 73.3029861,42.672 L77.5599861,42.672 Z M81.4849861,33.886 C81.1949861,35.722 79.7759861,37.075 77.0599861,37.075 L73.5859861,37.075 L74.6389861,30.395 L78.0499861,30.395 C80.8599861,30.401 81.7729861,32.058 81.4849861,33.891 L81.4849861,33.886 Z M107.862986,32.706 L103.409986,32.706 C103.066412,32.702002 102.772249,32.9514007 102.719986,33.291 L102.575986,34.215 C102.575986,34.215 99.1189861,30.44 93.0009861,32.99 C89.4909861,34.451 87.8069861,37.47 87.0909861,39.68 C87.0909861,39.68 84.8139861,46.398 89.9609861,50.097 C89.9609861,50.097 94.7319861,53.653 100.105986,49.877 L100.012986,50.466 C99.9837482,50.6514164 100.037121,50.8403412 100.159058,50.9830492 C100.280994,51.1257572 100.459279,51.207952 100.646986,51.208 L105.097986,51.208 C105.441717,51.2124332 105.736126,50.962825 105.787986,50.623 L108.495986,33.448 C108.524869,33.2626453 108.471367,33.0739198 108.349506,32.9312999 C108.227645,32.7886799 108.049577,32.7063888 107.861986,32.706 L107.862986,32.706 Z M101.315986,42.198 C100.955689,44.6729154 98.8208538,46.5000884 96.3199861,46.474 C95.8464479,46.4793866 95.3750127,46.4102067 94.9229861,46.269 C93.0029861,45.653 91.9079861,43.807 92.2229861,41.807 C92.5837159,39.3248218 94.7289785,37.494888 97.2369861,37.53 C97.7109861,37.525 98.1829861,37.595 98.6349861,37.736 C100.547986,38.35 101.635986,40.196 101.320986,42.198 L101.315986,42.198 L101.315986,42.198 Z"></path><path fill="#0070E0" fill-rule="nonzero" d="M141.671986,42.672 C146.656916,42.6706404 150.897643,39.037672 151.663986,34.112 C152.442986,29.145 148.562986,24.8089637 143.061986,24.8089637 L134.201986,24.8089637 C133.85879,24.805503 133.565196,25.0547804 133.512986,25.394 L129.550986,50.473 C129.504409,50.756977 129.654011,51.0369155 129.915986,51.156 C130.000231,51.1952988 130.092026,51.2160348 130.184986,51.2160348 L134.875986,51.2160348 C135.219509,51.2194242 135.513223,50.9696175 135.564986,50.63 L136.727986,43.265 C136.778939,42.9249317 137.073149,42.6747042 137.416986,42.679 L141.671986,42.672 L141.671986,42.672 Z M145.596986,33.886 C145.306986,35.722 143.887986,37.075 141.170986,37.075 L137.697986,37.075 L138.751986,30.395 L142.162986,30.395 C144.970986,30.401 145.885986,32.058 145.596986,33.891 L145.596986,33.886 Z M171.973986,32.706 L167.525986,32.706 C167.18279,32.702503 166.889196,32.9517804 166.836986,33.291 L166.690986,34.215 C166.690986,34.215 163.234986,30.44 157.116986,32.99 C153.607986,34.451 151.922986,37.47 151.205986,39.68 C151.205986,39.68 148.929986,46.398 154.075986,50.097 C154.075986,50.097 158.847986,53.653 164.221986,49.877 L164.128986,50.466 C164.082409,50.749977 164.232011,51.0299155 164.493986,51.149 C164.577986,51.189 164.669986,51.209 164.762986,51.209 L169.213986,51.209 C169.55814,51.2141761 169.852851,50.9635224 169.902986,50.623 L172.611986,33.448 C172.638967,33.2621157 172.585098,33.073572 172.463986,32.93 C172.342253,32.7859662 172.162559,32.7038202 171.973986,32.706 L171.973986,32.706 Z M165.427986,42.198 C165.071797,44.6751772 162.934454,46.5044962 160.431986,46.474 C159.957778,46.4795969 159.485652,46.4104146 159.032986,46.269 C157.111986,45.653 156.015986,43.807 156.330986,41.807 C156.69083,39.3316868 158.825789,37.5039809 161.326986,37.53 C161.801986,37.525 162.273986,37.594 162.725986,37.736 C164.658986,38.35 165.749986,40.196 165.432986,42.198 L165.427986,42.198 L165.427986,42.198 Z"></path><path fill="#003087" fill-rule="nonzero" d="M124.204986,33.131 L118.837986,42.19 L116.114986,33.198 C116.0272,32.9049326 115.756916,32.7046623 115.450986,32.7059048 L110.608986,32.7059048 C110.439552,32.7027489 110.279321,32.782901 110.180312,32.9204358 C110.081303,33.0579706 110.056138,33.2353538 110.112986,33.395 L114.992986,48.541 L110.579986,55.679 C110.47841,55.8390534 110.472572,56.0418621 110.564775,56.2074929 C110.656977,56.3731236 110.832432,56.4750118 111.021986,56.4730293 L116.238986,56.4730293 C116.542538,56.474558 116.82432,56.3156042 116.979986,56.055 L130.611986,33.503 C130.711981,33.342671 130.716344,33.140509 130.62336,32.9760149 C130.530376,32.8115209 130.354918,32.7110068 130.165986,32.714 L124.950986,32.714 C124.645859,32.7104527 124.361807,32.8692321 124.204986,33.131 L124.204986,33.131 ZLine truncated
|
||||
|
Before Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 130 KiB |
@@ -0,0 +1,11 @@
|
||||
"use strict";async function Module(i={}){var g,v=i,y=(...t)=>console.log(...t),h=(...t)=>console.error(...t);function T(){j?.(v)}G=(t=>()=>{t(),self.wasmMemory=B,self.HEAPU8C=new Uint8ClampedArray(B.buffer),self.HEAPU8=new Uint8Array(B.buffer)})(G);function P(t){throw t}var j,w,C,A,M,E,O,ie,oe,le=!1;function G(){var t=B.buffer;w=new Int8Array(t),A=new Int16Array(t),C=new Uint8Array(t),M=new Uint16Array(t),E=new Int32Array(t),O=new Uint32Array(t),ie=new Float32Array(t),oe=new Float64Array(t)}function $e(){{var t=62914560;B=new WebAssembly.Memory({initial:t/65536,maximum:32768})}G()}$e();var X=t=>Xe(t),Q=()=>Qe(),B,fe=new TextDecoder,Z=(t,r,n,s)=>{var o=r+n;if(s)return o;for(;t[r]&&!(r>=o);)++r;return r},q=(t,r,n)=>{if(!t)return"";var s=Z(C,t,r,n);return fe.decode(C.subarray(t,s))},Ce=(t,r,n,s)=>P(`Assertion failed: ${q(t)}, at: `+[r?q(r):"unknown filename",n,s?q(s):"unknown function"]);function _e(t,r,n){return 0}var we=(t,r,n)=>{};function tr(t,r,n){return 0}function nr(t,r,n,s){}var ar=()=>P(""),sr=(t,r,n,s,o)=>{},U=t=>{for(var r="";;){var n=C[t++];if(!n)return r;r+=String.fromCharCode(n)}},J={},K={},ue={},N=class extends Error{constructor(r){super(r),this.name="BindingError"}},$=t=>{throw new N(t)};function ir(t,r,n={}){var s=r.name;if(t||$(`type "${s}" must have a positive integer typeid pointer`),K.hasOwnProperty(t)){if(n.ignoreDuplicateRegistrations)return;$(`Cannot register type '${s}' twice`)}if(K[t]=r,delete ue[t],J.hasOwnProperty(t)){var o=J[t];delete J[t],o.forEach(l=>l())}}function L(t,r,n={}){return ir(t,r,n)}var or=(t,r,n,s)=>{r=U(r),L(t,{name:r,fromWireType:function(o){return!!o},toWireType:function(o,l){return l?n:s},readValueFromPointer:function(o){return this.fromWireType(C[o])},destructorFunction:null})},lr=t=>({count:t.count,deleteScheduled:t.deleteScheduled,preservePointerOnDelete:t.preservePointerOnDelete,ptr:t.ptr,ptrType:t.ptrType,smartPtr:t.smartPtr,smartPtrType:t.smartPtrType}),Te=t=>{function r(n){return n.$$.ptrType.registeredClass.name}$(r(t)+" instance already deleted")},Pe=!1,Me=t=>{},fr=t=>{t.smartPtr?t.smartPtrType.rawDestructor(t.smartPtr):t.ptrType.registeredClass.rawDestructor(t.ptr)},Re=t=>{t.count.value-=1;var r=t.count.value===0;r&&fr(t)},ee=t=>globalThis.FinalizationRegistry?(Pe=new FinalizationRegistry(r=>{Re(r.$$)}),ee=r=>{var n=r.$$,s=!!n.smartPtr;if(s){var o={$$:n};Pe.register(r,o,r)}return r},Me=r=>Pe.unregister(r),ee(t)):(ee=r=>r,t),ce=[],ur=()=>{for(;ce.length;){var t=ce.pop();t.$$.deleteScheduled=!1,t.delete()}},Ee,cr=()=>{let t=de.prototype;Object.assign(t,{isAliasOf(n){if(!(this instanceof de)||!(n instanceof de))return!1;var s=this.$$.ptrType.registeredClass,o=this.$$.ptr;n.$$=n.$$;for(var l=n.$$.ptrType.registeredClass,u=n.$$.ptr;s.baseClass;)o=s.upcast(o),s=s.baseClass;for(;l.baseClass;)u=l.upcast(u),l=l.baseClass;return s===l&&o===u},clone(){if(this.$$.ptr||Te(this),this.$$.preservePointerOnDelete)return this.$$.count.value+=1,this;var n=ee(Object.create(Object.getPrototypeOf(this),{$$:{value:lr(this.$$)}}));return n.$$.count.value+=1,n.$$.deleteScheduled=!1,n},delete(){this.$$.ptr||Te(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&$("Object already scheduled for deletion"),Me(this),Re(this.$$),this.$$.preservePointerOnDelete||(this.$$.smartPtr=void 0,this.$$.ptr=void 0)},isDeleted(){return!this.$$.ptr},deleteLater(){return this.$$.ptr||Te(this),this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete&&$("Object already scheduled for deletion"),ce.push(this),ce.length===1&&Ee&&Ee(ur),this.$$.deleteScheduled=!0,this}});const r=Symbol.dispose;r&&(t[r]=t.delete)};function de(){}var ke=(t,r)=>Object.defineProperty(r,"name",{value:t}),We={},Ue=(t,r,n)=>{if(t[r].overloadTable===void 0){var s=t[r];t[r]=function(...o){return t[r].overloadTable.hasOwnProperty(o.length)||$(`Function '${n}' called with an invalid number of arguments (${o.length}) - expects one of (${t[r].overloadTable})!`),t[r].overloadTable[o.length].apply(this,o)},t[r].overloadTable=[],t[r].overloadTable[s.argCount]=s}},dr=(t,r,n)=>{v.hasOwnProperty(t)?((n===void 0||v[t].overloadTable!==void 0&&v[t].overloadTable[n]!==void 0)&&$(`Cannot register public name '${t}' twice`),Ue(v,t,t),v[t].overloadTable.hasOwnProperty(n)&&$(`Cannot register multiple overloads of a function with the same number of arguments (${n})!`),v[t].overloadTable[n]=r):(v[t]=r,v[t].argCount=n)},vr=48,pr=57,gr=t=>{t=t.replace(/[^a-zA-Z0-9_]/g,"$");var r=t.charCodeAt(0);return r>=vr&&r<=pr?`_${t}`:t};function br(t,r,n,s,o,l,u,f){this.name=t,this.constructor=r,this.instancePrototype=n,this.rawDestructor=s,this.baseClass=o,this.getActualType=l,this.upcast=u,this.downcast=f,this.pureVirtualFunctions=[]}var ve=(t,r,n)=>{for(;r!==n;)r.upcast||$(`Expected null or instance of ${n.name}, got an instance of ${r.name}`),t=r.upcast(t),r=r.baseClass;return t},je=t=>{if(t===null)return"null";var r=typeof t;return r==="object"||r==="array"||r==="function"?t.toString():""+t};function hr(t,r){if(r===null)return this.isReferencLine truncated
|
||||
`;o&&(m+=`var destructors = [];
|
||||
`);var _=o?"destructors":"null",S=["humanName","throwBindingError","invoker","fn","runDestructors","fromRetWire","toClassParamWire"];r&&(m+=`var thisWired = toClassParamWire(${_}, this);
|
||||
`);for(var p=0;p<l;++p){var R=`toArg${p}Wire`;m+=`var arg${p}Wired = ${R}(${_}, arg${p});
|
||||
`,S.push(R)}if(m+=(n||s?"var rv = ":"")+`invoker(${f});
|
||||
`,o)m+=`runDestructors(destructors);
|
||||
`;else for(var p=r?1:2;p<t.length;++p){var F=p===1?"thisWired":"arg"+(p-2)+"Wired";t[p].destructorFunction!==null&&(m+=`${F}_dtor(${F});
|
||||
`,S.push(`${F}_dtor`))}return n&&(m+=`var ret = fromRetWire(rv);
|
||||
return ret;
|
||||
`),m+=`}
|
||||
`,new Function(S,m)}function He(t,r,n,s,o,l){var u=r.length;u<2&&$("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var f=r[1]!==null&&n!==null,p=xe(r),m=!r[0].isVoid,_=r[0],S=r[1],R=[t,$,s,o,Le,_.fromWireType.bind(_),S?.toWireType.bind(S)],F=2;F<u;++F){var k=r[F];R.push(k.toWireType.bind(k))}if(!p)for(var F=f?1:2;F<r.length;++F)r[F].destructorFunction!==null&&R.push(r[F].destructorFunction);var x=Er(r,f,m,l)(...R);return ke(t,x)}var kr=(t,r,n,s,o,l)=>{var u=Be(r,n);o=H(s,o),z([],[t],f=>{f=f[0];var p=`constructor ${f.name}`;if(f.registeredClass.constructor_body===void 0&&(f.registeredClass.constructor_body=[]),f.registeredClass.constructor_body[r-1]!==void 0)throw new N(`Cannot register multiple constructors with identical number of parameters (${r-1}) for class '${f.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);return f.registeredClass.constructor_body[r-1]=()=>{te(`Cannot construct ${f.name} due to unbound types`,u)},z([],u,m=>(m.splice(1,0,null),f.registeredClass.constructor_body[r-1]=He(p,m,null,o,l),[])),[]})},Wr=t=>{t=t.trim();const r=t.indexOf("(");return r===-1?t:t.slice(0,r)},Ur=(t,r,n,s,o,l,u,f,p,m)=>{var _=Be(n,s);r=U(r),r=Wr(r),l=H(o,l,p),z([],[t],S=>{S=S[0];var R=`${S.name}.${r}`;r.startsWith("@@")&&(r=Symbol[r.substring(2)]),f&&S.registeredClass.pureVirtualFunctions.push(r);function F(){te(`Cannot call ${R} due to unbound types`,_)}var k=S.registeredClass.instancePrototype,D=k[r];return D===void 0||D.overloadTable===void 0&&D.className!==S.name&&D.argCount===n-2?(F.argCount=n-2,F.className=S.name,k[r]=F):(Ue(k,r,R),k[r].overloadTable[n-2]=F),z([],_,x=>{var I=He(R,x,S,l,u,p);return k[r].overloadTable===void 0?(I.argCount=n-2,k[r]=I):k[r].overloadTable[n-2]=I,[]}),[]})},Ve=(t,r,n)=>(t instanceof Object||$(`${n} with invalid "this": ${t}`),t instanceof r.registeredClass.constructor||$(`${n} incompatible with "this" of type ${t.constructor.name}`),t.$$.ptr||$(`cannot call emscripten binding method ${n} on deleted object`),ve(t.$$.ptr,t.$$.ptrType.registeredClass,r.registeredClass)),Dr=(t,r,n,s,o,l,u,f,p,m)=>{r=U(r),o=H(s,o),z([],[t],_=>{_=_[0];var S=`${_.name}.${r}`,R={get(){te(`Cannot access ${S} due to unbound types`,[n,u])},enumerable:!0,configurable:!0};return p?R.set=()=>te(`Cannot access ${S} due to unbound types`,[n,u]):R.set=F=>$(S+" is a read-only property"),Object.defineProperty(_.registeredClass.instancePrototype,r,R),z([],p?[n,u]:[n],F=>{var k=F[0],D={get(){var I=Ve(this,_,S+" getter");return k.fromWireType(o(l,I))},enumerable:!0};if(p){p=H(f,p);var x=F[1];D.set=function(I){var se=Ve(this,_,S+" setter"),W=[];p(m,se,x.toWireType(W,I)),Le(W)}}return Object.defineProperty(_.registeredClass.instancePrototype,r,D),[]}),[]})},ze=[],Y=[0,1,,1,null,1,!0,1,!1,1],Ir=t=>{t>9&&--Y[t+1]===0&&(Y[t]=void 0,ze.push(t))},Fe={toValue:t=>(t||$(`Cannot use deleted val. handle = ${t}`),Y[t]),toHandle:t=>{switch(t){case void 0:return 2;case null:return 4;case!0:return 6;case!1:return 8;default:{const r=ze.pop()||Y.length;return Y[r]=t,Y[r+1]=1,r}}}},Br={name:"emscripten::val",fromWireType:t=>{var r=Fe.toValue(t);return Ir(t),r},toWireType:(t,r)=>Fe.toHandle(r),readValueFromPointer:pe,destructorFunction:null},Lr=t=>L(t,Br),xr=(t,r)=>{switch(r){case 4:return function(n){return this.fromWireType(ie[n>>2])};case 8:return function(n){return this.fromWireType(oe[n>>3])};default:throw new TypeError(`invalid float width (${r}): ${t}`)}},Hr=(t,r,n)=>{r=U(r),L(t,{name:r,fromWireType:s=>s,toWireType:(s,o)=>o,readValueFromPointer:xr(r,n),destructorFunction:null})},Vr=(t,r,n)=>{switch(r){case 1:return n?s=>w[s]:s=>C[s];case 2:return n?s=>A[s>>1]:s=>M[s>>1];case 4:return n?s=>E[s>>2]:s=>O[s>>2];default:throw new TypeError(`invalid integer width (${r}): ${t}`)}},zr=(t,r,n,s,o)=>{r=U(r);const l=s===0;let u=p=>p;if(l){var f=32-8*n;u=p=>p<<f>>>f,o=u(o)}L(t,{name:r,fromWireType:u,toWireType:(p,m)=>m,readValueFromPointer:Vr(r,n,s!==0),destructorFunction:null})},Gr=(t,r,n)=>{var s=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array],o=s[r];function l(u){var f=O[u>>2],p=O[u+4>>2];return new o(w.buffer,p,f)}n=U(n),L(t,{name:n,fromWireType:l,readValueFromPointer:l},{ignoreDuplicateRegistrations:!0})},qr=(t,r,n,s)=>{if(!(s>0))return 0;for(var o=n,l=n+s-1,u=0;u<t.length;++u){var f=t.codePointAt(u);if(f<=127){if(n>=l)break;r[n++]=f}else if(f<=2047){if(n+1>=l)break;r[n++]=192|f>>6,r[n++]=128|f&63}else if(f<=65535){if(n+2>=l)break;r[n++]=224|f>>12,r[n++]=128|f>>6&63,r[n++]=128|f&63}else{if(n+3>=l)break;r[n++]=240|f>>18,r[n++]=128|f>>12&63,r[n++]=128|f>>6&63,r[n++]=128|f&63,u++}}return r[n]=0,n-o},Ge=(t,r,n)=>qr(t,C,r,n),qe=t=>{for(var r=0,n=0;n<t.length;++n){var s=t.charCodeAt(n);s<=127?r++:s<=2047?r+=2:s>=55296&&s<=57343?(r+=4,++n):r+=3}return r},Jr=(t,r)=>{r=U(r),L(t,{name:r,fromWireType(n){var s=O[n>>2],o=n+4,l;return l=q(o,s,!0),V(n),l},toWireType(n,s){s instanceof ArrayBuffer&&(s=new Uint8Arr
Line truncated
|
||||
@@ -1,589 +0,0 @@
|
||||
var SubtitlesOctopus = function (options) {
|
||||
var supportsWebAssembly = false;
|
||||
try {
|
||||
if (typeof WebAssembly === "object"
|
||||
&& typeof WebAssembly.instantiate === "function") {
|
||||
const module = new WebAssembly.Module(Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
|
||||
if (module instanceof WebAssembly.Module)
|
||||
supportsWebAssembly = (new WebAssembly.Instance(module) instanceof WebAssembly.Instance);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
console.log("WebAssembly support detected: " + (supportsWebAssembly ? "yes" : "no"));
|
||||
|
||||
var self = this;
|
||||
self.canvas = options.canvas; // HTML canvas element (optional if video specified)
|
||||
self.lossyRender = options.lossyRender; // Speedup render for heavy subs
|
||||
self.isOurCanvas = false; // (internal) we created canvas and manage it
|
||||
self.video = options.video; // HTML video element (optional if canvas specified)
|
||||
self.canvasParent = null; // (internal) HTML canvas parent element
|
||||
self.fonts = options.fonts || []; // Array with links to fonts used in sub (optional)
|
||||
self.availableFonts = options.availableFonts || []; // Object with all available fonts (optional). Key is font name in lower case, value is link: {"arial": "/font1.ttf"}
|
||||
self.onReadyEvent = options.onReady; // Function called when SubtitlesOctopus is ready (optional)
|
||||
if (supportsWebAssembly) {
|
||||
self.workerUrl = options.workerUrl || 'subtitles-octopus-worker.js'; // Link to WebAssembly worker
|
||||
} else {
|
||||
self.workerUrl = options.legacyWorkerUrl || 'subtitles-octopus-worker-legacy.js'; // Link to legacy worker
|
||||
}
|
||||
self.subUrl = options.subUrl; // Link to sub file (optional if subContent specified)
|
||||
self.subContent = options.subContent || null; // Sub content (optional if subUrl specified)
|
||||
self.onErrorEvent = options.onError; // Function called in case of critical error meaning sub wouldn't be shown and you should use alternative method (for instance it occurs if browser doesn't support web workers).
|
||||
self.debug = options.debug || false; // When debug enabled, some performance info printed in console.
|
||||
self.lastRenderTime = 0; // (internal) Last time we got some frame from worker
|
||||
self.pixelRatio = window.devicePixelRatio || 1; // (internal) Device pixel ratio (for high dpi devices)
|
||||
|
||||
self.timeOffset = options.timeOffset || 0; // Time offset would be applied to currentTime from video (option)
|
||||
|
||||
self.hasAlphaBug = false;
|
||||
|
||||
(function() {
|
||||
if (typeof ImageData.prototype.constructor === 'function') {
|
||||
try {
|
||||
// try actually calling ImageData, as on some browsers it's reported
|
||||
// as existing but calling it errors out as "TypeError: Illegal constructor"
|
||||
new window.ImageData(new Uint8ClampedArray([0, 0, 0, 0]), 1, 1);
|
||||
return;
|
||||
} catch (e) {
|
||||
console.log("detected that ImageData is not constructable despite browser saying so");
|
||||
}
|
||||
}
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
window.ImageData = function () {
|
||||
var i = 0;
|
||||
if (arguments[0] instanceof Uint8ClampedArray) {
|
||||
var data = arguments[i++];
|
||||
}
|
||||
var width = arguments[i++];
|
||||
var height = arguments[i];
|
||||
|
||||
var imageData = ctx.createImageData(width, height);
|
||||
if (data) imageData.data.set(data);
|
||||
return imageData;
|
||||
}
|
||||
})();
|
||||
|
||||
self.workerError = function (error) {
|
||||
console.error('Worker error: ', error);
|
||||
if (self.onErrorEvent) {
|
||||
self.onErrorEvent(error);
|
||||
}
|
||||
if (!self.debug) {
|
||||
self.dispose();
|
||||
throw new Error('Worker error: ' + error);
|
||||
}
|
||||
};
|
||||
|
||||
// Not tested for repeated usage yet
|
||||
self.init = function () {
|
||||
if (!window.Worker) {
|
||||
self.workerError('worker not supported');
|
||||
return;
|
||||
}
|
||||
// Worker
|
||||
if (!self.worker) {
|
||||
self.worker = new Worker(self.workerUrl);
|
||||
self.worker.onmessage = self.onWorkerMessage;
|
||||
self.worker.onerror = self.workerError;
|
||||
}
|
||||
self.workerActive = false;
|
||||
self.createCanvas();
|
||||
self.setVideo(options.video);
|
||||
self.setSubUrl(options.subUrl);
|
||||
self.worker.postMessage({
|
||||
target: 'worker-init',
|
||||
width: self.canvas.width,
|
||||
height: self.canvas.height,
|
||||
URL: document.URL,
|
||||
currentScript: self.workerUrl,
|
||||
preMain: true,
|
||||
fastRender: self.lossyRender,
|
||||
subUrl: self.subUrl,
|
||||
subContent: self.subContent,
|
||||
fonts: self.fonts,
|
||||
availableFonts: self.availableFonts,
|
||||
debug: self.debug
|
||||
});
|
||||
};
|
||||
|
||||
self.createCanvas = function () {
|
||||
if (!self.canvas) {
|
||||
if (self.video) {
|
||||
self.isOurCanvas = true;
|
||||
self.canvas = document.createElement('canvas');
|
||||
self.canvas.className = 'libassjs-canvas';
|
||||
self.canvas.style.display = 'none';
|
||||
|
||||
self.canvasParent = document.createElement('div');
|
||||
self.canvasParent.className = 'libassjs-canvas-parent';
|
||||
self.canvasParent.appendChild(self.canvas);
|
||||
|
||||
if (self.video.nextSibling) {
|
||||
self.video.parentNode.insertBefore(self.canvasParent, self.video.nextSibling);
|
||||
}
|
||||
else {
|
||||
self.video.parentNode.appendChild(self.canvasParent);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!self.canvas) {
|
||||
self.workerError('Don\'t know where to render: you should give video or canvas in options.');
|
||||
}
|
||||
}
|
||||
}
|
||||
self.ctx = self.canvas.getContext('2d');
|
||||
self.bufferCanvas = document.createElement('canvas');
|
||||
self.bufferCanvasCtx = self.bufferCanvas.getContext('2d');
|
||||
|
||||
// test for alpha bug, where e.g. WebKit can render a transparent pixel
|
||||
// (with alpha == 0) as non-black which then leads to visual artifacts
|
||||
self.bufferCanvas.width = 1;
|
||||
self.bufferCanvas.height = 1;
|
||||
var testBuf = new Uint8ClampedArray([0, 255, 0, 0]);
|
||||
var testImage = new ImageData(testBuf, 1, 1);
|
||||
self.bufferCanvasCtx.clearRect(0, 0, 1, 1);
|
||||
self.ctx.clearRect(0, 0, 1, 1);
|
||||
var prePut = self.ctx.getImageData(0, 0, 1, 1).data;
|
||||
self.bufferCanvasCtx.putImageData(testImage, 0, 0);
|
||||
self.ctx.drawImage(self.bufferCanvas, 0, 0);
|
||||
var postPut = self.ctx.getImageData(0, 0, 1, 1).data;
|
||||
self.hasAlphaBug = prePut[1] != postPut[1];
|
||||
if (self.hasAlphaBug) {
|
||||
console.log("Detected a browser having issue with transparent pixels, applying workaround");
|
||||
}
|
||||
};
|
||||
|
||||
self.setVideo = function (video) {
|
||||
self.video = video;
|
||||
if (self.video) {
|
||||
var timeupdate = function () {
|
||||
self.setCurrentTime(video.currentTime + self.timeOffset);
|
||||
}
|
||||
self.video.addEventListener("timeupdate", timeupdate, false);
|
||||
self.video.addEventListener("playing", function () {
|
||||
self.setIsPaused(false, video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("pause", function () {
|
||||
self.setIsPaused(true, video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("seeking", function () {
|
||||
self.video.removeEventListener("timeupdate", timeupdate);
|
||||
}, false);
|
||||
self.video.addEventListener("seeked", function () {
|
||||
self.video.addEventListener("timeupdate", timeupdate, false);
|
||||
self.setCurrentTime(video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("ratechange", function () {
|
||||
self.setRate(video.playbackRate);
|
||||
}, false);
|
||||
self.video.addEventListener("timeupdate", function () {
|
||||
self.setCurrentTime(video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
self.video.addEventListener("waiting", function () {
|
||||
self.setIsPaused(true, video.currentTime + self.timeOffset);
|
||||
}, false);
|
||||
|
||||
document.addEventListener("fullscreenchange", self.resizeWithTimeout, false);
|
||||
document.addEventListener("mozfullscreenchange", self.resizeWithTimeout, false);
|
||||
document.addEventListener("webkitfullscreenchange", self.resizeWithTimeout, false);
|
||||
document.addEventListener("msfullscreenchange", self.resizeWithTimeout, false);
|
||||
window.addEventListener("resize", self.resizeWithTimeout, false);
|
||||
|
||||
// Support Element Resize Observer
|
||||
if (typeof ResizeObserver !== "undefined") {
|
||||
self.ro = new ResizeObserver(self.resizeWithTimeout);
|
||||
self.ro.observe(self.video);
|
||||
}
|
||||
|
||||
if (self.video.videoWidth > 0) {
|
||||
self.resize();
|
||||
}
|
||||
else {
|
||||
self.video.addEventListener("loadedmetadata", function (e) {
|
||||
e.target.removeEventListener(e.type, arguments.callee);
|
||||
self.resize();
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.getVideoPosition = function () {
|
||||
var videoRatio = self.video.videoWidth / self.video.videoHeight;
|
||||
var width = self.video.offsetWidth, height = self.video.offsetHeight;
|
||||
var elementRatio = width / height;
|
||||
var realWidth = width, realHeight = height;
|
||||
if (elementRatio > videoRatio) realWidth = Math.floor(height * videoRatio);
|
||||
else realHeight = Math.floor(width / videoRatio);
|
||||
|
||||
var x = (width - realWidth) / 2;
|
||||
var y = (height - realHeight) / 2;
|
||||
|
||||
return {
|
||||
width: realWidth,
|
||||
height: realHeight,
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
};
|
||||
|
||||
self.setSubUrl = function (subUrl) {
|
||||
self.subUrl = subUrl;
|
||||
};
|
||||
|
||||
self.renderFrameData = null;
|
||||
function renderFrames() {
|
||||
var data = self.renderFramesData;
|
||||
var beforeDrawTime = performance.now();
|
||||
self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
|
||||
for (var i = 0; i < data.canvases.length; i++) {
|
||||
var image = data.canvases[i];
|
||||
self.bufferCanvas.width = image.w;
|
||||
self.bufferCanvas.height = image.h;
|
||||
var imageBuffer = new Uint8ClampedArray(image.buffer);
|
||||
if (self.hasAlphaBug) {
|
||||
for (var j = 3; j < imageBuffer.length; j = j + 4) {
|
||||
imageBuffer[j] = (imageBuffer[j] >= 1) ? imageBuffer[j] : 1;
|
||||
}
|
||||
}
|
||||
var imageData = new ImageData(imageBuffer, image.w, image.h);
|
||||
self.bufferCanvasCtx.putImageData(imageData, 0, 0);
|
||||
self.ctx.drawImage(self.bufferCanvas, image.x, image.y);
|
||||
}
|
||||
if (self.debug) {
|
||||
var drawTime = Math.round(performance.now() - beforeDrawTime);
|
||||
console.log(Math.round(data.spentTime) + ' ms (+ ' + drawTime + ' ms draw)');
|
||||
self.renderStart = performance.now();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lossy Render Mode
|
||||
*
|
||||
*/
|
||||
function renderFastFrames() {
|
||||
var data = self.renderFramesData;
|
||||
var beforeDrawTime = performance.now();
|
||||
self.ctx.clearRect(0, 0, self.canvas.width, self.canvas.height);
|
||||
for (var i = 0; i < data.bitmaps.length; i++) {
|
||||
var image = data.bitmaps[i];
|
||||
self.ctx.drawImage(image.bitmap, image.x, image.y);
|
||||
}
|
||||
if (self.debug) {
|
||||
var drawTime = Math.round(performance.now() - beforeDrawTime);
|
||||
console.log(data.bitmaps.length + ' bitmaps, libass: ' + Math.round(data.libassTime) + 'ms, decode: ' + Math.round(data.decodeTime) + 'ms, draw: ' + drawTime + 'ms');
|
||||
self.renderStart = performance.now();
|
||||
}
|
||||
}
|
||||
|
||||
self.workerActive = false;
|
||||
self.frameId = 0;
|
||||
self.onWorkerMessage = function (event) {
|
||||
//dump('\nclient got ' + JSON.stringify(event.data).substr(0, 150) + '\n');
|
||||
if (!self.workerActive) {
|
||||
self.workerActive = true;
|
||||
if (self.onReadyEvent) {
|
||||
self.onReadyEvent();
|
||||
}
|
||||
}
|
||||
var data = event.data;
|
||||
switch (data.target) {
|
||||
case 'stdout': {
|
||||
console.log(data.content);
|
||||
break;
|
||||
}
|
||||
case 'console-log': {
|
||||
console.log.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-debug': {
|
||||
console.debug.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-info': {
|
||||
console.info.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-warn': {
|
||||
console.warn.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'console-error': {
|
||||
console.error.apply(console, JSON.parse(data.content));
|
||||
break;
|
||||
}
|
||||
case 'stderr': {
|
||||
console.error(data.content);
|
||||
break;
|
||||
}
|
||||
case 'window': {
|
||||
window[data.method]();
|
||||
break;
|
||||
}
|
||||
case 'canvas': {
|
||||
switch (data.op) {
|
||||
case 'getContext': {
|
||||
self.ctx = self.canvas.getContext(data.type, data.attributes);
|
||||
break;
|
||||
}
|
||||
case 'resize': {
|
||||
self.resize(data.width, data.height);
|
||||
break;
|
||||
}
|
||||
case 'renderCanvas': {
|
||||
if (self.lastRenderTime < data.time) {
|
||||
self.lastRenderTime = data.time;
|
||||
self.renderFramesData = data;
|
||||
window.requestAnimationFrame(renderFrames);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'renderFastCanvas': {
|
||||
if (self.lastRenderTime < data.time) {
|
||||
self.lastRenderTime = data.time;
|
||||
self.renderFramesData = data;
|
||||
window.requestAnimationFrame(renderFastFrames);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'setObjectProperty': {
|
||||
self.canvas[data.object][data.property] = data.value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw 'eh?';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'tick': {
|
||||
self.frameId = data.id;
|
||||
self.worker.postMessage({
|
||||
target: 'tock',
|
||||
id: self.frameId
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'custom': {
|
||||
if (self['onCustomMessage']) {
|
||||
self['onCustomMessage'](event);
|
||||
} else {
|
||||
throw 'Custom message received but client onCustomMessage not implemented.';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'setimmediate': {
|
||||
self.worker.postMessage({
|
||||
target: 'setimmediate'
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 'get-events': {
|
||||
console.log(data.target);
|
||||
console.log(data.events);
|
||||
break;
|
||||
}
|
||||
case 'get-styles': {
|
||||
console.log(data.target);
|
||||
console.log(data.styles);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw 'what? ' + data.target;
|
||||
}
|
||||
};
|
||||
|
||||
self.resize = function (width, height, top, left) {
|
||||
var videoSize = null;
|
||||
top = top || 0;
|
||||
left = left || 0;
|
||||
if ((!width || !height) && self.video) {
|
||||
videoSize = self.getVideoPosition();
|
||||
width = videoSize.width * self.pixelRatio;
|
||||
height = videoSize.height * self.pixelRatio;
|
||||
var offset = self.canvasParent.getBoundingClientRect().top - self.video.getBoundingClientRect().top;
|
||||
top = videoSize.y - offset;
|
||||
left = videoSize.x;
|
||||
}
|
||||
if (!width || !height) {
|
||||
if (!self.video) {
|
||||
console.error('width or height is 0. You should specify width & height for resize.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
self.canvas.width != width ||
|
||||
self.canvas.height != height ||
|
||||
self.canvas.style.top != top ||
|
||||
self.canvas.style.left != left
|
||||
) {
|
||||
self.canvas.width = width;
|
||||
self.canvas.height = height;
|
||||
|
||||
if (videoSize != null) {
|
||||
self.canvasParent.style.position = 'relative';
|
||||
self.canvas.style.display = 'block';
|
||||
self.canvas.style.position = 'absolute';
|
||||
self.canvas.style.width = videoSize.width + 'px';
|
||||
self.canvas.style.height = videoSize.height + 'px';
|
||||
self.canvas.style.top = top + 'px';
|
||||
self.canvas.style.left = left + 'px';
|
||||
self.canvas.style.pointerEvents = 'none';
|
||||
}
|
||||
|
||||
self.worker.postMessage({
|
||||
target: 'canvas',
|
||||
width: self.canvas.width,
|
||||
height: self.canvas.height
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
self.resizeWithTimeout = function () {
|
||||
self.resize();
|
||||
setTimeout(self.resize, 100);
|
||||
};
|
||||
|
||||
self.runBenchmark = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'runBenchmark'
|
||||
});
|
||||
};
|
||||
|
||||
self.customMessage = function (data, options) {
|
||||
options = options || {};
|
||||
self.worker.postMessage({
|
||||
target: 'custom',
|
||||
userData: data,
|
||||
preMain: options.preMain
|
||||
});
|
||||
};
|
||||
|
||||
self.setCurrentTime = function (currentTime) {
|
||||
self.worker.postMessage({
|
||||
target: 'video',
|
||||
currentTime: currentTime
|
||||
});
|
||||
};
|
||||
|
||||
self.setTrackByUrl = function (url) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-track-by-url',
|
||||
url: url
|
||||
});
|
||||
};
|
||||
|
||||
self.setTrack = function (content) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-track',
|
||||
content: content
|
||||
});
|
||||
};
|
||||
|
||||
self.freeTrack = function (content) {
|
||||
self.worker.postMessage({
|
||||
target: 'free-track'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
self.render = self.setCurrentTime;
|
||||
|
||||
self.setIsPaused = function (isPaused, currentTime) {
|
||||
self.worker.postMessage({
|
||||
target: 'video',
|
||||
isPaused: isPaused,
|
||||
currentTime: currentTime
|
||||
});
|
||||
};
|
||||
|
||||
self.setRate = function (rate) {
|
||||
self.worker.postMessage({
|
||||
target: 'video',
|
||||
rate: rate
|
||||
});
|
||||
};
|
||||
|
||||
self.dispose = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'destroy'
|
||||
});
|
||||
|
||||
self.worker.terminate();
|
||||
self.workerActive = false;
|
||||
// Remove the canvas element to remove residual subtitles rendered on player
|
||||
if (self.video) {
|
||||
self.video.parentNode.removeChild(self.canvasParent);
|
||||
}
|
||||
};
|
||||
|
||||
self.createEvent = function (event) {
|
||||
self.worker.postMessage({
|
||||
target: 'create-event',
|
||||
event: event
|
||||
});
|
||||
};
|
||||
|
||||
self.getEvents = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'get-events'
|
||||
});
|
||||
};
|
||||
|
||||
self.setEvent = function (event, index) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-event',
|
||||
event: event,
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.removeEvent = function (index) {
|
||||
self.worker.postMessage({
|
||||
target: 'remove-event',
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.createStyle = function (style) {
|
||||
self.worker.postMessage({
|
||||
target: 'create-style',
|
||||
style: style
|
||||
});
|
||||
};
|
||||
|
||||
self.getStyles = function () {
|
||||
self.worker.postMessage({
|
||||
target: 'get-styles'
|
||||
});
|
||||
};
|
||||
|
||||
self.setStyle = function (style, index) {
|
||||
self.worker.postMessage({
|
||||
target: 'set-style',
|
||||
style: style,
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.removeStyle = function (index) {
|
||||
self.worker.postMessage({
|
||||
target: 'remove-style',
|
||||
index: index
|
||||
});
|
||||
};
|
||||
|
||||
self.init();
|
||||
};
|
||||
|
||||
if (typeof SubtitlesOctopusOnLoad == 'function') {
|
||||
SubtitlesOctopusOnLoad();
|
||||
}
|
||||
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
exports = module.exports = SubtitlesOctopus
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
[Script Info]
|
||||
Title:
|
||||
ScriptType: v4.00+
|
||||
WrapStyle: 0
|
||||
PlayResX: 640
|
||||
PlayResY: 480
|
||||
ScaledBorderAndShadow: yes
|
||||
|
||||
[V4+ Styles]
|
||||
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
||||
Style: Default,Arial,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,0
|
||||
Style: Alt,Times New Roman,40,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,8,10,10,10,0
|
||||
|
||||
[Events]
|
||||
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
||||
Comment: 0,0:00:00.00,0:00:05.00,Default,,0000,0000,0000,,This line is a comment and should not display on rendered output. This file is intended to be rendered on a 640x480 video, preferably a single solid colour, or maybe a checkerboard pattern.
|
||||
Dialogue: 0,0:00:00.00,0:00:05.00,Default,,0000,0000,0000,,This is a test of the ASS format and some basic features in it.
|
||||
Dialogue: 0,0:00:05.00,0:00:07.00,Default,,0000,0000,0000,,This and the previous line should both show at the bottom of the video in 20 pixel high white Arial with a 2 pixel black outline and 2 pixel offset shadow. This line is long so it should automatically be broken into several lines that are approximately even length, with upper lines being longer.
|
||||
Dialogue: 0,0:00:07.00,0:00:09.00,Default,,0000,0000,0000,,Now going to test conflict resolution. {By the way, this is a common abuse, "inline-comments" in override tag groups. They should not be rendered and not generate errors, just be ignored.}
|
||||
Dialogue: 0,0:00:07.50,0:00:09.00,Default,,0000,0000,0000,,This line should be above the previous.
|
||||
Dialogue: 0,0:00:09.00,0:00:11.00,Default,,0000,0000,0000,,{\an1}This line should be lower-left aligned using the \an1 override.
|
||||
Dialogue: 0,0:00:11.00,0:00:13.00,Default,,0000,0000,0000,,{\an9}Upper right
|
||||
Dialogue: 0,0:00:12.00,0:00:14.00,Alt,,0000,0000,0000,,This one should be below the "Upper right" line and be centered on screen. It should also be in 40 pixel high Times New Roman.
|
||||
Dialogue: 0,0:00:14.00,0:00:16.00,Alt,,0000,0000,0000,,{\fs10}This should also be a toptitle in Times New Roman, but much smaller. Using an override tag to change size.
|
||||
Dialogue: 0,0:00:16.00,0:00:18.00,Alt,,0000,0000,0000,,{\a5}Top-left using the legacy \a5 tag
|
||||
Dialogue: 0,0:00:18.00,0:00:20.00,Default,,0000,0000,0000,,{\an5}This line is centered on screen.\NAt the bottom of the screen should be two lines in different layers, they are rendered on top of each other because conflict resolution only considers lines in the same layer.
|
||||
Dialogue: 0,0:00:18.00,0:00:20.00,Default,,0000,0000,0000,,This is in layer 0
|
||||
Dialogue: 1,0:00:18.00,0:00:20.00,Default,,0000,0000,0000,,And this line is in layer 1
|
||||
Dialogue: 0,0:00:20.00,0:00:22.00,Default,,0000,0000,0000,,Another line in layer 0
|
||||
Dialogue: 1,0:00:20.00,0:00:22.00,Default,,0050,0000,0020,,And this line is in layer 1, but has changed its margins so it isn't exactly centered, and it's raised above the other line.
|
||||
Dialogue: 0,0:00:22.00,0:00:24.00,Default,,0000,0000,0000,,Switching {\fnTimes New Roman}font inline, {\r}and resetting styles
|
||||
Dialogue: 0,0:00:24.00,0:00:26.00,Default,,0000,0000,0000,,Also {\rAlt}switching to a different style {\r}inline
|
||||
Dialogue: 0,0:00:26.00,0:00:28.00,Default,,0000,0000,0000,,{\an5\pos(258,131)}Positioning... this line should be in an odd place
|
||||
Dialogue: 0,0:00:26.00,0:00:28.00,Default,,0000,0000,0000,,{\an5\pos(222,338)\frz29.559}So should this one, and be rotated
|
||||
Dialogue: 0,0:00:28.00,0:00:30.00,Default,,0000,0000,0000,,{\pos(371,314)\frz338.403\frx42\fry30\org(187,165)}Some more rotation tricks, this time in 3D and with a different origin
|
||||
Dialogue: 0,0:00:30.00,0:00:32.00,Default,,0000,0000,0000,,{\an5\t(\frz360)}This line is animated and rotates 360 degrees over its duration
|
||||
Dialogue: 0,0:00:32.00,0:00:34.00,Default,,0000,0000,0000,,{\an5\move(182,157,414,311)}This line moves
|
||||
Dialogue: 0,0:00:34.00,0:00:36.00,Default,,0000,0000,0000,,{\an5\clip(126,192,487,241)}This line is only partially visible\Nso if you can see this, \clip is handled incorrectly
|
||||
Dialogue: 0,0:00:36.00,0:00:38.00,Default,,0000,0000,0000,,{\an5\clip(m 178 212 l 163 249 212 302 257 232 309 249 366 241 392 285 473 267 487 210 421 241 353 219 207 258)}And this line has a funnily-shaped clip area
|
||||
Dialogue: 0,0:00:38.00,0:00:40.00,Default,,0000,0000,0000,,{\an5\pos(321,193)}Here should be a pretty feather with a thin border and no shadow:
|
||||
Dialogue: 0,0:00:38.00,0:00:40.00,Default,,0000,0000,0000,,{\an5\bord1\shad0\p1\fscx300\fscy300\pos(316,312)}m 0 0 b 33 -3 48 -7 61 -19 b 53 -7 31 -1 1 2 m 9 0 b 9 -5 10 -6 14 -12 b 9 -5 10 -3 10 0 m 10 -1 b 10 -5 11 -8 16 -12 b 17 -12 18 -13 22 -14 b 18 -10 16 -6 15 -1 b 17 -6 19 -10 23 -14 l 26 -15 b 22 -11 20 -6 19 -2 b 24 -11 27 -14 28 -15 b 31 -16 35 -16 39 -16 b 37 -14 36 -10 36 -5 b 36 -9 38 -14 39 -16 b 41 -16 43 -16 45 -15 b 44 -13 43 -10 43 -7 l 29 -3 m 43 -7 b 44 -11 45 -13 47 -15 b 46 -13 46 -11 46 -9 b 46 -11 47 -13 49 -15 b 51 -15 48 -13 48 -9 b 49 -11 49 -14 52 -16 b 55 -16 53 -17 51 -11 l 48 -8 m 54 -13 b 53 -14 54 -15 54 -16 b 54 -15 54 -14 55 -13 b 57 -13 60 -12 62 -14 b 61 -12 55 -12 53 -12 b 55 -11 56 -10 61 -10 b 61 -7 53 -9 52 -11 b 53 -8 55 -7 58 -6 b 57 -5 56 -4 54 -3 b 49 -5 48 -6 47 -9 b 47 -6 50 -4 53 -2 b 49 -3 47 -6 45 -8 b 46 -6 49 -3 52 -1 b 46 2 45 3 43 3 b 40 0 39 -3 40 -6 b 39 -3 39 1 42 3 b 40 6 36 1 34 -4 b 35 -1 36 2 38 5 b 32 7 26 9 22 8 b 19 5 17 2 16 -1 b 17 3 19 5 20 7 b 17 4 16 2 15 0 b 15 2 17 5 19 8 b 15 9 13 3 12 0 l 25 -2 l 42 -7 m 12 0 b 13 3 13 7 17 9 b 12 7 10 1 10 0
|
||||
Dialogue: 0,0:00:40.00,0:00:42.00,Default,,0000,0000,0000,,Some other basic font style tests:\NNormal, {\b1}Boldface{\r}, {\i1}Italics{\r}, {\u1}Underline{\r}, {\s1}Strikethrough
|
||||
Dialogue: 0,0:00:42.00,0:00:44.00,Default,,0000,0000,0000,,There should be no linebreak here,\nbut there should be one here\Nso this is on a separate line.
|
||||
Dialogue: 0,0:00:44.00,0:00:46.00,Default,,0000,0000,0000,,This line is pushed left by adding some hard spaces to the right\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h\h
|
||||
Dialogue: 0,0:00:44.00,0:00:46.00,Default,,0000,0000,0000,, Regular spaces at line start/end are ignored, so this line is centered
|
||||
Dialogue: 0,0:00:46.00,0:00:48.00,Default,,0000,0000,0000,,{\an8\q2}This is a long line but it is not broken into several because it's using the \q override tag which changes the line-wrapping mode for a single line. The tag can take several values, 0 is the default which is "smart wrapping" with top lines longer, 1 is regular wrapping, 2 is no wrapping and 3 is smart-wrapping with bottom lines longer.
|
||||
Dialogue: 0,0:00:46.00,0:00:48.00,Default,,0000,0000,0000,,{\an5\q1}This is a long line using the \q1 override tag to get "dumb" wrapping, make as long lines as possible and first wrap when it'd go off screen. This is mostly visible when the last line generated is short.
|
||||
Dialogue: 0,0:00:46.00,0:00:48.00,Default,,0000,0000,0000,,{\q3}And this line uses the \q3 wrapping style, which is similar to the \q0 default smart-wrap style, but has lower lines longer than the upper ones.
|
||||
Dialogue: 0,0:00:48.00,0:00:50.00,Default,,0000,0000,0000,,{\an5}{\bord0\t(\bord10)}This text has a growing border\N{\r\shad0\t(\shad10)}This text has an increasing shadow\N{\r\t(\fry360)}This text is rotating around the Y axis\N{\r\t(\frz720)}This text rotates {\t(\frx360)}and this one even more
|
||||
Dialogue: 0,0:00:50.00,0:00:52.00,Default,,0000,0000,0000,,{\an5\bord0\shad0}All of this has no border or shadow...\N{\1c&H0000FF&}This is bright red, {\1c&H00FF00&}green, {\1c&HFF0000}blue{\1c&HFFFFFF&}\N{\1a&H80&}50% transparent
|
||||
Dialogue: 0,0:00:52.00,0:00:54.00,Default,,0000,0000,0000,,{\fsp10}Large inter-letter spacing
|
||||
Dialogue: 0,0:00:54.00,0:00:56.00,Default,,0000,0000,0000,,{\shad0}No shadow here, just regular border, {\be1}but this is \be1 blurred edges!
|
||||
Dialogue: 0,0:00:56.00,0:00:58.00,Default,,0000,0000,0000,,{\t(1000,2000,\alpha&HFF&)}Fading out after 1 sec on screen, using \alpha. Everything should fade.
|
||||
Dialogue: 0,0:00:58.00,0:01:00.00,Default,,0000,0000,0000,,{\fad(1000,1000)}Fading in and out using \fad
|
||||
Dialogue: 0,0:01:00.00,0:01:02.00,Default,,0000,0000,0000,,{\k10}And {\k5}now {\k20}for {\kf50}ka{\kf20}ra{\K70}o{\K10}ke{\k0}!
|
||||
Dialogue: 0,0:01:02.00,0:01:04.00,Default,,0000,0000,0000,,{\an5\t()\clip(69,215,573,267)\t(1000,2000,3,\clip(573,267,573,267))}And the last thing on the programme, an animated rectangular \clip, delayed by 1 second. And it even uses acceleration...!
|
||||
@@ -1,49 +0,0 @@
|
||||
[Script Info]
|
||||
; // 此字幕由爱幕生成
|
||||
Synch Point:1
|
||||
ScriptType:v4.00+
|
||||
Collisions:Normal
|
||||
|
||||
[V4+ Styles]
|
||||
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
||||
Style: Default, Microsoft YaHei, 20, &H00FFFFFF, &H000092FE, &H00000000, &H82000000, 0, 0, 0, 0, 100, 100, 0, 0, 1, 1, 2, 2, 10, 10, 30, 134
|
||||
Style: Style1, Microsoft YaHei, 20, &H0000DCFC, &H0000DCFC, &H00000000, &H82000000, 0, 0, 0, 0, 100, 100, 1, 0, 1, 1, 2, 2, 10, 10, 30, 134
|
||||
Style: Style2, ZCOOL KuaiLe, 20, &H0000DDA4, &H0000DDA4, &H00334D19, &H82000000, 0, 0, 0, 0, 100, 100, 1, 0, 4, 1, 3, 2, 10, 10, 50, 134
|
||||
Style: Style3, Source Han Sans CN Medium, 28, &H009E14AB, &H009E14AB, &H00009EFB, &H82000000, 0, 0, 0, 0, 100, 100, 1, 0, 1, 1, 2, 2, 10, 10, 100, 134
|
||||
|
||||
[Events]
|
||||
Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text
|
||||
Dialogue: 0,0:00:00.31,0:00:00.84,Style1,NTP,0000,0000,0000,,那一天\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}あの日
|
||||
Dialogue: 0,0:00:01.28,0:00:02.22,Style2,NTP,0000,0000,0000,,星星降落的日子\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}星が降った日
|
||||
Dialogue: 0,0:00:03.15,0:00:04.41,Style3,NTP,0000,0000,0000,,那简直是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}それはまるで
|
||||
Dialogue: 0,0:00:04.45,0:00:04.97,Default,NTP,0000,0000,0000,,简直\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}まるで
|
||||
Dialogue: 0,0:00:05.12,0:00:06.30,Default,NTP,0000,0000,0000,,像梦中的景色一样\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}夢の景色のように
|
||||
Dialogue: 0,0:00:07.44,0:00:08.98,Default,NTP,0000,0000,0000,,美丽的景色\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}美しい眺めだった
|
||||
Dialogue: 0,0:00:24.60,0:00:25.09,Default,NTP,0000,0000,0000,,放学后\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}放課後
|
||||
Dialogue: 0,0:00:25.70,0:00:26.26,Default,NTP,0000,0000,0000,,不好\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}悪い
|
||||
Dialogue: 0,0:00:26.48,0:00:27.68,Default,NTP,0000,0000,0000,,我今天开始打工\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}おれ今日これからバイト
|
||||
Dialogue: 0,0:00:29.34,0:00:31.69,Default,NTP,0000,0000,0000,,已经讨厌这样的乡下了\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}もうこんな田舎嫌だよー
|
||||
Dialogue: 0,0:00:31.97,0:00:33.53,Default,NTP,0000,0000,0000,,讨厌这样的人生\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}こんな人生嫌だ
|
||||
Dialogue: 0,0:00:33.93,0:00:37.97,Default,NTP,0000,0000,0000,,来世请让我成为东京的帅哥吧\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}来世は東京のイケメン男子にしてくださーい
|
||||
Dialogue: 0,0:00:42.08,0:00:42.87,Default,NTP,0000,0000,0000,,哪里\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}どこ
|
||||
Dialogue: 0,0:00:43.05,0:00:44.17,Default,NTP,0000,0000,0000,,那么说来\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}そういえば
|
||||
Dialogue: 0,0:00:44.55,0:00:47.08,Default,NTP,0000,0000,0000,,我觉得好像一直做着奇怪的梦\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}ずっと変な夢を見てたような気がするんだけど
|
||||
Dialogue: 0,0:00:48.32,0:00:50.63,Default,NTP,0000,0000,0000,,别人的人生中…梦\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}別の人の人生の…夢
|
||||
Dialogue: 0,0:00:51.45,0:00:52.74,Default,NTP,0000,0000,0000,,这是什么\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}何だ これ
|
||||
Dialogue: 0,0:00:54.78,0:00:55.44,Default,NTP,0000,0000,0000,,这个,这个\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}これって
|
||||
Dialogue: 0,0:00:56.72,0:00:57.72,Default,NTP,0000,0000,0000,,这难道是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}これってもしかして
|
||||
Dialogue: 0,0:00:58.08,0:00:59.33,Default,NTP,0000,0000,0000,,我们在梦中\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}俺達は夢の中で
|
||||
Dialogue: 0,0:01:00.14,0:01:01.20,Default,NTP,0000,0000,0000,,替换着\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}入れ替わってる
|
||||
Dialogue: 0,0:01:07.37,0:01:08.30,Default,NTP,0000,0000,0000,,确实的事情\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}確かなことが
|
||||
Dialogue: 0,0:01:08.76,0:01:09.54,Default,NTP,0000,0000,0000,,只有一个\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}一つだけある
|
||||
Dialogue: 0,0:01:10.33,0:01:11.04,Default,NTP,0000,0000,0000,,我们是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}私達は
|
||||
Dialogue: 0,0:01:11.42,0:01:12.32,Default,NTP,0000,0000,0000,,见面的话绝对\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}会えば絶対
|
||||
Dialogue: 0,0:01:12.68,0:01:13.53,Default,NTP,0000,0000,0000,,马上就明白\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}すぐにわかる
|
||||
Dialogue: 0,0:01:14.25,0:01:15.28,Default,NTP,0000,0000,0000,,我想说\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}言おうと思ったんだ
|
||||
Dialogue: 0,0:01:16.08,0:01:17.58,Default,NTP,0000,0000,0000,,你是世界的无论在哪里\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}お前が世界のどこにいても
|
||||
Dialogue: 0,0:01:17.95,0:01:19.05,Default,NTP,0000,0000,0000,,一定要去见你\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}必ず会いに行くって
|
||||
Dialogue: 0,0:01:20.14,0:01:20.94,Default,NTP,0000,0000,0000,,你是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}あなたは
|
||||
Dialogue: 0,0:01:21.36,0:01:21.80,Default,NTP,0000,0000,0000,,谁\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}誰
|
||||
Dialogue: 0,0:01:22.20,0:01:22.76,Default,NTP,0000,0000,0000,,你是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}お前は
|
||||
Dialogue: 0,0:01:23.48,0:01:24.04,Default,NTP,0000,0000,0000,,谁\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}誰だ
|
||||
Dialogue: 0,0:01:25.69,0:01:26.47,Default,NTP,0000,0000,0000,,你的名字是\N{\fs12}{\3c&&H00000000&}{\c&&H000092FE&}君の名は
|
||||
@@ -1,304 +1,312 @@
|
||||
(function () {
|
||||
Artplayer.DEBUG = true;
|
||||
Artplayer.DEBUG = true
|
||||
|
||||
if (Artplayer.utils.isMobile) {
|
||||
window.location.href = './mobile.html' + location.search;
|
||||
if (Artplayer.utils.isMobile) {
|
||||
window.location.href = `./mobile.html${location.search}`
|
||||
}
|
||||
|
||||
let $codeMirror = document.querySelector('.codeMirrorWrap')
|
||||
let $lib = document.querySelector('.libsInput')
|
||||
let $run = document.querySelector('.run')
|
||||
let $popups = document.querySelector('.popups')
|
||||
let $console = document.querySelector('.console')
|
||||
let $prod = document.querySelector('#prod')
|
||||
let $ts = document.querySelector('#ts')
|
||||
let $code = document.querySelector('#code')
|
||||
let $log = document.querySelector('#log')
|
||||
let $file = document.querySelector('#file')
|
||||
let $editor = document.querySelector('#editor')
|
||||
|
||||
window.consoleLog($console)
|
||||
|
||||
// Helper functions for localStorage
|
||||
const getStorageBoolean = (key) => localStorage.getItem(key) === 'true'
|
||||
const setStorageBoolean = (key, value) => localStorage.setItem(key, value ? 'true' : 'false')
|
||||
|
||||
$prod.checked = getStorageBoolean('prod')
|
||||
$ts.checked = getStorageBoolean('ts')
|
||||
$code.checked = getStorageBoolean('code')
|
||||
$log.checked = getStorageBoolean('log')
|
||||
|
||||
if ($code.checked) {
|
||||
$editor.style.display = 'none'
|
||||
}
|
||||
|
||||
if ($log.checked) {
|
||||
$console.style.display = 'none'
|
||||
}
|
||||
|
||||
let editor = null
|
||||
let loadedLibs = []
|
||||
require.config({ paths: { vs: './assets/js/vs' } })
|
||||
require(['vs/editor/editor.main'], async () => {
|
||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: false,
|
||||
})
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.languages.typescript.ScriptTarget.ES6,
|
||||
allowNonTsExtensions: true,
|
||||
})
|
||||
|
||||
let libUris = [
|
||||
'./assets/ts/artplayer-plugin-ads.d.ts',
|
||||
'./assets/ts/artplayer-plugin-ambilight.d.ts',
|
||||
'./assets/ts/artplayer-plugin-asr.d.ts',
|
||||
'./assets/ts/artplayer-plugin-audio-track.d.ts',
|
||||
'./assets/ts/artplayer-plugin-auto-thumbnail.d.ts',
|
||||
'./assets/ts/artplayer-plugin-chapter.d.ts',
|
||||
'./assets/ts/artplayer-plugin-chromecast.d.ts',
|
||||
'./assets/ts/artplayer-plugin-danmuku-mask.d.ts',
|
||||
'./assets/ts/artplayer-plugin-danmuku.d.ts',
|
||||
'./assets/ts/artplayer-plugin-dash-control.d.ts',
|
||||
'./assets/ts/artplayer-plugin-document-pip.d.ts',
|
||||
'./assets/ts/artplayer-plugin-hls-control.d.ts',
|
||||
'./assets/ts/artplayer-plugin-jassub.d.ts',
|
||||
'./assets/ts/artplayer-plugin-multiple-subtitles.d.ts',
|
||||
'./assets/ts/artplayer-plugin-vast.d.ts',
|
||||
'./assets/ts/artplayer-plugin-vtt-thumbnail.d.ts',
|
||||
'./assets/ts/artplayer-proxy-canvas.d.ts',
|
||||
'./assets/ts/artplayer-proxy-mediabunny.d.ts',
|
||||
'./assets/ts/artplayer-tool-iframe.d.ts',
|
||||
'./assets/ts/artplayer.d.ts',
|
||||
]
|
||||
|
||||
for (let index = 0; index < libUris.length; index++) {
|
||||
let libUri = libUris[index]
|
||||
let libSource = await (await fetch(libUri)).text()
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri)
|
||||
monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri))
|
||||
}
|
||||
|
||||
var $codeMirror = document.querySelector('.codeMirrorWrap');
|
||||
var $lib = document.querySelector('.libsInput');
|
||||
var $run = document.querySelector('.run');
|
||||
var $popups = document.querySelector('.popups');
|
||||
var $console = document.querySelector('.console');
|
||||
var $prod = document.querySelector('#prod');
|
||||
var $ts = document.querySelector('#ts');
|
||||
var $code = document.querySelector('#code');
|
||||
var $log = document.querySelector('#log');
|
||||
var $file = document.querySelector('#file');
|
||||
var $editor = document.querySelector('#editor');
|
||||
const disposable = monaco.editor.onDidCreateEditor(() => {
|
||||
disposable.dispose()
|
||||
setTimeout(initApp, 1000)
|
||||
})
|
||||
|
||||
window['consoleLog']($console);
|
||||
editor = monaco.editor.create($codeMirror, {
|
||||
theme: 'vs-dark',
|
||||
folding: true,
|
||||
automaticLayout: true,
|
||||
quickSuggestions: {
|
||||
other: true,
|
||||
comments: true,
|
||||
strings: true,
|
||||
},
|
||||
model: monaco.editor.createModel(
|
||||
[
|
||||
'var art = new Artplayer({',
|
||||
'\tcontainer: \'.artplayer-app\',',
|
||||
'\turl: \'/assets/sample/video.mp4\',',
|
||||
'});',
|
||||
].join('\n'),
|
||||
$ts.checked ? 'typescript' : 'javascript',
|
||||
),
|
||||
})
|
||||
})
|
||||
|
||||
$prod.checked = localStorage.getItem('prod') === 'true';
|
||||
$ts.checked = localStorage.getItem('ts') === 'true';
|
||||
$code.checked = localStorage.getItem('code') === 'true';
|
||||
$log.checked = localStorage.getItem('log') === 'true';
|
||||
function getURLParameters(url) {
|
||||
return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce((params, pair) => {
|
||||
const index = pair.indexOf('=')
|
||||
params[pair.slice(0, index)] = pair.slice(index + 1)
|
||||
return params
|
||||
}, {})
|
||||
}
|
||||
|
||||
if ($code.checked) {
|
||||
$editor.style.display = 'none';
|
||||
function getExt(url) {
|
||||
if (url.includes('?')) {
|
||||
return getExt(url.split('?')[0])
|
||||
}
|
||||
|
||||
if ($log.checked) {
|
||||
$console.style.display = 'none';
|
||||
if (url.includes('#')) {
|
||||
return getExt(url.split('#')[0])
|
||||
}
|
||||
|
||||
var editor = null;
|
||||
var loadedLibs = [];
|
||||
require.config({ paths: { vs: './assets/js/vs' } });
|
||||
require(['vs/editor/editor.main'], async function () {
|
||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
|
||||
noSemanticValidation: true,
|
||||
noSyntaxValidation: false,
|
||||
});
|
||||
return url.trim().toLowerCase().split('.').pop()
|
||||
}
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
target: monaco.languages.typescript.ScriptTarget.ES6,
|
||||
allowNonTsExtensions: true,
|
||||
});
|
||||
function loadScript(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const originalDefine = window.define
|
||||
window.define = undefined
|
||||
const script = document.createElement('script')
|
||||
script.type = 'text/javascript'
|
||||
script.src = url
|
||||
script.onload = () => {
|
||||
window.define = originalDefine
|
||||
resolve(url)
|
||||
}
|
||||
script.onerror = () => {
|
||||
window.define = originalDefine
|
||||
reject(new Error(`Loading script failed: ${url}`))
|
||||
}
|
||||
document.head.appendChild(script)
|
||||
})
|
||||
}
|
||||
|
||||
var libUris = [
|
||||
'./assets/ts/artplayer-plugin-ads.d.ts',
|
||||
'./assets/ts/artplayer-plugin-ambilight.d.ts',
|
||||
'./assets/ts/artplayer-plugin-auto-thumbnail.d.ts',
|
||||
'./assets/ts/artplayer-plugin-chapter.d.ts',
|
||||
'./assets/ts/artplayer-plugin-chromecast.d.ts',
|
||||
'./assets/ts/artplayer-plugin-danmuku-mask.d.ts',
|
||||
'./assets/ts/artplayer-plugin-danmuku.d.ts',
|
||||
'./assets/ts/artplayer-plugin-dash-control.d.ts',
|
||||
'./assets/ts/artplayer-plugin-hls-control.d.ts',
|
||||
'./assets/ts/artplayer-plugin-iframe.d.ts',
|
||||
'./assets/ts/artplayer-plugin-libass.d.ts',
|
||||
'./assets/ts/artplayer-plugin-multiple-subtitles.d.ts',
|
||||
'./assets/ts/artplayer-plugin-vast.d.ts',
|
||||
'./assets/ts/artplayer-plugin-vtt-thumbnail.d.ts',
|
||||
'./assets/ts/artplayer.d.ts',
|
||||
];
|
||||
|
||||
for (let index = 0; index < libUris.length; index++) {
|
||||
var libUri = libUris[index];
|
||||
var libSource = await (await fetch(libUri)).text();
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri);
|
||||
monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri));
|
||||
}
|
||||
function loadStyle(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const link = document.createElement('link')
|
||||
link.rel = 'stylesheet'
|
||||
link.href = url
|
||||
link.onload = () => resolve(url)
|
||||
link.onerror = () => reject(new Error(`Loading style failed: ${url}`))
|
||||
document.head.appendChild(link)
|
||||
})
|
||||
}
|
||||
|
||||
var disposable = monaco.editor.onDidCreateEditor(function () {
|
||||
disposable.dispose();
|
||||
setTimeout(initApp, 1000);
|
||||
});
|
||||
function loadLib(libs) {
|
||||
const libPromises = []
|
||||
const libsDecoded = decodeURIComponent(libs || '')
|
||||
const urls = libsDecoded
|
||||
.split(/\r?\n/)
|
||||
.filter((url) => url.trim() && !loadedLibs.includes(url))
|
||||
|
||||
urls.forEach((url) => {
|
||||
const ext = getExt(url)
|
||||
if (ext === 'js') {
|
||||
libPromises.push(loadScript(url))
|
||||
} else if (ext === 'css') {
|
||||
libPromises.push(loadStyle(url))
|
||||
}
|
||||
})
|
||||
|
||||
$lib.value = libsDecoded
|
||||
return Promise.all(libPromises)
|
||||
}
|
||||
|
||||
editor = monaco.editor.create($codeMirror, {
|
||||
theme: 'vs-dark',
|
||||
folding: true,
|
||||
automaticLayout: true,
|
||||
quickSuggestions: {
|
||||
other: true,
|
||||
comments: true,
|
||||
strings: true,
|
||||
},
|
||||
model: monaco.editor.createModel(
|
||||
[
|
||||
'var art = new Artplayer({',
|
||||
"\tcontainer: '.artplayer-app',",
|
||||
"\turl: '/assets/sample/video.mp4',",
|
||||
'});',
|
||||
].join('\n'),
|
||||
$ts.checked ? 'typescript' : 'javascript',
|
||||
),
|
||||
});
|
||||
});
|
||||
function runExample(name) {
|
||||
fetch(`./assets/example/${name}.js`)
|
||||
.then((response) => {
|
||||
return response.text()
|
||||
})
|
||||
.then((text) => {
|
||||
editor.setValue(text)
|
||||
runCode()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
function getURLParameters(url) {
|
||||
return (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(function (a, v) {
|
||||
return (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a;
|
||||
}, {});
|
||||
function loadCode(code, example) {
|
||||
if (example) {
|
||||
runExample(example)
|
||||
}
|
||||
|
||||
function getExt(url) {
|
||||
if (url.includes('?')) {
|
||||
return getExt(url.split('?')[0]);
|
||||
}
|
||||
|
||||
if (url.includes('#')) {
|
||||
return getExt(url.split('#')[0]);
|
||||
}
|
||||
|
||||
return url.trim().toLowerCase().split('.').pop();
|
||||
else if (code) {
|
||||
editor.setValue(decodeURIComponent(code).trim())
|
||||
runCode()
|
||||
}
|
||||
|
||||
function loadScript(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var define2 = window.define;
|
||||
window.define = undefined;
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.src = url;
|
||||
script.onload = function () {
|
||||
window.define = define2;
|
||||
resolve(url);
|
||||
};
|
||||
script.onerror = function () {
|
||||
reject(new Error('Loading script failed:' + url));
|
||||
};
|
||||
document.querySelector('head').appendChild(script);
|
||||
});
|
||||
else {
|
||||
runExample('index')
|
||||
}
|
||||
}
|
||||
|
||||
function loadStyle(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.href = url;
|
||||
link.onload = function () {
|
||||
resolve(url);
|
||||
};
|
||||
link.onerror = function () {
|
||||
reject(new Error('Loading style failed:' + url));
|
||||
};
|
||||
document.querySelector('head').appendChild(link);
|
||||
});
|
||||
function runCode() {
|
||||
// Destroy all existing instances
|
||||
Artplayer.instances.forEach((art) => art.destroy(true))
|
||||
|
||||
const value = editor.getValue()
|
||||
eval(value)
|
||||
window.art = Artplayer.instances[0]
|
||||
}
|
||||
|
||||
function initApp() {
|
||||
const urlParams = getURLParameters(window.location.href)
|
||||
const { code, libs, example } = urlParams
|
||||
|
||||
loadLib(libs)
|
||||
.then((result) => {
|
||||
loadedLibs.push(...result)
|
||||
loadCode(code, example)
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to initialize app:', err)
|
||||
})
|
||||
}
|
||||
|
||||
function restart() {
|
||||
const libs = encodeURIComponent($lib.value)
|
||||
const code = encodeURIComponent(editor.getValue())
|
||||
const url = `${window.location.origin}${window.location.pathname}?libs=${libs}&code=${code}`
|
||||
history.pushState(null, null, url)
|
||||
initApp()
|
||||
}
|
||||
|
||||
function readFile(file) {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader()
|
||||
reader.onload = () => resolve(reader.result)
|
||||
reader.readAsText(file)
|
||||
})
|
||||
}
|
||||
|
||||
$run.addEventListener('click', () => {
|
||||
restart()
|
||||
})
|
||||
|
||||
$popups.addEventListener('click', function (event) {
|
||||
if (event.target === this) {
|
||||
this.style.display = 'none'
|
||||
}
|
||||
})
|
||||
|
||||
function loadLib(libs) {
|
||||
var libPromise = [];
|
||||
var libsDecode = decodeURIComponent(libs || '');
|
||||
libsDecode
|
||||
.split(/\r?\n/)
|
||||
.filter(function (url) {
|
||||
return !loadedLibs.includes(url);
|
||||
})
|
||||
.forEach(function (url) {
|
||||
var ext = getExt(url);
|
||||
if (ext === 'js') {
|
||||
libPromise.push(loadScript(url));
|
||||
} else if (ext === 'css') {
|
||||
libPromise.push(loadStyle(url));
|
||||
}
|
||||
});
|
||||
$lib.value = libsDecode;
|
||||
return Promise.all(libPromise);
|
||||
$prod.addEventListener('change', () => {
|
||||
setStorageBoolean('prod', $prod.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$ts.addEventListener('change', () => {
|
||||
setStorageBoolean('ts', $ts.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$code.addEventListener('change', () => {
|
||||
setStorageBoolean('code', $code.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$log.addEventListener('change', () => {
|
||||
setStorageBoolean('log', $log.checked)
|
||||
window.location.reload()
|
||||
})
|
||||
|
||||
$file.addEventListener('change', async () => {
|
||||
for (let index = 0; index < $file.files.length; index++) {
|
||||
const file = $file.files[index]
|
||||
const name = file.name.toLowerCase().trim()
|
||||
if (name.endsWith('.css')) {
|
||||
const text = await readFile(file)
|
||||
const $style = document.createElement('style')
|
||||
$style.textContent = text
|
||||
document.body.appendChild($style)
|
||||
$lib.value = `\n[${name}]`
|
||||
$lib.value = $lib.value.trim()
|
||||
}
|
||||
if (name.endsWith('.js')) {
|
||||
const text = await readFile(file)
|
||||
const $script = document.createElement('script')
|
||||
$script.textContent = text
|
||||
document.body.appendChild($script)
|
||||
$lib.value = `\n[${name}]`
|
||||
$lib.value = $lib.value.trim()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function runExample(name) {
|
||||
fetch('./assets/example/' + name + '.js')
|
||||
.then(function (response) {
|
||||
return response.text();
|
||||
})
|
||||
.then(function (text) {
|
||||
editor.setValue(text);
|
||||
runCode();
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
window.addEventListener('error', (err) => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
window.addEventListener('unhandledrejection', (err) => {
|
||||
console.error(err)
|
||||
})
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
||||
event.preventDefault()
|
||||
restart()
|
||||
}
|
||||
|
||||
function loadCode(code, example) {
|
||||
if (example) {
|
||||
runExample(example);
|
||||
} else if (code) {
|
||||
editor.setValue(decodeURIComponent(code).trim());
|
||||
runCode();
|
||||
} else {
|
||||
runExample('index');
|
||||
}
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
[...Artplayer.instances].forEach(function (art) {
|
||||
art.destroy(true);
|
||||
});
|
||||
const value = editor.getValue();
|
||||
eval(value);
|
||||
window.art = Artplayer.instances[0];
|
||||
}
|
||||
|
||||
function initApp() {
|
||||
var _getURLParameters = getURLParameters(window.location.href),
|
||||
code = _getURLParameters.code,
|
||||
libs = _getURLParameters.libs;
|
||||
example = _getURLParameters.example;
|
||||
|
||||
loadLib(libs)
|
||||
.then(function (result) {
|
||||
loadedLibs = loadedLibs.concat(result);
|
||||
loadCode(code, example);
|
||||
})
|
||||
.catch(function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
function restart() {
|
||||
var libs = encodeURIComponent($lib.value);
|
||||
var code = encodeURIComponent(editor.getValue());
|
||||
var url = window.location.origin + window.location.pathname + '?libs=' + libs + '&code=' + code;
|
||||
history.pushState(null, null, url);
|
||||
initApp();
|
||||
}
|
||||
|
||||
function readFile(file) {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.readAsText(file);
|
||||
})
|
||||
}
|
||||
|
||||
$run.addEventListener('click', function () {
|
||||
restart();
|
||||
});
|
||||
|
||||
$popups.addEventListener('click', function (event) {
|
||||
if (event.target === this) {
|
||||
this.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
$prod.addEventListener('change', function () {
|
||||
localStorage.setItem('prod', $prod.checked ? 'true' : 'false');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$ts.addEventListener('change', function () {
|
||||
localStorage.setItem('ts', $ts.checked ? 'true' : 'false');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$code.addEventListener('change', function () {
|
||||
localStorage.setItem('code', $code.checked ? 'true' : 'false');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$log.addEventListener('change', function () {
|
||||
localStorage.setItem('log', $log.checked ? 'true' : 'false');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
$file.addEventListener('change', async function () {
|
||||
for (let index = 0; index < $file.files.length; index++) {
|
||||
const file = $file.files[index];
|
||||
const name = file.name.toLowerCase().trim()
|
||||
if (name.endsWith('.css')) {
|
||||
const text = await readFile(file);
|
||||
const $style = document.createElement('style');
|
||||
$style.textContent = text;
|
||||
document.body.appendChild($style);
|
||||
$lib.value = `\n[${name}]`;
|
||||
$lib.value = $lib.value.trim();
|
||||
}
|
||||
if (name.endsWith('.js')) {
|
||||
const text = await readFile(file);
|
||||
const $script = document.createElement('script');
|
||||
$script.textContent = text;
|
||||
document.body.appendChild($script);
|
||||
$lib.value = `\n[${name}]`;
|
||||
$lib.value = $lib.value.trim();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('error', function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
window.addEventListener('unhandledrejection', function (err) {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === 's') {
|
||||
event.preventDefault();
|
||||
restart();
|
||||
}
|
||||
});
|
||||
})();
|
||||
})
|
||||
})()
|
||||
@@ -0,0 +1,515 @@
|
||||
[Script Info]
|
||||
Title: bilibili ASS 弹幕在线转换
|
||||
Original Script: 根据 danmuku.xml 的弹幕信息,由 https://github.com/tiansh/us-danmaku 生成
|
||||
ScriptType: v4.00+
|
||||
Collisions: Normal
|
||||
PlayResX: 560
|
||||
PlayResY: 420
|
||||
Timer: 10.0000
|
||||
|
||||
[V4+ Styles]
|
||||
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
|
||||
Style: Fix,Source Han Sans CN Bold,25,&H66FFFFFF,&H66FFFFFF,&H66000000,&H66000000,1,0,0,0,100,100,0,0,1,2,0,2,20,20,2,0
|
||||
Style: R2L,Source Han Sans CN Bold,25,&H66FFFFFF,&H66FFFFFF,&H66000000,&H66000000,1,0,0,0,100,100,0,0,1,2,0,2,20,20,2,0
|
||||
|
||||
[Events]
|
||||
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
|
||||
Dialogue: 0,0:00:00.00,0:00:04.00,Fix,,20,20,2,,{\pos(280,25)\c&H000099\3c&HFFFFFF}自己看的
|
||||
Dialogue: 0,0:00:00.00,0:00:08.00,R2L,,20,20,2,,{\move(722.5,25,-162.5,25)}三叶的口嚼酒我能喝到肝硬化
|
||||
Dialogue: 0,0:00:00.00,0:00:04.00,Fix,,20,20,2,,{\pos(280,50)\c&HCCFF66}真·神作
|
||||
Dialogue: 0,0:00:00.00,0:00:08.00,R2L,,20,20,2,,{\move(590,50,-30,50)}mmp
|
||||
Dialogue: 0,0:00:00.31,0:00:08.31,R2L,,20,20,2,,{\move(597.5,75,-37.5,75)\c&H1200E7}龙思颖
|
||||
Dialogue: 0,0:00:00.47,0:00:04.47,Fix,,20,20,2,,{\pos(280,370)}我好喜欢这这一段话~~~
|
||||
Dialogue: 0,0:00:00.49,0:00:08.49,R2L,,20,20,2,,{\move(772.5,100,-212.5,100)\c&H1200E7}求野生字幕君把罗马音加上,急急急~
|
||||
Dialogue: 0,0:00:00.65,0:00:04.65,Fix,,20,20,2,,{\pos(280,75)}小僚机,我知道你会来看
|
||||
Dialogue: 0,0:00:00.66,0:00:04.66,Fix,,20,20,2,,{\pos(280,100)\c&H1200E7}@你的光头! !
|
||||
Dialogue: 0,0:00:00.91,0:00:04.91,Fix,,20,20,2,,{\pos(280,125)}这里的伴奏真的好配啊!
|
||||
Dialogue: 0,0:00:01.06,0:00:09.06,R2L,,20,20,2,,{\move(597.5,125,-37.5,125)}你好!
|
||||
Dialogue: 0,0:00:01.10,0:00:05.10,Fix,,20,20,2,,{\pos(280,150)}本大爷的名字,世间无人不晓
|
||||
Dialogue: 0,0:00:01.14,0:00:09.14,R2L,,20,20,2,,{\move(642.5,150,-82.5,150)}电影院6刷路过
|
||||
Dialogue: 0,0:00:01.24,0:00:05.24,Fix,,20,20,2,,{\pos(280,175)\c&H02F1FE}求BGM
|
||||
Dialogue: 0,0:00:01.32,0:00:09.32,R2L,,20,20,2,,{\move(660,175,-100,175)}看了两遍哭了两遍
|
||||
Dialogue: 0,0:00:01.33,0:00:05.33,Fix,,20,20,2,,{\pos(280,200)\c&H1200E7}结果跟基友看了。。。
|
||||
Dialogue: 0,0:00:01.38,0:00:05.38,Fix,,20,20,2,,{\pos(280,225)\c&H02F1FE}你的名字,茨木童子
|
||||
Dialogue: 0,0:00:01.56,0:00:09.56,R2L,,20,20,2,,{\move(628,50,-68,50)\c&H439800}五刷纪念 sc
|
||||
Dialogue: 0,0:00:01.58,0:00:09.58,R2L,,20,20,2,,{\move(677,200,-117,200)}这里的BGM是什么啊
|
||||
Dialogue: 0,0:00:01.73,0:00:05.73,Fix,,20,20,2,,{\pos(280,345)\c&H00FFFF}asa、me ga sameruto nazeka naiteiru。
|
||||
Dialogue: 0,0:00:01.81,0:00:05.81,Fix,,20,20,2,,{\pos(280,250)}bgm是黄昏之时 32秒开始
|
||||
Dialogue: 0,0:00:01.86,0:00:09.86,R2L,,20,20,2,,{\move(627,75,-67,75)}BGM好棒!
|
||||
Dialogue: 0,0:00:02.24,0:00:10.24,R2L,,20,20,2,,{\move(768.5,225,-208.5,225)\c&H1200E7}预告片都好燃 好喜欢 够我无限循环了
|
||||
Dialogue: 0,0:00:02.50,0:00:10.50,R2L,,20,20,2,,{\move(772.5,250,-212.5,250)}朝、目が覚めるとなぜか泣いている。
|
||||
Dialogue: 0,0:00:02.64,0:00:06.64,Fix,,20,20,2,,{\pos(280,275)\c&H1200E7}今晚三刷!
|
||||
Dialogue: 0,0:00:02.93,0:00:10.93,R2L,,20,20,2,,{\move(635,25,-75,25)}三刷回来留念
|
||||
Dialogue: 0,0:00:02.95,0:00:06.95,Fix,,20,20,2,,{\pos(280,300)\c&H1200E7}入宅神作
|
||||
Dialogue: 0,0:00:03.12,0:00:11.12,R2L,,20,20,2,,{\move(610,50,-50,50)}你的名字
|
||||
Dialogue: 0,0:00:03.16,0:00:11.16,R2L,,20,20,2,,{\move(660,125,-100,125)\c&H0000FF}你的名字:陈常鑫
|
||||
Dialogue: 0,0:00:03.42,0:00:11.42,R2L,,20,20,2,,{\move(660,175,-100,175)}为啥我听不见qwq
|
||||
Dialogue: 0,0:00:03.49,0:00:11.49,R2L,,20,20,2,,{\move(800.5,275,-240.5,275)\c&H000000\3c&HFFFFFF}“爱”就是科学与逻辑永远无法解释的程序。
|
||||
Dialogue: 0,0:00:03.78,0:00:11.78,R2L,,20,20,2,,{\move(697.5,150,-137.5,150)}在中国这样的评价不错了
|
||||
Dialogue: 0,0:00:03.93,0:00:11.93,R2L,,20,20,2,,{\move(810,300,-250,300)}每天刷几遍!预告片真的超好 字幕翻译也好
|
||||
Dialogue: 0,0:00:03.94,0:00:11.94,R2L,,20,20,2,,{\move(672.5,200,-112.5,200)}国语版的真心不好听
|
||||
Dialogue: 0,0:00:03.95,0:00:11.95,R2L,,20,20,2,,{\move(772.5,100,-212.5,100)\c&H1200E7}朝、目が覚めるとなぜか泣いている。
|
||||
Dialogue: 0,0:00:04.00,0:00:08.00,Fix,,20,20,2,,{\pos(280,50)\c&H1200E7}好温柔的声音,大爱
|
||||
Dialogue: 0,0:00:04.00,0:00:08.00,Fix,,20,20,2,,{\pos(280,25)\c&HEAA000}嵩嵩
|
||||
Dialogue: 0,0:00:04.24,0:00:12.24,R2L,,20,20,2,,{\move(969,325,-409,325)}宫水三叶立花泷,夫妻携手战B萌。泷叶八进四生死局,请大家投票支援!
|
||||
Dialogue: 0,0:00:04.33,0:00:12.33,R2L,,20,20,2,,{\move(597.5,50,-37.5,50)}美哭了
|
||||
Dialogue: 0,0:00:04.47,0:00:08.47,Fix,,20,20,2,,{\pos(280,370)\c&H3300CC}2016 12月 一起看的同学们 你们好吗
|
||||
Dialogue: 0,0:00:04.65,0:00:12.65,R2L,,20,20,2,,{\move(710,75,-150,75)}果然还是大陆版的预告最好
|
||||
Dialogue: 0,0:00:04.66,0:00:08.66,Fix,,20,20,2,,{\pos(280,100)\c&H00FFFF}miteita hazu no yume wa itsumo omoidasenai
|
||||
Dialogue: 0,0:00:04.67,0:00:12.67,R2L,,20,20,2,,{\move(637.5,25,-77.5,25)}2017年继续刷
|
||||
Dialogue: 0,0:00:05.27,0:00:13.27,R2L,,20,20,2,,{\move(597.5,125,-37.5,125)}嘟嘟嘟
|
||||
Dialogue: 0,0:00:05.54,0:00:09.53,Fix,,20,20,2,,{\pos(280,75)\c&HEAA000}刚看完国语感觉各种不适应
|
||||
Dialogue: 0,0:00:05.55,0:00:13.55,R2L,,20,20,2,,{\move(610,50,-50,50)}再次回归
|
||||
Dialogue: 0,0:00:05.65,0:00:13.65,R2L,,20,20,2,,{\move(735,225,-175,225)\c&H0000FF}预告片,大陆这版做的最为优秀
|
||||
Dialogue: 0,0:00:05.89,0:00:13.89,R2L,,20,20,2,,{\move(685,175,-125,175)\c&H0203FE}这预告片比电影还带劲
|
||||
Dialogue: 0,0:00:06.05,0:00:10.05,Fix,,20,20,2,,{\pos(280,345)\c&H02F1FE}朝目が覚めると なぜか泣いている
|
||||
Dialogue: 0,0:00:06.20,0:00:14.20,R2L,,20,20,2,,{\move(969,350,-409,350)}宫水三叶立花泷,夫妻携手战B萌。泷叶八进四生死局,请大家投票支援!
|
||||
Dialogue: 0,0:00:06.21,0:00:14.21,R2L,,20,20,2,,{\move(565.5,125,-5.5,125)}1
|
||||
Dialogue: 0,0:00:06.42,0:00:14.42,R2L,,20,20,2,,{\move(829,250,-269,250)}三叶的口嚼酒喝到肝硬化的站住,我能喝到肾衰~
|
||||
Dialogue: 0,0:00:06.57,0:00:14.57,R2L,,20,20,2,,{\move(647.5,25,-87.5,25)}王卿一起去看吧
|
||||
Dialogue: 0,0:00:06.81,0:00:14.81,R2L,,20,20,2,,{\move(730.5,150,-170.5,150)\c&H02F1FE}一般般我也就看了100多遍而已
|
||||
Dialogue: 0,0:00:07.18,0:00:15.18,R2L,,20,20,2,,{\move(785,275,-225,275)\c&H1200E7}見ていたはずの夢はいつも思い出せない
|
||||
Dialogue: 0,0:00:07.24,0:00:11.24,Fix,,20,20,2,,{\pos(280,125)\c&H1200E7}看预告比正片有感觉系列
|
||||
Dialogue: 0,0:00:07.43,0:00:15.43,R2L,,20,20,2,,{\move(610,125,-50,125)}啦啦啦啦
|
||||
Dialogue: 0,0:00:07.44,0:00:15.44,R2L,,20,20,2,,{\move(697.5,75,-137.5,75)}一周年后,我还是一个人
|
||||
Dialogue: 0,0:00:07.52,0:00:11.52,Fix,,20,20,2,,{\pos(280,320)\c&H02F1FE}見ていたはずの夢は いつも思い出せない
|
||||
Dialogue: 0,0:00:07.72,0:00:15.72,R2L,,20,20,2,,{\move(810,100,-250,100)}无数次刷预告片,如果电影院能在上映就好了
|
||||
Dialogue: 0,0:00:07.97,0:00:15.97,R2L,,20,20,2,,{\move(844.5,200,-284.5,200)}看完中毒了,越看中毒越深,新海诚你算计我..........
|
||||
Dialogue: 0,0:00:08.56,0:00:12.56,Fix,,20,20,2,,{\pos(280,25)\c&H1200E7}希望下辈子可以做个东京的帅哥
|
||||
Dialogue: 0,0:00:08.73,0:00:16.73,R2L,,20,20,2,,{\move(585,225,-25,225)}哈哈
|
||||
Dialogue: 0,0:00:09.10,0:00:17.10,R2L,,20,20,2,,{\move(747.5,175,-187.5,175)}希望快出资源,没能二刷有点遗憾
|
||||
Dialogue: 0,0:00:09.12,0:00:17.12,R2L,,20,20,2,,{\move(635,125,-75,125)}这段话好喜欢
|
||||
Dialogue: 0,0:00:09.13,0:00:13.13,Fix,,20,20,2,,{\pos(280,50)\c&H7F02E2}1.5倍速出戏
|
||||
Dialogue: 0,0:00:09.24,0:00:17.24,R2L,,20,20,2,,{\move(969,300,-409,300)\c&HEAA000}宫水三叶立花泷,夫妻携手战B萌。泷叶八进四生死局,请大家投票支援!
|
||||
Dialogue: 0,0:00:09.24,0:00:17.24,R2L,,20,20,2,,{\move(800.5,50,-240.5,50)\c&H000000\3c&HFFFFFF}“爱”就是科学与逻辑永远无法解释的程序。
|
||||
Dialogue: 0,0:00:09.59,0:00:13.59,Fix,,20,20,2,,{\pos(280,75)}我看几遍都没想哭的感觉
|
||||
Dialogue: 0,0:00:09.65,0:00:17.65,R2L,,20,20,2,,{\move(735,25,-175,25)\c&H993333}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:00:09.67,0:00:17.67,R2L,,20,20,2,,{\move(597.5,225,-37.5,225)}我来了
|
||||
Dialogue: 0,0:00:09.84,0:00:13.84,Fix,,20,20,2,,{\pos(280,370)\c&H00FFFF}tada (tada) zutto nanika o sagashiteiru.
|
||||
Dialogue: 0,0:00:10.07,0:00:18.07,R2L,,20,20,2,,{\move(610,75,-50,75)}画质好评
|
||||
Dialogue: 0,0:00:10.18,0:00:18.18,R2L,,20,20,2,,{\move(764.5,150,-204.5,150)}本大爷下次要做个漂亮的小姐姐 芒果
|
||||
Dialogue: 0,0:00:10.34,0:00:18.34,R2L,,20,20,2,,{\move(723.5,250,-163.5,250)}你的名字 一目连_(:3 」∠ )_
|
||||
Dialogue: 0,0:00:10.60,0:00:14.60,Fix,,20,20,2,,{\pos(280,345)\c&H02F1FE}ただ ずっと何かを探している
|
||||
Dialogue: 0,0:00:10.75,0:00:18.75,R2L,,20,20,2,,{\move(681.5,275,-121.5,275)}mjx你为什么要拒绝我
|
||||
Dialogue: 0,0:00:10.76,0:00:14.76,Fix,,20,20,2,,{\pos(280,295)\c&H1200E7}看透太多
|
||||
Dialogue: 0,0:00:11.02,0:00:19.02,R2L,,20,20,2,,{\move(647.5,125,-87.5,125)}真的是百看不厌
|
||||
Dialogue: 0,0:00:11.13,0:00:19.13,R2L,,20,20,2,,{\move(622.5,225,-62.5,225)}三叶毒晚期
|
||||
Dialogue: 0,0:00:11.29,0:00:19.29,R2L,,20,20,2,,{\move(585,75,-25,75)}十刷
|
||||
Dialogue: 0,0:00:11.49,0:00:19.49,R2L,,20,20,2,,{\move(647.5,100,-87.5,100)}什么时候可以看
|
||||
Dialogue: 0,0:00:11.50,0:00:15.50,Fix,,20,20,2,,{\pos(280,100)}看了很多地区预还是觉得大陆预告舒服
|
||||
Dialogue: 0,0:00:12.01,0:00:20.01,R2L,,20,20,2,,{\move(710,200,-150,200)}还是大陆版的预告片最好看
|
||||
Dialogue: 0,0:00:12.04,0:00:20.04,R2L,,20,20,2,,{\move(969,325,-409,325)\c&HEAA000}宫水三叶立花泷,夫妻携手战B萌。泷叶八进四生死局,请大家投票支援!
|
||||
Dialogue: 0,0:00:12.06,0:00:20.06,R2L,,20,20,2,,{\move(590,75,-30,75)}6666
|
||||
Dialogue: 0,0:00:12.31,0:00:20.31,R2L,,20,20,2,,{\move(584.5,175,-24.5,175)}.......
|
||||
Dialogue: 0,0:00:12.59,0:00:20.59,R2L,,20,20,2,,{\move(622.5,225,-62.5,225)\c&H439800}每日刷预告
|
||||
Dialogue: 0,0:00:12.71,0:00:20.71,R2L,,20,20,2,,{\move(760,350,-200,350)}一直不敢看第二遍,怕把自己又看哭
|
||||
Dialogue: 0,0:00:12.73,0:00:20.73,R2L,,20,20,2,,{\move(660,25,-100,25)}最喜欢的这段对话
|
||||
Dialogue: 0,0:00:12.93,0:00:20.93,R2L,,20,20,2,,{\move(610,125,-50,125)}耶稣基督
|
||||
Dialogue: 0,0:00:13.00,0:00:21.00,R2L,,20,20,2,,{\move(597.5,75,-37.5,75)}看哭了
|
||||
Dialogue: 0,0:00:13.02,0:00:21.02,R2L,,20,20,2,,{\move(810,50,-250,50)\c&H1200E7}ただ、ずっと何かを・・・誰かを探している
|
||||
Dialogue: 0,0:00:13.12,0:00:21.12,R2L,,20,20,2,,{\move(591.5,175,-31.5,175)},,,,
|
||||
Dialogue: 0,0:00:13.17,0:00:21.17,R2L,,20,20,2,,{\move(610,275,-50,275)}耶稣基督
|
||||
Dialogue: 0,0:00:13.29,0:00:21.29,R2L,,20,20,2,,{\move(693.5,250,-133.5,250)}0.5声线都变了2333333
|
||||
Dialogue: 0,0:00:13.40,0:00:21.40,R2L,,20,20,2,,{\move(642.5,100,-82.5,100)}66666666666
|
||||
Dialogue: 0,0:00:13.56,0:00:21.56,R2L,,20,20,2,,{\move(649,150,-89,150)}bgm:黄昏之时
|
||||
Dialogue: 0,0:00:13.80,0:00:17.80,Fix,,20,20,2,,{\pos(280,320)}你的名字:奥巴马
|
||||
Dialogue: 0,0:00:13.93,0:00:21.93,R2L,,20,20,2,,{\move(572.5,175,-12.5,175)}!
|
||||
Dialogue: 0,0:00:13.99,0:00:21.99,R2L,,20,20,2,,{\move(672.5,300,-112.5,300)}声优的声音太无敌了
|
||||
Dialogue: 0,0:00:14.05,0:00:22.05,R2L,,20,20,2,,{\move(597.5,225,-37.5,225)\c&H000000\3c&HFFFFFF}二刷了
|
||||
Dialogue: 0,0:00:14.14,0:00:22.14,R2L,,20,20,2,,{\move(585,125,-25,125)}爱♥
|
||||
Dialogue: 0,0:00:14.27,0:00:22.27,R2L,,20,20,2,,{\move(572.5,175,-12.5,175)}!
|
||||
Dialogue: 0,0:00:14.57,0:00:22.57,R2L,,20,20,2,,{\move(628,75,-68,75)}好巧我101遍
|
||||
Dialogue: 0,0:00:14.80,0:00:22.80,R2L,,20,20,2,,{\move(625.5,200,-65.5,200)\c&H1200E7}神木dd!!
|
||||
Dialogue: 0,0:00:14.83,0:00:22.83,R2L,,20,20,2,,{\move(647.5,25,-87.5,25)}每次看都激动啊
|
||||
Dialogue: 0,0:00:14.93,0:00:22.93,R2L,,20,20,2,,{\move(585,175,-25,175)\c&H000000\3c&HFFFFFF}好ㄟ
|
||||
Dialogue: 0,0:00:15.08,0:00:23.08,R2L,,20,20,2,,{\move(597.5,125,-37.5,125)}刚看完
|
||||
Dialogue: 0,0:00:15.22,0:00:23.22,R2L,,20,20,2,,{\move(622.5,100,-62.5,100)}声音好甜啊
|
||||
Dialogue: 0,0:00:15.66,0:00:23.66,R2L,,20,20,2,,{\move(660,150,-100,150)}天啊,整屏都是字
|
||||
Dialogue: 0,0:00:15.80,0:00:23.80,R2L,,20,20,2,,{\move(697.5,275,-137.5,275)}你的名字是,,,吉良吉影
|
||||
Dialogue: 0,0:00:15.88,0:00:19.88,Fix,,20,20,2,,{\pos(280,370)\c&H00FFFF}takikun....oboete nai?
|
||||
Dialogue: 0,0:00:15.98,0:00:23.98,R2L,,20,20,2,,{\move(649,225,-89,225)}bgm:黄昏之时
|
||||
Dialogue: 0,0:00:16.03,0:00:24.03,R2L,,20,20,2,,{\move(585,125,-25,125)}好看
|
||||
Dialogue: 0,0:00:16.14,0:00:24.14,R2L,,20,20,2,,{\move(610,175,-50,175)}明天二刷
|
||||
Dialogue: 0,0:00:16.62,0:00:24.62,R2L,,20,20,2,,{\move(697.5,300,-137.5,300)}我也觉得大陆的预告最好
|
||||
Dialogue: 0,0:00:16.68,0:00:24.68,R2L,,20,20,2,,{\move(622.5,100,-62.5,100)}三叶是我的
|
||||
Dialogue: 0,0:00:16.79,0:00:24.79,R2L,,20,20,2,,{\move(685,50,-125,50)}中国版预告片真的很棒
|
||||
Dialogue: 0,0:00:16.79,0:00:24.79,R2L,,20,20,2,,{\move(800.5,325,-240.5,325)\c&H000000\3c&HFFFFFF}“爱”就是科学与逻辑永远无法解释的程序。
|
||||
Dialogue: 0,0:00:16.84,0:00:20.84,Fix,,20,20,2,,{\pos(280,25)\c&H1200E7}表白能当着面去说么
|
||||
Dialogue: 0,0:00:16.86,0:00:24.86,R2L,,20,20,2,,{\move(785,250,-225,250)}你……我……想和你一起看《你的名字》
|
||||
Dialogue: 0,0:00:16.93,0:00:24.93,R2L,,20,20,2,,{\move(872.5,350,-312.5,350)}看了也没脱单,让我找一个漂亮的德国妹子做女朋友吧!
|
||||
Dialogue: 0,0:00:16.94,0:00:24.94,R2L,,20,20,2,,{\move(660,25,-100,25)}极速救不了这画质
|
||||
Dialogue: 0,0:00:17.24,0:00:25.24,R2L,,20,20,2,,{\move(610,125,-50,125)}画质感人
|
||||
Dialogue: 0,0:00:17.35,0:00:25.35,R2L,,20,20,2,,{\move(597.5,175,-37.5,175)}艾子健
|
||||
Dialogue: 0,0:00:17.65,0:00:25.65,R2L,,20,20,2,,{\move(735,75,-175,75)\c&H1200E7}希望下辈子可以做个京都的帅哥
|
||||
Dialogue: 0,0:00:17.73,0:00:25.73,R2L,,20,20,2,,{\move(722.5,200,-162.5,200)}想看看不了啊啊啊啊啊啊啊啊
|
||||
Dialogue: 0,0:00:17.82,0:00:21.82,Fix,,20,20,2,,{\pos(280,345)\c&H0000FF}滝君 覚えて ない?
|
||||
Dialogue: 0,0:00:18.28,0:00:26.28,R2L,,20,20,2,,{\move(672.5,225,-112.5,225)}一年后再来看预告片
|
||||
Dialogue: 0,0:00:18.44,0:00:26.44,R2L,,20,20,2,,{\move(680,275,-120,275)\c&H00FFFF}其他9位老伙伴你们好
|
||||
Dialogue: 0,0:00:18.45,0:00:26.45,R2L,,20,20,2,,{\move(581,125,-21,125)}......
|
||||
Dialogue: 0,0:00:18.56,0:00:26.56,R2L,,20,20,2,,{\move(610,175,-50,175)}字为什么
|
||||
Dialogue: 0,0:00:18.72,0:00:26.72,R2L,,20,20,2,,{\move(733,150,-173,150)\c&HEAA000}赶上了我们这儿的最后一场π_π
|
||||
Dialogue: 0,0:00:18.97,0:00:26.97,R2L,,20,20,2,,{\move(672.5,100,-112.5,100)}大陆这剪辑真是人才
|
||||
Dialogue: 0,0:00:19.42,0:00:27.42,R2L,,20,20,2,,{\move(697.5,50,-137.5,50)\c&H0000FF}你的名字是,,,吉良吉影
|
||||
Dialogue: 0,0:00:19.66,0:00:27.66,R2L,,20,20,2,,{\move(610,125,-50,125)}看哭了我
|
||||
Dialogue: 0,0:00:19.79,0:00:23.79,Fix,,20,20,2,,{\pos(280,320)\c&H1200E7}覚えってない
|
||||
Dialogue: 0,0:00:20.01,0:00:28.01,R2L,,20,20,2,,{\move(735,25,-175,25)\c&HCC00FF}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:00:20.02,0:00:28.02,R2L,,20,20,2,,{\move(622.5,175,-62.5,175)\c&H397992}相変わらず
|
||||
Dialogue: 0,0:00:20.42,0:00:28.42,R2L,,20,20,2,,{\move(747.5,250,-187.5,250)\c&H000000\3c&HFFFFFF}和我家小可爱一起去看的(男的)
|
||||
Dialogue: 0,0:00:20.57,0:00:28.57,R2L,,20,20,2,,{\move(636.5,225,-76.5,225)}bgm黄昏之时
|
||||
Dialogue: 0,0:00:20.64,0:00:24.64,Fix,,20,20,2,,{\pos(280,50)}bgm燃起
|
||||
Dialogue: 0,0:00:20.67,0:00:28.67,R2L,,20,20,2,,{\move(647.5,200,-87.5,200)\c&H000000\3c&HFFFFFF}欠的电影票已还
|
||||
Dialogue: 0,0:00:20.72,0:00:28.72,R2L,,20,20,2,,{\move(697.5,75,-137.5,75)}HYJ真的好想和你一起看
|
||||
Dialogue: 0,0:00:21.07,0:00:29.07,R2L,,20,20,2,,{\move(697.5,275,-137.5,275)}每次到着都鸡皮疙瘩一身
|
||||
Dialogue: 0,0:00:21.12,0:00:29.12,R2L,,20,20,2,,{\move(622.5,125,-62.5,125)}感动的要死
|
||||
Dialogue: 0,0:00:21.26,0:00:29.26,R2L,,20,20,2,,{\move(585,100,-25,100)}爱♥
|
||||
Dialogue: 0,0:00:21.37,0:00:29.37,R2L,,20,20,2,,{\move(969,300,-409,300)\c&HEAA000}宫水三叶立花泷,夫妻携手战B萌。泷叶八进四生死局,请大家投票支援!
|
||||
Dialogue: 0,0:00:21.77,0:00:29.77,R2L,,20,20,2,,{\move(685,150,-125,150)}我还是忘不了巨石强森
|
||||
Dialogue: 0,0:00:22.06,0:00:30.06,R2L,,20,20,2,,{\move(610,50,-50,50)}你的绳子
|
||||
Dialogue: 0,0:00:22.17,0:00:30.17,R2L,,20,20,2,,{\move(662.5,175,-102.5,175)\c&H1200E7}电影院20刷达成!
|
||||
Dialogue: 0,0:00:22.58,0:00:30.58,R2L,,20,20,2,,{\move(610,200,-50,200)}你的名字
|
||||
Dialogue: 0,0:00:22.58,0:00:30.58,R2L,,20,20,2,,{\move(622.5,125,-62.5,125)}我看了四遍
|
||||
Dialogue: 0,0:00:22.72,0:00:30.72,R2L,,20,20,2,,{\move(622.5,100,-62.5,100)}算是考古吧
|
||||
Dialogue: 0,0:00:23.09,0:00:31.09,R2L,,20,20,2,,{\move(647.5,25,-87.5,25)}雅蠛蝶!!!!
|
||||
Dialogue: 0,0:00:23.27,0:00:31.27,R2L,,20,20,2,,{\move(591,50,-31,50)}.........
|
||||
Dialogue: 0,0:00:23.36,0:00:31.36,R2L,,20,20,2,,{\move(622.5,75,-62.5,75)\c&H000000\3c&HFFFFFF}看完泪目了
|
||||
Dialogue: 0,0:00:23.69,0:00:31.69,R2L,,20,20,2,,{\move(739.5,225,-179.5,225)}看完以后老子月考就上去了 神奇
|
||||
Dialogue: 0,0:00:24.18,0:00:32.18,R2L,,20,20,2,,{\move(622.5,100,-62.5,100)}我要看整部
|
||||
Dialogue: 0,0:00:24.18,0:00:32.18,R2L,,20,20,2,,{\move(630,125,-70,125)}画质666666
|
||||
Dialogue: 0,0:00:24.24,0:00:32.24,R2L,,20,20,2,,{\move(660,150,-100,150)}预告片看了好多次
|
||||
Dialogue: 0,0:00:24.28,0:00:32.28,R2L,,20,20,2,,{\move(747.5,275,-187.5,275)}对!就是这个纪录片超感动!!!
|
||||
Dialogue: 0,0:00:24.44,0:00:28.44,Fix,,20,20,2,,{\pos(280,25)\c&H00FFFF}av7752928 萌新剪辑英文歌BGM加你的名字求支持
|
||||
Dialogue: 0,0:00:24.48,0:00:32.48,R2L,,20,20,2,,{\move(610,50,-50,50)}哭什么哭
|
||||
Dialogue: 0,0:00:24.82,0:00:32.82,R2L,,20,20,2,,{\move(610,75,-50,75)\c&H000000\3c&HFFFFFF}非常喜欢
|
||||
Dialogue: 0,0:00:24.94,0:00:32.94,R2L,,20,20,2,,{\move(709,175,-149,175)}CJX ZZC 2017.2.17想念你
|
||||
Dialogue: 0,0:00:24.98,0:00:28.98,Fix,,20,20,2,,{\pos(280,370)\c&H0000FF}これってもしかして
|
||||
Dialogue: 0,0:00:24.99,0:00:32.99,R2L,,20,20,2,,{\move(610,25,-50,25)}每日一刷
|
||||
Dialogue: 0,0:00:25.17,0:00:33.17,R2L,,20,20,2,,{\move(969,250,-409,250)\c&HEAA000}宫水三叶立花泷,夫妻携手战B萌。泷叶八进四生死局,请大家投票支援!
|
||||
Dialogue: 0,0:00:25.51,0:00:33.51,R2L,,20,20,2,,{\move(722.5,200,-162.5,200)}让我失忆一天,我再去看一遍
|
||||
Dialogue: 0,0:00:25.87,0:00:33.87,R2L,,20,20,2,,{\move(635,100,-75,100)\c&H1200E7}夸爆洋次郎哇
|
||||
Dialogue: 0,0:00:25.87,0:00:33.87,R2L,,20,20,2,,{\move(635,125,-75,125)}中文字幕最美
|
||||
Dialogue: 0,0:00:26.12,0:00:34.12,R2L,,20,20,2,,{\move(969,300,-409,300)\c&HEAA000}宫水三叶立花泷,夫妻携手战B萌。泷叶八进四生死局,请大家投票支援!
|
||||
Dialogue: 0,0:00:26.17,0:00:34.17,R2L,,20,20,2,,{\move(635,50,-75,50)}刚看完中文的
|
||||
Dialogue: 0,0:00:26.69,0:00:34.69,R2L,,20,20,2,,{\move(635,25,-75,25)\c&H1200E7}エッチしたい
|
||||
Dialogue: 0,0:00:27.32,0:00:35.32,R2L,,20,20,2,,{\move(735,150,-175,150)\c&HCCFF99}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:00:27.64,0:00:35.64,R2L,,20,20,2,,{\move(712.5,75,-152.5,75)\c&H33FF99}请高数CYQ我下辈子还爱他
|
||||
Dialogue: 0,0:00:27.70,0:00:31.70,Fix,,20,20,2,,{\pos(280,345)\c&H0000FF}俺たち夢の中で
|
||||
Dialogue: 0,0:00:27.75,0:00:35.75,R2L,,20,20,2,,{\move(847.5,225,-287.5,225)}这个宣传片的字幕不知道比电影院播放的正片好多少
|
||||
Dialogue: 0,0:00:28.08,0:00:36.08,R2L,,20,20,2,,{\move(647.5,50,-87.5,50)}看完第二天分手
|
||||
Dialogue: 0,0:00:28.14,0:00:36.14,R2L,,20,20,2,,{\move(897.5,275,-337.5,275)}看了四遍不止,还各种安利给别人看,可惜别人好像都看不懂
|
||||
Dialogue: 0,0:00:28.15,0:00:36.15,R2L,,20,20,2,,{\move(747.5,175,-187.5,175)}这就是我们梦寐以求的,唐朝和尚
|
||||
Dialogue: 0,0:00:28.34,0:00:36.34,R2L,,20,20,2,,{\move(685,100,-125,100)\c&H33FF99}来世我要做东京的帅哥
|
||||
Dialogue: 0,0:00:28.66,0:00:36.66,R2L,,20,20,2,,{\move(710,125,-150,125)}不对,不是纪录片是预告片
|
||||
Dialogue: 0,0:00:28.67,0:00:36.67,R2L,,20,20,2,,{\move(742,200,-182,200)}为什么会早就该分手呢哈哈,zwj
|
||||
Dialogue: 0,0:00:29.15,0:00:37.15,R2L,,20,20,2,,{\move(685,25,-125,25)}超级喜欢大陆的版本!
|
||||
Dialogue: 0,0:00:29.81,0:00:33.81,Fix,,20,20,2,,{\pos(280,370)\c&H0000FF}入れ替わってる
|
||||
Dialogue: 0,0:00:29.98,0:00:37.98,R2L,,20,20,2,,{\move(610,50,-50,50)\c&H000000\3c&HFFFFFF}五刷路过
|
||||
Dialogue: 0,0:00:30.55,0:00:38.55,R2L,,20,20,2,,{\move(720,75,-160,75)}你的好友:RADWIMPS已上线
|
||||
Dialogue: 0,0:00:30.81,0:00:38.81,R2L,,20,20,2,,{\move(685,100,-125,100)}听到这音乐就鸡皮疙瘩
|
||||
Dialogue: 0,0:00:31.33,0:00:35.33,Fix,,20,20,2,,{\pos(280,25)\c&H7F02E2}哈哈哈哈哈哈哈0.5倍速
|
||||
Dialogue: 0,0:00:31.36,0:00:35.36,Fix,,20,20,2,,{\pos(280,320)\c&H0000FF}3刷路过
|
||||
Dialogue: 0,0:00:31.36,0:00:35.36,Fix,,20,20,2,,{\pos(280,295)\c&H1200E7}约会必看
|
||||
Dialogue: 0,0:00:31.37,0:00:39.37,R2L,,20,20,2,,{\move(619,50,-59,50)}^o^已看完
|
||||
Dialogue: 0,0:00:31.46,0:00:39.46,R2L,,20,20,2,,{\move(660,125,-100,125)}从隔壁英语版过来
|
||||
Dialogue: 0,0:00:31.56,0:00:39.56,R2L,,20,20,2,,{\move(622.5,150,-62.5,150)}看来八遍了
|
||||
Dialogue: 0,0:00:31.56,0:00:35.56,Fix,,20,20,2,,{\pos(280,270)\c&HEAA000}幸瑜,我们一起去看吧
|
||||
Dialogue: 0,0:00:31.62,0:00:39.62,R2L,,20,20,2,,{\move(672.5,25,-112.5,25)}最喜欢大陆的预告片
|
||||
Dialogue: 0,0:00:31.70,0:00:35.70,Fix,,20,20,2,,{\pos(280,345)}浓缩的都是精华
|
||||
Dialogue: 0,0:00:31.75,0:00:39.75,R2L,,20,20,2,,{\move(747.5,175,-187.5,175)}被同事安利好久,所以决定不看了
|
||||
Dialogue: 0,0:00:32.60,0:00:36.60,Fix,,20,20,2,,{\pos(280,245)\c&H00FFFF}tyotto takikun, danshi no shisen, sukato tyui
|
||||
Dialogue: 0,0:00:32.77,0:00:40.77,R2L,,20,20,2,,{\move(610,50,-50,50)\c&H000000\3c&HFFFFFF}生蛋胯热
|
||||
Dialogue: 0,0:00:33.28,0:00:41.28,R2L,,20,20,2,,{\move(649,100,-89,100)}怎么下载成mp3
|
||||
Dialogue: 0,0:00:33.37,0:00:37.37,Fix,,20,20,2,,{\pos(280,220)\c&H0000CC}ちょっと 滝君
|
||||
Dialogue: 0,0:00:33.46,0:00:41.46,R2L,,20,20,2,,{\move(630,75,-70,75)\c&H000000\3c&HFFFFFF}2017-03-19
|
||||
Dialogue: 0,0:00:33.98,0:00:41.98,R2L,,20,20,2,,{\move(597.5,50,-37.5,50)}好球!
|
||||
Dialogue: 0,0:00:34.92,0:00:42.92,R2L,,20,20,2,,{\move(572.5,50,-12.5,50)}…
|
||||
Dialogue: 0,0:00:35.06,0:00:43.06,R2L,,20,20,2,,{\move(597.5,75,-37.5,75)}王彬力
|
||||
Dialogue: 0,0:00:35.07,0:00:39.07,Fix,,20,20,2,,{\pos(280,370)\c&H0000CC}男子の視線 スカッと注意
|
||||
Dialogue: 0,0:00:35.19,0:00:43.19,R2L,,20,20,2,,{\move(785,25,-225,25)\c&H02F1FE}一个人刷了七遍就我了吧,我还是个男生
|
||||
Dialogue: 0,0:00:36.37,0:00:44.37,R2L,,20,20,2,,{\move(735,125,-175,125)\c&H7B3A68}我想下辈子是一个漂亮的小姐姐
|
||||
Dialogue: 0,0:00:36.75,0:00:40.75,Fix,,20,20,2,,{\pos(280,345)\c&H0000CC}てめぇ 三葉
|
||||
Dialogue: 0,0:00:37.17,0:00:45.17,R2L,,20,20,2,,{\move(825,100,-265,100)\c&H7F02E2}截止到20号,断断续续去刷了六遍,也是没谁了
|
||||
Dialogue: 0,0:00:37.52,0:00:41.52,Fix,,20,20,2,,{\pos(280,25)\c&H1200E7}三刷 无悔!
|
||||
Dialogue: 0,0:00:37.60,0:00:45.60,R2L,,20,20,2,,{\move(635,50,-75,50)}口昌占戈哥欠
|
||||
Dialogue: 0,0:00:37.60,0:00:45.60,R2L,,20,20,2,,{\move(572.5,75,-12.5,75)}爱
|
||||
Dialogue: 0,0:00:38.22,0:00:42.22,Fix,,20,20,2,,{\pos(280,320)\c&H0000CC}俺の人間関係変えるなよ
|
||||
Dialogue: 0,0:00:38.75,0:00:46.75,R2L,,20,20,2,,{\move(660,25,-100,25)}和朋友去看的……
|
||||
Dialogue: 0,0:00:38.81,0:00:46.81,R2L,,20,20,2,,{\move(610,75,-50,75)\c&H000000\3c&HFFFFFF}看了八遍
|
||||
Dialogue: 0,0:00:39.45,0:00:47.45,R2L,,20,20,2,,{\move(697.5,125,-137.5,125)}不怎么好看,天天想而已
|
||||
Dialogue: 0,0:00:40.87,0:00:44.87,Fix,,20,20,2,,{\pos(280,370)\c&H0000CC}ほんとに自分のおっぱい好きあな
|
||||
Dialogue: 0,0:00:40.90,0:00:44.90,Fix,,20,20,2,,{\pos(280,50)\c&H1200E7}这不是你们的表白墙谢谢
|
||||
Dialogue: 0,0:00:40.94,0:00:48.94,R2L,,20,20,2,,{\move(597.5,25,-37.5,25)}看看看
|
||||
Dialogue: 0,0:00:41.12,0:00:45.12,Fix,,20,20,2,,{\pos(280,345)\c&H7B3A68}希望我下辈子能做一个漂亮的小姐姐
|
||||
Dialogue: 0,0:00:41.37,0:00:45.37,Fix,,20,20,2,,{\pos(280,295)\c&H00FFFF}hontoni jibun no oppai suki yana
|
||||
Dialogue: 0,0:00:42.27,0:00:50.27,R2L,,20,20,2,,{\move(735,50,-175,50)\c&H00FFFF}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:00:42.56,0:00:50.56,R2L,,20,20,2,,{\move(720,75,-160,75)}我电影院刷了2遍,云盘20遍
|
||||
Dialogue: 0,0:00:42.66,0:00:46.66,Fix,,20,20,2,,{\pos(280,25)\c&H1200E7}这样好痛苦,我记得你,你不记得我
|
||||
Dialogue: 0,0:00:43.57,0:00:51.57,R2L,,20,20,2,,{\move(624.5,25,-64.5,25)}6的一批- -
|
||||
Dialogue: 0,0:00:43.82,0:00:51.82,R2L,,20,20,2,,{\move(660,100,-100,100)\c&H1200E7}和对象一起去看过
|
||||
Dialogue: 0,0:00:43.85,0:00:51.85,R2L,,20,20,2,,{\move(810,125,-250,125)\c&H000000\3c&HFFFFFF}看完电影再看预告的那个等等我,我也是哈哈
|
||||
Dialogue: 0,0:00:44.90,0:00:48.90,Fix,,20,20,2,,{\pos(280,50)\c&HCBC084}一个星期连着看了4遍,看一遍哭一遍(17.11.8)
|
||||
Dialogue: 0,0:00:45.34,0:00:53.34,R2L,,20,20,2,,{\move(647.5,50,-87.5,50)}日刷一遍。哈哈
|
||||
Dialogue: 0,0:00:45.40,0:00:53.40,R2L,,20,20,2,,{\move(659,143,-99,143)\c&HEAA000\fs18}喵,还记得一起看完的么
|
||||
Dialogue: 0,0:00:45.47,0:00:53.47,R2L,,20,20,2,,{\move(681.5,75,-121.5,75)}刷3遍的在此(*¯︶¯*)
|
||||
Dialogue: 0,0:00:45.48,0:00:53.48,R2L,,20,20,2,,{\move(647.5,25,-87.5,25)\c&H1200E7}电影院去了四遍
|
||||
Dialogue: 0,0:00:45.93,0:00:53.93,R2L,,20,20,2,,{\move(572.5,100,-12.5,100)}嘉
|
||||
Dialogue: 0,0:00:46.61,0:00:54.61,R2L,,20,20,2,,{\move(586,100,-26,100)}0.5#
|
||||
Dialogue: 0,0:00:47.38,0:00:55.38,R2L,,20,20,2,,{\move(636,25,-76,25)}0.5#瞬间解毒
|
||||
Dialogue: 0,0:00:47.45,0:00:55.45,R2L,,20,20,2,,{\move(660,50,-100,50)\c&H0000FF}超喜欢预告的剪辑
|
||||
Dialogue: 0,0:00:47.54,0:00:51.54,Fix,,20,20,2,,{\pos(280,370)\c&H0000CC}あの男(女)は
|
||||
Dialogue: 0,0:00:47.63,0:00:55.63,R2L,,20,20,2,,{\move(727,125,-167,125)}过了半年再刷 还是激动到捂嘴
|
||||
Dialogue: 0,0:00:47.64,0:00:51.64,Fix,,20,20,2,,{\pos(280,345)\c&H00FFFF}ano otoko (onna) wa
|
||||
Dialogue: 0,0:00:47.83,0:00:55.83,R2L,,20,20,2,,{\move(735,100,-175,100)}看完中文版,看一下原版压压惊
|
||||
Dialogue: 0,0:00:47.89,0:00:55.89,R2L,,20,20,2,,{\move(593,75,-33,75)}hyx♡
|
||||
Dialogue: 0,0:00:49.69,0:00:53.69,Fix,,20,20,2,,{\pos(280,320)\c&H00FFFF}kieteku
|
||||
Dialogue: 0,0:00:49.80,0:00:57.80,R2L,,20,20,2,,{\move(585,25,-25,25)}虐了
|
||||
Dialogue: 0,0:00:49.89,0:00:53.89,Fix,,20,20,2,,{\pos(280,295)\c&H0000CC}消えてる
|
||||
Dialogue: 0,0:00:50.16,0:00:58.16,R2L,,20,20,2,,{\move(610,50,-50,50)}三刷归来
|
||||
Dialogue: 0,0:00:51.13,0:00:59.13,R2L,,20,20,2,,{\move(685,75,-125,75)\c&H000000\3c&HFFFFFF}没声音的我是一个人吗
|
||||
Dialogue: 0,0:00:51.37,0:00:55.37,Fix,,20,20,2,,{\pos(280,270)\c&H0000CC}まさか
|
||||
Dialogue: 0,0:00:51.70,0:00:55.70,Fix,,20,20,2,,{\pos(280,370)\c&H00FFFF}masaka hakkiri oboeteru
|
||||
Dialogue: 0,0:00:51.74,0:00:59.74,R2L,,20,20,2,,{\move(610,25,-50,25)}2017双11
|
||||
Dialogue: 0,0:00:51.90,0:00:59.90,R2L,,20,20,2,,{\move(599.5,50,-39.5,50)}217.6.1
|
||||
Dialogue: 0,0:00:52.23,0:00:56.23,Fix,,20,20,2,,{\pos(280,345)\c&H0000CC}はっきり覚えてる
|
||||
Dialogue: 0,0:00:52.47,0:00:56.47,Fix,,20,20,2,,{\pos(280,25)\c&H00FF00}真想问问表白那些人
|
||||
Dialogue: 0,0:00:52.47,0:00:56.47,Fix,,20,20,2,,{\pos(280,50)\c&H00FF00}在这里表白算什么
|
||||
Dialogue: 0,0:00:52.47,0:00:56.47,Fix,,20,20,2,,{\pos(280,75)\c&H00FF00}只能说你是懦夫
|
||||
Dialogue: 0,0:00:52.55,0:01:00.55,R2L,,20,20,2,,{\move(663,100,-103,100)}神木dd声音好棒啊
|
||||
Dialogue: 0,0:00:52.68,0:01:00.68,R2L,,20,20,2,,{\move(735,125,-175,125)}没感觉还点进来的你是有多贱?
|
||||
Dialogue: 0,0:00:52.78,0:01:00.78,R2L,,20,20,2,,{\move(716,150,-156,150)}up的头像把我的感动整没了.
|
||||
Dialogue: 0,0:00:52.96,0:01:00.96,R2L,,20,20,2,,{\move(583,25,-23,25)}-0-
|
||||
Dialogue: 0,0:00:53.12,0:01:01.12,R2L,,20,20,2,,{\move(610,50,-50,50)}鸡皮疙瘩
|
||||
Dialogue: 0,0:00:53.78,0:00:57.78,Fix,,20,20,2,,{\pos(280,100)}这个宣传片的字幕比影院播放的正片好太多了
|
||||
Dialogue: 0,0:00:54.21,0:01:02.21,R2L,,20,20,2,,{\move(735,75,-175,75)}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:00:54.52,0:01:02.52,R2L,,20,20,2,,{\move(610,25,-50,25)}看了八次
|
||||
Dialogue: 0,0:00:55.00,0:01:03.00,R2L,,20,20,2,,{\move(635,50,-75,50)}盘李猿的够了
|
||||
Dialogue: 0,0:00:55.43,0:00:59.43,Fix,,20,20,2,,{\pos(280,125)}说的对↑
|
||||
Dialogue: 0,0:00:55.97,0:01:03.97,R2L,,20,20,2,,{\move(605,25,-45,25)\c&H000000\3c&HFFFFFF}我3刷了
|
||||
Dialogue: 0,0:00:57.52,0:01:01.52,Fix,,20,20,2,,{\pos(280,25)\c&HEAA000}这个背影由我承包↓
|
||||
Dialogue: 0,0:00:57.84,0:01:01.84,Fix,,20,20,2,,{\pos(280,370)\c&H0000CC}誰だ
|
||||
Dialogue: 0,0:00:58.26,0:01:06.26,R2L,,20,20,2,,{\move(847.5,75,-287.5,75)}说实话陨石这里的音乐能加进一个防空警报就更好了
|
||||
Dialogue: 0,0:00:58.72,0:01:02.72,Fix,,20,20,2,,{\pos(280,345)\c&H0000CC}誰
|
||||
Dialogue: 0,0:00:58.94,0:01:02.94,Fix,,20,20,2,,{\pos(280,50)\c&H0203FE}不想忘记你
|
||||
Dialogue: 0,0:00:59.15,0:01:07.15,R2L,,20,20,2,,{\move(563.5,25,-3.5,25)}.
|
||||
Dialogue: 0,0:00:59.22,0:01:07.22,R2L,,20,20,2,,{\move(860,50,-300,50)\c&H439800}无论你在世界的哪里,我都会再一次的去见你,周佳音
|
||||
Dialogue: 0,0:00:59.22,0:01:07.22,R2L,,20,20,2,,{\move(860,100,-300,100)\c&H7B3A68}无论你在世界的哪里,我都会再一次的去见你,周佳音
|
||||
Dialogue: 0,0:00:59.23,0:01:07.23,R2L,,20,20,2,,{\move(669,125,-109,125)}lxc 我想和你一起看
|
||||
Dialogue: 0,0:00:59.55,0:01:07.55,R2L,,20,20,2,,{\move(860,150,-300,150)\c&HEAA000}无论你在世界的哪里,我都会再一次的去见你,周佳音
|
||||
Dialogue: 0,0:00:59.61,0:01:07.61,R2L,,20,20,2,,{\move(760,175,-200,175)}想问一下手机里的信息是怎么消失的
|
||||
Dialogue: 0,0:00:59.93,0:01:03.93,Fix,,20,20,2,,{\pos(280,320)\c&H0000CC}誰に会いに来た
|
||||
Dialogue: 0,0:01:01.47,0:01:09.47,R2L,,20,20,2,,{\move(650,125,-90,125)}必须刷50遍以上
|
||||
Dialogue: 0,0:01:02.09,0:01:10.09,R2L,,20,20,2,,{\move(722.5,25,-162.5,25)}不想出门,在网上看了盗版的
|
||||
Dialogue: 0,0:01:02.31,0:01:10.31,R2L,,20,20,2,,{\move(714.5,75,-154.5,75)} 每次到这里总会起鸡皮疙瘩
|
||||
Dialogue: 0,0:01:02.43,0:01:06.43,Fix,,20,20,2,,{\pos(280,370)\c&HFF0000\3c&HFFFFFF}運命だとか未来とか
|
||||
Dialogue: 0,0:01:02.54,0:01:06.54,Fix,,20,20,2,,{\pos(280,25)\c&H722E00\3c&HFFFFFF}语文课PPT
|
||||
Dialogue: 0,0:01:02.95,0:01:10.95,R2L,,20,20,2,,{\move(572.5,175,-12.5,175)}。
|
||||
Dialogue: 0,0:01:03.36,0:01:11.36,R2L,,20,20,2,,{\move(697.5,50,-137.5,50)}韩越珊走吧,相约电影院
|
||||
Dialogue: 0,0:01:03.36,0:01:11.36,R2L,,20,20,2,,{\move(663.5,100,-103.5,100)}别说了,三叶是我的
|
||||
Dialogue: 0,0:01:03.42,0:01:11.42,R2L,,20,20,2,,{\move(579.5,125,-19.5,125)}MS
|
||||
Dialogue: 0,0:01:03.63,0:01:07.63,Fix,,20,20,2,,{\pos(280,345)\c&HFF6600\fs18}不管“命运”“未来”这种话语有多少
|
||||
Dialogue: 0,0:01:03.69,0:01:11.69,R2L,,20,20,2,,{\move(747.5,150,-187.5,150)}神木小天使的声音啊啊啊啊苏爆了
|
||||
Dialogue: 0,0:01:03.80,0:01:11.80,R2L,,20,20,2,,{\move(885,200,-325,200)}我的妈呀那些不知道男主女主名字的人不要刷好吗看着别扭
|
||||
Dialogue: 0,0:01:04.47,0:01:12.47,R2L,,20,20,2,,{\move(648,175,-88,175)\c&H000000\3c&HFFFFFF}电影院看完的+1
|
||||
Dialogue: 0,0:01:04.63,0:01:12.63,R2L,,20,20,2,,{\move(610,125,-50,125)}天降正义
|
||||
Dialogue: 0,0:01:05.02,0:01:13.02,R2L,,20,20,2,,{\move(610,25,-50,25)}耳机福利
|
||||
Dialogue: 0,0:01:05.16,0:01:13.16,R2L,,20,20,2,,{\move(647.5,75,-87.5,75)}真的是神剪辑!
|
||||
Dialogue: 0,0:01:05.52,0:01:13.52,R2L,,20,20,2,,{\move(597.5,100,-37.5,100)}斯提拉
|
||||
Dialogue: 0,0:01:05.76,0:01:09.76,Fix,,20,20,2,,{\pos(280,327)\c&HFF0000\3c&HFFFFFF}って言葉が どれだけ手を
|
||||
Dialogue: 0,0:01:05.99,0:01:13.99,R2L,,20,20,2,,{\move(610,50,-50,50)}配音好好
|
||||
Dialogue: 0,0:01:06.35,0:01:14.35,R2L,,20,20,2,,{\move(615.5,25,-55.5,25)\c&H000000\3c&HFFFFFF}bgm 火花
|
||||
Dialogue: 0,0:01:06.52,0:01:10.52,Fix,,20,20,2,,{\pos(280,370)\c&H0000FF}夢は
|
||||
Dialogue: 0,0:01:06.68,0:01:14.68,R2L,,20,20,2,,{\move(697.5,100,-137.5,100)}这是什么歌啊啊啊好好听
|
||||
Dialogue: 0,0:01:06.69,0:01:14.69,R2L,,20,20,2,,{\move(902,225,-342,225)\c&H000000\3c&HFFFFFF}这部电影的BGM次次听都能想起来电影里的场景然后开始泪目
|
||||
Dialogue: 0,0:01:06.90,0:01:14.90,R2L,,20,20,2,,{\move(710,150,-150,150)\c&H000000\3c&HFFFFFF}全片最感动的地方之一!!
|
||||
Dialogue: 0,0:01:07.21,0:01:15.21,R2L,,20,20,2,,{\move(585,50,-25,50)}夢は
|
||||
Dialogue: 0,0:01:07.26,0:01:15.26,R2L,,20,20,2,,{\move(660,75,-100,75)\c&H0000FF}刷人名的原地爆炸
|
||||
Dialogue: 0,0:01:07.37,0:01:11.37,Fix,,20,20,2,,{\pos(280,302)\c&H0000FF}目覚めればいつか消える
|
||||
Dialogue: 0,0:01:07.47,0:01:11.47,Fix,,20,20,2,,{\pos(280,277)\c&HFF6600\fs18}来伸出手吧
|
||||
Dialogue: 0,0:01:07.54,0:01:15.54,R2L,,20,20,2,,{\move(735,175,-175,175)}每次到陨石这里就一身鸡皮疙瘩
|
||||
Dialogue: 0,0:01:07.57,0:01:15.57,R2L,,20,20,2,,{\move(722.5,125,-162.5,125)}男主たき女主みつはみやみつ
|
||||
Dialogue: 0,0:01:08.17,0:01:16.17,R2L,,20,20,2,,{\move(896.5,200,-336.5,200)}这里的BGM确实是スパ一クル的,不过要等7分多钟才到那儿
|
||||
Dialogue: 0,0:01:08.25,0:01:16.25,R2L,,20,20,2,,{\move(647.5,25,-87.5,25)}我们已经分手了
|
||||
Dialogue: 0,0:01:09.42,0:01:17.42,R2L,,20,20,2,,{\move(706,100,-146,100)}见你 哪怕是借助神的力量
|
||||
Dialogue: 0,0:01:10.14,0:01:14.14,Fix,,20,20,2,,{\pos(280,345)\c&HFF0000\3c&HFFFFFF}伸ばそうと 届かない
|
||||
Dialogue: 0,0:01:10.28,0:01:18.28,R2L,,20,20,2,,{\move(735,50,-175,50)\c&H66FF33}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:01:10.49,0:01:18.49,R2L,,20,20,2,,{\move(827,75,-267,75)}花火的最后一分钟才是。。。这个BGM是10分钟的
|
||||
Dialogue: 0,0:01:10.52,0:01:14.52,Fix,,20,20,2,,{\pos(280,370)\c&H0000FF}違う
|
||||
Dialogue: 0,0:01:10.55,0:01:18.55,R2L,,20,20,2,,{\move(672.5,25,-112.5,25)\c&HFF0000\3c&HFFFFFF}運命だとか未来とか
|
||||
Dialogue: 0,0:01:10.69,0:01:14.69,Fix,,20,20,2,,{\pos(280,259)\c&H00FFFF}tigau, yume jya nakatta.
|
||||
Dialogue: 0,0:01:11.50,0:01:15.50,Fix,,20,20,2,,{\pos(280,25)\c&H02F1FE}这段BGM在一个近⑨分钟的音乐里,非常好听。
|
||||
Dialogue: 0,0:01:11.78,0:01:15.78,Fix,,20,20,2,,{\pos(280,320)\c&H0000FF}夢じゃなかった
|
||||
Dialogue: 0,0:01:12.30,0:01:16.30,Fix,,20,20,2,,{\pos(280,295)\c&HFF6600\fs18}我们在它们传达不到的地方恋爱
|
||||
Dialogue: 0,0:01:12.84,0:01:20.84,R2L,,20,20,2,,{\move(647.5,25,-87.5,25)}我们已经分手了
|
||||
Dialogue: 0,0:01:13.28,0:01:21.28,R2L,,20,20,2,,{\move(622.5,100,-62.5,100)}预告好良心
|
||||
Dialogue: 0,0:01:13.36,0:01:21.36,R2L,,20,20,2,,{\move(660,50,-100,50)}在哪里可以看整部
|
||||
Dialogue: 0,0:01:13.36,0:01:17.36,Fix,,20,20,2,,{\pos(280,234)\c&H0000FF}あの人の
|
||||
Dialogue: 0,0:01:13.49,0:01:17.49,Fix,,20,20,2,,{\pos(280,209)\c&HFF0000\3c&HFFFFFF}場所で僕ら恋をする
|
||||
Dialogue: 0,0:01:13.55,0:01:21.55,R2L,,20,20,2,,{\move(665.5,125,-105.5,125)}神木DD少年音好苏
|
||||
Dialogue: 0,0:01:13.95,0:01:17.95,Fix,,20,20,2,,{\pos(280,184)\c&H00FFFF}anohito no mamae omoidasen no
|
||||
Dialogue: 0,0:01:14.40,0:01:22.40,R2L,,20,20,2,,{\move(585,75,-25,75)}火花
|
||||
Dialogue: 0,0:01:15.13,0:01:23.13,R2L,,20,20,2,,{\move(672.5,25,-112.5,25)}看过电影还是很激动
|
||||
Dialogue: 0,0:01:15.34,0:01:23.34,R2L,,20,20,2,,{\move(597.5,75,-37.5,75)}求地址
|
||||
Dialogue: 0,0:01:15.40,0:01:23.40,R2L,,20,20,2,,{\move(610,100,-50,100)}十刷路过
|
||||
Dialogue: 0,0:01:15.46,0:01:23.46,R2L,,20,20,2,,{\move(610,50,-50,50)}白色强势
|
||||
Dialogue: 0,0:01:16.62,0:01:24.62,R2L,,20,20,2,,{\move(735,125,-175,125)}看完之后更加不可能有女朋友了
|
||||
Dialogue: 0,0:01:16.68,0:01:24.68,R2L,,20,20,2,,{\move(610,50,-50,50)}配音好赞
|
||||
Dialogue: 0,0:01:16.85,0:01:20.85,Fix,,20,20,2,,{\pos(280,370)}misuha!!!
|
||||
Dialogue: 0,0:01:16.89,0:01:24.89,R2L,,20,20,2,,{\move(789.5,150,-229.5,150)}无限大な梦のあとの 何もない世の中じゃ
|
||||
Dialogue: 0,0:01:17.26,0:01:25.26,R2L,,20,20,2,,{\move(635,100,-75,100)\c&H000000\3c&HFFFFFF}みつは!!!
|
||||
Dialogue: 0,0:01:17.42,0:01:25.42,R2L,,20,20,2,,{\move(660,25,-100,25)}米萨!!!!!!
|
||||
Dialogue: 0,0:01:18.22,0:01:22.22,Fix,,20,20,2,,{\pos(280,345)\c&HFF0000\3c&HFFFFFF}時計の針を2人を
|
||||
Dialogue: 0,0:01:18.41,0:01:22.41,Fix,,20,20,2,,{\pos(280,320)\c&HFF6600\fs18}在两人深情对视时
|
||||
Dialogue: 0,0:01:18.42,0:01:26.42,R2L,,20,20,2,,{\move(735,75,-175,75)\c&H9999CC}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:01:18.58,0:01:26.58,R2L,,20,20,2,,{\move(647.5,50,-87.5,50)\c&HEAA000}想不起就别想了
|
||||
Dialogue: 0,0:01:18.95,0:01:26.95,R2L,,20,20,2,,{\move(622.5,100,-62.5,100)}スパークル
|
||||
Dialogue: 0,0:01:19.94,0:01:27.94,R2L,,20,20,2,,{\move(735,125,-175,125)\c&HFF9933}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:01:20.06,0:01:28.06,R2L,,20,20,2,,{\move(697.5,25,-137.5,25)}是米子哈,不是米傻好吧
|
||||
Dialogue: 0,0:01:20.41,0:01:28.41,R2L,,20,20,2,,{\move(595.5,100,-35.5,100)}misha
|
||||
Dialogue: 0,0:01:20.53,0:01:28.53,R2L,,20,20,2,,{\move(650,50,-90,50)}89这个数字神了
|
||||
Dialogue: 0,0:01:20.58,0:01:28.58,R2L,,20,20,2,,{\move(610,150,-50,150)}超级好看
|
||||
Dialogue: 0,0:01:20.88,0:01:24.88,Fix,,20,20,2,,{\pos(280,370)\c&H00FFFF}iutamontanda
|
||||
Dialogue: 0,0:01:21.08,0:01:25.08,Fix,,20,20,2,,{\pos(280,25)\c&H1200E7}表白神木小天使!!!
|
||||
Dialogue: 0,0:01:21.50,0:01:29.50,R2L,,20,20,2,,{\move(597.5,75,-37.5,75)}求地址
|
||||
Dialogue: 0,0:01:21.54,0:01:25.54,Fix,,20,20,2,,{\pos(280,302)\c&HFF0000\3c&HFFFFFF}横目に見ながら進む
|
||||
Dialogue: 0,0:01:21.82,0:01:29.82,R2L,,20,20,2,,{\move(611.5,150,-51.5,150)}bgm火花
|
||||
Dialogue: 0,0:01:21.84,0:01:29.84,R2L,,20,20,2,,{\move(822.5,175,-262.5,175)}当年一起看你的名字的同学,现在,你们还好吗
|
||||
Dialogue: 0,0:01:21.87,0:01:29.87,R2L,,20,20,2,,{\move(622.5,100,-62.5,100)}每天看一遍
|
||||
Dialogue: 0,0:01:22.08,0:01:30.08,R2L,,20,20,2,,{\move(735,200,-175,200)\c&HFFCC00}什么时候中国也能出这样的电影
|
||||
Dialogue: 0,0:01:22.44,0:01:30.44,R2L,,20,20,2,,{\move(585,75,-25,75)\c&H000000\3c&HFFFFFF}张瀚
|
||||
Dialogue: 0,0:01:22.47,0:01:30.47,R2L,,20,20,2,,{\move(597.5,50,-37.5,50)}米兹哈
|
||||
Dialogue: 0,0:01:22.54,0:01:26.54,Fix,,20,20,2,,{\pos(280,345)\c&H00FFFF}omae no sekai doko ni itemo kanarazu ainiku te
|
||||
Dialogue: 0,0:01:22.67,0:01:26.67,Fix,,20,20,2,,{\pos(280,50)\c&H1200E7}ly一起看吧
|
||||
Dialogue: 0,0:01:22.69,0:01:30.69,R2L,,20,20,2,,{\move(588.5,25,-28.5,25)}misa
|
||||
Dialogue: 0,0:01:23.02,0:01:31.02,R2L,,20,20,2,,{\move(660,125,-100,125)}在哪里可以看整部
|
||||
Dialogue: 0,0:01:23.57,0:01:31.57,R2L,,20,20,2,,{\move(582.5,75,-22.5,75)\c&H000000\3c&HFFFFFF}666
|
||||
Dialogue: 0,0:01:23.80,0:01:31.80,R2L,,20,20,2,,{\move(615.5,50,-55.5,50)}bgm 花火
|
||||
Dialogue: 0,0:01:23.83,0:01:31.83,R2L,,20,20,2,,{\move(759,150,-199,150)}讲真 大陆剪辑是我觉得最好的版本..
|
||||
Dialogue: 0,0:01:23.91,0:01:31.91,R2L,,20,20,2,,{\move(610,25,-50,25)\c&H000000\3c&HFFFFFF}好浪漫噢
|
||||
Dialogue: 0,0:01:24.22,0:01:32.22,R2L,,20,20,2,,{\move(860,225,-300,225)\c&H7B3A68}无论你在世界的哪里,我都会再一次的去见你,周佳音
|
||||
Dialogue: 0,0:01:24.23,0:01:32.23,R2L,,20,20,2,,{\move(585,75,-25,75)}火花
|
||||
Dialogue: 0,0:01:24.51,0:01:32.51,R2L,,20,20,2,,{\move(697.5,100,-137.5,100)}大陆版的宣传片最有感觉
|
||||
Dialogue: 0,0:01:25.37,0:01:33.37,R2L,,20,20,2,,{\move(622.5,25,-62.5,25)}承包新海诚
|
||||
Dialogue: 0,0:01:25.44,0:01:29.44,Fix,,20,20,2,,{\pos(280,370)\c&HFF0000\3c&HFFFFFF}そんな世界を2人で
|
||||
Dialogue: 0,0:01:25.92,0:01:29.92,Fix,,20,20,2,,{\pos(280,320)\c&HFF6600\fs18}两人在那样的世界里
|
||||
Dialogue: 0,0:01:25.97,0:01:33.97,R2L,,20,20,2,,{\move(860,175,-300,175)\c&H20C390}无论你在世界的哪里,我都会再一次的去见你,周佳音
|
||||
Dialogue: 0,0:01:26.33,0:01:34.33,R2L,,20,20,2,,{\move(660,75,-100,75)}你的名字:陈常鑫
|
||||
Dialogue: 0,0:01:26.59,0:01:34.59,R2L,,20,20,2,,{\move(785,125,-225,125)\c&H00FF00}你们这群渣渣我直接带她看的看完就表白
|
||||
Dialogue: 0,0:01:26.75,0:01:34.75,R2L,,20,20,2,,{\move(724,50,-164,50)}火花的后半段,中间bgm特长
|
||||
Dialogue: 0,0:01:27.00,0:01:35.00,R2L,,20,20,2,,{\move(597.5,25,-37.5,25)}看过了
|
||||
Dialogue: 0,0:01:28.13,0:01:32.13,Fix,,20,20,2,,{\pos(280,25)\c&H7F02E2}这段剪的好
|
||||
Dialogue: 0,0:01:28.16,0:01:36.16,R2L,,20,20,2,,{\move(607.5,25,-47.5,25)\c&H000000\3c&HFFFFFF}mitsuha
|
||||
Dialogue: 0,0:01:28.38,0:01:36.38,R2L,,20,20,2,,{\move(822.5,100,-262.5,100)\c&H000000\3c&HFFFFFF}无论你在这个世界上的任何地方,我都会去见你
|
||||
Dialogue: 0,0:01:28.44,0:01:36.44,R2L,,20,20,2,,{\move(628.5,75,-68.5,75)}豆瓣现在8.5
|
||||
Dialogue: 0,0:01:29.43,0:01:37.43,R2L,,20,20,2,,{\move(852,150,-292,150)}好棒看的午夜场 整个电影院就像是被我们四人包场了
|
||||
Dialogue: 0,0:01:29.64,0:01:37.64,R2L,,20,20,2,,{\move(610,25,-50,25)\c&H7F02E2}你是谁?
|
||||
Dialogue: 0,0:01:29.71,0:01:37.71,R2L,,20,20,2,,{\move(685,50,-125,50)\c&H02F1FE}表示看预告片也能看哭
|
||||
Dialogue: 0,0:01:29.72,0:01:33.72,Fix,,20,20,2,,{\pos(280,370)\c&HFF0000\3c&HFFFFFF}一生いや何生でも
|
||||
Dialogue: 0,0:01:29.76,0:01:33.76,Fix,,20,20,2,,{\pos(280,345)\c&HFF6600\fs18}永生永世
|
||||
Dialogue: 0,0:01:30.09,0:01:38.09,R2L,,20,20,2,,{\move(633,75,-73,75)}米子哈他ki谷
|
||||
Dialogue: 0,0:01:30.15,0:01:38.15,R2L,,20,20,2,,{\move(735,125,-175,125)\c&H1200E7}表白我神木的声音啊啊啊啊啊啊
|
||||
Dialogue: 0,0:01:30.89,0:01:34.89,Fix,,20,20,2,,{\pos(280,50)\c&H0000FF}靓女啊
|
||||
Dialogue: 0,0:01:30.89,0:01:34.89,Fix,,20,20,2,,{\pos(280,75)\c&H0000FF}在 这 停 顿
|
||||
Dialogue: 0,0:01:31.24,0:01:35.24,Fix,,20,20,2,,{\pos(280,100)\c&HCBC084}新海诚不相信爱情
|
||||
Dialogue: 0,0:01:31.27,0:01:35.27,Fix,,20,20,2,,{\pos(280,327)\c&H00FFFF}kimi no namae wa? namae wa?
|
||||
Dialogue: 0,0:01:31.33,0:01:39.33,R2L,,20,20,2,,{\move(635,25,-75,25)}我和我的左手
|
||||
Dialogue: 0,0:01:31.75,0:01:39.75,R2L,,20,20,2,,{\move(589.5,75,-29.5,75)}麦涛
|
||||
Dialogue: 0,0:01:32.18,0:01:40.18,R2L,,20,20,2,,{\move(660,50,-100,50)\c&H6633FF}哪买啊!!!!!
|
||||
Dialogue: 0,0:01:32.25,0:01:40.25,R2L,,20,20,2,,{\move(656,100,-96,100)}你的名字 郑安琪
|
||||
Dialogue: 0,0:01:32.66,0:01:36.66,Fix,,20,20,2,,{\pos(280,302)\c&H00FFFF}哪买啊
|
||||
Dialogue: 0,0:01:33.02,0:01:41.02,R2L,,20,20,2,,{\move(610,25,-50,25)}自己看吧
|
||||
Dialogue: 0,0:01:33.03,0:01:41.03,R2L,,20,20,2,,{\move(610,75,-50,75)\c&H1200E7}在下坂本
|
||||
Dialogue: 0,0:01:33.23,0:01:41.23,R2L,,20,20,2,,{\move(699,125,-139,125)}距喜欢pv这段了!!!!
|
||||
Dialogue: 0,0:01:33.28,0:01:41.28,R2L,,20,20,2,,{\move(863.5,175,-303.5,175)}ovuvuevuevue enyetuenwuevue ugbemugbem osas
|
||||
Dialogue: 0,0:01:33.36,0:01:41.36,R2L,,20,20,2,,{\move(772.5,200,-212.5,200)\c&HEAA000}吾名欧布,我将照亮黑暗,击退邪恶。
|
||||
Dialogue: 0,0:01:33.51,0:01:37.51,Fix,,20,20,2,,{\pos(280,25)\c&H1200E7}走低的原因还不是因为某些“先进”的家长
|
||||
Dialogue: 0,0:01:33.51,0:01:37.51,Fix,,20,20,2,,{\pos(280,125)\c&H1200E7}以为这是吸氧羊就带着孩子去看,结果呢?
|
||||
Dialogue: 0,0:01:33.59,0:01:41.59,R2L,,20,20,2,,{\move(863.5,150,-303.5,150)}ovuvuevuevue enyetuenwuevue ugbemugbem osas
|
||||
Dialogue: 0,0:01:33.65,0:01:37.65,Fix,,20,20,2,,{\pos(280,277)\c&H1200E7}我叫欧布,欧布奥特曼!
|
||||
Dialogue: 0,0:01:33.65,0:01:41.65,R2L,,20,20,2,,{\move(722.5,225,-162.5,225)}看完就表白,然后就在一起了
|
||||
Dialogue: 0,0:01:33.81,0:01:37.81,Fix,,20,20,2,,{\pos(280,370)\c&HFF6600\fs18}坚强地活下去
|
||||
Dialogue: 0,0:01:33.94,0:01:37.94,Fix,,20,20,2,,{\pos(280,150)\c&H1200E7}名侦探柯南 是个侦探
|
||||
Dialogue: 0,0:01:33.96,0:01:37.96,Fix,,20,20,2,,{\pos(280,352)}滚滚滚走错片场了,瞬间笑了
|
||||
Dialogue: 0,0:01:34.02,0:01:38.02,Fix,,20,20,2,,{\pos(280,175)\c&H1200E7}吉良吉影
|
||||
Dialogue: 0,0:01:34.04,0:01:38.04,Fix,,20,20,2,,{\pos(280,252)\c&HFF0000\3c&HFFFFFF}生き抜いていこう
|
||||
Dialogue: 0,0:01:34.23,0:01:42.23,R2L,,20,20,2,,{\move(585,25,-25,25)\c&H000000\3c&HFFFFFF}LYR
|
||||
Dialogue: 0,0:01:34.28,0:01:42.28,R2L,,20,20,2,,{\move(622.5,50,-62.5,50)}郑立!!!
|
||||
Dialogue: 0,0:01:34.29,0:01:42.29,R2L,,20,20,2,,{\move(572.5,100,-12.5,100)}。
|
||||
Dialogue: 0,0:01:34.49,0:01:42.49,R2L,,20,20,2,,{\move(622.5,75,-62.5,75)}欧蕾哇索隆
|
||||
Dialogue: 0,0:01:34.49,0:01:38.49,Fix,,20,20,2,,{\pos(280,200)}老子有杯存了三年的抠脚酒,那些抢着要喝的我这里有
|
||||
Dialogue: 0,0:01:35.77,0:01:43.77,R2L,,20,20,2,,{\move(627,25,-67,25)\c&H000000\3c&HFFFFFF}欧布奥特曼!
|
||||
Dialogue: 0,0:01:36.28,0:01:44.28,R2L,,20,20,2,,{\move(653.5,50,-93.5,50)}mistuha 拼错了
|
||||
Dialogue: 0,0:01:36.30,0:01:44.30,R2L,,20,20,2,,{\move(735,125,-175,125)\c&H99FF66}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:01:36.74,0:01:44.74,R2L,,20,20,2,,{\move(683.5,100,-123.5,100)}老娘名字tara(滑稽)
|
||||
Dialogue: 0,0:01:36.83,0:01:44.83,R2L,,20,20,2,,{\move(597.5,200,-37.5,200)\c&HEAA000}欧布!
|
||||
Dialogue: 0,0:01:37.14,0:01:45.14,R2L,,20,20,2,,{\move(647.5,225,-87.5,225)}我的鸡皮疙瘩~
|
||||
Dialogue: 0,0:01:37.28,0:01:45.28,R2L,,20,20,2,,{\move(710,75,-150,75)\c&H000000\3c&HFFFFFF}哦列哇,速趴塞牙人贝剧塔
|
||||
Dialogue: 0,0:01:37.32,0:01:45.32,R2L,,20,20,2,,{\move(610,25,-50,25)}鸡皮疙瘩
|
||||
Dialogue: 0,0:01:37.44,0:01:45.44,R2L,,20,20,2,,{\move(660,175,-100,175)}超喜欢这段!!!
|
||||
Dialogue: 0,0:01:37.75,0:01:45.75,R2L,,20,20,2,,{\move(697.5,150,-137.5,150)}看宣传片都会泪目的电影
|
||||
Dialogue: 0,0:01:38.04,0:01:46.04,R2L,,20,20,2,,{\move(610,200,-50,200)}君の名は
|
||||
Dialogue: 0,0:01:38.29,0:01:46.29,R2L,,20,20,2,,{\move(647.5,50,-87.5,50)}看的我泪流满面
|
||||
Dialogue: 0,0:01:38.46,0:01:42.46,Fix,,20,20,2,,{\pos(280,25)}表白的原地爆炸啊!(╯‵□′)╯︵┴─┴
|
||||
Dialogue: 0,0:01:38.54,0:01:46.54,R2L,,20,20,2,,{\move(610.5,25,-50.5,25)}16刷无悔
|
||||
Dialogue: 0,0:01:38.90,0:01:42.90,Fix,,20,20,2,,{\pos(280,50)\c&H1200E7}我的入宅作!
|
||||
Dialogue: 0,0:01:39.19,0:01:47.19,R2L,,20,20,2,,{\move(585,100,-25,100)\c&H1200E7}泪目
|
||||
Dialogue: 0,0:01:39.38,0:01:47.38,R2L,,20,20,2,,{\move(641.5,125,-81.5,125)}他的名字是-xr
|
||||
Dialogue: 0,0:01:39.55,0:01:47.55,R2L,,20,20,2,,{\move(635,175,-75,175)}泪目!!!!
|
||||
Dialogue: 0,0:01:39.76,0:01:47.76,R2L,,20,20,2,,{\move(610,25,-50,25)}那买啊哇
|
||||
Dialogue: 0,0:01:39.84,0:01:47.84,R2L,,20,20,2,,{\move(585,100,-25,100)}赵威
|
||||
Dialogue: 0,0:01:40.07,0:01:48.07,R2L,,20,20,2,,{\move(610,75,-50,75)}虎艺寻♡
|
||||
Dialogue: 0,0:01:40.19,0:01:48.19,R2L,,20,20,2,,{\move(622.5,50,-62.5,50)\c&H439800}我咧瓦路飞
|
||||
Dialogue: 0,0:01:40.48,0:01:44.48,Fix,,20,20,2,,{\pos(280,370)\c&H330000\3c&HFFFFFF}それは、夢のような景色のように
|
||||
Dialogue: 0,0:01:40.79,0:01:48.79,R2L,,20,20,2,,{\move(597.5,100,-37.5,100)}好感动
|
||||
Dialogue: 0,0:01:40.97,0:01:48.97,R2L,,20,20,2,,{\move(604,25,-44,25)\c&HCCFF66}真·神作
|
||||
Dialogue: 0,0:01:41.25,0:01:49.25,R2L,,20,20,2,,{\move(735,150,-175,150)\c&HCC0066}无论在哪我都会去找你,周元歆
|
||||
Dialogue: 0,0:01:41.29,0:01:49.29,R2L,,20,20,2,,{\move(597.5,75,-37.5,75)}加藤惠
|
||||
Dialogue: 0,0:01:41.34,0:01:45.34,Fix,,20,20,2,,{\pos(280,345)\c&H330000\3c&HFFFFFF}それは、まるで夢の景色のように
|
||||
Dialogue: 0,0:01:42.04,0:01:46.04,Fix,,20,20,2,,{\pos(280,75)\c&H1200E7}在下版本 有何贵干
|
||||
Dialogue: 0,0:01:42.53,0:01:50.53,R2L,,20,20,2,,{\move(579.5,100,-19.5,100)}zzy
|
||||
Dialogue: 0,0:01:42.66,0:01:50.66,R2L,,20,20,2,,{\move(635,25,-75,25)}讲的是什么啊
|
||||
Dialogue: 0,0:01:42.83,0:01:50.83,R2L,,20,20,2,,{\move(697.5,50,-137.5,50)}每次看都有说不出的东西
|
||||
Dialogue: 0,0:01:42.98,0:01:50.98,R2L,,20,20,2,,{\move(635,75,-75,75)}欧布的等等我
|
||||
Dialogue: 0,0:01:43.13,0:01:51.13,R2L,,20,20,2,,{\move(610,125,-50,125)}那一买哇
|
||||
Dialogue: 0,0:01:43.74,0:01:51.74,R2L,,20,20,2,,{\move(610,100,-50,100)}好感人啊
|
||||
Dialogue: 0,0:01:44.35,0:01:52.35,R2L,,20,20,2,,{\move(584.5,25,-24.5,25)}mzx
|
||||
Dialogue: 0,0:01:44.40,0:01:48.40,Fix,,20,20,2,,{\pos(280,320)\c&H330000\3c&HFFFFFF}ただひたすらに
|
||||
Dialogue: 0,0:01:44.46,0:01:52.46,R2L,,20,20,2,,{\move(747.5,150,-187.5,150)}带有色眼镜的小粉红求你原地爆炸
|
||||
Dialogue: 0,0:01:44.67,0:01:52.67,R2L,,20,20,2,,{\move(635,75,-75,75)}电影院看超棒
|
||||
Dialogue: 0,0:01:44.96,0:01:52.96,R2L,,20,20,2,,{\move(610,100,-50,100)}真的感动
|
||||
Dialogue: 0,0:01:45.01,0:01:53.01,R2L,,20,20,2,,{\move(585,25,-25,25)}泪目
|
||||
Dialogue: 0,0:01:45.38,0:01:53.38,R2L,,20,20,2,,{\move(702,175,-142,175)}我在电视看了完整 的电影
|
||||
Dialogue: 0,0:01:45.42,0:01:53.42,R2L,,20,20,2,,{\move(672.5,125,-112.5,125)}祝表白的单身到死。
|
||||
Dialogue: 0,0:01:45.46,0:01:53.46,R2L,,20,20,2,,{\move(585,50,-25,50)}神作
|
||||
Dialogue: 0,0:01:45.67,0:01:53.67,R2L,,20,20,2,,{\move(585,25,-25,25)\c&H1200E7}卓涵
|
||||
Dialogue: 0,0:01:45.76,0:01:49.76,Fix,,20,20,2,,{\pos(280,370)\c&H330000\3c&HFFFFFF}美しい眺めだった
|
||||
Dialogue: 0,0:01:45.99,0:01:49.99,Fix,,20,20,2,,{\pos(280,345)\c&HEAA000}嗷嗷嗷最后一句太好听了
|
||||
Dialogue: 0,0:01:46.57,0:01:54.57,R2L,,20,20,2,,{\move(647.5,75,-87.5,75)\c&HCBC084}自己看感觉不错
|
||||
Dialogue: 0,0:01:46.67,0:01:54.67,R2L,,20,20,2,,{\move(610,50,-50,50)}美不胜收
|
||||
Dialogue: 0,0:01:46.88,0:01:54.88,R2L,,20,20,2,,{\move(610,25,-50,25)}那买的啊
|
||||
Dialogue: 0,0:01:47.02,0:01:55.02,R2L,,20,20,2,,{\move(657.5,100,-97.5,100)}是mistuha!!!
|
||||
Dialogue: 0,0:01:47.54,0:01:51.54,Fix,,20,20,2,,{\pos(280,25)\c&H02F1FE}子个看的笑哭我
|
||||
Dialogue: 0,0:01:47.55,0:01:51.55,Fix,,20,20,2,,{\pos(280,50)\c&HFFFF00}我也觉得最后一句太美了
|
||||
Dialogue: 0,0:01:47.61,0:01:51.61,Fix,,20,20,2,,{\pos(280,75)\c&H6600FF}自个儿看吧!
|
||||
Dialogue: 0,0:01:47.75,0:01:51.75,Fix,,20,20,2,,{\pos(280,100)\c&HEAA000}最后一句太好听了
|
||||
Dialogue: 0,0:01:47.83,0:01:55.83,R2L,,20,20,2,,{\move(660,125,-100,125)}鸡皮疙瘩,最喜欢
|
||||
Dialogue: 0,0:01:48.09,0:01:56.09,R2L,,20,20,2,,{\move(579,25,-19,25)}。。
|
||||
Dialogue: 0,0:01:48.13,0:01:56.13,R2L,,20,20,2,,{\move(622.5,50,-62.5,50)}美丽而致命
|
||||
Dialogue: 0,0:01:48.26,0:01:52.26,Fix,,20,20,2,,{\pos(280,125)\c&H439800}自己看吧
|
||||
Dialogue: 0,0:01:48.48,0:01:56.48,R2L,,20,20,2,,{\move(610,75,-50,75)\c&H0000CC}美不胜收
|
||||
Dialogue: 0,0:01:48.97,0:01:56.97,R2L,,20,20,2,,{\move(922.5,150,-362.5,150)}不要说票房低。你的名字在浙江青少年间的知名度几乎是百分之后
|
||||
Dialogue: 0,0:01:48.98,0:01:56.98,R2L,,20,20,2,,{\move(863,200,-303,200)}啊,“一起看吧”,这句话简直太美了,不去看都不行啊
|
||||
Dialogue: 0,0:01:49.07,0:01:57.07,R2L,,20,20,2,,{\move(800.5,175,-240.5,175)\c&H000000\3c&HFFFFFF}“爱”就是科学与逻辑永远无法解释的程序。
|
||||
Dialogue: 0,0:01:49.17,0:01:53.17,Fix,,20,20,2,,{\pos(280,320)}最后一句真美
|
||||
Dialogue: 0,0:01:49.20,0:01:57.20,R2L,,20,20,2,,{\move(664.5,100,-104.5,100)}哭了 呼吸都在颤抖
|
||||
Dialogue: 0,0:01:49.21,0:01:57.21,R2L,,20,20,2,,{\move(847.5,225,-287.5,225)\c&H02F1FE}订电影票时就看到只有我的头像是没有泷的三叶。。。
|
||||
Dialogue: 0,0:01:49.39,0:01:57.39,R2L,,20,20,2,,{\move(614.5,25,-54.5,25)} 美不胜收
|
||||
Dialogue: 0,0:01:49.51,0:01:53.51,Fix,,20,20,2,,{\pos(280,150)\c&H722E00\3c&HFFFFFF}自己看吧
|
||||
Dialogue: 0,0:01:49.77,0:01:53.77,Fix,,20,20,2,,{\pos(280,175)\c&H1200E7}神木DD赛高!!!
|
||||
Dialogue: 0,0:01:50.04,0:01:58.04,R2L,,20,20,2,,{\move(647.5,50,-87.5,50)}自己一个人看吧
|
||||
Dialogue: 0,0:01:50.12,0:01:54.12,Fix,,20,20,2,,{\pos(280,200)\c&H7F02E2}自己看吧
|
||||
Dialogue: 0,0:01:50.52,0:01:58.52,R2L,,20,20,2,,{\move(702,125,-142,125)}ctOS的别跑,决战到天亮
|
||||
Dialogue: 0,0:01:50.85,0:01:58.85,R2L,,20,20,2,,{\move(622.5,25,-62.5,25)\c&H000000\3c&HFFFFFF}我叫赵卫东
|
||||
Dialogue: 0,0:01:51.37,0:01:59.37,R2L,,20,20,2,,{\move(585,100,-25,100)}合影
|
||||
Dialogue: 0,0:01:51.62,0:01:59.62,R2L,,20,20,2,,{\move(741.5,75,-181.5,75)}和美美哒女孩子一起看的,开心~
|
||||
Dialogue: 0,0:01:52.31,0:02:00.31,R2L,,20,20,2,,{\move(597.5,25,-37.5,25)\c&H2AABF0}贼好看
|
||||
Dialogue: 0,0:01:52.67,0:02:00.67,R2L,,20,20,2,,{\move(697.5,50,-137.5,50)}超级喜欢大陆版这个预告
|
||||
Dialogue: 0,0:01:53.35,0:02:01.35,R2L,,20,20,2,,{\move(652,100,-92,100)}你的名字 陈同宙
|
||||
|
After Width: | Height: | Size: 2.0 MiB |
@@ -1,52 +1,52 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
interface Option {
|
||||
/**
|
||||
* 广告源文本,支持视频链接、图片链接、HTML文本
|
||||
*/
|
||||
source: string
|
||||
|
||||
export = artplayerPluginAds;
|
||||
/**
|
||||
* 知名广告的类型:'video' | 'image' | 'html'
|
||||
*/
|
||||
type: 'video' | 'image' | 'html'
|
||||
|
||||
/**
|
||||
* 广告必看的时长,单位为秒
|
||||
*/
|
||||
playDuration?: number
|
||||
|
||||
/**
|
||||
* 广告总的时长,单位为秒
|
||||
*/
|
||||
totalDuration?: number
|
||||
|
||||
/**
|
||||
* 视频广告是否默认静音
|
||||
*/
|
||||
muted?: boolean
|
||||
}
|
||||
|
||||
interface Ads {
|
||||
name: 'artplayerPluginAds'
|
||||
|
||||
/**
|
||||
* 跳过广告
|
||||
*/
|
||||
skip: () => void
|
||||
|
||||
/**
|
||||
* 暂停广告
|
||||
*/
|
||||
pause: () => void
|
||||
|
||||
/**
|
||||
* 播放广告
|
||||
*/
|
||||
play: () => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginAds: (option: Option) => (art: Artplayer) => Ads
|
||||
|
||||
export default artplayerPluginAds
|
||||
|
||||
export = artplayerPluginAds
|
||||
export as namespace artplayerPluginAds;
|
||||
|
||||
type Option = {
|
||||
/**
|
||||
* 广告源文本,支持视频链接、图片链接、HTML文本
|
||||
*/
|
||||
source: string;
|
||||
|
||||
/**
|
||||
* 知名广告的类型:'video' | 'image' | 'html'
|
||||
*/
|
||||
type: 'video' | 'image' | 'html';
|
||||
|
||||
/**
|
||||
* 广告必看的时长,单位为秒
|
||||
*/
|
||||
playDuration?: number;
|
||||
|
||||
/**
|
||||
* 广告总的时长,单位为秒
|
||||
*/
|
||||
totalDuration?: number;
|
||||
|
||||
/**
|
||||
* 视频广告是否默认静音
|
||||
*/
|
||||
muted?: boolean;
|
||||
};
|
||||
|
||||
type Ads = {
|
||||
name: 'artplayerPluginAds';
|
||||
|
||||
/**
|
||||
* 跳过广告
|
||||
*/
|
||||
skip: () => void;
|
||||
|
||||
/**
|
||||
* 暂停广告
|
||||
*/
|
||||
pause: () => void;
|
||||
|
||||
/**
|
||||
* 播放广告
|
||||
*/
|
||||
play: () => void;
|
||||
};
|
||||
|
||||
declare const artplayerPluginAds: (option: Option) => (art: Artplayer) => Ads;
|
||||
@@ -1,20 +1,20 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
interface Option {
|
||||
blur?: string
|
||||
opacity?: number
|
||||
frequency?: number
|
||||
zIndex?: number
|
||||
duration?: number
|
||||
}
|
||||
|
||||
export = artplayerPluginAmbilight;
|
||||
interface Result {
|
||||
name: 'artplayerPluginAmbilight'
|
||||
start: () => void
|
||||
stop: () => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginAmbilight
|
||||
|
||||
export = artplayerPluginAmbilight
|
||||
export as namespace artplayerPluginAmbilight;
|
||||
|
||||
type Option = {
|
||||
blur?: string;
|
||||
opacity?: number;
|
||||
frequency?: number;
|
||||
zIndex?: number;
|
||||
duration?: number;
|
||||
};
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerPluginAmbilight';
|
||||
start: () => void;
|
||||
stop: () => void;
|
||||
};
|
||||
|
||||
declare const artplayerPluginAmbilight: (option: Option) => (art: Artplayer) => Result;
|
||||
@@ -0,0 +1,26 @@
|
||||
interface AudioChunk {
|
||||
pcm: ArrayBuffer
|
||||
wav: ArrayBuffer
|
||||
}
|
||||
|
||||
interface AsrPluginOption {
|
||||
length?: number
|
||||
interval?: number
|
||||
sampleRate?: number
|
||||
autoHideTimeout?: number
|
||||
onAudioChunk?: (chunk: AudioChunk) => void | Promise<void>
|
||||
}
|
||||
|
||||
interface AsrPluginInstance {
|
||||
name: 'artplayerPluginAsr'
|
||||
stop: () => void
|
||||
hide: () => void
|
||||
append: (subtitle: string) => void
|
||||
}
|
||||
|
||||
declare function artplayerPluginAsr(option?: AsrPluginOption): (art: Artplayer) => AsrPluginInstance
|
||||
|
||||
export default artplayerPluginAsr
|
||||
|
||||
export = artplayerPluginAsr
|
||||
export as namespace artplayerPluginAsr;
|
||||
@@ -0,0 +1,40 @@
|
||||
interface Option {
|
||||
/**
|
||||
* Audio track URL
|
||||
*/
|
||||
url: string
|
||||
|
||||
/**
|
||||
* Time offset in seconds between video and audio
|
||||
* Positive value means audio plays ahead of video
|
||||
* Negative value means audio plays behind video
|
||||
* @default 0
|
||||
*/
|
||||
offset?: number
|
||||
|
||||
/**
|
||||
* Synchronization threshold in seconds
|
||||
* @default 0.3
|
||||
*/
|
||||
sync?: number
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginAudioTrack'
|
||||
/**
|
||||
* The audio element
|
||||
*/
|
||||
audio: HTMLAudioElement
|
||||
|
||||
/**
|
||||
* Update option
|
||||
*/
|
||||
update: (option: Option) => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginAudioTrack: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginAudioTrack
|
||||
|
||||
export = artplayerPluginAudioTrack
|
||||
export as namespace artplayerPluginAudioTrack;
|
||||
@@ -1,17 +1,17 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
interface Option {
|
||||
url?: string
|
||||
width?: number
|
||||
number?: number
|
||||
scale?: number
|
||||
}
|
||||
|
||||
export = artplayerPluginAutoThumbnail;
|
||||
interface Result {
|
||||
name: 'artplayerPluginAutoThumbnail'
|
||||
}
|
||||
|
||||
declare const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginAutoThumbnail
|
||||
|
||||
export = artplayerPluginAutoThumbnail
|
||||
export as namespace artplayerPluginAutoThumbnail;
|
||||
|
||||
type Option = {
|
||||
url?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
scale?: number;
|
||||
};
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerPluginAutoThumbnail';
|
||||
};
|
||||
|
||||
declare const artplayerPluginAutoThumbnail: (option: Option) => (art: Artplayer) => Result;
|
||||
@@ -1,21 +1,21 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
|
||||
export = artplayerPluginChapter;
|
||||
export as namespace artplayerPluginChapter;
|
||||
|
||||
type Chapters = {
|
||||
start: number;
|
||||
end: number;
|
||||
title: string;
|
||||
}[];
|
||||
start: number
|
||||
end: number
|
||||
title: string
|
||||
}[]
|
||||
|
||||
type Option = {
|
||||
chapters?: Chapters;
|
||||
};
|
||||
interface Option {
|
||||
chapters?: Chapters
|
||||
}
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerPluginChapter';
|
||||
update: (option: Option) => void;
|
||||
};
|
||||
interface Result {
|
||||
name: 'artplayerPluginChapter'
|
||||
update: (option: Option) => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginChapter: (option: Option) => (art: Artplayer) => Result;
|
||||
declare const artplayerPluginChapter: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginChapter
|
||||
|
||||
export = artplayerPluginChapter
|
||||
export as namespace artplayerPluginChapter;
|
||||
@@ -1,17 +1,17 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
interface Option {
|
||||
url?: string
|
||||
sdk?: string
|
||||
icon?: string
|
||||
mimeType?: string
|
||||
}
|
||||
|
||||
export = artplayerPluginChromecast;
|
||||
interface Chromecast {
|
||||
name: 'artplayerPluginChromecast'
|
||||
}
|
||||
|
||||
declare const artplayerPluginChromecast: (option: Option) => (art: Artplayer) => Chromecast
|
||||
|
||||
export default artplayerPluginChromecast
|
||||
|
||||
export = artplayerPluginChromecast
|
||||
export as namespace artplayerPluginChromecast;
|
||||
|
||||
type Option = {
|
||||
url?: string;
|
||||
sdk?: string;
|
||||
icon?: string;
|
||||
mimeType?: string;
|
||||
};
|
||||
|
||||
type Chromecast = {
|
||||
name: 'artplayerPluginChromecast';
|
||||
};
|
||||
|
||||
declare const artplayerPluginChromecast: (option: Option) => (art: Artplayer) => Chromecast;
|
||||
@@ -1,25 +1,25 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
interface Option {
|
||||
solutionPath?: string
|
||||
modelSelection?: number
|
||||
smoothSegmentation?: boolean
|
||||
minDetectionConfidence?: number
|
||||
minTrackingConfidence?: number
|
||||
selfieMode?: boolean
|
||||
drawContour?: boolean
|
||||
foregroundThreshold?: number
|
||||
opacity?: number
|
||||
maskBlurAmount?: number
|
||||
}
|
||||
|
||||
export = artplayerPluginDanmukuMask;
|
||||
interface Result {
|
||||
name: 'artplayerPluginDanmukuMask'
|
||||
start: () => Promise<void>
|
||||
stop: () => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDanmukuMask
|
||||
|
||||
export = artplayerPluginDanmukuMask
|
||||
export as namespace artplayerPluginDanmukuMask;
|
||||
|
||||
type Option = {
|
||||
solutionPath?: string;
|
||||
modelSelection?: number;
|
||||
smoothSegmentation?: boolean;
|
||||
minDetectionConfidence?: number;
|
||||
minTrackingConfidence?: number;
|
||||
selfieMode?: boolean;
|
||||
drawContour?: boolean;
|
||||
foregroundThreshold?: number;
|
||||
opacity?: number;
|
||||
maskBlurAmount?: number;
|
||||
};
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerPluginDanmukuMask';
|
||||
start: () => Promise<void>;
|
||||
stop: () => void;
|
||||
};
|
||||
|
||||
declare const artplayerPluginDanmukuMask: (option?: Option) => (art: Artplayer) => Result;
|
||||
@@ -1,255 +1,259 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
export type Mode = 0 | 1 | 2
|
||||
export type Danmuku
|
||||
= | Danmu[]
|
||||
| string // URL
|
||||
| (() => Promise<Danmu[]>)
|
||||
| Promise<Danmu[]>
|
||||
|
||||
export = artplayerPluginDanmuku;
|
||||
export interface Slider {
|
||||
min?: number
|
||||
max?: number
|
||||
steps?: {
|
||||
name?: string
|
||||
value?: number | string
|
||||
show?: boolean
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface Danmu {
|
||||
/**
|
||||
* 弹幕文本
|
||||
*/
|
||||
text: string
|
||||
|
||||
/**
|
||||
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
|
||||
/**
|
||||
* 弹幕颜色
|
||||
*/
|
||||
color?: string
|
||||
|
||||
/**
|
||||
* 弹幕出现的时间,单位为秒
|
||||
*/
|
||||
time?: number
|
||||
|
||||
/**
|
||||
* 弹幕是否有描边, 默认为 false
|
||||
*/
|
||||
border?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕自定义样式
|
||||
*/
|
||||
style?: Partial<CSSStyleDeclaration>
|
||||
}
|
||||
|
||||
export interface Option {
|
||||
/**
|
||||
* 弹幕数据: 函数,数组,Promise,URL
|
||||
*/
|
||||
danmuku: Danmuku
|
||||
|
||||
/**
|
||||
* 弹幕持续时间,范围在[1 ~ 10]
|
||||
*/
|
||||
speed?: number
|
||||
|
||||
/**
|
||||
* 弹幕上下边距,支持像素数字和百分比
|
||||
*/
|
||||
margin?: [number | `${number}%`, number | `${number}%`]
|
||||
|
||||
/**
|
||||
* 弹幕透明度,范围在[0 ~ 1]
|
||||
*/
|
||||
opacity?: number
|
||||
|
||||
/**
|
||||
* 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
*/
|
||||
color?: string
|
||||
|
||||
/**
|
||||
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode
|
||||
|
||||
/**
|
||||
* 弹幕可见的模式
|
||||
*/
|
||||
modes?: Mode[]
|
||||
|
||||
/**
|
||||
* 弹幕字体大小,支持像素数字和百分比
|
||||
*/
|
||||
fontSize?: number | `${number}%`
|
||||
|
||||
/**
|
||||
* 弹幕是否防重叠
|
||||
*/
|
||||
antiOverlap?: boolean
|
||||
|
||||
/**
|
||||
* 是否同步播放速度
|
||||
*/
|
||||
synchronousPlayback?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
*/
|
||||
mount?: HTMLDivElement | string
|
||||
|
||||
/**
|
||||
* 是否开启弹幕热度图
|
||||
*/
|
||||
heatmap?:
|
||||
| boolean
|
||||
| {
|
||||
xMin?: number
|
||||
xMax?: number
|
||||
yMin?: number
|
||||
yMax?: number
|
||||
scale?: number
|
||||
opacity?: number
|
||||
minHeight?: number
|
||||
sampling?: number
|
||||
smoothing?: number
|
||||
flattening?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
*/
|
||||
width?: number
|
||||
|
||||
/**
|
||||
* 热力图数据
|
||||
*/
|
||||
points?: { time: number, value: number }[]
|
||||
|
||||
/**
|
||||
* 弹幕载入前的过滤器,只支持返回布尔值
|
||||
*/
|
||||
filter?: (danmu: Danmu) => boolean
|
||||
|
||||
/**
|
||||
* 弹幕发送前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
|
||||
/**
|
||||
* 弹幕显示前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>
|
||||
|
||||
/**
|
||||
* 弹幕是否可见
|
||||
*/
|
||||
visible?: boolean
|
||||
|
||||
/**
|
||||
* 是否开启弹幕发射器
|
||||
*/
|
||||
emitter?: boolean
|
||||
|
||||
/**
|
||||
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
*/
|
||||
maxLength?: number
|
||||
|
||||
/**
|
||||
* 输入框锁定时间,范围在[1 ~ 60]
|
||||
*/
|
||||
lockTime?: number
|
||||
|
||||
/**
|
||||
* 弹幕主题,只在自定义挂载时生效
|
||||
*/
|
||||
theme?: 'light' | 'dark'
|
||||
|
||||
/**
|
||||
* 不透明度配置项
|
||||
*/
|
||||
OPACITY?: Slider
|
||||
|
||||
/**
|
||||
* 弹幕速度配置项
|
||||
*/
|
||||
SPEED?: Slider
|
||||
|
||||
/**
|
||||
* 显示区域配置项
|
||||
*/
|
||||
MARGIN?: Slider
|
||||
|
||||
/**
|
||||
* 弹幕字号配置项
|
||||
*/
|
||||
FONT_SIZE?: Slider
|
||||
|
||||
/**
|
||||
* 颜色列表配置项
|
||||
*/
|
||||
COLOR?: string[]
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
name: 'artplayerPluginDanmuku'
|
||||
|
||||
/**
|
||||
* 发送一条实时弹幕
|
||||
*/
|
||||
emit: (danmu: Danmu) => Result
|
||||
|
||||
/**
|
||||
* 重载弹幕源,或者切换新弹幕
|
||||
*/
|
||||
load: (danmuku?: Danmuku) => Promise<Result>
|
||||
|
||||
/**
|
||||
* 实时改变弹幕配置
|
||||
*/
|
||||
config: (option: Option) => Result
|
||||
|
||||
/**
|
||||
* 隐藏弹幕层
|
||||
*/
|
||||
hide: () => Result
|
||||
|
||||
/**
|
||||
* 显示弹幕层
|
||||
*/
|
||||
show: () => Result
|
||||
|
||||
/**
|
||||
* 挂载弹幕输入框
|
||||
*/
|
||||
mount: (el?: HTMLDivElement | string) => void
|
||||
|
||||
/**
|
||||
* 重置弹幕
|
||||
*/
|
||||
reset: () => Result
|
||||
|
||||
/**
|
||||
* 弹幕配置
|
||||
*/
|
||||
option: Option
|
||||
|
||||
/**
|
||||
* 是否隐藏弹幕层
|
||||
*/
|
||||
isHide: boolean
|
||||
|
||||
/**
|
||||
* 是否弹幕层停止状态
|
||||
*/
|
||||
isStop: boolean
|
||||
}
|
||||
|
||||
declare const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDanmuku
|
||||
|
||||
export = artplayerPluginDanmuku
|
||||
export as namespace artplayerPluginDanmuku;
|
||||
|
||||
type Mode = 0 | 1 | 2;
|
||||
type Danmuku = Danmu[] | string | (() => Promise<Danmu[]>) | Promise<Danmu[]>;
|
||||
|
||||
type Slider = {
|
||||
min?: number;
|
||||
max?: number;
|
||||
steps?: {
|
||||
name?: string;
|
||||
value?: any;
|
||||
show?: boolean;
|
||||
}[];
|
||||
};
|
||||
|
||||
type Danmu = {
|
||||
/**
|
||||
* 弹幕文本
|
||||
*/
|
||||
text: string;
|
||||
|
||||
/**
|
||||
* 弹幕发送模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode;
|
||||
|
||||
/**
|
||||
* 弹幕颜色
|
||||
*/
|
||||
color?: string;
|
||||
|
||||
/**
|
||||
* 弹幕出现的时间,单位为秒
|
||||
*/
|
||||
time?: number;
|
||||
|
||||
/**
|
||||
* 弹幕是否有描边, 默认为 false
|
||||
*/
|
||||
border?: boolean;
|
||||
|
||||
/**
|
||||
* 弹幕自定义样式
|
||||
*/
|
||||
style?: Partial<CSSStyleDeclaration>;
|
||||
};
|
||||
|
||||
type Option = {
|
||||
/**
|
||||
* 弹幕数据: 函数,数组,Promise,URL
|
||||
*/
|
||||
danmuku: Danmuku;
|
||||
|
||||
/**
|
||||
* 弹幕持续时间,范围在[1 ~ 10]
|
||||
*/
|
||||
speed?: number;
|
||||
|
||||
/**
|
||||
* 弹幕上下边距,支持像素数字和百分比
|
||||
*/
|
||||
margin?: [number | `${number}%`, number | `${number}%`];
|
||||
|
||||
/**
|
||||
* 弹幕透明度,范围在[0 ~ 1]
|
||||
*/
|
||||
opacity?: number;
|
||||
|
||||
/**
|
||||
* 默认弹幕颜色,可以被单独弹幕项覆盖
|
||||
*/
|
||||
color?: string;
|
||||
|
||||
/**
|
||||
* 弹幕模式: 0: 滚动,1: 顶部,2: 底部
|
||||
*/
|
||||
mode?: Mode;
|
||||
|
||||
/**
|
||||
* 弹幕可见的模式
|
||||
*/
|
||||
modes?: Mode[];
|
||||
|
||||
/**
|
||||
* 弹幕字体大小,支持像素数字和百分比
|
||||
*/
|
||||
fontSize?: number | `${number}%`;
|
||||
|
||||
/**
|
||||
* 弹幕是否防重叠
|
||||
*/
|
||||
antiOverlap?: boolean;
|
||||
|
||||
/**
|
||||
* 是否同步播放速度
|
||||
*/
|
||||
synchronousPlayback?: boolean;
|
||||
|
||||
/**
|
||||
* 弹幕发射器挂载点, 默认为播放器控制栏中部
|
||||
*/
|
||||
mount?: HTMLDivElement | string;
|
||||
|
||||
/**
|
||||
* 是否开启弹幕热度图
|
||||
*/
|
||||
heatmap?:
|
||||
| boolean
|
||||
| {
|
||||
xMin?: number;
|
||||
xMax?: number;
|
||||
yMin?: number;
|
||||
yMax?: number;
|
||||
scale?: number;
|
||||
opacity?: number;
|
||||
minHeight?: number;
|
||||
sampling?: number;
|
||||
smoothing?: number;
|
||||
flattening?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* 当播放器宽度小于此值时,弹幕发射器置于播放器底部
|
||||
*/
|
||||
width?: number;
|
||||
|
||||
/**
|
||||
* 热力图数据
|
||||
*/
|
||||
points?: any[];
|
||||
|
||||
/**
|
||||
* 弹幕载入前的过滤器,只支持返回布尔值
|
||||
*/
|
||||
filter?: (danmu: Danmu) => boolean;
|
||||
|
||||
/**
|
||||
* 弹幕发送前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeEmit?: (danmu: Danmu) => boolean | Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 弹幕显示前的过滤器,支持返回 Promise
|
||||
*/
|
||||
beforeVisible?: (danmu: Danmu) => boolean | Promise<boolean>;
|
||||
|
||||
/**
|
||||
* 弹幕是否可见
|
||||
*/
|
||||
visible?: boolean;
|
||||
|
||||
/**
|
||||
* 是否开启弹幕发射器
|
||||
*/
|
||||
emitter?: boolean;
|
||||
|
||||
/**
|
||||
* 弹幕输入框最大长度, 范围在[1 ~ 1000]
|
||||
*/
|
||||
maxLength?: number;
|
||||
|
||||
/**
|
||||
* 输入框锁定时间,范围在[1 ~ 60]
|
||||
*/
|
||||
lockTime?: number;
|
||||
|
||||
/**
|
||||
* 弹幕主题,只在自定义挂载时生效
|
||||
*/
|
||||
theme?: 'light' | 'dark';
|
||||
|
||||
/**
|
||||
* 不透明度配置项
|
||||
*/
|
||||
OPACITY?: Slider;
|
||||
|
||||
/**
|
||||
* 弹幕速度配置项
|
||||
*/
|
||||
SPEED?: Slider;
|
||||
|
||||
/**
|
||||
* 显示区域配置项
|
||||
*/
|
||||
MARGIN?: Slider;
|
||||
|
||||
/**
|
||||
* 弹幕字号配置项
|
||||
*/
|
||||
FONT_SIZE?: Slider;
|
||||
|
||||
/**
|
||||
* 颜色列表配置项
|
||||
*/
|
||||
COLOR?: string[];
|
||||
};
|
||||
|
||||
type Result = {
|
||||
name: 'artplayerPluginDanmuku';
|
||||
|
||||
/**
|
||||
* 发送一条实时弹幕
|
||||
*/
|
||||
emit: (danmu: Danmu) => Result;
|
||||
|
||||
/**
|
||||
* 重载弹幕源,或者切换新弹幕
|
||||
*/
|
||||
load: (danmuku?: Danmuku) => Promise<Result>;
|
||||
|
||||
/**
|
||||
* 实时改变弹幕配置
|
||||
*/
|
||||
config: (option: Option) => Result;
|
||||
|
||||
/**
|
||||
* 隐藏弹幕层
|
||||
*/
|
||||
hide: () => Result;
|
||||
|
||||
/**
|
||||
* 显示弹幕层
|
||||
*/
|
||||
show: () => Result;
|
||||
|
||||
/**
|
||||
* 挂载弹幕输入框
|
||||
*/
|
||||
mount: (el?: HTMLDivElement | string) => void;
|
||||
|
||||
/**
|
||||
* 重置弹幕
|
||||
*/
|
||||
reset: () => Result;
|
||||
|
||||
/**
|
||||
* 弹幕配置
|
||||
*/
|
||||
option: Option;
|
||||
|
||||
/**
|
||||
* 是否隐藏弹幕层
|
||||
*/
|
||||
isHide: boolean;
|
||||
|
||||
/**
|
||||
* 是否弹幕层停止状态
|
||||
*/
|
||||
isStop: boolean;
|
||||
};
|
||||
|
||||
declare const artplayerPluginDanmuku: (option: Option) => (art: Artplayer) => Result;
|
||||
@@ -1,17 +1,17 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
interface Config {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (level: object) => string
|
||||
}
|
||||
|
||||
export = artplayerPluginDashControl;
|
||||
declare const artplayerPluginDashControl: (option: { quality?: Config, audio?: Config }) => (art: Artplayer) => {
|
||||
name: 'artplayerPluginDashControl'
|
||||
update: () => void
|
||||
}
|
||||
|
||||
export default artplayerPluginDashControl
|
||||
|
||||
export = artplayerPluginDashControl
|
||||
export as namespace artplayerPluginDashControl;
|
||||
|
||||
type Config = {
|
||||
control?: boolean;
|
||||
setting?: boolean;
|
||||
title?: string;
|
||||
auto?: string;
|
||||
getName?(level: object): String;
|
||||
};
|
||||
|
||||
declare const artplayerPluginDashControl: (option: { quality?: Config; audio?: Config }) => (art: Artplayer) => {
|
||||
name: 'artplayerPluginDashControl';
|
||||
update: () => void;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
interface Option {
|
||||
width?: number
|
||||
height?: number
|
||||
placeholder?: string
|
||||
fallbackToVideoPiP?: boolean
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginDocumentPip'
|
||||
isSupported: boolean
|
||||
isActive: boolean
|
||||
open: () => void
|
||||
close: () => void
|
||||
toggle: () => void
|
||||
}
|
||||
|
||||
declare const artplayerPluginDocumentPip: (option: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginDocumentPip
|
||||
|
||||
export = artplayerPluginDocumentPip
|
||||
export as namespace artplayerPluginDocumentPip;
|
||||
@@ -1,17 +1,17 @@
|
||||
import type Artplayer from 'artplayer';
|
||||
interface Config {
|
||||
control?: boolean
|
||||
setting?: boolean
|
||||
title?: string
|
||||
auto?: string
|
||||
getName?: (level: object) => string
|
||||
}
|
||||
|
||||
export = artplayerPluginHlsControl;
|
||||
declare const artplayerPluginHlsControl: (option: { quality?: Config, audio?: Config }) => (art: Artplayer) => {
|
||||
name: 'artplayerPluginHlsControl'
|
||||
update: () => void
|
||||
}
|
||||
|
||||
export default artplayerPluginHlsControl
|
||||
|
||||
export = artplayerPluginHlsControl
|
||||
export as namespace artplayerPluginHlsControl;
|
||||
|
||||
type Config = {
|
||||
control?: boolean;
|
||||
setting?: boolean;
|
||||
title?: string;
|
||||
auto?: string;
|
||||
getName?(level: object): String;
|
||||
};
|
||||
|
||||
declare const artplayerPluginHlsControl: (option: { quality?: Config; audio?: Config }) => (art: Artplayer) => {
|
||||
name: 'artplayerPluginHlsControl';
|
||||
update: () => void;
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
export = ArtplayerPluginIframe;
|
||||
export as namespace ArtplayerPluginIframe;
|
||||
|
||||
type Message = {
|
||||
type: string;
|
||||
data: any;
|
||||
id?: number;
|
||||
};
|
||||
|
||||
declare class ArtplayerPluginIframe {
|
||||
constructor(option: { iframe: HTMLIFrameElement; url: string });
|
||||
|
||||
static iframe: boolean;
|
||||
static postMessage(message: Message): void;
|
||||
static onMessage(event: MessageEvent & { data: Message }): void;
|
||||
static inject(): void;
|
||||
|
||||
readonly promises: Record<number, { resove: Function; reject: Function }>;
|
||||
readonly injected: boolean;
|
||||
readonly destroyed: boolean;
|
||||
readonly $iframe: HTMLIFrameElement;
|
||||
readonly url: string;
|
||||
readonly messageCallback: (...args: any[]) => any;
|
||||
|
||||
onMessage(event: MessageEvent & { data: Message }): void;
|
||||
postMessage(message: Message): Promise<any>;
|
||||
commit<T extends (...args: any[]) => any>(callback: T): Promise<ReturnType<T>>;
|
||||
message(callback: (...args: any[]) => any): void;
|
||||
destroy(): void;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
export interface JassubOption {
|
||||
workerUrl: string
|
||||
wasmUrl: string
|
||||
modernWasmUrl: string
|
||||
subUrl?: string
|
||||
subContent?: string
|
||||
timeOffset?: number
|
||||
debug?: boolean
|
||||
prescaleFactor?: number
|
||||
prescaleHeightLimit?: number
|
||||
maxRenderHeight?: number
|
||||
fonts?: string[] | Uint8Array[]
|
||||
availableFonts?: Record<string, Uint8Array | string>
|
||||
fallbackFont?: string
|
||||
useLocalFonts?: boolean
|
||||
libassMemoryLimit?: number
|
||||
libassGlyphLimit?: number
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface JassubInstance {
|
||||
resize: (force?: boolean, width?: number, height?: number, top?: number, left?: number) => Promise<void>
|
||||
setVideo: (video: HTMLVideoElement) => Promise<void>
|
||||
destroy: () => Promise<void>
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
interface Result {
|
||||
name: 'artplayerPluginJassub'
|
||||
instance: JassubInstance
|
||||
}
|
||||
|
||||
declare const artplayerPluginJassub: (option: JassubOption) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginJassub
|
||||
|
||||
export = artplayerPluginJassub
|
||||
export as namespace artplayerPluginJassub;
|
||||