├── .babelrc
├── .eslintrc.js
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── package.json
└── source
└── Meting.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "targets": {
7 | "edge": "14",
8 | "firefox": "60",
9 | "chrome": "49",
10 | "safari": "10.3"
11 | },
12 | "useBuiltIns": "entry"
13 | }
14 | ],
15 | "minify"
16 | ],
17 | "plugins": []
18 | }
19 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true
6 | },
7 | "extends": "eslint:recommended",
8 | "parserOptions": {
9 | "ecmaVersion": 2018
10 | },
11 | "rules": {
12 | "indent": [
13 | "error",
14 | 2
15 | ],
16 | "linebreak-style": [
17 | "error",
18 | "unix"
19 | ],
20 | "quotes": [
21 | "error",
22 | "single"
23 | ],
24 | "semi": [
25 | "error",
26 | "never"
27 | ],
28 | "no-console": "off",
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | yarn.lock
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js: node
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 metowolf
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## Requirement
13 |
14 | https://github.com/MoePlayer/APlayer
15 |
16 | |Version|API Status|APlayer|
17 | |---|---|---|
18 | |1.2.x|Supported|[](https://github.com/MoePlayer/APlayer)|
19 | |2.0.x|Latest|[](https://github.com/MoePlayer/APlayer)|
20 |
21 | ## CDN
22 | - https://cdn.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js
23 | - https://unpkg.com/meting@2.0.1/dist/Meting.min.js
24 |
25 | ## Quick Start
26 | ```html
27 |
28 |
29 |
30 |
31 |
32 |
33 |
37 |
38 | ```
39 | https://music.163.com/#/playlist?id=60198
40 |
41 | ```html
42 |
44 |
45 | ```
46 | https://y.qq.com/n/yqq/song/001RGrEX3ija5X.html
47 |
48 | ```html
49 |
54 |
55 | ```
56 | for self-hosted media
57 |
58 | ```html
59 |
65 |
66 | [00:00.00]This
67 | [00:04.01]is
68 | [00:08.02]lyric
69 |
70 |
71 | ```
72 | Fixed mode with Lyric text
73 |
74 |
75 | ## Option
76 |
77 | |option |default |description|
78 | |:--------------------|:------------:|:----------|
79 | |id |**require** |song id / playlist id / album id / search keyword|
80 | |server |**require** |music platform: `netease`, `tencent`, `kugou`, `xiami`, `baidu`|
81 | |type |**require** |`song`, `playlist`, `album`, `search`, `artist`|
82 | |auto |options |music link, support: `netease`, `tencent`, `xiami`|
83 | |fixed |`false` |enable fixed mode|
84 | |mini |`false` |enable mini mode|
85 | |autoplay |`false` |audio autoplay|
86 | |theme |`#2980b9` |main color|
87 | |loop |`all` |player loop play, values: 'all', 'one', 'none'|
88 | |order |`list` |player play order, values: 'list', 'random'|
89 | |preload |`auto` |values: 'none', 'metadata', 'auto'|
90 | |volume |`0.7` |default volume, notice that player will remember user setting, default volume will not work after user set volume themselves|
91 | |mutex |`true` |prevent to play multiple player at the same time, pause other players when this player start play|
92 | |lrc-type |`0` |lyric type|
93 | |list-folded |`false` |indicate whether list should folded at first|
94 | |list-max-height |`340px` |list max height|
95 | |storage-name |`metingjs` |localStorage key that store player setting|
96 |
97 | Documentation for APlayer can be found at https://aplayer.js.org/#/home?id=options
98 |
99 | ## Advanced
100 |
101 | MetingJS allow you to use self-hosted API, [more information about Meting](https://github.com/metowolf/Meting).
102 |
103 | ```html
104 |
107 |
108 |
109 | ```
110 |
111 | ## Browser support
112 |
113 | Browsers without [native custom element support](https://caniuse.com/#feat=custom-elementsv1) require a [polyfill](https://github.com/webcomponents/custom-elements).
114 |
115 | - Chrome
116 | - Firefox
117 | - Safari
118 | - Internet Explorer 11
119 | - Microsoft Edge
120 |
121 | ## Author
122 |
123 | **MetingJS** © [metowolf](https://github.com/metowolf), Released under the [MIT](./LICENSE) License.
124 |
125 | > Blog [@meto](https://i-meto.com) · GitHub [@metowolf](https://github.com/metowolf) · Twitter [@metowolf](https://twitter.com/metowolf) · Telegram Channel [@metooooo](https://t.me/metooooo)
126 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "meting",
3 | "version": "2.0.1",
4 | "description": "Wow, such a beautiful html5 music player (with Meting API)",
5 | "license": "MIT",
6 | "homepage": "https://github.com/metowolf/MetingJS",
7 | "repository": {
8 | "url": "git+https://github.com/metowolf/MetingJS.git",
9 | "type": "git"
10 | },
11 | "author": {
12 | "name": "metowolf",
13 | "email": "i@i-meto.com",
14 | "url": "https://i-meto.com/"
15 | },
16 | "main": "dist",
17 | "scripts": {
18 | "lint": "eslint source",
19 | "build": "del dist && mkdir dist && babel source/Meting.js -o dist/Meting.min.js",
20 | "test": "npm run build",
21 | "prepublishOnly": "npm run build"
22 | },
23 | "files": [
24 | "dist"
25 | ],
26 | "keywords": [
27 | "player",
28 | "music",
29 | "api",
30 | "meting",
31 | "html5"
32 | ],
33 | "devDependencies": {
34 | "@babel/cli": "^7.2.3",
35 | "@babel/core": "^7.3.3",
36 | "@babel/preset-env": "^7.3.1",
37 | "babel-preset-minify": "^0.5.0",
38 | "del-cli": "^1.1.0",
39 | "eslint": "^5.14.0"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/source/Meting.js:
--------------------------------------------------------------------------------
1 | class MetingJSElement extends HTMLElement {
2 |
3 | connectedCallback() {
4 | if (window.APlayer && window.fetch) {
5 | this._init()
6 | this._parse()
7 | }
8 | }
9 |
10 | disconnectedCallback() {
11 | if (!this.lock) {
12 | this.aplayer.destroy()
13 | }
14 | }
15 |
16 | _camelize(str) {
17 | return str
18 | .replace(/^[_.\- ]+/, '')
19 | .toLowerCase()
20 | .replace(/[_.\- ]+(\w|$)/g, (m, p1) => p1.toUpperCase())
21 | }
22 |
23 | _init() {
24 | let config = {}
25 | for (let i = 0; i < this.attributes.length; i += 1) {
26 | config[this._camelize(this.attributes[i].name)] = this.attributes[i].value
27 | }
28 | let keys = [
29 | 'server', 'type', 'id', 'api', 'auth',
30 | 'auto', 'lock',
31 | 'name', 'title', 'artist', 'author', 'url', 'cover', 'pic', 'lyric', 'lrc',
32 | ]
33 | this.meta = {}
34 | for (let key of keys) {
35 | this.meta[key] = config[key]
36 | delete config[key]
37 | }
38 | this.config = config
39 |
40 | this.api = this.meta.api || window.meting_api || 'https://api.i-meto.com/meting/api?server=:server&type=:type&id=:id&r=:r'
41 | if (this.meta.auto) this._parse_link()
42 | }
43 |
44 | _parse_link() {
45 | let rules = [
46 | ['music.163.com.*song.*id=(\\d+)', 'netease', 'song'],
47 | ['music.163.com.*album.*id=(\\d+)', 'netease', 'album'],
48 | ['music.163.com.*artist.*id=(\\d+)', 'netease', 'artist'],
49 | ['music.163.com.*playlist.*id=(\\d+)', 'netease', 'playlist'],
50 | ['music.163.com.*discover/toplist.*id=(\\d+)', 'netease', 'playlist'],
51 | ['y.qq.com.*song/(\\w+).html', 'tencent', 'song'],
52 | ['y.qq.com.*album/(\\w+).html', 'tencent', 'album'],
53 | ['y.qq.com.*singer/(\\w+).html', 'tencent', 'artist'],
54 | ['y.qq.com.*playsquare/(\\w+).html', 'tencent', 'playlist'],
55 | ['y.qq.com.*playlist/(\\w+).html', 'tencent', 'playlist'],
56 | ['xiami.com.*song/(\\w+)', 'xiami', 'song'],
57 | ['xiami.com.*album/(\\w+)', 'xiami', 'album'],
58 | ['xiami.com.*artist/(\\w+)', 'xiami', 'artist'],
59 | ['xiami.com.*collect/(\\w+)', 'xiami', 'playlist'],
60 | ]
61 |
62 | for (let rule of rules) {
63 | let patt = new RegExp(rule[0])
64 | let res = patt.exec(this.meta.auto)
65 | if (res !== null) {
66 | this.meta.server = rule[1]
67 | this.meta.type = rule[2]
68 | this.meta.id = res[1]
69 | return
70 | }
71 | }
72 | }
73 |
74 | _parse() {
75 | if (this.meta.url) {
76 | let result = {
77 | name: this.meta.name || this.meta.title || 'Audio name',
78 | artist: this.meta.artist || this.meta.author || 'Audio artist',
79 | url: this.meta.url,
80 | cover: this.meta.cover || this.meta.pic,
81 | lrc: this.meta.lrc || this.meta.lyric || '',
82 | type: this.meta.type || 'auto',
83 | }
84 | if (!result.lrc) {
85 | this.meta.lrcType = 0
86 | }
87 | if (this.innerText) {
88 | result.lrc = this.innerText
89 | this.meta.lrcType = 2
90 | }
91 | this._loadPlayer([result])
92 | return
93 | }
94 |
95 | let url = this.api
96 | .replace(':server', this.meta.server)
97 | .replace(':type', this.meta.type)
98 | .replace(':id', this.meta.id)
99 | .replace(':auth', this.meta.auth)
100 | .replace(':r', Math.random())
101 |
102 | fetch(url)
103 | .then(res => res.json())
104 | .then(result => this._loadPlayer(result))
105 | }
106 |
107 | _loadPlayer(data) {
108 |
109 | let defaultOption = {
110 | audio: data,
111 | mutex: true,
112 | lrcType: this.meta.lrcType || 3,
113 | storageName: 'metingjs'
114 | }
115 |
116 | if (!data.length) return
117 |
118 | let options = {
119 | ...defaultOption,
120 | ...this.config,
121 | }
122 | for (let optkey in options) {
123 | if (options[optkey] === 'true' || options[optkey] === 'false') {
124 | options[optkey] = (options[optkey] === 'true')
125 | }
126 | }
127 |
128 | let div = document.createElement('div')
129 | options.container = div
130 | this.appendChild(div)
131 |
132 | this.aplayer = new APlayer(options)
133 | }
134 |
135 | }
136 |
137 | console.log('\n %c MetingJS v2.0.1 %c https://github.com/metowolf/MetingJS \n', 'color: #fadfa3; background: #030307; padding:5px 0;', 'background: #fadfa3; padding:5px 0;')
138 |
139 | if (window.customElements && !window.customElements.get('meting-js')) {
140 | window.MetingJSElement = MetingJSElement
141 | window.customElements.define('meting-js', MetingJSElement)
142 | }
143 |
--------------------------------------------------------------------------------