├── .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 | Meting 3 |

4 | 5 |

6 | Author 7 | Version 8 | Travis 9 | License 10 |

11 | 12 | ## Requirement 13 | 14 | https://github.com/MoePlayer/APlayer 15 | 16 | |Version|API Status|APlayer| 17 | |---|---|---| 18 | |1.2.x|Supported|[![](https://img.shields.io/badge/APlayer-^1.10.0-green.svg?longCache=true&style=for-the-badge)](https://github.com/MoePlayer/APlayer)| 19 | |2.0.x|Latest|[![](https://img.shields.io/badge/APlayer-^1.10.0-green.svg?longCache=true&style=for-the-badge)](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 | 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 | --------------------------------------------------------------------------------