├── .babelrc
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── README.md
├── api
├── .gitignore
├── .npmignore
├── app.js
├── package.json
├── public
│ └── index.html
├── router
│ ├── album.js
│ ├── artist_album.js
│ ├── artists.js
│ ├── artists_desc.js
│ ├── artists_mv.js
│ ├── banner.js
│ ├── check_music.js
│ ├── comment_album.js
│ ├── comment_dj.js
│ ├── comment_like.js
│ ├── comment_music.js
│ ├── comment_mv.js
│ ├── comment_playlist.js
│ ├── daily_signin.js
│ ├── dj_catelist.js
│ ├── dj_detail.js
│ ├── dj_hot.js
│ ├── dj_program.js
│ ├── dj_program_detail.js
│ ├── dj_recommend.js
│ ├── dj_recommend_type.js
│ ├── dj_sub.js
│ ├── event.js
│ ├── fm_trash.js
│ ├── follow.js
│ ├── like.js
│ ├── likelist.js
│ ├── logWeb.js
│ ├── login.js
│ ├── loginCellphone.js
│ ├── login_refresh.js
│ ├── lyric.js
│ ├── musicUrl.js
│ ├── mv.js
│ ├── mv_first.js
│ ├── mv_url.js
│ ├── personal_fm.js
│ ├── personalized.js
│ ├── personalized_djprogram.js
│ ├── personalized_mv.js
│ ├── personalized_newsong.js
│ ├── personalized_privatecontent.js
│ ├── playlist_catlist.js
│ ├── playlist_detail.js
│ ├── playlist_hot.js
│ ├── playlist_tracks.js
│ ├── program_recommend.js
│ ├── recommend_dislike.js
│ ├── recommend_resource.js
│ ├── recommend_songs.js
│ ├── resource_like.js
│ ├── search.js
│ ├── search_hot.js
│ ├── search_multimatch.js
│ ├── search_suggest.js
│ ├── simi_artists.js
│ ├── simi_mv.js
│ ├── simi_playlist.js
│ ├── simi_song.js
│ ├── simi_user.js
│ ├── song_detail.js
│ ├── top_album.js
│ ├── top_artists.js
│ ├── top_list.js
│ ├── top_mv.js
│ ├── top_playlist.js
│ ├── top_playlist_highquality.js
│ ├── top_songs.js
│ ├── toplist.js
│ ├── toplist_artist.js
│ ├── toplist_detail.js
│ ├── user_audio.js
│ ├── user_cloud.js
│ ├── user_cloud_search.js
│ ├── user_detail.js
│ ├── user_dj.js
│ ├── user_event.js
│ ├── user_followeds.js
│ ├── user_follows.js
│ ├── user_playlist.js
│ ├── user_playrecord.js
│ └── user_subcount.js
├── test
│ ├── album.test.js
│ ├── comment.test.js
│ ├── login.test.js
│ ├── lyric.test.js
│ ├── musicUrl.test.js
│ └── search.test.js
└── util
│ ├── crypto.js
│ └── util.js
├── build
└── icons
│ ├── 256x256.png
│ ├── icon.icns
│ └── icon.ico
├── config
├── build.config.js
├── build.js
├── dev-client.js
├── dev-runner.js
├── webpack.main.config.js
├── webpack.renderer.config.js
└── webpack.web.config.js
├── doc
├── 1588237435-599597952042d_articlex.jpeg
├── 3872766167-5999ac798b713_articlex.png
└── 3913213729-5999ac98a8c6c_articlex.jpeg
├── package.json
├── src
├── index.ejs
├── main
│ ├── command.js
│ ├── index.dev.js
│ └── index.js
└── renderer
│ ├── App.vue
│ ├── api
│ ├── api.js
│ └── config.js
│ ├── assets
│ ├── scss
│ │ ├── common.scss
│ │ ├── core
│ │ │ ├── _css3.scss
│ │ │ ├── _grid.scss
│ │ │ ├── _mixin.scss
│ │ │ └── _setting.scss
│ │ ├── forms.scss
│ │ ├── function.scss
│ │ └── var.scss
│ └── style
│ │ ├── app.scss
│ │ ├── forms.scss
│ │ ├── grid.scss
│ │ ├── instructViews.scss
│ │ └── table.scss
│ ├── components
│ ├── common
│ │ ├── 404
│ │ │ ├── 404.scss
│ │ │ ├── 404.vue
│ │ │ └── assets
│ │ │ │ └── 404.svg
│ │ ├── banner
│ │ │ ├── banner.scss
│ │ │ ├── banner.vue
│ │ │ └── index.js
│ │ ├── barButton
│ │ │ ├── barButton.scss
│ │ │ └── barButton.vue
│ │ ├── dropdown
│ │ │ ├── dropdown.scss
│ │ │ └── dropdown.vue
│ │ ├── header
│ │ │ ├── assets
│ │ │ │ ├── dropdown-a.svg
│ │ │ │ ├── dropdown.svg
│ │ │ │ ├── i-left.svg
│ │ │ │ ├── i-right.svg
│ │ │ │ ├── icon-left.svg
│ │ │ │ ├── icon-right.svg
│ │ │ │ ├── logo.svg
│ │ │ │ └── so.svg
│ │ │ ├── header.scss
│ │ │ └── header.vue
│ │ ├── loading
│ │ │ ├── index.js
│ │ │ └── loading.vue
│ │ ├── pagination
│ │ │ ├── assets
│ │ │ │ ├── i-left.svg
│ │ │ │ └── i-right.svg
│ │ │ ├── index.js
│ │ │ ├── pagination.scss
│ │ │ └── pagination.vue
│ │ ├── playDetail
│ │ │ ├── api.js
│ │ │ ├── assets
│ │ │ │ ├── close_1.svg
│ │ │ │ ├── close_2.svg
│ │ │ │ ├── close_3.svg
│ │ │ │ ├── collect.svg
│ │ │ │ ├── download.svg
│ │ │ │ ├── like.svg
│ │ │ │ ├── like_1.svg
│ │ │ │ ├── like_2.svg
│ │ │ │ ├── share_1.svg
│ │ │ │ └── share_2.svg
│ │ │ ├── playDetail.scss
│ │ │ └── playDetail.vue
│ │ ├── playList
│ │ │ ├── assets
│ │ │ │ ├── 1clone.svg
│ │ │ │ └── clone.svg
│ │ │ ├── playList.scss
│ │ │ └── playList.vue
│ │ ├── playerBar
│ │ │ ├── assets
│ │ │ │ ├── for.svg
│ │ │ │ ├── list.svg
│ │ │ │ ├── lyric.svg
│ │ │ │ ├── next.svg
│ │ │ │ ├── pause.svg
│ │ │ │ ├── play.svg
│ │ │ │ ├── prev.svg
│ │ │ │ ├── voice-close.svg
│ │ │ │ └── voice-open.svg
│ │ │ ├── playerBar.scss
│ │ │ └── playerBar.vue
│ │ ├── sideBar
│ │ │ ├── api.js
│ │ │ ├── assets
│ │ │ │ ├── download.svg
│ │ │ │ ├── fm.svg
│ │ │ │ ├── friend.svg
│ │ │ │ ├── iTunes.svg
│ │ │ │ ├── likes.svg
│ │ │ │ ├── list.svg
│ │ │ │ ├── music.svg
│ │ │ │ ├── mv.svg
│ │ │ │ └── shows.svg
│ │ │ ├── sideBar.scss
│ │ │ └── sideBar.vue
│ │ ├── slider
│ │ │ ├── slider.scss
│ │ │ └── slider.vue
│ │ ├── toast
│ │ │ ├── index.js
│ │ │ ├── toast.scss
│ │ │ └── toast.vue
│ │ └── windowTop
│ │ │ └── windowTop.vue
│ ├── instructViews.vue
│ ├── views
│ │ ├── details
│ │ │ ├── api.js
│ │ │ └── details.vue
│ │ ├── download
│ │ │ └── download.vue
│ │ ├── fm
│ │ │ └── fm.vue
│ │ ├── friend
│ │ │ └── friend.vue
│ │ ├── home
│ │ │ ├── api.js
│ │ │ ├── assets
│ │ │ │ └── emoji-20.svg
│ │ │ ├── home.scss
│ │ │ └── home.vue
│ │ ├── iTunes
│ │ │ ├── assets
│ │ │ │ └── itunes.svg
│ │ │ ├── iTunes.scss
│ │ │ └── iTunes.vue
│ │ ├── login
│ │ │ ├── api.js
│ │ │ ├── assets
│ │ │ │ ├── bg.png
│ │ │ │ ├── clone.svg
│ │ │ │ ├── mobile.svg
│ │ │ │ ├── password.svg
│ │ │ │ ├── phone.svg
│ │ │ │ └── yes.svg
│ │ │ ├── login.scss
│ │ │ └── login.vue
│ │ ├── mv
│ │ │ └── mv.vue
│ │ └── search
│ │ │ ├── api.js
│ │ │ ├── component
│ │ │ ├── album
│ │ │ │ ├── album.scss
│ │ │ │ ├── album.vue
│ │ │ │ └── assets
│ │ │ │ │ └── default.svg
│ │ │ ├── lyric
│ │ │ │ └── lyric.vue
│ │ │ ├── mv
│ │ │ │ ├── assets
│ │ │ │ │ └── default.svg
│ │ │ │ ├── mv.scss
│ │ │ │ └── mv.vue
│ │ │ ├── radio
│ │ │ │ └── radio.vue
│ │ │ ├── singer
│ │ │ │ ├── assets
│ │ │ │ │ └── default.svg
│ │ │ │ ├── singer.scss
│ │ │ │ └── singer.vue
│ │ │ ├── single
│ │ │ │ ├── assets
│ │ │ │ │ ├── collect.svg
│ │ │ │ │ ├── download.svg
│ │ │ │ │ └── right.svg
│ │ │ │ ├── single.scss
│ │ │ │ └── single.vue
│ │ │ ├── song
│ │ │ │ ├── assets
│ │ │ │ │ └── default.svg
│ │ │ │ ├── song.scss
│ │ │ │ └── song.vue
│ │ │ └── user
│ │ │ │ └── user.vue
│ │ │ ├── search.scss
│ │ │ └── search.vue
│ └── windowViews.vue
│ ├── main.js
│ ├── router
│ └── index.js
│ ├── store
│ ├── index.js
│ ├── modules
│ │ ├── index.js
│ │ ├── play.js
│ │ ├── routes.js
│ │ ├── search.js
│ │ ├── toggle.js
│ │ └── user.js
│ └── mutation-types.js
│ └── utils
│ ├── background.js
│ ├── ipcRenderer.js
│ ├── libs.js
│ └── storage.js
├── static
└── .gitkeep
└── test
├── .eslintrc
├── e2e
├── index.js
├── specs
│ └── Launch.spec.js
└── utils.js
└── unit
├── index.js
├── karma.conf.js
└── specs
└── LandingPage.spec.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "comments": false,
3 | "env": {
4 | "test": {
5 | "presets": [
6 | ["env", {
7 | "targets": { "node": 7 }
8 | }],
9 | "stage-0"
10 | ],
11 | "plugins": ["istanbul"]
12 | },
13 | "main": {
14 | "presets": [
15 | ["env", {
16 | "targets": { "node": 7 }
17 | }],
18 | "stage-0"
19 | ]
20 | },
21 | "renderer": {
22 | "presets": [
23 | ["env", {
24 | "modules": false
25 | }],
26 | "stage-0"
27 | ]
28 | },
29 | "web": {
30 | "presets": [
31 | ["env", {
32 | "modules": false
33 | }],
34 | "stage-0"
35 | ]
36 | }
37 | },
38 | "plugins": ["transform-runtime"]
39 | }
40 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | test/unit/coverage/**
2 | test/unit/*.js
3 | test/e2e/*.js
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: 'babel-eslint',
4 | parserOptions: {
5 | sourceType: 'module'
6 | },
7 | env: {
8 | browser: true,
9 | node: true
10 | },
11 | extends: 'standard',
12 | globals: {
13 | __static: true
14 | },
15 | plugins: [
16 | 'html'
17 | ],
18 | 'rules': {
19 | // allow paren-less arrow functions
20 | 'arrow-parens': 0,
21 | // allow async-await
22 | 'generator-star-spacing': 0,
23 | // allow debugger during development
24 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
25 | 'space-before-function-paren': 0,
26 | 'indent': ['warn', 2],
27 | 'no-tabs': 0,
28 | 'semi': 0
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js linguist-language=Vue
2 | *.css linguist-language=Vue
3 | *.html linguist-language=Vue
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist/electron/*
3 | dist/web/*
4 | build/*
5 | !build/icons
6 | coverage
7 | node_modules/
8 | npm-debug.log
9 | npm-debug.log.*
10 | thumbs.db
11 | !.gitkeep
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-electron-music
2 |
3 | > nodejs、vue、electron制作的网易云音乐客户端(MacOs)版,目前没有在Windows运行过,所以样式可能有点差异,时间不足,有空再更新。
4 |
5 | [运行效果预览视频](http://v.youku.com/v_show/id_XMjk2MzYxODUyMA==.html?spm=a2hzp.8244740.0.0)
6 |
7 | ### 技术栈
8 | - vue全家桶(vue vue-router vuex)
9 | - electron(应用框架)
10 | - request(请求数据)
11 | - ES6
12 | - SCSS
13 | - 更多...
14 |
15 | ## 图片预览
16 | 
17 | 
18 | 
19 |
20 | ## 安装运行(Build Setup)
21 |
22 | > 确保项目正常运行,请将你的node版本升级为7.0+以上,低版本node没有测试过。
23 |
24 | ``` bash
25 |
26 | # 克隆项目
27 | git clone https://github.com/eugeneCN/vue-electron-music.git
28 |
29 | # 安装依赖
30 | npm install
31 |
32 | # 启动api localhost:3000
33 | cd api/
34 | npm install
35 | npm start
36 |
37 | # 启动本地服务 localhost:9080
38 | npm run dev
39 |
40 | # 打包成本地应用
41 | npm run build
42 |
43 | # 开启控制台
44 | Ctrl + Shift + i
45 |
46 | ```
47 |
48 | ## 鸣谢
49 |
50 | 此应用提供的API: [https://github.com/Binaryify/NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) ,此接口的说明请到这里[查看](https://binaryify.github.io/NeteaseCloudMusicApi/#/)
51 |
--------------------------------------------------------------------------------
/api/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | *.log
4 |
--------------------------------------------------------------------------------
/api/.npmignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "NeteaseCloudMusicApi",
3 | "version": "2.5.9",
4 | "description": "网易云音乐 NodeJS 版 API",
5 | "scripts": {
6 | "start": "node app.js",
7 | "test": "mocha -r intelli-espower-loader -t 20000 test"
8 | },
9 | "keywords": [
10 | "网易云音乐",
11 | "网易云",
12 | "音乐",
13 | "网易云音乐nodejs"
14 | ],
15 | "author": "",
16 | "license": "MIT",
17 | "dependencies": {
18 | "big-integer": "^1.6.17",
19 | "express": "^4.15.2",
20 | "request": "^2.81.0"
21 | },
22 | "devDependencies": {
23 | "intelli-espower-loader": "^1.0.1",
24 | "mocha": "^3.2.0",
25 | "power-assert": "^1.4.2"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/api/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | 网易云音乐 API
8 |
9 |
10 | 网易云音乐 API
11 | 当你看到这个页面时,这个服务已经成功跑起来了~
12 | 查看文档
13 | 例子:
14 |
19 |
47 |
48 |
--------------------------------------------------------------------------------
/api/router/album.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | const id = req.query.id
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | `/weapi/v1/album/${id}`,
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => {
18 | res.send(music_req)
19 | },
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/artist_album.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const id = req.query.id
8 | const data = {
9 | 'offset': req.query.offset || 0,
10 | 'total': true,
11 | 'limit': req.query.limit || 30,
12 | "csrf_token": ""
13 | }
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | `/weapi/artist/albums/${id}`,
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => res.send(music_req),
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/artists.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | const id = req.query.id
11 | const offset = req.query.offset || 0
12 | const limit = req.query.limit || 50
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | `/weapi/v1/artist/${id}?offset=${offset}&limit=${limit}`,
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => res.send(music_req),
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/artists_desc.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const id = req.query.id
8 | const data = {
9 | id,
10 | "csrf_token": ""
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | `/weapi/artist/introduction`,
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => res.send(music_req),
19 | err => res.status(502).send('fetch error')
20 | )
21 | })
22 |
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/artists_mv.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const id = req.query.id
8 | const data = {
9 | artistId: id,
10 | "total": true,
11 | "offset": req.query.offset,
12 | "limit": req.query.limit,
13 | "csrf_token": ""
14 | }
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | `/weapi/artist/mvs`,
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => res.send(music_req),
22 | err => res.status(502).send('fetch error')
23 | )
24 | })
25 |
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/banner.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | createRequest('/api/v2/banner/get', 'GET', null)
7 | .then(result => {
8 | res.setHeader("Content-Type", "application/json")
9 | res.send(result)
10 | })
11 | .catch(err => {
12 | res.status(502).send('fetch error')
13 | })
14 | })
15 |
16 |
17 | module.exports = router
--------------------------------------------------------------------------------
/api/router/check_music.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const request = require("request")
4 | const { createWebAPIRequest } = require("../util/util")
5 | router.get("/", (req, res) => {
6 | const id = parseInt(req.query.id)
7 | const br = parseInt(req.query.br || 999000)
8 | const data = {
9 | "ids": [id],
10 | "br": br,
11 | "csrf_token": ""
12 | }
13 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
14 |
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | '/weapi/song/enhance/player/url',
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => {
22 | if(JSON.parse(music_req).code==200){
23 | return res.send({success: true, message: 'ok'})
24 | }
25 | return res.send({success: false, message: '亲爱的,暂无版权'});
26 | },
27 | err => {
28 | res.status(502).send('fetch error')
29 | }
30 | )
31 | })
32 |
33 |
34 | module.exports = router
--------------------------------------------------------------------------------
/api/router/comment_album.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const rid=req.query.id
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | "offset": req.query.offset || 0,
10 | "rid": rid,
11 | "limit": req.query.limit || 20,
12 | "csrf_token": ""
13 | }
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | `/weapi/v1/resource/comments/R_AL_3_${rid}/?csrf_token=`,
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => {
21 | res.send(music_req)
22 | },
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/comment_dj.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const rid=req.query.id
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | "offset": req.query.offset || 0,
10 | "rid": rid,
11 | "limit": req.query.limit || 20,
12 | "csrf_token": ""
13 | }
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | `/weapi/v1/resource/comments/A_DJ_1_${rid}/?csrf_token=`,
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => {
21 | res.send(music_req)
22 | },
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/comment_like.js:
--------------------------------------------------------------------------------
1 | //comment like
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const cid = req.query.cid //评论 id
9 | const id=req.query.id// 歌曲 id
10 | const typeMap={
11 | 0:"R_SO_4_",//歌曲
12 | 1:"R_MV_5_",//mv
13 | 2:"A_PL_0_",//歌单
14 | 3:"R_AL_3_",//专辑
15 | 4:"A_DJ_1_",//电台
16 | }
17 | const type=typeMap[req.query.type]
18 | const data = {
19 | "threadId": `${type}${id}`,
20 | commentId:cid,
21 | "csrf_token": ""
22 | }
23 | const action=(req.query.t==1?'like':'unlike')
24 |
25 | const url = `/weapi/v1/comment/${action}`
26 | createWebAPIRequest(
27 | 'music.163.com',
28 | url,
29 | 'POST',
30 | data,
31 | cookie,
32 | music_req => res.send(music_req),
33 | err => res.status(502).send('fetch error')
34 | )
35 | })
36 |
37 |
38 |
39 | module.exports = router
--------------------------------------------------------------------------------
/api/router/comment_music.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const rid=req.query.id
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | "offset": req.query.offset || 0,
10 | "rid": rid,
11 | "limit": req.query.limit || 20,
12 | "csrf_token": ""
13 | }
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | `/weapi/v1/resource/comments/R_SO_4_${rid}/?csrf_token=`,
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => {
21 | res.send(music_req)
22 | },
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/comment_mv.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const rid=req.query.id
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | "offset": req.query.offset || 0,
10 | "rid": rid,
11 | "limit": req.query.limit || 20,
12 | "csrf_token": ""
13 | }
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | `/weapi/v1/resource/comments/R_MV_5_${rid}/?csrf_token=`,
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => {
21 | res.send(music_req)
22 | },
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/comment_playlist.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const rid=req.query.id
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | "offset": req.query.offset || 0,
10 | "rid": rid,
11 | "limit": req.query.limit || 20,
12 | "csrf_token": ""
13 | }
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | `/weapi/v1/resource/comments/A_PL_0_${rid}/?csrf_token=`,
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => {
21 | res.send(music_req)
22 | },
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/daily_signin.js:
--------------------------------------------------------------------------------
1 | // 签到
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | "csrf_token": ""
10 | }
11 | // {'android': {'point': 3, 'code': 200}, 'web': {'point': 2, 'code': 200}}
12 | // {'android': {'code': -2, 'msg': '重复签到'}, 'web': {'code': -2, 'msg': '重复签到'}}
13 | // 'android': {'code': 301}, 'web': {'code': 301}}
14 |
15 | let type = req.query.type || 0 //0为安卓端签到 3点经验,1为网页签到,2点经验
16 | const action = `/weapi/point/dailyTask?type=${type}`
17 | createWebAPIRequest(
18 | 'music.163.com',
19 | action,
20 | 'POST',
21 | data,
22 | cookie,
23 | music_req => res.send(music_req),
24 | err => res.status(502).send('fetch error')
25 | )
26 | })
27 |
28 |
29 |
30 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_catelist.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | createWebAPIRequest(
11 | 'music.163.com',
12 | '/weapi/djradio/category/get',
13 | 'POST',
14 | data,
15 | cookie,
16 | music_req => {
17 | res.send(music_req)
18 | },
19 | err => res.status(502).send('fetch error')
20 | )
21 | })
22 |
23 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_detail.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const rid=req.query.rid
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | 'id': rid,
10 | "csrf_token": ""
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/djradio/get',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_hot.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | 'cat': req.query.type,
9 | cateId: req.query.type,
10 | type: req.query.type,
11 | categoryId: req.query.type,
12 | category: req.query.type,
13 | limit: req.query.limit,
14 | offset: req.query.offset,
15 | "csrf_token": ""
16 | }
17 | createWebAPIRequest(
18 | 'music.163.com',
19 | '/weapi/djradio/hot/v1',
20 | 'POST',
21 | data,
22 | cookie,
23 | music_req => {
24 | res.send(music_req)
25 | },
26 | err => res.status(502).send('fetch error')
27 | )
28 | })
29 |
30 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_program.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const rid=req.query.rid
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | 'asc': req.query.asc,
10 | 'radioId': rid,
11 | 'limit': req.query.limit,
12 | 'offset': req.query.offset,
13 | "csrf_token": ""
14 | }
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | '/weapi/dj/program/byradio',
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => {
22 | res.send(music_req)
23 | },
24 | err => res.status(502).send('fetch error')
25 | )
26 | })
27 |
28 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_program_detail.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | 'id': req.query.id,
9 | "csrf_token": ""
10 | }
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/dj/program/detail',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => {
18 | res.send(music_req)
19 | },
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_recommend.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | createWebAPIRequest(
11 | 'music.163.com',
12 | '/weapi/djradio/recommend/v1',
13 | 'POST',
14 | data,
15 | cookie,
16 | music_req => {
17 | res.send(music_req)
18 | },
19 | err => res.status(502).send('fetch error')
20 | )
21 | })
22 |
23 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_recommend_type.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | cateId: req.query.type,
9 | "csrf_token": ""
10 | }
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/djradio/recommend',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => {
18 | res.send(music_req)
19 | },
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/dj_sub.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "id": req.query.rid,
9 | "csrf_token": ""
10 | }
11 | const action=(req.query.t==1?'sub':'unsub')
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | `/weapi/djradio/${action}`,
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/event.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | createWebAPIRequest(
11 | 'music.163.com',
12 | '/weapi/v1/event/get',
13 | 'POST',
14 | data,
15 | cookie,
16 | music_req => res.send(music_req),
17 | err => res.status(502).send('fetch error')
18 | )
19 | })
20 |
21 | module.exports = router
22 |
--------------------------------------------------------------------------------
/api/router/fm_trash.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | const songid = req.query.id
11 | const alg = "RT"
12 | const time = req.query.time || 25
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | `/weapi/radio/trash/add?alg=${alg}&songId=${songid}&time=${time}`,
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => res.send(music_req),
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 |
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/follow.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | const url = req.query.type == 'add' ? 'follow' : "delfollow"
11 | const id = req.query.id
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | `/weapi/user/${url}/${id}`,
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/like.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | const trackId = req.query.id
11 | const like = req.query.like || true
12 | const alg = req.query.alg || "itembased"
13 | const time = req.query.time || 25
14 | console.log(alg)
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | `/weapi/radio/like?alg=${alg}&trackId=${trackId}&like=${like}&time=${time}`,
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => res.send(music_req),
22 | err => res.status(502).send('fetch error')
23 | )
24 | })
25 |
26 |
27 |
28 | module.exports = router
--------------------------------------------------------------------------------
/api/router/likelist.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | uid: req.query.uid,
9 | "csrf_token": ""
10 | }
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | `/weapi/song/like/get`,
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => {
18 | res.send(music_req)
19 | },
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 |
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/logWeb.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": "",
9 | }
10 |
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/feedback/weblog',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => res.send(music_req),
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/login.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const crypto = require('crypto')
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const email = req.query.email
8 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
9 | const md5sum = crypto.createHash('md5')
10 | md5sum.update(req.query.password)
11 | const data = {
12 | 'username': email,
13 | 'password': md5sum.digest('hex'),
14 | 'rememberLogin': 'true',
15 | 'clientToken':"1_jVUMqWEPke0/1/Vu56xCmJpo5vP1grjn_SOVVDzOc78w8OKLVZ2JH7IfkjSXqgfmh"
16 | }
17 | console.log(email,req.query.password);
18 |
19 | createWebAPIRequest(
20 | 'music.163.com',
21 | '/weapi/login?csrf_token=',
22 | 'POST',
23 | data,
24 | cookie,
25 | (music_req, cookie) => {
26 | console.log(music_req)
27 | res.set({
28 | 'Set-Cookie': cookie,
29 | })
30 | res.send(music_req)
31 | },
32 | err => res.status(502).send('fetch error')
33 | )
34 | })
35 |
36 | module.exports = router
--------------------------------------------------------------------------------
/api/router/loginCellphone.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const crypto = require('crypto')
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const phone = req.query.phone
8 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
9 | const md5sum = crypto.createHash('md5')
10 | md5sum.update(req.query.password)
11 | const data = {
12 | 'phone': phone,
13 | 'password': md5sum.digest('hex'),
14 | 'rememberLogin': 'true'
15 | }
16 |
17 | createWebAPIRequest(
18 | 'music.163.com',
19 | '/weapi/login/cellphone',
20 | 'POST',
21 | data,
22 | cookie,
23 | (music_req, cookie) => {
24 | console.log(music_req)
25 | res.set({
26 | 'Set-Cookie': cookie,
27 | })
28 | res.send(music_req)
29 | },
30 | err => res.status(502).send('fetch error')
31 | )
32 | })
33 |
34 | module.exports = router
--------------------------------------------------------------------------------
/api/router/login_refresh.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | let csrf = req.query.t || ''
8 | for (let i in cookie) {
9 | if (cookie[i].name == '__csrf') {
10 | csrf = cookie.value
11 | }
12 | }
13 | const data = {
14 | "csrf_token": csrf
15 | }
16 | createWebAPIRequest(
17 | 'music.163.com',
18 | `/weapi/login/token/refresh?csrf_token=${csrf}`,
19 | 'POST',
20 | data,
21 | cookie,
22 | music_req => {
23 | res.send(music_req)
24 | },
25 | err => res.status(502).send('fetch error')
26 | )
27 | })
28 |
29 | module.exports = router
--------------------------------------------------------------------------------
/api/router/lyric.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const id = req.query.id
7 | createRequest('/api/song/lyric?os=osx&id=' + id + '&lv=-1&kv=-1&tv=-1', 'GET', null)
8 | .then(result => {
9 | res.setHeader("Content-Type", "application/json")
10 | res.send(result)
11 | })
12 | .catch(err => {
13 | res.status(502).send('fetch error')
14 | })
15 | })
16 |
17 |
18 | module.exports = router
--------------------------------------------------------------------------------
/api/router/musicUrl.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const id = req.query.id
7 | const br = req.query.br || 999000
8 | const data = {
9 | "ids": [id],
10 | "br": br,
11 | "csrf_token": ""
12 | }
13 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
14 |
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | '/weapi/song/enhance/player/url',
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => {
22 | res.setHeader("Content-Type", "application/json")
23 | res.send(music_req)
24 | },
25 | err => {
26 | res.status(502).send('fetch error')
27 | }
28 | )
29 | })
30 |
31 | module.exports = router
--------------------------------------------------------------------------------
/api/router/mv.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createRequest } = require("../util/util")
4 | const request=require("request")
5 | router.get("/", (req, res) => {
6 | const mvid = req.query.mvid
7 | createRequest(`/api/mv/detail/?id=${mvid}&type=mp4`, 'GET', null)
8 | .then(result => {
9 | res.setHeader("Content-Type", "application/json")
10 | res.send(result)
11 | })
12 | .catch(err => {
13 | res.status(502).send('fetch error')
14 | })
15 | })
16 |
17 |
18 | module.exports = router
--------------------------------------------------------------------------------
/api/router/mv_first.js:
--------------------------------------------------------------------------------
1 | //最新mv
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | // type ALL, ZH,EA,KR,JP
7 | router.get("/", (req, res) => {
8 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
9 | const data = {
10 | // 'offset': req.query.offset || 0,
11 | 'total': true,
12 | 'limit': req.query.limit || 30,
13 | "csrf_token": ""
14 | }
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | '/weapi/mv/first',
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => res.send(music_req),
22 | err => res.status(502).send('fetch error')
23 | )
24 | })
25 |
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/mv_url.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const request = require("request")
4 |
5 | router.get("/", (req, res) => {
6 | const url = req.query.url
7 | const headers = {
8 | "Referer": "http://music.163.com/",
9 | "Cookie": "appver=1.5.0.75771;",
10 | 'Content-Type': 'video/mp4',
11 | 'Location': url
12 | }
13 | const options = {
14 | header: headers,
15 | url: url
16 | }
17 | request(options)
18 | .on('error', err => {
19 | res.send({ err })
20 | })
21 | .pipe(res)
22 | })
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/personal_fm.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 |
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/v1/radio/get',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => res.send(music_req),
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/personalized.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | }
9 | createWebAPIRequest(
10 | 'music.163.com',
11 | '/api/personalized/playlist',
12 | 'POST',
13 | data,
14 | cookie,
15 | music_req => {
16 | res.send(music_req)
17 | },
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 | module.exports = router
--------------------------------------------------------------------------------
/api/router/personalized_djprogram.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | }
9 | createWebAPIRequest(
10 | 'music.163.com',
11 | '/api/personalized/djprogram',
12 | 'POST',
13 | data,
14 | cookie,
15 | music_req => {
16 | res.send(music_req)
17 | },
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 | module.exports = router
--------------------------------------------------------------------------------
/api/router/personalized_mv.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | }
9 | createWebAPIRequest(
10 | 'music.163.com',
11 | '/api/personalized/mv',
12 | 'POST',
13 | data,
14 | cookie,
15 | music_req => {
16 | res.send(music_req)
17 | },
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 | module.exports = router
--------------------------------------------------------------------------------
/api/router/personalized_newsong.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | type: "recommend"
9 | }
10 | createWebAPIRequest(
11 | 'music.163.com',
12 | '/api/personalized/newsong',
13 | 'POST',
14 | data,
15 | cookie,
16 | music_req => {
17 | res.send(music_req)
18 | },
19 | err => res.status(502).send('fetch error')
20 | )
21 | })
22 |
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/personalized_privatecontent.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | }
9 | createWebAPIRequest(
10 | 'music.163.com',
11 | '/api/personalized/privatecontent',
12 | 'POST',
13 | data,
14 | cookie,
15 | music_req => {
16 | res.send(music_req)
17 | },
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 | module.exports = router
--------------------------------------------------------------------------------
/api/router/playlist_catlist.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | createWebAPIRequest(
11 | 'music.163.com',
12 | '/weapi/playlist/catalogue',
13 | 'POST',
14 | data,
15 | cookie,
16 | music_req => {
17 | res.send(music_req)
18 | },
19 | err => res.status(502).send('fetch error')
20 | )
21 | })
22 |
23 | module.exports = router
--------------------------------------------------------------------------------
/api/router/playlist_detail.js:
--------------------------------------------------------------------------------
1 | const http = require('http')
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | let detail, imgurl
9 | const data = {
10 | "id": req.query.id,
11 | "offset": 0,
12 | "total": true,
13 | "limit": 1000,
14 | "n": 1000,
15 | "csrf_token": ""
16 | }
17 |
18 | createWebAPIRequest(
19 | 'music.163.com',
20 | '/weapi/v3/playlist/detail',
21 | 'POST',
22 | data,
23 | cookie,
24 | music_req => {
25 | console.log(music_req)
26 | // detail = music_req
27 | res.send(music_req)
28 | // mergeRes()
29 | },
30 | err => {
31 | res.status(502).send('fetch error')
32 | }
33 | )
34 |
35 | // FIXME:i dont know the api to get coverimgurl
36 | // so i get it by parsing html
37 | // const http_client = http.get({
38 | // hostname: 'music.163.com',
39 | // path: '/playlist?id=' + req.query.id,
40 | // headers: {
41 | // 'Referer': 'http://music.163.com',
42 | // },
43 | // }, function (res) {
44 | // res.setEncoding('utf8')
45 | // let html = ''
46 | // res.on('data', function (chunk) {
47 | // html += chunk
48 | // })
49 | // res.on('end', function () {
50 | // console.log('end', html)
51 | // const regImgCover = /\
{
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | }
9 | createWebAPIRequest(
10 | 'music.163.com',
11 | '/api/playlist/hottags',
12 | 'POST',
13 | data,
14 | cookie,
15 | music_req => {
16 | res.send(music_req)
17 | },
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 | module.exports = router
--------------------------------------------------------------------------------
/api/router/playlist_tracks.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 | //收藏单曲到歌单,从歌单删除歌曲 op=del,add;pid=歌单id,tracks=歌曲id
5 | router.get("/", (req, res) => {
6 | const op = req.query.op
7 | const pid = req.query.pid
8 | const tracks = req.query.tracks
9 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
10 | // console.log('COOKIESS', cookie)
11 | const data = {
12 | "op": op,
13 | "pid": pid,
14 | "tracks": tracks,
15 | "trackIds": JSON.stringify([tracks]),
16 | "csrf_token": "",
17 | }
18 | createWebAPIRequest(
19 | 'music.163.com',
20 | '/weapi/playlist/manipulate/tracks',
21 | 'POST',
22 | data,
23 | cookie,
24 | music_req => res.send(music_req),
25 | err => res.status(502).send('fetch error')
26 |
27 | )
28 | })
29 |
30 | module.exports = router
--------------------------------------------------------------------------------
/api/router/program_recommend.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | cateId: req.query.type,
9 | "csrf_token": ""
10 | }
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/program/recommend/v1',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => {
18 | res.send(music_req)
19 | },
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/recommend_dislike.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 |
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/v1/radio/get',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => res.send(music_req),
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/recommend_resource.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 |
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/v1/discovery/recommend/resource',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => res.send(music_req),
18 | err => res.status(502).send('fetch error')
19 | )
20 | })
21 |
22 |
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/recommend_songs.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/",(req,res)=>{
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "offset": 0,
9 | "total": true,
10 | "limit": 20,
11 | "csrf_token": ""
12 | }
13 |
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | '/weapi/v1/discovery/recommend/songs',
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => res.send(music_req),
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 |
26 |
27 | module.exports=router
--------------------------------------------------------------------------------
/api/router/resource_like.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "threadId": req.query.id,
9 | "csrf_token": ""
10 | }
11 | const action = (req.query.t == 1 ? 'like' : 'unlike')
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | `/weapi/resource/${action}`,
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/search.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const keywords = req.query.keywords
7 | const type = req.query.type || 1
8 | const limit = req.query.limit || 30
9 | const offset = req.query.offset || 0
10 | // 搜索单曲(1),歌手(100),专辑(10),歌单(1000),用户(1002) *(type)*
11 | const data = 's=' + keywords + '&limit=' + limit + '&type=' + type + '&offset=' + offset
12 | createRequest('/api/search/pc/', 'POST', data)
13 | .then(result => {
14 | res.setHeader("Content-Type", "application/json")
15 | res.send(result)
16 | })
17 | .catch(err => {
18 | res.status(502).send('fetch error')
19 | })
20 | })
21 |
22 | module.exports = router
--------------------------------------------------------------------------------
/api/router/search_hot.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": "",
9 | type: req.query.type || 1,
10 | s: keywords || req.query.keywords || ''
11 | }
12 |
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | '/api/search/hot?type=1',
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => res.send(music_req),
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 |
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/search_multimatch.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": "",
9 | type: req.query.type || 1,
10 | s: req.query.keywords || req.query.keywords || ''
11 | }
12 |
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | '/weapi/search/suggest/multimatch',
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => {
20 | res.send(music_req)
21 | console.log(Object.keys(JSON.parse(music_req).result))
22 | },
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 |
28 |
29 | module.exports = router
--------------------------------------------------------------------------------
/api/router/search_suggest.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": "",
9 | s: req.query.keywords || req.query.keywords || ''
10 | }
11 |
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/search/suggest/web',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 |
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/simi_artists.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const id = req.query.id
8 | const data = {
9 | artistid:id,
10 | "csrf_token": ""
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | `/weapi/discovery/simiArtist`,
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => res.send(music_req),
19 | err => res.status(502).send('fetch error')
20 | )
21 | })
22 |
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/simi_mv.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | mvid: req.query.mvid
9 | }
10 | createWebAPIRequest(
11 | 'music.163.com',
12 | '/weapi/discovery/simiMV',
13 | 'POST',
14 | data,
15 | cookie,
16 | music_req => res.send(music_req),
17 | err => res.status(502).send('fetch error')
18 | )
19 | })
20 |
21 |
22 | module.exports = router
--------------------------------------------------------------------------------
/api/router/simi_playlist.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | songid: req.query.id,
9 | offset: req.query.offset || 0,
10 | limit: req.query.limit || 50
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/discovery/simiPlaylist',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/simi_song.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | songid: req.query.id,
9 | offset: req.query.offset || 0,
10 | limit: req.query.limit || 50
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/v1/discovery/simiSong',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/simi_user.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | songid: req.query.id,
9 | offset: req.query.offset || 0,
10 | limit: req.query.limit || 50
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/discovery/simiUser',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/song_detail.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const id = parseInt(req.query.ids)
8 | const data = {
9 | // "id": id,
10 | 'c': JSON.stringify([{ id: id }]),
11 | "ids": '[' + id + ']',
12 | "csrf_token": ""
13 | }
14 | console.log(data)
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | '/weapi/v3/song/detail',
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => {
22 | res.send(music_req)
23 | },
24 | err => res.status(502).send('fetch error')
25 | )
26 | })
27 |
28 | module.exports = router
--------------------------------------------------------------------------------
/api/router/top_album.js:
--------------------------------------------------------------------------------
1 | //最新mv
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | // type ALL, ZH,EA,KR,JP
7 | router.get("/", (req, res) => {
8 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
9 | const data = {
10 | 'offset': req.query.offset,
11 | 'total': true,
12 | 'limit': req.query.limit,
13 | 'area': req.query.type,
14 | "csrf_token": ""
15 | }
16 | createWebAPIRequest(
17 | 'music.163.com',
18 | '/weapi/album/new',
19 | 'POST',
20 | data,
21 | cookie,
22 | music_req => {
23 | res.send(music_req)
24 | },
25 | err => res.status(502).send('fetch error')
26 | )
27 | })
28 |
29 |
30 | module.exports = router
--------------------------------------------------------------------------------
/api/router/top_artists.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const offset = req.query.offset || 0
7 | const limit = req.query.limit || 50
8 | createRequest(`/api/artist/top?offset=${offset}&total=false&limit=${limit}`, 'GET', null)
9 | .then(result => {
10 | res.setHeader("Content-Type", "application/json")
11 | res.send(result)
12 | })
13 | .catch(err => {
14 | res.status(502).send('fetch error')
15 | })
16 | })
17 |
18 |
19 | module.exports = router
--------------------------------------------------------------------------------
/api/router/top_list.js:
--------------------------------------------------------------------------------
1 | const top_list_all = {
2 | "0": ['云音乐新歌榜', '/api/playlist/detail?id=3779629'],
3 | "1": ['云音乐热歌榜', '/api/playlist/detail?id=3778678'],
4 | "2": ['网易原创歌曲榜', '/api/playlist/detail?id=2884035'],
5 | "3": ['云音乐飙升榜', '/api/playlist/detail?id=19723756'],
6 | "4": ['云音乐电音榜', '/api/playlist/detail?id=10520166'],
7 | "5": ['UK排行榜周榜', '/api/playlist/detail?id=180106'],
8 | "6": ['美国Billboard周榜', '/api/playlist/detail?id=60198'],
9 | "7": ['KTV嗨榜', '/api/playlist/detail?id=21845217'],
10 | "8": ['iTunes榜', '/api/playlist/detail?id=11641012'],
11 | "9": ['Hit FM Top榜', '/api/playlist/detail?id=120001'],
12 | "10": ['日本Oricon周榜', '/api/playlist/detail?id=60131'],
13 | "11": ['韩国Melon排行榜周榜', '/api/playlist/detail?id=3733003'],
14 | "12": ['韩国Mnet排行榜周榜', '/api/playlist/detail?id=60255'],
15 | "13": ['韩国Melon原声周榜', '/api/playlist/detail?id=46772709'],
16 | "14": ['中国TOP排行榜(港台榜)', '/api/playlist/detail?id=112504'],
17 | "15": ['中国TOP排行榜(内地榜)', '/api/playlist/detail?id=64016'],
18 | "16": ['香港电台中文歌曲龙虎榜', '/api/playlist/detail?id=10169002'],
19 | "17": ['华语金曲榜', '/api/playlist/detail?id=4395559'],
20 | "18": ['中国嘻哈榜', '/api/playlist/detail?id=1899724'],
21 | "19": ['法国 NRJ EuroHot 30周榜', '/api/playlist/detail?id=27135204'],
22 | "20": ['台湾Hito排行榜', '/api/playlist/detail?id=112463'],
23 | "21": ['Beatport全球电子舞曲榜', '/api/playlist/detail?id=3812895']
24 | }
25 | const express = require("express")
26 | const router = express()
27 | const { createRequest } = require("../util/util")
28 |
29 | router.get("/", (req, res) => {
30 | const idx = req.query.idx
31 | const action = 'http://music.163.com' + top_list_all[idx][1]
32 | createRequest(`${action}`, 'GET', null)
33 | .then(result => {
34 | res.setHeader("Content-Type", "application/json")
35 | res.send(result)
36 | })
37 | .catch(err => {
38 | res.status(502).send('fetch error')
39 | })
40 | })
41 |
42 |
43 | module.exports = router
--------------------------------------------------------------------------------
/api/router/top_mv.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | 'offset': req.query.offset || 0,
9 | 'total': true,
10 | 'limit': req.query.limit || 30,
11 | "csrf_token": ""
12 | }
13 |
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | '/weapi/mv/toplist',
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => {
21 | res.setHeader("Content-Type", "application/json")
22 | res.send(music_req)
23 | },
24 | err => res.status(502).send('fetch error')
25 | )
26 | })
27 |
28 |
29 |
30 | module.exports = router
--------------------------------------------------------------------------------
/api/router/top_playlist.js:
--------------------------------------------------------------------------------
1 | //分类歌单
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | // order可为 'hot' 可为 'new'
9 | const data = {
10 | cat: req.query.cat || "全部",
11 | order: req.query.order || "hot",
12 | offset: req.query.offset || 0,
13 | total: req.query.total ? 'true' : 'false',
14 | limit: req.query.limit || 50
15 | }
16 | createWebAPIRequest(
17 | 'music.163.com',
18 | '/weapi/playlist/list',
19 | 'POST',
20 | data,
21 | cookie,
22 | music_req => {
23 | res.send(music_req)
24 | },
25 | err => res.status(502).send('fetch error')
26 | )
27 | })
28 |
29 | module.exports = router
--------------------------------------------------------------------------------
/api/router/top_playlist_highquality.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | cat: req.query.cat || "全部",
9 | offset: req.query.offset || 0,
10 | limit: req.query.limit || 20
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/playlist/highquality/list',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/top_songs.js:
--------------------------------------------------------------------------------
1 | //新歌上架
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | // type ALL, ZH,EA,KR,JP
7 | router.get("/", (req, res) => {
8 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
9 | const data = {
10 | 'offset': request.query.offset,
11 | 'total': true,
12 | 'limit': request.query.limit,
13 | 'area': request.query.type,
14 | "csrf_token": ""
15 | }
16 | createWebAPIRequest(
17 | 'music.163.com',
18 | '/weapi/v1/discovery/new/songs',
19 | 'POST',
20 | data,
21 | cookie,
22 | music_req => {
23 | res.send(music_req)
24 | },
25 | err => res.status(502).send('fetch error')
26 | )
27 | })
28 |
29 |
30 | module.exports = router
--------------------------------------------------------------------------------
/api/router/toplist.js:
--------------------------------------------------------------------------------
1 | // 排行榜
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | "csrf_token": "",
10 | }
11 | createWebAPIRequest(
12 | 'music.163.com',
13 | '/weapi/toplist',
14 | 'POST',
15 | data,
16 | cookie,
17 | music_req => {
18 | res.send(music_req)
19 | },
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/toplist_artist.js:
--------------------------------------------------------------------------------
1 | //艺术家分类
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | type: request.query.type,
10 | "csrf_token": "",
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/toplist/artist',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/toplist_detail.js:
--------------------------------------------------------------------------------
1 | // 排行榜详情
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const data = {
9 | id: request.query.id,
10 | limit: 20,
11 | "csrf_token": "",
12 | }
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | '/weapi/toplist/detail',
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => {
20 | res.send(music_req)
21 | },
22 | err => res.status(502).send('fetch error')
23 | )
24 | })
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_audio.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const data = {
7 | "userId": req.query.uid,
8 | "csrf_token": ""
9 | }
10 | console.log(data)
11 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
12 |
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | '/weapi/djradio/get/byuser',
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => {
20 | res.setHeader("Content-Type", "application/json")
21 | res.send(music_req)
22 | },
23 | err => {
24 | res.status(502).send('fetch error')
25 | }
26 | )
27 | })
28 |
29 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_cloud.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const data = {
7 | limit: req.query.limit || 10,
8 | offset: req.query.offset || 0,
9 | "csrf_token": ""
10 | }
11 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/v1/cloud/get',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.setHeader("Content-Type", "application/json")
20 | res.send(music_req)
21 | },
22 | err => {
23 | res.status(502).send('fetch error')
24 | }
25 | )
26 | })
27 |
28 |
29 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_cloud_search.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const data = {
7 | byids: req.query.id,
8 | id: req.query.id,
9 | "csrf_token": ""
10 | }
11 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | '/weapi/v1/cloud/get/byids',
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.setHeader("Content-Type", "application/json")
20 | res.send(music_req)
21 | },
22 | err => {
23 | res.status(502).send('fetch error')
24 | }
25 | )
26 | })
27 |
28 |
29 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_detail.js:
--------------------------------------------------------------------------------
1 | // 用户详情
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const id = req.query.uid
9 | const data = {
10 | "csrf_token": ""
11 | }
12 | createWebAPIRequest(
13 | 'music.163.com',
14 | `/api/v1/user/detail/${id}`,
15 | 'POST',
16 | data,
17 | cookie,
18 | music_req => {
19 | res.send(music_req)
20 | },
21 | err => res.status(502).send('fetch error')
22 | )
23 | })
24 |
25 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_dj.js:
--------------------------------------------------------------------------------
1 | // 用户电台
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 | const id = req.query.uid
9 | const data = {
10 | 'offset': req.query.offset || '0',
11 | 'limit': req.query.limit || 30,
12 | "csrf_token": ""
13 | }
14 | createWebAPIRequest(
15 | 'music.163.com',
16 | `/weapi/dj/program/${id}`,
17 | 'POST',
18 | data,
19 | cookie,
20 | music_req => {
21 | res.send(music_req)
22 | },
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_event.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const id = req.query.uid
8 | const data = {
9 | 'time': -1,
10 | 'getcounts': true,
11 | "csrf_token": ""
12 | }
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | `/weapi/event/get/${id}`,
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => {
20 | res.send(music_req)
21 | },
22 | err => res.status(502).send('fetch error')
23 | )
24 | })
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_followeds.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | 'userId': req.query.uid,
9 | offset: req.query.offset || '0',
10 | limit: req.query.limit || 30,
11 | "csrf_token": ""
12 | }
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | `/weapi/user/getfolloweds/`,
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => {
20 | res.send(music_req)
21 | },
22 | err => res.status(502).send('fetch error')
23 | )
24 | })
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_follows.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const id = req.query.uid
8 | const data = {
9 | offset: req.query.offset || '0',
10 | limit: req.query.limit || 30,
11 | order: true
12 | }
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | `/weapi/user/getfollows/${id}`,
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => {
20 | res.send(music_req)
21 | },
22 | err => res.status(502).send('fetch error')
23 | )
24 | })
25 |
26 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_playlist.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "offset": 0,
9 | "uid": req.query.uid,
10 | "limit": 1000,
11 | "csrf_token": ""
12 | }
13 | createWebAPIRequest(
14 | 'music.163.com',
15 | '/weapi/user/playlist',
16 | 'POST',
17 | data,
18 | cookie,
19 | music_req => res.send(music_req),
20 | err => res.status(502).send('fetch error')
21 | )
22 | })
23 |
24 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_playrecord.js:
--------------------------------------------------------------------------------
1 | //播放记录
2 | const express = require("express")
3 | const router = express()
4 | const { createWebAPIRequest } = require("../util/util")
5 |
6 | router.get("/", (req, res) => {
7 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
8 |
9 | // type=1时只返回weekData, type=0时返回allData
10 | const data = {
11 | 'type': req.query.type || 0,
12 | uid: req.query.uid, //用户 id,
13 | "csrf_token": ""
14 | }
15 | const action = `/weapi/v1/play/record`
16 | createWebAPIRequest(
17 | 'music.163.com',
18 | action,
19 | 'POST',
20 | data,
21 | cookie,
22 | music_req => res.send(music_req),
23 | err => res.status(502).send('fetch error')
24 | )
25 | })
26 |
27 |
28 |
29 | module.exports = router
--------------------------------------------------------------------------------
/api/router/user_subcount.js:
--------------------------------------------------------------------------------
1 | const express = require("express")
2 | const router = express()
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | router.get("/", (req, res) => {
6 | const cookie = req.get('Cookie') ? req.get('Cookie') : ''
7 | const data = {
8 | "csrf_token": ""
9 | }
10 | createWebAPIRequest(
11 | 'music.163.com',
12 | '/weapi/subcount',
13 | 'POST',
14 | data,
15 | cookie,
16 | music_req => res.send(music_req),
17 | err => res.status(502).send('fetch error')
18 | )
19 | })
20 |
21 | module.exports = router
--------------------------------------------------------------------------------
/api/test/album.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const crypto = require('crypto')
3 | const { createRequest } = require("../util/util")
4 |
5 | describe('测试获取歌手专辑列表是否正常', () => {
6 | it('数据的 code 应该为200', done => {
7 | const id = 32311
8 | createRequest(`/api/album/${id}`, 'GET', null)
9 | .then(result => {
10 | const code = JSON.parse(result).code
11 | console.log("code:" + code)
12 | assert(code === 200)
13 | done()
14 | })
15 | .catch(err => done(err))
16 | })
17 | })
--------------------------------------------------------------------------------
/api/test/comment.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const crypto = require('crypto')
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | describe('测试获取评论是否正常', () => {
6 | it('数据的 code 应该为200', done => {
7 | const rid = 32311
8 | const cookie = ''
9 | const data = {
10 | "offset": 0,
11 | "rid": rid,
12 | "limit": 20,
13 | "csrf_token": ""
14 | }
15 | createWebAPIRequest(
16 | 'music.163.com',
17 | `/weapi/v1/resource/comments/R_SO_4_${rid}/?csrf_token=`,
18 | 'POST',
19 | data,
20 | cookie,
21 | music_req => {
22 | console.log({
23 | code:JSON.parse(music_req).code
24 | })
25 | assert(JSON.parse(music_req).code === 200)
26 | done()
27 | },
28 | err => done(err)
29 | )
30 | })
31 | })
--------------------------------------------------------------------------------
/api/test/login.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const crypto = require('crypto')
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | console.log("注意:测试登陆需要替换这里的账号密码!!!")
6 |
7 | describe('测试登录是否正常', () => {
8 | it('手机登录 code 应该等于200', done => {
9 | const phone = "换成你的手机号"
10 | const password = "换成你的密码"
11 | let cookie = ''
12 | const md5sum = crypto.createHash('md5')
13 | md5sum.update(password)
14 | const data = {
15 | 'phone': phone,
16 | 'password': md5sum.digest('hex'),
17 | 'rememberLogin': 'true'
18 | }
19 |
20 | createWebAPIRequest(
21 | 'music.163.com',
22 | '/weapi/login/cellphone',
23 | 'POST',
24 | data,
25 | cookie,
26 | (music_req, cookie) => {
27 | const result = JSON.parse(music_req)
28 | console.log({
29 | loginType: result.loginType,
30 | code: result.code,
31 | account: result.account
32 | })
33 | assert(result.code === 200)
34 | done()
35 | },
36 | err => done(err)
37 | )
38 | })
39 |
40 | it('邮箱登录 code 应该等于200', done => {
41 | const email = "换成你的163网易邮箱"
42 | const password = "换成你的密码"
43 | const cookie = ''
44 | const md5sum = crypto.createHash('md5')
45 | md5sum.update(password)
46 | const data = {
47 | 'username': email,
48 | 'password': md5sum.digest('hex'),
49 | 'rememberLogin': 'true'
50 | }
51 |
52 | createWebAPIRequest(
53 | 'music.163.com',
54 | '/weapi/login',
55 | 'POST',
56 | data,
57 | cookie,
58 | (music_req, cookie) => {
59 | const result = JSON.parse(music_req)
60 | console.log({
61 | loginType: result.loginType,
62 | code: result.code,
63 | account: result.account
64 | })
65 | assert(result.code === 200)
66 | done()
67 | },
68 | err => done(err)
69 | )
70 | })
71 | })
--------------------------------------------------------------------------------
/api/test/lyric.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const crypto = require('crypto')
3 | const { createRequest } = require("../util/util")
4 |
5 | describe('测试获取歌词是否正常', () => {
6 | it('数据应该有 lrc 字段', done => {
7 | const id = 347230
8 | createRequest('/api/song/lyric?os=osx&id=' + id + '&lv=-1&kv=-1&tv=-1', 'GET', null)
9 | .then(result => {
10 | console.log(JSON.parse(result).lrc)
11 | assert(typeof JSON.parse(result).lrc!=='undefined')
12 | done()
13 | })
14 | .catch(err => {
15 | done(err)
16 | })
17 | })
18 | })
--------------------------------------------------------------------------------
/api/test/musicUrl.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const crypto = require('crypto')
3 | const { createWebAPIRequest } = require("../util/util")
4 |
5 | describe('测试获取歌曲是否正常', () => {
6 | it('歌曲的 url 不应该为空', done => {
7 | const id = 347230
8 | const br = 999000
9 | const data = {
10 | "ids": [id],
11 | "br": br,
12 | "csrf_token": ""
13 | }
14 | const cookie = ''
15 |
16 | createWebAPIRequest(
17 | 'music.163.com',
18 | '/weapi/song/enhance/player/url',
19 | 'POST',
20 | data,
21 | cookie,
22 | music_req => {
23 | console.log(JSON.parse(music_req).data[0].url)
24 | assert(!!JSON.parse(music_req).data[0].url)
25 | done()
26 | },
27 | err => {
28 | done(err)
29 | }
30 | )
31 | })
32 | })
--------------------------------------------------------------------------------
/api/test/search.test.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert')
2 | const crypto = require('crypto')
3 | const { createRequest } = require("../util/util")
4 |
5 | describe('测试搜索是否正常', () => {
6 | it('获取到的数据的 name 应该和搜索关键词一致', done => {
7 | const keywords = "海阔天空"
8 | const type = 1
9 | const limit = 30
10 | const data = 's=' + keywords + '&limit=' + limit + '&type=' + type + '&offset=0'
11 | createRequest('/api/search/pc/', 'POST', data)
12 | .then(result => {
13 | console.log(JSON.parse(result).result.songs[0].mp3Url)
14 | assert(JSON.parse(result).result.songs[0].name === '海阔天空')
15 | done()
16 | })
17 | .catch(err => {
18 | done(err)
19 | })
20 | })
21 | })
--------------------------------------------------------------------------------
/api/util/crypto.js:
--------------------------------------------------------------------------------
1 | // 参考 https://github.com/darknessomi/musicbox/wiki/
2 | 'use strict'
3 | const crypto = require('crypto')
4 | const bigInt = require('big-integer')
5 | const modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
6 | const nonce = '0CoJUm6Qyw8W8jud'
7 | const pubKey = '010001'
8 |
9 | String.prototype.hexEncode = function(){
10 | let hex, i
11 |
12 | let result = ""
13 | for (i=0; i {
4 | /**
5 | * Reload browser when HTMLWebpackPlugin emits a new index.html
6 | */
7 | if (event.action === 'reload') {
8 | window.location.reload()
9 | }
10 |
11 | /**
12 | * Notify `mainWindow` when `main` process is compiling,
13 | * giving notice for an expected reload of the `electron` process
14 | */
15 | if (event.action === 'compiling') {
16 | document.body.innerHTML += `
17 |
30 |
31 |
32 | Compiling Main Process...
33 |
34 | `
35 | }
36 | })
37 |
--------------------------------------------------------------------------------
/config/webpack.main.config.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | process.env.BABEL_ENV = 'main'
4 |
5 | const path = require('path')
6 | const { dependencies } = require('../package.json')
7 | const webpack = require('webpack')
8 |
9 | const BabiliWebpackPlugin = require('babili-webpack-plugin')
10 |
11 | let mainConfig = {
12 | entry: {
13 | main: path.join(__dirname, '../src/main/index.js')
14 | },
15 | externals: [
16 | ...Object.keys(dependencies || {})
17 | ],
18 | module: {
19 | rules: [
20 | {
21 | test: /\.(js)$/,
22 | enforce: 'pre',
23 | exclude: /node_modules/,
24 | use: {
25 | loader: 'eslint-loader',
26 | options: {
27 | formatter: require('eslint-friendly-formatter')
28 | }
29 | }
30 | },
31 | {
32 | test: /\.js$/,
33 | use: 'babel-loader',
34 | exclude: /node_modules/
35 | },
36 | {
37 | test: /\.node$/,
38 | use: 'node-loader'
39 | }
40 | ]
41 | },
42 | node: {
43 | __dirname: process.env.NODE_ENV !== 'production',
44 | __filename: process.env.NODE_ENV !== 'production'
45 | },
46 | output: {
47 | filename: '[name].js',
48 | libraryTarget: 'commonjs2',
49 | path: path.join(__dirname, '../dist/electron')
50 | },
51 | plugins: [
52 | new webpack.NoEmitOnErrorsPlugin()
53 | ],
54 | resolve: {
55 | extensions: ['.js', '.json', '.node']
56 | },
57 | target: 'electron-main'
58 | }
59 |
60 | /**
61 | * Adjust mainConfig for development settings
62 | */
63 | if (process.env.NODE_ENV !== 'production') {
64 | mainConfig.plugins.push(
65 | new webpack.DefinePlugin({
66 | '__static': `"${path.join(__dirname, '../static')}"`
67 | })
68 | )
69 | }
70 |
71 | /**
72 | * Adjust mainConfig for production settings
73 | */
74 | if (process.env.NODE_ENV === 'production') {
75 | mainConfig.plugins.push(
76 | new BabiliWebpackPlugin(),
77 | new webpack.DefinePlugin({
78 | 'process.env.NODE_ENV': '"production"'
79 | })
80 | )
81 | }
82 |
83 | module.exports = mainConfig
84 |
--------------------------------------------------------------------------------
/doc/1588237435-599597952042d_articlex.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eugeneCN/vue-electron-music/896f902ce93ff3537228f8f852b305bad8514195/doc/1588237435-599597952042d_articlex.jpeg
--------------------------------------------------------------------------------
/doc/3872766167-5999ac798b713_articlex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eugeneCN/vue-electron-music/896f902ce93ff3537228f8f852b305bad8514195/doc/3872766167-5999ac798b713_articlex.png
--------------------------------------------------------------------------------
/doc/3913213729-5999ac98a8c6c_articlex.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eugeneCN/vue-electron-music/896f902ce93ff3537228f8f852b305bad8514195/doc/3913213729-5999ac98a8c6c_articlex.jpeg
--------------------------------------------------------------------------------
/src/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | vue-electron-music
6 | <% if (htmlWebpackPlugin.options.nodeModules) { %>
7 |
8 |
11 | <% } %>
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main/index.dev.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This file is used specifically and only for development. It installs
3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to
4 | * modify this file, but it can be used to extend your development
5 | * environment.
6 | */
7 |
8 | /* eslint-disable */
9 |
10 | // Set environment for development
11 | process.env.NODE_ENV = 'development'
12 |
13 | // Install `electron-debug` with `devtron`
14 | require('electron-debug')({ showDevTools: true })
15 |
16 | // Install `vue-devtools`
17 | require('electron').app.on('ready', () => {
18 | let installExtension = require('electron-devtools-installer')
19 | installExtension.default(installExtension.VUEJS_DEVTOOLS)
20 | .then(() => {})
21 | .catch(err => {
22 | console.log('Unable to install `vue-devtools`: \n', err)
23 | })
24 | })
25 |
26 | // Require `main` process to boot app
27 | require('./index')
28 |
--------------------------------------------------------------------------------
/src/main/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | import { app, BrowserWindow } from 'electron'
4 | import { command } from './command'
5 |
6 | /**
7 | * Set `__static` path to static files in production
8 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
9 | */
10 | if (process.env.NODE_ENV !== 'development') {
11 | global.__static = require('path').join(__dirname, '/static')
12 | }
13 |
14 | let mainWindow
15 | const winURL = process.env.NODE_ENV === 'development' ? `http://localhost:9080` : `file://${__dirname}/index.html`
16 |
17 | function createWindow() {
18 | /**
19 | * Initial window options
20 | */
21 | const win = new BrowserWindow({
22 | height: 670,
23 | minHieght: 670,
24 | width: 1000,
25 | minWidth: 1000,
26 | useContentSize: true,
27 | transparent: false,
28 | frame: false,
29 | darkTheme: true,
30 | backgroundColor: '#FFFFFFFF'
31 | })
32 |
33 | win.loadURL(winURL)
34 |
35 | win.on('closed', () => {
36 | mainWindow = null
37 | })
38 |
39 | return win
40 | }
41 |
42 | app.on('ready', () => {
43 | mainWindow = createWindow()
44 | command(mainWindow)
45 | })
46 |
47 | app.on('window-all-closed', () => {
48 | if (process.platform !== 'darwin') {
49 | app.quit()
50 | }
51 | })
52 |
53 | app.on('activate', () => {
54 | if (mainWindow === null) {
55 | createWindow()
56 | }
57 | })
58 |
--------------------------------------------------------------------------------
/src/renderer/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
--------------------------------------------------------------------------------
/src/renderer/api/api.js:
--------------------------------------------------------------------------------
1 | import { config } from './config.js'
2 |
3 | export default {
4 | loginCellphone: config + '/login/cellphone', // 手机登陆
5 | userPlaylist: config + '/user/playlist', // 获取用户歌单
6 | playlistDetail: config + '/playlist/detail', // 获取歌单详情
7 | musicUrl: config + '/music/url', // 获取音乐url
8 | search: config + '/search', // 搜素音乐
9 | lyric: config + '/lyric', // 获取歌词
10 | comment: config + '/comment', // 获取评论
11 | album: config + '/album', // 获取专辑内容
12 | artists: config + '/artists', // 获取歌手单曲列表
13 | artistAlbum: config + '/artist/album', // 获取歌手专辑列表
14 | artistDesc: config + '/artist/desc', // 获取歌手信息
15 | recommendResource: '/recommend/resource', // 获取每日推荐歌单(用户级)
16 | recommendSongs: config + '/recommend/songs', // 获取每日推荐歌曲(用户级)
17 | personalFm: config + '/personal_fm', // 私人FM(用户级)
18 | dailySignin: config + '/daily_signin', // 签到(用户级)
19 | likeMusic: config + '/like', // 添加喜欢的音乐(用户级)
20 | fmTrash: config + '/fm_trash', // 将音乐从私人FM中移除至垃圾桶
21 | topPlaylist: config + '/top/playlist', // 歌单(网友精选歌单)
22 | newAlbum: config + '/top/albums', // 新碟上架
23 | topArtists: config + '/top/artists', // 热门歌手
24 | topList: config + '/top/list', // 音乐排行榜
25 | personalized: config + '/personalized', // 推荐歌单
26 | privatecontent: config + '/personalized/privatecontent', // 独家放送
27 | personalizedMv: config + '/personalized/mv' // 推荐MV
28 | }
29 |
--------------------------------------------------------------------------------
/src/renderer/api/config.js:
--------------------------------------------------------------------------------
1 | export const config = 'http://localhost:3000'
2 |
--------------------------------------------------------------------------------
/src/renderer/assets/scss/common.scss:
--------------------------------------------------------------------------------
1 | /*! minireset.css v0.0.3 | MIT License | github.com/jgthms/minireset.css */
2 | blockquote,
3 | body,
4 | dd,
5 | dl,
6 | dt,
7 | fieldset,
8 | figure,
9 | h1,
10 | h2,
11 | h3,
12 | h4,
13 | h5,
14 | h6,
15 | hr,
16 | html,
17 | iframe,
18 | legend,
19 | li,
20 | ol,
21 | p,
22 | pre,
23 | textarea,
24 | ul {
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 | h1,
30 | h2,
31 | h3,
32 | h4,
33 | h5,
34 | h6 {
35 | font-size: 100%;
36 | font-weight: normal;
37 | }
38 |
39 | ul {
40 | list-style: none;
41 | }
42 |
43 | button,
44 | input,
45 | select,
46 | textarea {
47 | margin: 0;
48 | }
49 |
50 | html {
51 | box-sizing: border-box;
52 | }
53 | *,
54 | *:after,
55 | *:before {
56 | box-sizing: inherit;
57 | outline: inherit;
58 | }
59 |
60 | audio,
61 | embed,
62 | iframe,
63 | img,
64 | object,
65 | video {
66 | height: auto;
67 | max-width: 100%;
68 | }
69 |
70 | iframe {
71 | border: 0;
72 | }
73 |
74 | table {
75 | border-collapse: collapse;
76 | border-spacing: 0;
77 | }
78 |
79 | td,
80 | th {
81 | padding: 0;
82 | text-align: left;
83 | }
84 | body {
85 | color: #333;
86 | font-family: Arial, Helvetica, sans-serif;
87 | }
88 |
89 | body,
90 | html {
91 | overflow: hidden;
92 | font-size: 100%;
93 | height: 100%;
94 | }
95 |
96 | .ellipsis {
97 | overflow: hidden;
98 | text-overflow: ellipsis;
99 | white-space: nowrap;
100 | }
101 |
102 | .wordwrap {
103 | word-wrap: break-word;
104 | word-break: break-all;
105 | }
106 |
--------------------------------------------------------------------------------
/src/renderer/assets/scss/function.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | //-----------------------------------------------------
3 | // function scss
4 | //-----------------------------------------------------
5 | // 导入所有功能类相关文件
6 | //-----------------------------------------------------
7 | @import "core/setting";
8 | @import "core/css3";
9 | @import "core/mixin";
10 | @import "core/grid";
11 |
--------------------------------------------------------------------------------
/src/renderer/assets/scss/var.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/function.scss";
2 | /**/
3 | //-----------------------------------------------------
4 | // var scss 2017年07月04日19:36:15
5 | //-----------------------------------------------------
6 | // ----------------------------------------------------
7 | // Colors
8 | //-----------------------------------------------------
9 | $primary: #20a0ff;
10 | $success: #13ce66;
11 | $warning: #f7ba2a;
12 | $danger: #ff4949;
13 | $info: #50BFFF;
14 | $red: #b72712;
15 | $red-light: #d43c33;
16 | $red-lighter: rgba($red, 0.12);
17 | $white: #fafafa;
18 | $black: #000;
19 | $grey: #636363;
20 | $grey-main: #f5f5f5;
21 | $grey-light: #c5c5c5;
22 | $grey-lighter: #d1d1d1;
23 | /**/
24 | // ----------------------------------------------------
25 | // Font Colors
26 | //-----------------------------------------------------
27 | $font-light: #999999;
28 | $font: #636363;
29 | $font-dark: #5e6a76;
30 | $font-darker: #222222;
31 | $font-gary: #bbbbbb;
32 | $font-red: #d43c33;
33 |
34 | /**/
35 | // ----------------------------------------------------
36 | // Font size
37 | //-----------------------------------------------------
38 | $font-size-big: 18px;
39 | $font-size-large: 16px;
40 | $font-size-head: 13px;
41 | $font-size-base: 12px;
42 | /**/
43 | // ----------------------------------------------------
44 | // bar Width
45 | //-----------------------------------------------------
46 | $nav-width: 200px;
47 | $head-height: 60px;
48 | $play-bar-height: 65px;
49 |
50 | /**/
51 | // ----------------------------------------------------
52 | // 主体混合函数
53 | //-----------------------------------------------------
54 | @mixin min-height($height) {
55 | min-height: $height;
56 | height: auto;
57 | }
58 | @mixin line-height($height) {
59 | height: $height;
60 | line-height: $height;
61 | }
62 | @mixin case($box) {
63 | width: $box;
64 | height: $box;
65 | }
66 | @mixin horizontal-center {
67 | margin-left: auto;
68 | margin-right: auto;
69 | }
70 | @mixin position-all {
71 | position: absolute;
72 | top: 0;
73 | right: 0;
74 | bottom: 0;
75 | left: 0;
76 | }
77 | @mixin transition-set($args) {
78 | -webkit-transition: $args;
79 | transition: $args;
80 | }
81 |
--------------------------------------------------------------------------------
/src/renderer/assets/style/app.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .bar {
3 | position: absolute;
4 | right: 0;
5 | left: 0;
6 | z-index: 100;
7 | height: $head-height;
8 | background-color: #f7f7f8;
9 | -webkit-backface-visibility: hidden;
10 | backface-visibility: hidden;
11 | }
12 | .bar-header {
13 | top: 0;
14 | }
15 | .bar-footer {
16 | bottom: 0;
17 | }
18 | .views {
19 | @include position-all;
20 | overflow: hidden;
21 | -webkit-overflow-scrolling: touch;
22 | }
23 | .bar-footer ~ .views {
24 | bottom: $play-bar-height;
25 | }
26 | .bar-header ~ .views {
27 | top: $head-height;
28 | }
29 | .page {
30 | overflow: hidden;
31 | position: relative;
32 | height: 100%;
33 | }
34 | .scrollBar {
35 | overflow-y: scroll !important;
36 | position: relative;
37 | top: 0;
38 | left: 0;
39 | right: 0;
40 | height: 100%;
41 | z-index: 500;
42 | }
43 | ::-webkit-scrollbar-track {
44 | background-color: rgba(0,0,0,0.05);
45 | }
46 |
47 | ::-webkit-scrollbar {
48 | width: 5px;
49 | }
50 |
51 | ::-webkit-scrollbar-thumb {
52 | border-radius: 1000px;
53 | background-color: rgba(0,0,0,0.2);
54 | }
55 | ::-webkit-scrollbar-thumb:hover {
56 | background-color: rgba(0,0,0,0.3);
57 | }
58 |
59 | .radius-border {
60 | position: relative;
61 | }
62 | @media screen and (-webkit-min-device-pixel-ratio: 2) {
63 | .radius-border:before {
64 | content: '';
65 | pointer-events: none;
66 | box-sizing: border-box;
67 | position: absolute;
68 | width: 200%;
69 | height: 200%;
70 | left: 0;
71 | top: 0;
72 | /* 改变这个值 100% 就是我们平常的border-radius 50% */
73 | border-radius: 100%;
74 | border: 1px solid #999;
75 | transform: scale(0.5);
76 | transform-origin: 0 0;
77 | }
78 | }
79 | * {
80 | background-color: rgba(0,0,0, 0);
81 | }
82 |
83 | .btn {
84 | -webkit-app-region: no-drag;
85 | }
86 | .drag {
87 | -webkit-app-region: no-drag;
88 | }
89 |
--------------------------------------------------------------------------------
/src/renderer/assets/style/instructViews.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .instructViews {
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | padding-left: $nav-width;
7 | width: 100%;
8 | height: 100%;
9 | z-index: 10;
10 | > div {
11 | position: relative;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/renderer/assets/style/table.scss:
--------------------------------------------------------------------------------
1 | .table {
2 | /* Remove spacing between table cells (from Normalize.css) */
3 | border-collapse: collapse;
4 | border-spacing: 0;
5 | empty-cells: show;
6 | border: 1px solid #cbcbcb;
7 | }
8 |
9 | .table caption {
10 | color: #000;
11 | font: italic 85%/1 arial, sans-serif;
12 | padding: 1em 0;
13 | text-align: center;
14 | }
15 |
16 | .table td,
17 | .table th {
18 | border-left: 1px solid #cbcbcb;
19 | /* inner column border */
20 | border-width: 0 0 0 1px;
21 | font-size: inherit;
22 | margin: 0;
23 | overflow: visible;
24 | /*to make ths where the title is really long work*/
25 | padding: 0.5em 1em;
26 | /* cell padding */
27 | }
28 | /* Consider removing this next declaration block, as it causes problems when
29 | there's a rowspan on the first cell. Case added to the tests. issue#432 */
30 | .table td:first-child,
31 | .table th:first-child {
32 | border-left-width: 0;
33 | }
34 |
35 | .table thead {
36 | background-color: #e0e0e0;
37 | color: #000;
38 | text-align: left;
39 | vertical-align: bottom;
40 | }
41 | /*
42 | striping:
43 | even - #fff (white)
44 | odd - #f2f2f2 (light gray)
45 | */
46 | .table td {
47 | background-color: transparent;
48 | }
49 |
50 | .table-odd td {
51 | background-color: #f2f2f2;
52 | }
53 | /* nth-child selector for modern browsers */
54 | .table-striped tr:nth-child(2n-1) td {
55 | background-color: #f2f2f2;
56 | }
57 | /* BORDERED TABLES */
58 | .table-bordered td {
59 | border-bottom: 1px solid #cbcbcb;
60 | }
61 |
62 | .table-bordered tbody > tr:last-child > td {
63 | border-bottom-width: 0;
64 | }
65 | /* HORIZONTAL BORDERED TABLES */
66 | .table-horizontal td,
67 | .table-horizontal th {
68 | border-width: 0 0 1px 0;
69 | border-bottom: 1px solid #cbcbcb;
70 | }
71 |
72 | .table-horizontal tbody > tr:last-child > td {
73 | border-bottom-width: 0;
74 | }
75 |
--------------------------------------------------------------------------------
/src/renderer/components/common/404/404.scss:
--------------------------------------------------------------------------------
1 |
2 | .page-404 {
3 | height: 100%;
4 | text-align: center;
5 | .box {
6 | width: 200px;
7 | height: 200px;
8 | position: absolute;
9 | left: 50%;
10 | top: 50%;
11 | margin-left: -100px;
12 | margin-top: -100px;
13 | }
14 | .background {
15 | background: url('./assets/404.svg') no-repeat;
16 | width: 128px;
17 | height: 128px;
18 | opacity: 0.6;
19 | margin: 10px auto;
20 | }
21 | p {
22 | color: #777;
23 | font-size: 14px;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/renderer/components/common/404/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
给个star吧,有时间更新...
6 |
7 |
8 |
9 |
10 |
13 |
--------------------------------------------------------------------------------
/src/renderer/components/common/banner/index.js:
--------------------------------------------------------------------------------
1 | import loading from './loading'
2 |
3 | export default {
4 | install: function (Vue) {
5 | Vue.component('v-loading', loading)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/renderer/components/common/barButton/barButton.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 |
3 | .header-bar-button {
4 | position: relative;
5 | font-size: 0;
6 | z-index: 200;
7 | padding: 3px 5px;
8 | .btn {
9 | -webkit-app-region: no-drag;
10 | display: inline-block;
11 | position: relative;
12 | padding: 0;
13 | border: none;
14 | box-shadow: 0 0 1px rgba(0,0,0,0.3);
15 | @include case(12px);
16 | border-radius: 50%;
17 | margin: 0 4px;
18 | cursor: pointer;
19 | &.closes {
20 | background-color: #fc625d;
21 | }
22 | &.minimize {
23 | background-color: #fdbc40;
24 | }
25 | &.maximize {
26 | background-color: #34c84a;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/renderer/components/common/barButton/barButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
34 |
37 |
--------------------------------------------------------------------------------
/src/renderer/components/common/dropdown/dropdown.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .dropdownList {
3 |
4 | .user-dropdown {
5 | .arrow {
6 | display: inline-block;
7 | font-size: 0;
8 | margin: 0 7px;
9 | position: absolute;
10 | top: 0;
11 | right: 0;
12 | &:after,
13 | &:before {
14 | display: inline-block;
15 | content: '';
16 | width: 0;
17 | height: 0;
18 | position: absolute;
19 | top: 0;
20 | right: 0;
21 | border-left: 8px solid transparent;
22 | border-right: 8px solid transparent;
23 | }
24 | &:after {
25 | border-bottom: 7px solid #c3c3c3;
26 | margin-top: -7px;
27 | }
28 | &:before {
29 | border-bottom: 7px solid $white;
30 | margin-top: -6px;
31 | z-index: 1;
32 | }
33 | }
34 | position: absolute;
35 | width: 250px;
36 | box-shadow: 0 0 10px rgba(0,0,0,0.3);
37 | background-color: $white;
38 | top: 0;
39 | right: 0;
40 | margin-top: $head-height;
41 | margin-right: 20px;
42 | z-index: 100;
43 | border-radius: 5px;
44 | border: 1px solid #c3c3c3;
45 | li {
46 | .user {
47 | padding: 15px 20px;
48 | img {
49 | display: inline-block;
50 | @include case(40px);
51 | border-radius: 50%;
52 | vertical-align: middle;
53 | border: 1px solid $grey-main;
54 | }
55 | span {
56 | display: inline-block;
57 | @include line-height(40px);
58 | vertical-align: middle;
59 | font-size: 14px;
60 | margin: 0 10px;
61 | color: $font;
62 | }
63 | }
64 |
65 | .item {
66 | padding: 8px 20px;
67 | border-top: 1px solid rgba($grey-lighter,0.5);
68 | a {
69 | display: block;
70 | text-align: center;
71 | text-decoration: none;
72 | font-size: 14px;
73 | color: $font;
74 | }
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/renderer/components/common/dropdown/dropdown.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | -
7 |
8 |
![]()
9 |
{{user.nickname}}
10 |
11 |
12 | -
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
67 |
70 |
--------------------------------------------------------------------------------
/src/renderer/components/common/header/assets/dropdown-a.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/header/assets/dropdown.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/header/assets/i-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/header/assets/i-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/header/assets/icon-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/header/assets/icon-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/header/assets/so.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/loading/index.js:
--------------------------------------------------------------------------------
1 | import loading from './loading'
2 |
3 | export default {
4 | install: function (Vue) {
5 | Vue.component('v-loading', loading)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/renderer/components/common/loading/loading.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
28 |
29 |
34 |
--------------------------------------------------------------------------------
/src/renderer/components/common/pagination/assets/i-left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/pagination/assets/i-right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/pagination/index.js:
--------------------------------------------------------------------------------
1 | import pagination from './pagination'
2 |
3 | export default {
4 | install: function (Vue) {
5 | Vue.component('v-pagination', pagination)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/renderer/components/common/pagination/pagination.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .pager {
3 | text-align: center;
4 | font-size: 14px;
5 | margin: 30px 0;
6 | height: 24px;
7 | }
8 |
9 | .btn-pager {
10 | font-size: 0;
11 | padding: 0;
12 | margin: 0 5px;
13 | width: 26px;
14 | height: 24px;
15 | text-align: center;
16 | background-color: #fafafa;
17 | color: $black;
18 | border: 1px solid $grey-lighter;
19 | border-radius: 4px;
20 | &:after {
21 | content: '';
22 | display: inline-block;
23 | @include case(10px);
24 | }
25 | &.prev:after {
26 | background: url('./assets/i-left.svg') no-repeat;
27 | background-size: 100%;
28 | }
29 | &.next:after {
30 | background: url('./assets/i-right.svg') no-repeat;
31 | background-size: 100%;
32 | }
33 | &:active {
34 | box-shadow: none;
35 | background-color: #f9f9f9;
36 | border-color: $grey-light;
37 | }
38 | }
39 |
40 | .page-index {
41 | margin: 0 4px;
42 | display: inline-block;
43 | @include case(24px);
44 | line-height: 24px;
45 | background-color: #fafafa;
46 | cursor: pointer;
47 | color: $black;
48 | }
49 |
50 | .active {
51 | color: $red;
52 | text-decoration: underline;
53 | }
54 | .btn[disabled] {
55 | border: 1px solid $grey-lighter;
56 | }
57 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/api.js:
--------------------------------------------------------------------------------
1 | import { ajax } from '@/utils/libs'
2 | import { config } from '@/api/config.js'
3 | /**
4 | * 获取歌词
5 | * @param {Object} param 参数
6 | * @param {Function} callback 返回函数
7 | * @param return
8 | */
9 | export default {
10 | loadLyric(param, callback) {
11 | ajax(`${config}/lyric`, param, callback)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/close_1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/close_2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/close_3.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/like.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/like_1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/like_2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playDetail/assets/share_2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playList/assets/1clone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playList/assets/clone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/for.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/pause.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/play.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/prev.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/voice-close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/playerBar/assets/voice-open.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/api.js:
--------------------------------------------------------------------------------
1 | import { ajax } from '@/utils/libs'
2 | import { config } from '@/api/config.js'
3 | /**
4 | * 获取用户歌单
5 | * @param {Object} param 参数
6 | * @param {Function} callback 返回函数
7 | * @param return
8 | */
9 | export default {
10 | userPlay(param, callback) {
11 | ajax(`${config}/user/playlist`, param, callback)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/fm.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/friend.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/iTunes.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/likes.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/list.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/music.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/mv.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/sideBar/assets/shows.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/common/slider/slider.scss:
--------------------------------------------------------------------------------
1 | .mu-slider {
2 | width: 100%;
3 | position: relative;
4 | height: 24px;
5 | display: flex;
6 | align-items: center;
7 | cursor: default;
8 | user-select: none;
9 | outline: none;
10 | }
11 |
12 | .mu-slider-track {
13 | position: absolute;
14 | height: 4px;
15 | left: 0;
16 | right: 0;
17 | top: 50%;
18 | margin-top: -2px;
19 | background-color: #bbbfc4;
20 | border-radius: 1000px;
21 | }
22 |
23 | .mu-slider-fill {
24 | position: absolute;
25 | height: 4px;
26 | width: 100%;
27 | background-color: #d43c33;
28 | left: 0;
29 | top: 50%;
30 | margin-top: -2px;
31 | border-radius: 1000px;
32 | .mu-slider.disabled & {
33 | background-color: #bbbfc4;
34 | }
35 | }
36 |
37 | .mu-slider-thumb {
38 | position: absolute;
39 | top: 50%;
40 | width: 14px;
41 | height: 14px;
42 | background-color: #fff;
43 | color: #d43c33;
44 | border-radius: 50%;
45 | transform: translate(-50%, -50%);
46 | transition: background 450ms cubic-bezier(0.23, 1, 0.32, 1), border-color 450ms cubic-bezier(0.23, 1, 0.32, 1), width 450ms cubic-bezier(0.23, 1, 0.32, 1), height 450ms cubic-bezier(0.23, 1, 0.32, 1);
47 | cursor: pointer;
48 | box-shadow: 0 0 3px rgba(0,0,0,0.5);
49 |
50 | &::after {
51 | content: '';
52 | font-size: 0;
53 | display: block;
54 | padding: 2px;
55 | border-radius: 8px;
56 | background-color: #d43c33;
57 | position: absolute;
58 | top: 50%;
59 | margin-left: 1px;
60 | transform: translate(100%, -50%);
61 | }
62 | }
63 |
64 | .volume {
65 | .mu-slider-track {
66 | background-color: #ddd;
67 | }
68 | .mu-slider-thumb {
69 | width: 10px;
70 | height: 10px;
71 | &::after {
72 | display: none;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/renderer/components/common/toast/index.js:
--------------------------------------------------------------------------------
1 | import toast from './toast'
2 |
3 | export default {
4 | install: function (Vue) {
5 | Vue.component('v-toast', toast)
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/renderer/components/common/toast/toast.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .toast-mask {
3 | position: fixed;
4 | z-index: 1024;
5 | top: 0;
6 | right: 0;
7 | bottom: 0;
8 | left: 0;
9 | font-size: 16px;
10 | background-color: transparent;
11 | pointer-events: none;
12 | }
13 | .toast {
14 | @include line-height(60px);
15 | padding: 0 24px;
16 | background-color: rgba(0,0,0,0.8);
17 | color: #fff;
18 | border-radius: 5px;
19 | width: auto;
20 | position: fixed;
21 | left: 50%;
22 | top: 50%;
23 | bottom: 0;
24 | transform: translate(-50%, -50%);
25 | }
26 |
27 | .toast-enter-active,
28 | .toast-leave-active {
29 | transition: opacity 0.2s;
30 | backface-visibility: hidden;
31 | }
32 |
33 | .toast-enter,
34 | .toast-leave-active {
35 | opacity: 0;
36 | }
37 |
--------------------------------------------------------------------------------
/src/renderer/components/common/toast/toast.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{loading}}{{message}}
6 |
7 |
8 |
9 |
10 |
11 |
48 |
49 |
52 |
--------------------------------------------------------------------------------
/src/renderer/components/common/windowTop/windowTop.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
21 |
--------------------------------------------------------------------------------
/src/renderer/components/instructViews.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
35 |
38 |
--------------------------------------------------------------------------------
/src/renderer/components/views/details/api.js:
--------------------------------------------------------------------------------
1 | import { ajax } from '@/utils/libs'
2 | import { config } from '@/api/config.js'
3 | /**
4 | * 获取歌单详情
5 | * @param {Object} param 参数
6 | * @param {Function} callback 返回函数
7 | * @param return
8 | */
9 | export default {
10 | playDetails(param, callback) {
11 | ajax(`${config}/playlist/detail`, param, callback)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/renderer/components/views/details/details.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
50 |
51 |
60 |
--------------------------------------------------------------------------------
/src/renderer/components/views/download/download.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/renderer/components/views/fm/fm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/renderer/components/views/friend/friend.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/renderer/components/views/home/api.js:
--------------------------------------------------------------------------------
1 | import { ajax } from '@/utils/libs'
2 | import { config } from '@/api/config.js'
3 | /**
4 | * 获取banner
5 | * @param {Object} param 参数
6 | * @param {Function} callback 返回函数
7 | * @param return
8 | */
9 | export default {
10 | banner(param, callback) {
11 | ajax(`${config}/banner`, param, callback)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/renderer/components/views/home/home.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 |
3 | .home {
4 | .nav {
5 | @include line-height(42px);
6 | text-align: center;
7 | font-size: 0;
8 | border-bottom: 1px solid $grey-light;
9 | a {
10 | margin: 0 34px;
11 | display: inline-block;
12 | text-decoration: none;
13 | font-size: 14px;
14 | color: $font;
15 | &.active {
16 | color: $red;
17 | }
18 | }
19 | }
20 | .up {
21 | padding: 100px 0;
22 | text-align: center;
23 | color: $font-light;
24 | font-size: $font-size-base;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/renderer/components/views/home/home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
有空再更新吧, you give me the star ???
13 |
14 |
15 |
16 |
17 |
44 |
45 |
48 |
--------------------------------------------------------------------------------
/src/renderer/components/views/iTunes/iTunes.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .iTunes {
3 | height: 100%;
4 | .headers {
5 | border-bottom: 1px solid $grey-lighter;
6 | height: 52px;
7 | line-height: 1;
8 | padding-top: 24px;
9 | padding-left: 40px;
10 | span {
11 | font-size: 20px;
12 | }
13 | small {
14 | font-size: $font-size-base;
15 | color: $font;
16 | }
17 | }
18 | .content {
19 | position: relative;
20 | text-align: center;
21 | font-weight: 500;
22 | width: 300px;
23 | height: 180px;
24 | position: absolute;
25 | top: 50%;
26 | left: 50%;
27 | margin-left: -150px;
28 | margin-top: -90px;
29 | p {
30 | color: $font-light;
31 | font-size: $font-size-head;
32 | margin-bottom: 5px;
33 | }
34 | a {
35 | cursor: pointer;
36 | display: inline-block;
37 | font-size: $font-size-base;
38 | margin: 10px;
39 | color: #2b77cd;
40 | }
41 | img {
42 | @include case(68px);
43 | margin-bottom: 10px;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/renderer/components/views/iTunes/iTunes.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |

9 |
还没有iTunes音乐,
10 |
升级iTunes音乐为高品质音乐并和朋友分享~
11 |
iTunes音乐不显示?
12 |
13 |
14 |
15 |
16 |
28 |
29 |
32 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/api.js:
--------------------------------------------------------------------------------
1 | import { ajax } from '@/utils/libs'
2 | import { config } from '@/api/config.js'
3 | /**
4 | * 登录
5 | * @param {Object} param 参数
6 | * @param {Function} callback 返回函数
7 | * @param return
8 | */
9 | export default {
10 | login(param, callback) {
11 | ajax(`${config}/login/cellphone`, param, callback)
12 | },
13 | refresh(param, callback) {
14 | ajax(`${config}/login/refresh`, param, callback)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/assets/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eugeneCN/vue-electron-music/896f902ce93ff3537228f8f852b305bad8514195/src/renderer/components/views/login/assets/bg.png
--------------------------------------------------------------------------------
/src/renderer/components/views/login/assets/clone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/assets/mobile.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/assets/password.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/assets/phone.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/assets/yes.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/login.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 |
3 | .form {
4 | background-color: #fafafa;
5 | height: 100%;
6 | header {
7 | height: 34px;
8 | }
9 | .bg {
10 | background: url('./assets/bg.png') no-repeat;
11 | width: 100%;
12 | background-size: 100%;
13 | height: 150px;
14 | }
15 | .form-group {
16 | margin: 0 auto;
17 | padding: 20px;
18 | width: 300px;
19 | border-radius: 5px;
20 | }
21 |
22 | .input-group {
23 | position: relative;
24 | .icon {
25 | display: inline-block;
26 | @include case(19px);
27 | position: absolute;
28 | left: 0;
29 | top: 0;
30 | }
31 | .phone {
32 | background: url('./assets/phone.svg') no-repeat;
33 | background-size: 100%;
34 | margin: 10px 5px;
35 | }
36 | .password {
37 | background: url('./assets/password.svg') no-repeat;
38 | background-size: 100%;
39 | margin: 9px 5px;
40 | }
41 | input {
42 | width: 100%;
43 | font-size: 12px;
44 | border: 1px solid #d9d9d9;
45 | border-radius: 5px 5px 0 0;
46 | height: 38px;
47 | padding-left: 30px;
48 | }
49 | &:nth-child(2) {
50 | input {
51 | margin-top: -1px;
52 | border-radius: 0 0 5px 5px;
53 | }
54 | margin-bottom: 20px;
55 | }
56 | }
57 | .button-group {
58 | button {
59 | font-size: 12px;
60 | background-color: #de3f42;
61 | border: none;
62 | width: 100%;
63 | height: 40px;
64 | color: #fff;
65 | font-size: 15px;
66 | &.on {
67 | opacity: 0.8;
68 | pointer-events: none;
69 | }
70 | }
71 | }
72 |
73 | .tip {
74 | color: #de3f42;
75 | line-height: 40px;
76 | font-size: $font-size-base;
77 | }
78 | }
79 | .closed {
80 | position: absolute;
81 | top: 0;
82 | left: 0;
83 | background: url('./assets/clone.svg') no-repeat;
84 | background-size: 100%;
85 | @include case(12px);
86 | border: 0;
87 | padding: 0;
88 | border-radius: 0;
89 | margin: 15px;
90 | &:active {
91 | background-color: rgba(0,0,0,0);
92 | box-shadow: none;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/renderer/components/views/login/login.vue:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |
81 |
82 |
85 |
--------------------------------------------------------------------------------
/src/renderer/components/views/mv/mv.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/api.js:
--------------------------------------------------------------------------------
1 | import { ajax } from '@/utils/libs'
2 | import { config } from '@/api/config.js'
3 | /**
4 | * 搜索歌曲
5 | * @param {Object} param 参数
6 | * @param {Function} callback 返回函数
7 | * @param return
8 | */
9 | export default {
10 | search(param, callback, error) {
11 | ajax(`${config}/search`, param, callback, error)
12 | },
13 | loadUrl(param, callback, error) {
14 | ajax(`${config}/music/url`, param, callback, error)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/album/album.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .album {
3 | li {
4 | padding: 10px 30px;
5 | a {
6 | display: block;
7 | @include line-height(40px);
8 | text-decoration: none;
9 | font-size: 0;
10 | }
11 | .coverImg {
12 | display: inline-block;
13 | @include case(40px);
14 | background-size: 100%;
15 | }
16 | .picUrl {
17 | @include case(40px);
18 | vertical-align: middle;
19 | border: 1px solid $grey-lighter;
20 | }
21 | .name {
22 | display: inline-block;
23 | font-size: $font-size-head;
24 | color: $black;
25 | vertical-align: middle;
26 | margin: 0 10px;
27 | }
28 | .album {
29 | margin: 0;
30 | font-size: $font-size-base;
31 | color: $grey;
32 | }
33 | &:nth-child(even) {
34 | background-color: #f4f4f4;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/album/album.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
54 |
55 |
58 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/album/assets/default.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/lyric/lyric.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/mv/assets/default.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/mv/mv.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .mv {
3 | padding: 30px;
4 | width: 100%;
5 | .list {
6 | display: flex;
7 | justify-content: space-between;
8 | margin-bottom: 25px;
9 | &:last-child {
10 | margin-bottom: 0;
11 | }
12 | }
13 | .item {
14 | width: 150px;
15 | }
16 | .coverImg {
17 | display: flex;
18 | height: 90px;
19 | background-size: 100%;
20 | background-position: center center;
21 | position: relative;
22 | color: $white;
23 | font-size: $font-size-base;
24 | span {
25 | @include position-all;
26 | padding: 5px;
27 | }
28 | .playCount {
29 | bottom: auto;
30 | text-align: right;
31 | background: -webkit-gradient(linear,right center,center top,from(rgba(0,0,0,1)),to(rgba(0,0,0,0)));
32 | }
33 | .time {
34 | top: auto;
35 | bottom: 0;
36 | text-align: left;
37 | }
38 | }
39 | .desc {
40 | font-size: 14px;
41 | font-weight: normal;
42 | .name {
43 | display: inline-block;
44 | padding: 5px 0;
45 | }
46 | .artist {
47 | font-size: $font-size-base;
48 | color: $grey-light;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/radio/radio.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/singer/assets/default.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/singer/singer.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .singer {
3 | li {
4 | padding: 10px 30px;
5 | a {
6 | display: block;
7 | @include line-height(40px);
8 | text-decoration: none;
9 | font-size: 0;
10 | }
11 | .coverImg {
12 | display: inline-block;
13 | @include case(40px);
14 | background-size: 100%;
15 | }
16 | .picUrl {
17 | @include case(40px);
18 | vertical-align: middle;
19 | border: 1px solid $grey-lighter;
20 | }
21 | .name {
22 | display: inline-block;
23 | font-size: $font-size-head;
24 | color: $black;
25 | vertical-align: middle;
26 | margin: 0 10px;
27 | }
28 | &:nth-child(even) {
29 | background-color: #f4f4f4;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/singer/singer.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
53 |
54 |
57 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/single/assets/collect.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/single/assets/download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/single/assets/right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/song/assets/default.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/song/song.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 | .song {
3 | li {
4 | padding: 10px 30px;
5 | a {
6 | display: block;
7 | @include line-height(40px);
8 | text-decoration: none;
9 | font-size: 0;
10 | }
11 | .coverImg {
12 | display: inline-block;
13 | @include case(40px);
14 | background-size: 100%;
15 | }
16 | .picUrl {
17 | @include case(40px);
18 | vertical-align: middle;
19 | border: 1px solid $grey-lighter;
20 | }
21 | .name {
22 | display: inline-block;
23 | font-size: $font-size-head;
24 | color: $black;
25 | vertical-align: middle;
26 | margin: 0 10px;
27 | }
28 | .album {
29 | display: block;
30 | margin: 0;
31 | font-size: $font-size-base;
32 | color: $grey;
33 | }
34 | &:nth-child(even) {
35 | background-color: #f4f4f4;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/song/song.vue:
--------------------------------------------------------------------------------
1 |
2 |
28 |
29 |
30 |
57 |
58 |
61 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/component/user/user.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/renderer/components/views/search/search.scss:
--------------------------------------------------------------------------------
1 | @import "src/renderer/assets/scss/var.scss";
2 |
3 | .search-main {
4 | background-color: #fafafa;
5 | .keywords {
6 | @include line-height(54px);
7 | font-size: $font-size-base;
8 | padding: 0 30px;
9 | span {
10 | color: #2b77cd;
11 | }
12 | }
13 |
14 | .search-nav {
15 | border-bottom: 2px solid $red;
16 | padding: 0 30px;
17 | font-size: 0;
18 | li {
19 | display: inline-block;
20 | }
21 | a {
22 | display: inline-block;
23 | width: 80px;
24 | text-align: center;
25 | font-size: $font-size-head;
26 | text-decoration: none;
27 | border: 1px solid #c8c8c8;
28 | border-bottom: none;
29 | background-color: #f4f4f4;
30 | margin-right: 5px;
31 | @include line-height(32px);
32 | padding: 0 20px;
33 | color: $black;
34 | &.active {
35 | background-color: $red-light;
36 | border-color: $red;
37 | color: $white;
38 | }
39 | }
40 | }
41 |
42 | .loading {
43 | text-align: center;
44 | padding: 50px;
45 | }
46 |
47 | .not-data {
48 | font-size: $font-size-base;
49 | padding: 100px 0;
50 | text-align: center;
51 | span {
52 | color: #2b77cd;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/renderer/components/windowViews.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
21 |
--------------------------------------------------------------------------------
/src/renderer/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App'
3 | import router from './router'
4 | import store from './store'
5 | import loading from '@/components/common/loading'
6 | import toast from '@/components/common/toast'
7 | import pagination from '@/components/common/pagination'
8 | // loading
9 | Vue.use(loading)
10 | // toast
11 | Vue.use(toast);
12 | // pagination
13 | Vue.use(pagination)
14 |
15 | if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
16 | Vue.config.productionTip = false
17 |
18 | /* eslint-disable no-new */
19 | new Vue({
20 | components: { App },
21 | router,
22 | store,
23 | template: ''
24 | }).$mount('#app')
25 |
--------------------------------------------------------------------------------
/src/renderer/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 | import logger from 'vuex/dist/logger'
4 |
5 | import modules from './modules'
6 |
7 | Vue.use(Vuex)
8 |
9 | const debug = process.env.NODE_ENV !== 'production'
10 |
11 | if (debug) {
12 | console.log(modules)
13 | }
14 |
15 | export default new Vuex.Store({
16 | modules,
17 | strict: debug,
18 | plugins: !debug ? [logger()] : []
19 | })
20 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * The file enables `@/store/index.js` to import all vuex modules
3 | * in a one-shot manner. There should not be any reason to edit this file.
4 | */
5 |
6 | const files = require.context('.', false, /\.js$/)
7 | const modules = {}
8 |
9 | files.keys().forEach(key => {
10 | if (key === './index.js') return
11 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default
12 | })
13 |
14 | export default modules
15 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/routes.js:
--------------------------------------------------------------------------------
1 | import * as types from '../mutation-types'
2 |
3 | const state = {
4 | record: [],
5 | index: 0,
6 | routesBtn: false,
7 | backActive: false,
8 | forwardActive: false
9 | }
10 |
11 | const getters = {
12 | getBackStatus: state => state.backActive,
13 | getForwardStatus: state => state.forwardActive,
14 | getRoutesBtn: state => state.routesBtn
15 | }
16 |
17 | const actions = {
18 | routesBack({ state, commit }, router) {
19 | commit(types.ROUTERS_BACKS, router)
20 | },
21 | routesForward({ state, commit }, router) {
22 | commit(types.ROUTERS_FORWARD, router)
23 | },
24 | routesRecord({ state, commit }, path) {
25 | commit(types.ROUTERS_RECORD, path)
26 | },
27 | routesBtnReset({ state, commit }, param) {
28 | commit(types.ROUTERS_STATUS, param)
29 | }
30 | }
31 |
32 | const callbacks = {
33 | buttonBack(index) {
34 | if (index > 0) {
35 | state.backActive = true
36 | } else {
37 | state.backActive = false
38 | }
39 | },
40 | buttonForward(index) {
41 | if ((index + 1) === state.record.length) {
42 | state.forwardActive = false
43 | } else {
44 | state.forwardActive = true
45 | }
46 | },
47 | buttonHighlight(index) {
48 | state.routesBtn = true
49 | this.buttonBack(index)
50 | this.buttonForward(index)
51 | }
52 | }
53 |
54 | const mutations = {
55 | [types.ROUTERS_RECORD](state, path) {
56 | state.record.push(path.fullPath)
57 | state.index = state.record.length - 1
58 | state.forwardActive = false
59 | callbacks.buttonBack(state.index)
60 | },
61 | [types.ROUTERS_BACKS](state, router) {
62 | if ((state.index - 1) < 0) return
63 | state.index--;
64 | callbacks.buttonHighlight(state.index)
65 | router.replace({ path: state.record[state.index] })
66 | },
67 | [types.ROUTERS_FORWARD](state, router) {
68 | if ((state.index + 1) >= state.record.length) return
69 | state.index++;
70 | callbacks.buttonHighlight(state.index)
71 | router.replace({ path: state.record[state.index] })
72 | },
73 | [types.ROUTERS_STATUS](state, param) {
74 | state.routesBtn = param
75 | }
76 | }
77 | export default {
78 | state,
79 | getters,
80 | actions,
81 | mutations
82 | }
83 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/search.js:
--------------------------------------------------------------------------------
1 | import * as types from '../mutation-types'
2 |
3 | const state = {
4 | data: {}
5 | }
6 |
7 | const getters = {
8 | getSearchStatus: state => state.data
9 | }
10 |
11 | const actions = {
12 | setSearchData({ state, commit }, data) {
13 | commit(types.SEARCH_DATA_SAVE, data)
14 | }
15 | }
16 |
17 | const mutations = {
18 | [types.SEARCH_DATA_SAVE](state, data) {
19 | state.data = data
20 | }
21 | }
22 |
23 | export default {
24 | state,
25 | getters,
26 | actions,
27 | mutations
28 | }
29 |
--------------------------------------------------------------------------------
/src/renderer/store/modules/user.js:
--------------------------------------------------------------------------------
1 | import * as types from '../mutation-types'
2 | import { local } from '@/utils/storage'
3 |
4 | const obj = {}
5 |
6 | const state = {
7 | user: local.getItem('user') || obj,
8 | path: obj,
9 | data: obj
10 | }
11 |
12 | const getters = {
13 | getUserStatus: state => state.data,
14 | getUserPathStatus: state => state.path
15 | }
16 |
17 | const actions = {
18 | userSignin({ commit }, user) {
19 | commit(types.USER_SIGNIN, user)
20 | },
21 | userSignout({ commit }) {
22 | commit(types.USER_SIGNOUT)
23 | },
24 | instructionRoute({ state, commit }, path) {
25 | commit(types.USER_ROUTER_PATH, path)
26 | },
27 | setUserData({ state, commit }, data) {
28 | commit(types.USER_DATA_SAVE, data)
29 | }
30 | }
31 |
32 | const mutations = {
33 | [types.USER_SIGNIN](state, user) {
34 | local.setItem('user', user)
35 | state.user = user
36 | },
37 | [types.USER_SIGNOUT](state) {
38 | local.removeItem('user')
39 | state.user = {}
40 | },
41 | [types.USER_ROUTER_PATH](state, path) {
42 | state.path = path
43 | },
44 | [types.USER_DATA_SAVE](state, data) {
45 | state.data = data
46 | }
47 | }
48 |
49 | export default {
50 | state,
51 | getters,
52 | actions,
53 | mutations
54 | }
55 |
--------------------------------------------------------------------------------
/src/renderer/store/mutation-types.js:
--------------------------------------------------------------------------------
1 | // S toggle.js
2 | export const TOGGLE_LOGIN_DIALOG = 'TOGGLE_LOGIN_DIALOG' // 登录Dialog
3 | export const TOGGLE_DROPDOWN_LIST = 'TOGGLE_DROPDOWN_LIST' // 用户菜单
4 | export const TOGGLE_PLAY_LIST = 'TOGGLE_PLAY_LIST' // 播放列表
5 | export const TOGGLE_PLAY_INFO_BAR = 'TOGGLE_PLAY_INFO_BAR' // 导航下方播放信息
6 | export const TOGGLE_PLAY_DETAIL = 'TOGGLE_PLAY_DETAIL' // 播放音乐详情
7 | // E toggle.js
8 |
9 | // S user.js
10 | export const USER_SIGNIN = 'USER_SIGNIN' // 登录成功
11 | export const USER_SIGNOUT = 'USER_SIGNOUT' // 退出登录
12 | export const USER_ROUTER_PATH = 'USER_ROUTER_PATH' // 用户路由
13 | export const USER_DATA_SAVE = 'USER_DATA_SAVE' // 用户数据
14 | // E user.js
15 |
16 | // S play.js
17 | export const SET_MUSIC_URL = 'SET_MUSIC_URL' // 存入音乐地址
18 | export const SET_MUSIC_LIST = 'SET_MUSIC_LIST' // 添加播放列表
19 | export const SET_MUSIC_DETAILS = 'SET_MUSIC_DETAILS' // 存入音乐详情
20 | export const SET_MUSIC_CHANGE = 'SET_MUSIC_CHANGE' // ...
21 | export const MUSIC_PLAY = 'MUSIC_PLAY' // 设置音乐播放
22 | export const MUSIC_PAUSE = 'MUSIC_PAUSE' // 设置音乐暂停
23 | export const PLAY_PREV = 'PLAY_PREV' // 播放上一曲
24 | export const PLAY_NEXT = 'PLAY_NEXT' // 播放下一曲
25 | export const PLAY_CHANGE_TIME = 'PLAY_CHANGE_TIME' // 改变播放时间
26 | export const UPDATE_CURRENT_TIME = 'UPDATE_CURRENT_TIME' // ..
27 | export const UPDATE_DURATION_TIME = 'UPDATE_DURATION_TIME' // ..
28 | export const UPDATE_BUFFERED_TIME = 'UPDATE_BUFFERED_TIME' // ..
29 | // E play.js
30 |
31 | // S search.js
32 | export const SEARCH_DATA_SAVE = 'SEARCH_DATA_SAVE' // 用户数据
33 | // E search.js
34 |
35 | // S roters.js
36 | export const ROUTERS_BACKS = 'ROUTERS_BACKS' // 路由后退
37 | export const ROUTERS_FORWARD = 'ROUTERS_FORWARD' // 路由前进
38 | export const ROUTERS_RECORD = 'ROUTERS_RECORD' // 路由记录
39 | export const ROUTERS_STATUS = 'ROUTERS_STATUS' // 路由状态
40 | // E roters.js
41 |
--------------------------------------------------------------------------------
/src/renderer/utils/background.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer, remote } from 'electron';
2 | import { renderer } from '@/utils/ipcRenderer'
3 | import { session } from '@/utils/storage'
4 | renderer()
5 | export const app = {
6 | showMenus() {
7 | /**
8 | * 显示原生下拉菜单
9 | * @param return
10 | */
11 | // settingsMenu()
12 | ipcRenderer.send('show-content-menu', session.getItem('CREATEPLAY'))
13 | },
14 | openDialog() {
15 | /**
16 | * 打开登录新窗口
17 | * @param return
18 | */
19 | ipcRenderer.send('open-login-window', `${window.location.origin}/#/login`)
20 | },
21 | closeDialog() {
22 | /**
23 | * 关闭登录新窗口
24 | * @param return
25 | */
26 | ipcRenderer.send('close-login-window')
27 | },
28 | sendUserData(data) {
29 | /**
30 | * 登录成功发送登录信息
31 | * @param {Object} 登录详情
32 | */
33 | ipcRenderer.send('user-data', data)
34 | },
35 | loadUserData(callback) {
36 | /**
37 | * 登录成功接收登录信息
38 | * @param {Function} 接收成功返回
39 | */
40 | remote.ipcMain.on('user-data', (event, data) => {
41 | callback(data)
42 | })
43 | }
44 | }
45 |
46 | export function isDialog(dialog) {
47 | if (dialog) {
48 | app.openDialog()
49 | } else {
50 | app.closeDialog()
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/renderer/utils/ipcRenderer.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from 'electron';
2 | import { session } from '@/utils/storage'
3 | import store from '@/store'
4 |
5 | export function renderer() {
6 | // 开始播放
7 | ipcRenderer.on('play-start', (event) => {
8 | console.log('开始播放吧')
9 | var audio = session.getItem('AUDIO')
10 | store.dispatch('setMusicList', audio)
11 | store.dispatch('loadMusicUrl', audio.id)
12 | })
13 | // 添加到播放列表
14 | ipcRenderer.on('add-play-list', (event) => {
15 | console.log('添加到播放列表')
16 | var audio = session.getItem('AUDIO')
17 | audio['addUrl'] = true
18 | store.dispatch('setMusicList', audio)
19 | })
20 | //
21 | ipcRenderer.on('i-like-star', (event) => {
22 | window.alert('来个star给我动力做下去~ ^_^')
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/src/renderer/utils/libs.js:
--------------------------------------------------------------------------------
1 | import os from 'os'
2 | import request from 'request'
3 | import _ from 'lodash'
4 | const platform = os.platform()
5 | const color = 'color:rgb(66, 185, 131)'
6 | /**
7 | * 获取Dom元素
8 | * @param return
9 | */
10 | export const $ = document.querySelector.bind(document)
11 |
12 | /**
13 | * 获取平台信息
14 | * @param {String} types win32(windows) || darwin(mac)
15 | * @param return
16 | */
17 | export function platforms(types) {
18 | if (types === 'darwin' || types === 'win32') {
19 | return platform === types
20 | }
21 | return undefined
22 | }
23 |
24 | /**
25 | * 判断对象是否为空
26 | * @param {Object} obj 对象
27 | * @param return
28 | */
29 | export function isNullObject(obj) {
30 | for (let i in obj) {
31 | return false
32 | }
33 | return true
34 | }
35 |
36 | /**
37 | * 封装ajax
38 | * @param {String} url 请求地址
39 | * @param {Object} param 请求参数
40 | * @param {Function} callback 请求成功后,服务器返回数据
41 | * @param {Function} err 错误处理
42 | * @param return
43 | */
44 | export function ajax(url, param, callback, err) {
45 | console.log('%c接口: ' + url, color)
46 | console.log('%c参数: ' + JSON.stringify(param), color)
47 | var options = {
48 | method: 'GET',
49 | url: url,
50 | qs: param,
51 | headers: { 'content-type': 'application/x-www-form-urlencoded' }
52 | };
53 | console.log('request参数=> ', [options])
54 | request(options, (error, response, body) => {
55 | if (!error && response.statusCode === 200) {
56 | // 返回json字符串 `{}`,最好做个判断
57 | if (body.startsWith('{') && body.endsWith('}')) {
58 | body = JSON.parse(body)
59 | console.log('成功返回=>', body)
60 | callback(body)
61 | } else {
62 | console.error(body)
63 | }
64 | } else {
65 | console.log('错误返回=>', error)
66 | if (_.isFunction(err)) err()
67 | }
68 | })
69 | }
70 |
--------------------------------------------------------------------------------
/src/renderer/utils/storage.js:
--------------------------------------------------------------------------------
1 | const JSON = window.JSON
2 | const localStorage = window.localStorage
3 | const sessionStorage = window.sessionStorage
4 |
5 | export const local = {
6 | getItem(name) {
7 | let value = localStorage.getItem(name)
8 | if (/^\{.*\}$/.test(value)) value = JSON.parse(value)
9 | return value
10 | },
11 | setItem(name, value) {
12 | if (typeof value === typeof {}) value = JSON.stringify(value)
13 | return localStorage.setItem(name, value)
14 | },
15 | removeItem(name) {
16 | return localStorage.removeItem(name)
17 | }
18 | }
19 |
20 | export const session = {
21 | getItem(name) {
22 | let value = sessionStorage.getItem(name)
23 | if (/^\{.*\}$/.test(value)) value = JSON.parse(value)
24 | return value
25 | },
26 | setItem(name, value) {
27 | if (typeof value === typeof {}) value = JSON.stringify(value)
28 | return sessionStorage.setItem(name, value)
29 | },
30 | removeItem(name) {
31 | return sessionStorage.removeItem(name)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/static/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eugeneCN/vue-electron-music/896f902ce93ff3537228f8f852b305bad8514195/static/.gitkeep
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "mocha": true
4 | },
5 | "globals": {
6 | "assert": true,
7 | "expect": true,
8 | "should": true,
9 | "__static": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/e2e/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // Set BABEL_ENV to use proper env config
4 | process.env.BABEL_ENV = 'test'
5 |
6 | // Enable use of ES6+ on required files
7 | require('babel-register')({
8 | ignore: /node_modules/
9 | })
10 |
11 | // Attach Chai APIs to global scope
12 | const { expect, should, assert } = require('chai')
13 | global.expect = expect
14 | global.should = should
15 | global.assert = assert
16 |
17 | // Require all JS files in `./specs` for Mocha to consume
18 | require('require-dir')('./specs')
19 |
--------------------------------------------------------------------------------
/test/e2e/specs/Launch.spec.js:
--------------------------------------------------------------------------------
1 | import utils from '../utils'
2 |
3 | describe('Launch', function () {
4 | beforeEach(utils.beforeEach)
5 | afterEach(utils.afterEach)
6 |
7 | it('shows the proper application title', function () {
8 | return this.app.client.getTitle()
9 | .then(title => {
10 | expect(title).to.equal('vue-electron-music')
11 | })
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/test/e2e/utils.js:
--------------------------------------------------------------------------------
1 | import electron from 'electron'
2 | import { Application } from 'spectron'
3 |
4 | export default {
5 | afterEach () {
6 | this.timeout(10000)
7 |
8 | if (this.app && this.app.isRunning()) {
9 | return this.app.stop()
10 | }
11 | },
12 | beforeEach () {
13 | this.timeout(10000)
14 | this.app = new Application({
15 | path: electron,
16 | args: ['dist/electron/main.js'],
17 | startTimeout: 10000,
18 | waitTimeout: 10000
19 | })
20 |
21 | return this.app.start()
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/test/unit/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | Vue.config.devtools = false
3 | Vue.config.productionTip = false
4 |
5 | // require all test files (files that ends with .spec.js)
6 | const testsContext = require.context('./specs', true, /\.spec$/)
7 | testsContext.keys().forEach(testsContext)
8 |
9 | // require all src files except main.js for coverage.
10 | // you can also change this to match only the subset of files that
11 | // you want coverage for.
12 | const srcContext = require.context('../../src/renderer', true, /^\.\/(?!main(\.js)?$)/)
13 | srcContext.keys().forEach(srcContext)
14 |
--------------------------------------------------------------------------------
/test/unit/karma.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const path = require('path')
4 | const merge = require('webpack-merge')
5 | const webpack = require('webpack')
6 |
7 | const baseConfig = require('../../.config/webpack.renderer.config')
8 | const projectRoot = path.resolve(__dirname, '../../src/renderer')
9 |
10 | // Set BABEL_ENV to use proper preset config
11 | process.env.BABEL_ENV = 'test'
12 |
13 | let webpackConfig = merge(baseConfig, {
14 | devtool: '#inline-source-map',
15 | plugins: [
16 | new webpack.DefinePlugin({
17 | 'process.env.NODE_ENV': '"testing"'
18 | })
19 | ]
20 | })
21 |
22 | // don't treat dependencies as externals
23 | delete webpackConfig.entry
24 | delete webpackConfig.externals
25 | delete webpackConfig.output.libraryTarget
26 |
27 | // apply vue option to apply isparta-loader on js
28 | webpackConfig.module.rules
29 | .find(rule => rule.use.loader === 'vue-loader').use.options.loaders.js = 'babel-loader'
30 |
31 | module.exports = config => {
32 | config.set({
33 | browsers: ['visibleElectron'],
34 | client: {
35 | useIframe: false
36 | },
37 | coverageReporter: {
38 | dir: './coverage',
39 | reporters: [
40 | { type: 'lcov', subdir: '.' },
41 | { type: 'text-summary' }
42 | ]
43 | },
44 | customLaunchers: {
45 | 'visibleElectron': {
46 | base: 'Electron',
47 | flags: ['--show']
48 | }
49 | },
50 | frameworks: ['mocha', 'chai'],
51 | files: ['./index.js'],
52 | preprocessors: {
53 | './index.js': ['webpack', 'sourcemap']
54 | },
55 | reporters: ['spec', 'coverage'],
56 | singleRun: true,
57 | webpack: webpackConfig,
58 | webpackMiddleware: {
59 | noInfo: true
60 | }
61 | })
62 | }
63 |
--------------------------------------------------------------------------------
/test/unit/specs/LandingPage.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import LandingPage from '@/components/LandingPage'
3 |
4 | describe('LandingPage.vue', () => {
5 | it('should render correct contents', () => {
6 | const vm = new Vue({
7 | el: document.createElement('div'),
8 | render: h => h(LandingPage)
9 | }).$mount()
10 |
11 | expect(vm.$el.querySelector('.title').textContent).to.contain('Welcome to your new project!')
12 | })
13 | })
14 |
--------------------------------------------------------------------------------