mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2024-11-22 12:32:07 +08:00
Merge branch 'master' into electron
This commit is contained in:
commit
ed0dbc842a
11
README.md
11
README.md
|
@ -26,6 +26,8 @@
|
|||
- 🖥️ 支持 PWA,可在 Chrome/Edge 里点击地址栏右边的 ➕ 安装到电脑
|
||||
- 🙉 支持显示歌曲和专辑的 Explicit 标志
|
||||
- 📺 MV 播放
|
||||
- ✔️ 每日自动签到(手机端和电脑端同时签到)
|
||||
- 🌚 Light/Dark Mode 自动切换
|
||||
- 🚫🤝 无任何社交功能
|
||||
- 🛠 更多特性开发中
|
||||
|
||||
|
@ -60,14 +62,9 @@ npm run build
|
|||
|
||||
## ☑️ Todo
|
||||
|
||||
- 中文支持
|
||||
- Dark Mode
|
||||
- 歌词
|
||||
- 私人 FM
|
||||
- 播放记录
|
||||
- 无限播放模式(播放完列表后自动播放相似歌曲)
|
||||
查看 Todo 请访问本项目的 [Projects](https://github.com/qier222/YesPlayMusic/projects/1)
|
||||
|
||||
欢迎提 issue 和 pull request。
|
||||
欢迎提 Issue 和 Pull request。
|
||||
|
||||
## 📜 开源许可
|
||||
|
||||
|
|
28
src/App.vue
28
src/App.vue
|
@ -50,11 +50,36 @@ export default {
|
|||
<style lang="scss">
|
||||
@import url("https://fonts.googleapis.com/css2?family=Barlow:ital,wght@0,500;0,600;0,700;0,800;0,900;1,500;1,600;1,700;1,800;1,900&display=swap");
|
||||
|
||||
:root {
|
||||
--color-body-bg: #ffffff;
|
||||
--color-text: #000;
|
||||
--color-primary: #335eea;
|
||||
--color-primary-bg: #eaeffd;
|
||||
--color-secondary: #7a7a7b;
|
||||
--color-secondary-bg: #f5f5f7;
|
||||
--color-navbar-bg: rgba(255, 255, 255, 0.86);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--color-body-bg: #222222;
|
||||
--color-text: #ffffff;
|
||||
--color-primary: #335eea;
|
||||
--color-primary-bg: #bbcdff;
|
||||
--color-secondary: #7a7a7b;
|
||||
--color-secondary-bg: #323232;
|
||||
--color-navbar-bg: #335eea;
|
||||
--color-navbar-bg: rgba(34, 34, 34, 0.86);
|
||||
}
|
||||
|
||||
#app {
|
||||
font-family: "Barlow", -apple-system, BlinkMacSystemFont, Helvetica Neue,
|
||||
PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC,
|
||||
WenQuanYi Micro Hei, sans-serif;
|
||||
width: 100%;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
body {
|
||||
background-color: var(--color-body-bg);
|
||||
}
|
||||
|
||||
html {
|
||||
|
@ -102,12 +127,13 @@ a {
|
|||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-left: 1px solid rgba(128, 128, 128, 0.18);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
background: rgb(216, 216, 216);
|
||||
background: var(--color-secondary-bg);
|
||||
}
|
||||
|
||||
.slide-up-enter-active,
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
|
||||
/**
|
||||
* 获取专辑内容
|
||||
* 说明 : 调用此接口 , 传入专辑 id, 可获得专辑内容
|
||||
* @param {number} id
|
||||
*/
|
||||
export function getAlbum(id) {
|
||||
return request({
|
||||
url: "/album",
|
||||
|
@ -14,10 +19,18 @@ export function getAlbum(id) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 全部新碟
|
||||
* 说明 : 登录后调用此接口 ,可获取全部新碟
|
||||
* - limit - 返回数量 , 默认为 30
|
||||
* - offset - 偏移数量,用于分页 , 如 :( 页数 -1)*30, 其中 30 为 limit 的值 , 默认为 0
|
||||
* - area - ALL:全部,ZH:华语,EA:欧美,KR:韩国,JP:日本
|
||||
* @param {Object} params
|
||||
* @param {number} params.limit
|
||||
* @param {number=} params.offset
|
||||
* @param {string} params.area
|
||||
*/
|
||||
export function newAlbums(params) {
|
||||
// limit : 返回数量 , 默认为 30
|
||||
// offset : 偏移数量,用于分页 , 如 :( 页数 -1)*30, 其中 30 为 limit 的值 , 默认为 0
|
||||
// area : ALL:全部,ZH:华语,EA:欧美,KR:韩国,JP:日本
|
||||
return request({
|
||||
url: "/album/new",
|
||||
method: "get",
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
|
||||
/**
|
||||
* 获取歌手单曲
|
||||
* 说明 : 调用此接口 , 传入歌手 id, 可获得歌手部分信息和热门歌曲
|
||||
* @param {number} id - 歌手 id, 可由搜索接口获得
|
||||
*/
|
||||
export function getArtist(id) {
|
||||
return request({
|
||||
url: "/artists",
|
||||
|
@ -14,10 +19,18 @@ export function getArtist(id) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取歌手专辑
|
||||
* 说明 : 调用此接口 , 传入歌手 id, 可获得歌手专辑内容
|
||||
* - id: 歌手 id
|
||||
* - limit: 取出数量 , 默认为 50
|
||||
* - offset: 偏移数量 , 用于分页 , 如 :( 页数 -1)*50, 其中 50 为 limit 的值 , 默认为 0
|
||||
* @param {Object} params
|
||||
* @param {number} params.id
|
||||
* @param {number=} params.limit
|
||||
* @param {number=} params.offset
|
||||
*/
|
||||
export function getArtistAlbum(params) {
|
||||
// 必选参数 : id: 歌手 id
|
||||
// 可选参数 : limit: 取出数量 , 默认为 50
|
||||
// offset: 偏移数量 , 用于分页 , 如 :( 页数 -1)*50, 其中 50 为 limit 的值 , 默认 为 0
|
||||
return request({
|
||||
url: "/artist/album",
|
||||
method: "get",
|
||||
|
@ -25,12 +38,17 @@ export function getArtistAlbum(params) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 歌手榜
|
||||
* 说明 : 调用此接口 , 可获取排行榜中的歌手榜
|
||||
* - type : 地区
|
||||
* 1: 华语
|
||||
* 2: 欧美
|
||||
* 3: 韩国
|
||||
* 4: 日本
|
||||
* @param {number=} type
|
||||
*/
|
||||
export function toplistOfArtists(type = null) {
|
||||
// type : 地区
|
||||
// 1: 华语
|
||||
// 2: 欧美
|
||||
// 3: 韩国
|
||||
// 4: 日本
|
||||
return request({
|
||||
url: "/toplist/artist",
|
||||
method: "get",
|
||||
|
@ -39,7 +57,11 @@ export function toplistOfArtists(type = null) {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取歌手 mv
|
||||
* 说明 : 调用此接口 , 传入歌手 id, 可获得歌手 mv 信息 , 具体 mv 播放地址可调 用/mv传入此接口获得的 mvid 来拿到 , 如 : /artist/mv?id=6452,/mv?mvid=5461064
|
||||
* @param {number} id 歌手 id, 可由搜索接口获得
|
||||
*/
|
||||
export function artistMv(id) {
|
||||
return request({
|
||||
url: "/artist/mv",
|
||||
|
|
|
@ -1,25 +1,35 @@
|
|||
import request from "@/utils/request";
|
||||
|
||||
/**
|
||||
* 手机登录
|
||||
* - phone: 手机号码
|
||||
* - password: 密码
|
||||
* - countrycode: 国家码,用于国外手机号登录,例如美国传入:1
|
||||
* - md5_password: md5加密后的密码,传入后 password 将失效
|
||||
* @param {Object} params
|
||||
* @param {string} params.phone
|
||||
* @param {string} params.password
|
||||
* @param {string=} params.countrycode
|
||||
* @param {string=} params.md5_password
|
||||
*/
|
||||
export function loginWithPhone(params) {
|
||||
//必选参数 :
|
||||
// phone: 手机号码
|
||||
// password: 密码
|
||||
// 可选参数 :
|
||||
// countrycode: 国家码,用于国外手机号登录,例如美国传入:1
|
||||
// md5_password: md5加密后的密码,传入后 password 将失效
|
||||
return request({
|
||||
url: "/login/cellphone",
|
||||
method: "post",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱登录
|
||||
* - email: 163 网易邮箱
|
||||
* - password: 密码
|
||||
* - md5_password: md5加密后的密码,传入后 password 将失效
|
||||
* @param {Object} params
|
||||
* @param {string} params.email
|
||||
* @param {string} params.password
|
||||
* @param {string=} params.md5_password
|
||||
*/
|
||||
export function loginWithEmail(params) {
|
||||
// 必选参数 :
|
||||
// email: 163 网易邮箱
|
||||
// password: 密码
|
||||
// 可选参数 :
|
||||
// md5_password: md5加密后的密码,传入后 password 将失效
|
||||
return request({
|
||||
url: "/login",
|
||||
method: "post",
|
||||
|
@ -27,13 +37,22 @@ export function loginWithEmail(params) {
|
|||
});
|
||||
}
|
||||
|
||||
export function loginRefresh() {
|
||||
/**
|
||||
* 刷新登录
|
||||
* 说明 : 调用此接口 , 可刷新登录状态
|
||||
* - 调用例子 : /login/refresh
|
||||
*/
|
||||
export function refreshCookie() {
|
||||
return request({
|
||||
url: "/login/refresh",
|
||||
method: "post",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
* 说明 : 调用此接口 , 可退出登录
|
||||
*/
|
||||
export function logout() {
|
||||
return request({
|
||||
url: "/logout",
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import request from "@/utils/request";
|
||||
|
||||
/**
|
||||
* 获取 mv 数据
|
||||
* 说明 : 调用此接口 , 传入 mvid ( 在搜索音乐的时候传 type=1004 获得 ) , 可获取对应 MV 数据 , 数据包含 mv 名字 , 歌手 , 发布时间 , mv 视频地址等数据 ,
|
||||
* 其中 mv 视频 网易做了防盗链处理 , 可能不能直接播放 , 需要播放的话需要调用 ' mv 地址' 接口
|
||||
* - 调用例子 : /mv/detail?mvid=5436712
|
||||
* @param {number} mvid mv 的 id
|
||||
*/
|
||||
export function mvDetail(mvid) {
|
||||
return request({
|
||||
url: "/mv/detail",
|
||||
|
@ -10,16 +17,29 @@ export function mvDetail(mvid) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* mv 地址
|
||||
* 说明 : 调用此接口 , 传入 mv id,可获取 mv 播放地址
|
||||
* - id: mv id
|
||||
* - r: 分辨率,默认1080,可从 /mv/detail 接口获取分辨率列表
|
||||
* - 调用例子 : /mv/url?id=5436712 /mv/url?id=10896407&r=1080
|
||||
* @param {Object} params
|
||||
* @param {number} params.id
|
||||
* @param {number=} params.r
|
||||
*/
|
||||
|
||||
export function mvUrl(params) {
|
||||
// 必选参数 : id: mv id
|
||||
// 可选参数 : r: 分辨率,默认1080,可从 /mv/detail 接口获取分辨率列表
|
||||
return request({
|
||||
url: "/mv/url",
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 相似 mv
|
||||
* 说明 : 调用此接口 , 传入 mvid 可获取相似 mv
|
||||
* @param {number} mvid
|
||||
*/
|
||||
export function simiMv(mvid) {
|
||||
return request({
|
||||
url: "/simi/mv",
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
|
||||
/**
|
||||
* 搜索
|
||||
* 说明 : 调用此接口 , 传入搜索关键词可以搜索该音乐 / 专辑 / 歌手 / 歌单 / 用户 , 关键词可以多个 , 以空格隔开 ,
|
||||
* 如 " 周杰伦 搁浅 "( 不需要登录 ), 搜索获取的 mp3url 不能直接用 , 可通过 /song/url 接口传入歌曲 id 获取具体的播放链接
|
||||
* - keywords : 关键词
|
||||
* - limit : 返回数量 , 默认为 30
|
||||
* - offset : 偏移数量,用于分页 , 如 : 如 :( 页数 -1)*30, 其中 30 为 limit 的值 , 默认为 0
|
||||
* - type: 搜索类型;默认为 1 即单曲 , 取值意义 : 1: 单曲, 10: 专辑, 100: 歌手, 1000: 歌单, 1002: 用户, 1004: MV, 1006: 歌词, 1009: 电台, 1014: 视频, 1018:综合
|
||||
* - 调用例子 : /search?keywords=海阔天空 /cloudsearch?keywords=海阔天空(更全)
|
||||
* @param {Object} params
|
||||
* @param {string} params.keywords
|
||||
* @param {number=} params.limit
|
||||
* @param {number=} params.offset
|
||||
* @param {number=} params.type
|
||||
*/
|
||||
export function search(params) {
|
||||
return request({
|
||||
url: "/search",
|
||||
|
|
|
@ -1,23 +1,44 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
|
||||
/**
|
||||
* 推荐歌单
|
||||
* 说明 : 调用此接口 , 可获取推荐歌单
|
||||
* - limit: 取出数量 , 默认为 30 (不支持 offset)
|
||||
* - 调用例子 : /personalized?limit=1
|
||||
* @param {Object} params
|
||||
* @param {number=} params.limit
|
||||
*/
|
||||
export function recommendPlaylist(params) {
|
||||
// limit: 取出数量 , 默认为 30
|
||||
return request({
|
||||
url: "/personalized",
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取每日推荐歌单
|
||||
* 说明 : 调用此接口 , 可获得每日推荐歌单 ( 需要登录 )
|
||||
* @param {Object} params
|
||||
* @param {number=} params.limit
|
||||
*/
|
||||
export function dailyRecommendPlaylist(params) {
|
||||
// limit: 取出数量 , 默认为 30
|
||||
return request({
|
||||
url: "/recommend/resource",
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取歌单详情
|
||||
* 说明 : 歌单能看到歌单名字, 但看不到具体歌单内容 , 调用此接口 , 传入歌单 id, 可以获取对应歌单内的所有的音乐(未登录状态只能获取不完整的歌单,登录后是完整的),
|
||||
* 但是返回的trackIds是完整的,tracks 则是不完整的,可拿全部 trackIds 请求一次 song/detail 接口
|
||||
* 获取所有歌曲的详情 (https://github.com/Binaryify/NeteaseCloudMusicApi/issues/452)
|
||||
* - id : 歌单 id
|
||||
* - s : 歌单最近的 s 个收藏者, 默认为8
|
||||
* @param {number} id
|
||||
* @param {boolean=} noCache
|
||||
*/
|
||||
export function getPlaylistDetail(id, noCache = false) {
|
||||
let params = { id };
|
||||
if (noCache) params.timestamp = new Date().getTime();
|
||||
|
@ -30,11 +51,18 @@ export function getPlaylistDetail(id, noCache = false) {
|
|||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取精品歌单
|
||||
* 说明 : 调用此接口 , 可获取精品歌单
|
||||
* - cat: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 "全部", 可从精品歌单标签列表接口获取(/playlist/highquality/tags)
|
||||
* - limit: 取出歌单数量 , 默认为 20
|
||||
* - before: 分页参数,取上一页最后一个歌单的 updateTime 获取下一页数据
|
||||
* @param {Object} params
|
||||
* @param {string} params.cat
|
||||
* @param {number=} params.limit
|
||||
* @param {number} params.before
|
||||
*/
|
||||
export function highQualityPlaylist(params) {
|
||||
// 可选参数: cat: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 "全部", 可从精品歌单标签列表接口获取(/playlist/highquality / tags)
|
||||
// limit: 取出歌单数量 , 默认为 20
|
||||
// before: 分页参数,取上一页最后一个歌单的 updateTime 获取下一页数据
|
||||
return request({
|
||||
url: "/top/playlist/highquality",
|
||||
method: "get",
|
||||
|
@ -42,11 +70,18 @@ export function highQualityPlaylist(params) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 歌单 ( 网友精选碟 )
|
||||
* 说明 : 调用此接口 , 可获取网友精选碟歌单
|
||||
* - order: 可选值为 'new' 和 'hot', 分别对应最新和最热 , 默认为 'hot'
|
||||
* - cat: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 "全部",可从歌单分类接口获取(/playlist/catlist)
|
||||
* - limit: 取出歌单数量 , 默认为 50
|
||||
* @param {Object} params
|
||||
* @param {string} params.order
|
||||
* @param {string} params.cat
|
||||
* @param {number=} params.limit
|
||||
*/
|
||||
export function topPlaylist(params) {
|
||||
// 可选参数 : order: 可选值为 'new' 和 'hot', 分别对应最新和最热 , 默认为 'hot'
|
||||
// cat:cat: tag, 比如 " 华语 "、" 古风 " 、" 欧美 "、" 流行 ", 默认为 "全部",可从歌单分类接口获取(/playlist/catlist)
|
||||
// limit: 取出歌单数量 , 默认为 50
|
||||
// offset: 偏移数量 , 用于分页 , 如 :( 评论页数 -1)*50, 其中 50 为 limit 的值
|
||||
return request({
|
||||
url: "/top/playlist",
|
||||
method: "get",
|
||||
|
@ -54,23 +89,36 @@ export function topPlaylist(params) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 歌单分类
|
||||
* 说明 : 调用此接口,可获取歌单分类,包含 category 信息
|
||||
*/
|
||||
export function playlistCatlist() {
|
||||
return request({
|
||||
url: "/playlist/catlist",
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有榜单
|
||||
* 说明 : 调用此接口,可获取所有榜单 接口地址 : /toplist
|
||||
*/
|
||||
export function toplists() {
|
||||
return request({
|
||||
url: "/toplist",
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收藏/取消收藏歌单
|
||||
* 说明 : 调用此接口, 传入类型和歌单 id 可收藏歌单或者取消收藏歌单
|
||||
* - t : 类型,1:收藏,2:取消收藏
|
||||
* - id : 歌单 id
|
||||
* @param {Object} params
|
||||
* @param {number} params.t
|
||||
* @param {number} params.id
|
||||
*/
|
||||
export function subscribePlaylist(params) {
|
||||
// 必选参数 :
|
||||
// t : 类型,1:收藏,2:取消收藏 id : 歌单 id
|
||||
return request({
|
||||
url: "/playlist/subscribe",
|
||||
method: "get",
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import store from "@/store";
|
||||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
import store from "@/store";
|
||||
|
||||
/**
|
||||
* 获取音乐 url
|
||||
* 说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口, 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url,
|
||||
* !!!未登录状态返回试听片段(返回字段包含被截取的正常歌曲的开始时间和结束时间)
|
||||
* @param {string} id - 音乐的 id,例如 id=405998841,33894312
|
||||
*/
|
||||
export function getMP3(id) {
|
||||
let br =
|
||||
store.state.settings?.musicQuality !== undefined
|
||||
|
@ -16,37 +21,44 @@ export function getMP3(id) {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function getTrackDetail(id) {
|
||||
/**
|
||||
* 获取歌曲详情
|
||||
* 说明 : 调用此接口 , 传入音乐 id(支持多个 id, 用 , 隔开), 可获得歌曲详情(注意:歌曲封面现在需要通过专辑内容接口获取)
|
||||
* @param {string} ids - 音乐 id, 例如 ids=405998841,33894312
|
||||
*/
|
||||
export function getTrackDetail(ids) {
|
||||
return request({
|
||||
url: "/song/detail",
|
||||
method: "get",
|
||||
params: {
|
||||
ids: id,
|
||||
ids,
|
||||
},
|
||||
}).then((data) => {
|
||||
data.songs = mapTrackPlayableStatus(data.songs);
|
||||
return data;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 获取歌词
|
||||
* 说明 : 调用此接口 , 传入音乐 id 可获得对应音乐的歌词 ( 不需要登录 )
|
||||
* @param {number} id - 音乐 id
|
||||
*/
|
||||
|
||||
export function getLyric(id) {
|
||||
return request({
|
||||
url: "/lyric",
|
||||
method: "get",
|
||||
params: {
|
||||
id: id,
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新歌速递
|
||||
* 说明 : 调用此接口 , 可获取新歌速递
|
||||
* @param {number} type - 地区类型 id, 对应以下: 全部:0 华语:7 欧美:96 日本:8 韩国:16
|
||||
*/
|
||||
export function topSong(type) {
|
||||
// type: 地区类型 id,对应以下:
|
||||
// 全部:0
|
||||
// 华语:7
|
||||
// 欧美:96
|
||||
// 日本:8
|
||||
// 韩国:16
|
||||
return request({
|
||||
url: "/top/song",
|
||||
method: "get",
|
||||
|
@ -55,10 +67,16 @@ export function topSong(type) {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 喜欢音乐
|
||||
* 说明 : 调用此接口 , 传入音乐 id, 可喜欢该音乐
|
||||
* - id - 歌曲 id
|
||||
* - like - 默认为 true 即喜欢 , 若传 false, 则取消喜欢
|
||||
* @param {Object} params
|
||||
* @param {number} params.id
|
||||
* @param {boolean=} [params.like]
|
||||
*/
|
||||
export function likeATrack(params) {
|
||||
// 必选参数: id: 歌曲 id
|
||||
// 可选参数 : like: 布尔值 , 默认为 true 即喜欢 , 若传 false, 则取消喜欢
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/like",
|
||||
|
@ -67,9 +85,18 @@ export function likeATrack(params) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 听歌打卡
|
||||
* 说明 : 调用此接口 , 传入音乐 id, 来源 id,歌曲时间 time,更新听歌排行数据
|
||||
* - id - 歌曲 id
|
||||
* - sourceid - 歌单或专辑 id
|
||||
* - time - 歌曲播放时间,单位为秒
|
||||
* @param {Object} params
|
||||
* @param {number} params.id
|
||||
* @param {number} params.sourceid
|
||||
* @param {number=} params.time
|
||||
*/
|
||||
export function scrobble(params) {
|
||||
// 必选参数 : id: 歌曲 id, sourceid: 歌单或专辑 id
|
||||
// 可选参数 : time: 歌曲播放时间,单位为秒
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/scrobble",
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
import request from "@/utils/request";
|
||||
|
||||
export function login(params) {
|
||||
// 必选参数 :
|
||||
// phone: 手机号码
|
||||
// password: 密码
|
||||
// 可选参数 :
|
||||
// countrycode: 国家码,用于国外手机号登陆,例如美国传入:1
|
||||
// md5_password: md5加密后的密码,传入后 password 将失效
|
||||
return request({
|
||||
url: "/login/cellphone",
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户详情
|
||||
* 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户详情
|
||||
* - uid : 用户 id
|
||||
* @param {number} uid
|
||||
*/
|
||||
export function userDetail(uid) {
|
||||
return request({
|
||||
url: "/user/detail",
|
||||
|
@ -24,9 +16,18 @@ export function userDetail(uid) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户歌单
|
||||
* 说明 : 登录后调用此接口 , 传入用户 id, 可以获取用户歌单
|
||||
* - uid : 用户 id
|
||||
* - limit : 返回数量 , 默认为 30
|
||||
* - offset : 偏移数量,用于分页 , 如 :( 页数 -1)*30, 其中 30 为 limit 的值 , 默认为 0
|
||||
* @param {Object} params
|
||||
* @param {number} params.uid
|
||||
* @param {number} params.limit
|
||||
* @param {number=} params.offset
|
||||
*/
|
||||
export function userPlaylist(params) {
|
||||
// limit : 返回数量 , 默认为 30
|
||||
// offset : 偏移数量,用于分页 , 如 :( 页数 -1)*30, 其中 30 为 limit 的值 , 默认为 0
|
||||
return request({
|
||||
url: "/user/playlist",
|
||||
method: "get",
|
||||
|
@ -34,6 +35,12 @@ export function userPlaylist(params) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 喜欢音乐列表
|
||||
* 说明 : 调用此接口 , 传入用户 id, 可获取已喜欢音乐id列表(id数组)
|
||||
* - uid: 用户 id
|
||||
* @param {number} uid
|
||||
*/
|
||||
export function userLikedSongsIDs(uid) {
|
||||
return request({
|
||||
url: "/likelist",
|
||||
|
@ -44,3 +51,14 @@ export function userLikedSongsIDs(uid) {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function dailySignin(type = 0) {
|
||||
//可选参数 : type: 签到类型 , 默认 0, 其中 0 为安卓端签到 ,1 为 web/PC 签到
|
||||
return request({
|
||||
url: "/daily_signin",
|
||||
method: "post",
|
||||
params: {
|
||||
type,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* rail style */
|
||||
.vue-slider-rail {
|
||||
background-color: #eee;
|
||||
background-color: rgba(128, 128, 128, 0.18);
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,8 @@
|
|||
|
||||
/* volume style */
|
||||
.volume-control .vue-slider-process {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
opacity: 0.8;
|
||||
background-color: var(--color-text);
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ button {
|
|||
border-radius: 25%;
|
||||
transition: 0.2s;
|
||||
.svg-icon {
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
color: var(--color-text);
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ button {
|
|||
margin-left: 0;
|
||||
}
|
||||
&:hover {
|
||||
background: #f5f5f7;
|
||||
background: var(--color-secondary-bg);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.92);
|
||||
|
|
|
@ -54,8 +54,8 @@ button {
|
|||
justify-content: center;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
background-color: rgba(51, 94, 234, 0.1);
|
||||
color: #335eea;
|
||||
background-color: var(--color-primary-bg);
|
||||
color: var(--color-primary);
|
||||
margin-right: 12px;
|
||||
transition: 0.2s;
|
||||
.svg-icon {
|
||||
|
@ -70,8 +70,8 @@ button {
|
|||
}
|
||||
}
|
||||
button.grey {
|
||||
background-color: #f5f5f7;
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
background-color: var(--color-secondary-bg);
|
||||
color: var(--color-secondary);
|
||||
}
|
||||
button.transparent {
|
||||
background-color: transparent;
|
||||
|
|
|
@ -163,6 +163,7 @@ export default {
|
|||
filter: blur(16px) opacity(0.6);
|
||||
z-index: -1;
|
||||
height: 208px;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
.play-button {
|
||||
opacity: 0;
|
||||
|
|
|
@ -129,13 +129,13 @@ export default {
|
|||
|
||||
.item {
|
||||
margin: 12px 12px 24px 12px;
|
||||
color: var(--color-text);
|
||||
.text {
|
||||
width: 208px;
|
||||
margin-top: 8px;
|
||||
.name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
line-height: 20px;
|
||||
|
||||
display: -webkit-box;
|
||||
|
@ -145,7 +145,7 @@ export default {
|
|||
}
|
||||
.info {
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
line-height: 18px;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
|
@ -170,7 +170,8 @@ export default {
|
|||
}
|
||||
|
||||
.explicit-symbol {
|
||||
color: rgba(0, 0, 0, 0.28);
|
||||
opacity: 0.28;
|
||||
color: var(--color-text);
|
||||
float: right;
|
||||
.svg-icon {
|
||||
margin-bottom: -3px;
|
||||
|
@ -178,7 +179,8 @@ export default {
|
|||
}
|
||||
|
||||
.lock-icon {
|
||||
color: rgba(0, 0, 0, 0.28);
|
||||
opacity: 0.28;
|
||||
color: var(--color-text);
|
||||
margin-right: 4px;
|
||||
// float: right;
|
||||
.svg-icon {
|
||||
|
@ -189,7 +191,8 @@ export default {
|
|||
|
||||
.play-count {
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.58);
|
||||
opacity: 0.58;
|
||||
color: var(--color-text);
|
||||
font-size: 12px;
|
||||
.svg-icon {
|
||||
margin-right: 3px;
|
||||
|
|
|
@ -76,11 +76,12 @@ export default {
|
|||
.mv {
|
||||
margin: 12px 12px 24px 12px;
|
||||
width: 204px;
|
||||
color: var(--color-text);
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
|
@ -88,7 +89,7 @@ export default {
|
|||
}
|
||||
.artist {
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
>
|
||||
</div>
|
||||
<div class="right-part">
|
||||
<a href="https://github.com/qier222/YesPlayMusic" target="blank"
|
||||
<a
|
||||
href="https://github.com/qier222/YesPlayMusic"
|
||||
target="blank"
|
||||
v-if="settings.showGithubIcon !== false"
|
||||
><svg-icon icon-class="github" class="github"
|
||||
/></a>
|
||||
<div class="search-box">
|
||||
|
@ -47,6 +50,7 @@
|
|||
|
||||
<script>
|
||||
import ButtonIcon from "@/components/ButtonIcon.vue";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
export default {
|
||||
name: "Navbar",
|
||||
|
@ -60,6 +64,9 @@ export default {
|
|||
langs: ["zh-CN", "en"],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["settings"]),
|
||||
},
|
||||
methods: {
|
||||
go(where) {
|
||||
if (where === "back") this.$router.go(-1);
|
||||
|
@ -96,7 +103,10 @@ nav {
|
|||
left: 10vw;
|
||||
}
|
||||
backdrop-filter: saturate(180%) blur(30px);
|
||||
background-color: rgba(255, 255, 255, 0.86);
|
||||
|
||||
// background: var(--color-body-bg);
|
||||
// background-color: rgba(255, 255, 255, 0.86);
|
||||
background-color: var(--color-navbar-bg);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
@ -120,15 +130,15 @@ nav {
|
|||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
padding: 6px 10px;
|
||||
color: black;
|
||||
color: var(--color-text);
|
||||
transition: 0.2s;
|
||||
margin: {
|
||||
right: 12px;
|
||||
left: 12px;
|
||||
}
|
||||
&:hover {
|
||||
background: #eaeffd;
|
||||
color: #335eea;
|
||||
background: var(--color-primary-bg);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.92);
|
||||
|
@ -136,7 +146,7 @@ nav {
|
|||
}
|
||||
}
|
||||
a.active {
|
||||
color: #335eea;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +166,7 @@ nav {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
height: 32px;
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
background: var(--color-secondary-bg);
|
||||
border-radius: 8px;
|
||||
width: 200px;
|
||||
}
|
||||
|
@ -164,7 +174,8 @@ nav {
|
|||
.svg-icon {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
color: #aaaaaa;
|
||||
color: var(--color-text);
|
||||
opacity: 0.28;
|
||||
margin: {
|
||||
left: 8px;
|
||||
right: 4px;
|
||||
|
@ -178,13 +189,15 @@ nav {
|
|||
width: 96%;
|
||||
font-weight: 600;
|
||||
margin-top: -1px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.active {
|
||||
background: #eaeffd;
|
||||
background: var(--color-primary-bg);
|
||||
input,
|
||||
.svg-icon {
|
||||
color: #335eea;
|
||||
opacity: 1;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -198,6 +211,7 @@ nav {
|
|||
margin-right: 16px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -36,7 +36,8 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="like-button" v-show="isLoggedIn">
|
||||
<!-- 账号登录才会显示 like 图标 -->
|
||||
<div class="like-button" v-show="accountLogin">
|
||||
<button-icon
|
||||
@click.native="likeCurrentSong"
|
||||
:title="$t('player.like')"
|
||||
|
@ -118,7 +119,7 @@
|
|||
<script>
|
||||
import { updateMediaSessionMetaData } from "@/utils/mediaSession";
|
||||
import { mapState, mapMutations, mapActions } from "vuex";
|
||||
import { isLoggedIn } from "@/utils/auth";
|
||||
import { isAccountLoggedIn } from "@/utils/auth";
|
||||
import { userLikedSongsIDs } from "@/api/user";
|
||||
import { likeATrack } from "@/api/track";
|
||||
import "@/assets/css/slider.css";
|
||||
|
@ -144,14 +145,14 @@ export default {
|
|||
setInterval(() => {
|
||||
this.progress = ~~this.howler.seek();
|
||||
}, 1000);
|
||||
if (this.isLoggedIn) {
|
||||
if (isAccountLoggedIn()) {
|
||||
userLikedSongsIDs(this.settings.user.userId).then((data) => {
|
||||
this.updateLikedSongs(data.ids);
|
||||
});
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player", "howler", "settings", "liked"]),
|
||||
...mapState(["player", "howler", "settings", "liked", "accountLogin"]),
|
||||
currentTrack() {
|
||||
return this.player.currentTrack;
|
||||
},
|
||||
|
@ -174,9 +175,6 @@ export default {
|
|||
let max = ~~(this.currentTrack.dt / 1000);
|
||||
return max > 1 ? max - 1 : max;
|
||||
},
|
||||
isLoggedIn() {
|
||||
return isLoggedIn();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations([
|
||||
|
@ -296,7 +294,8 @@ export default {
|
|||
justify-content: space-around;
|
||||
height: 64px;
|
||||
backdrop-filter: saturate(180%) blur(30px);
|
||||
background-color: rgba(255, 255, 255, 0.86);
|
||||
// background-color: rgba(255, 255, 255, 0.86);
|
||||
background-color: var(--color-navbar-bg);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
@ -336,7 +335,8 @@ export default {
|
|||
.name {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 4px;
|
||||
cursor: pointer;
|
||||
display: -webkit-box;
|
||||
|
@ -350,7 +350,8 @@ export default {
|
|||
}
|
||||
.artist {
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.58);
|
||||
opacity: 0.58;
|
||||
color: var(--color-text);
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
@ -396,7 +397,7 @@ export default {
|
|||
}
|
||||
}
|
||||
.active .svg-icon {
|
||||
color: #335eea;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.volume-control {
|
||||
margin-left: 4px;
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<div></div>
|
||||
</div>
|
||||
<div class="actions" v-if="!isTracklist">
|
||||
<button v-if="isLoggedIn" @click="likeThisSong">
|
||||
<button v-if="accountLogin" @click="likeThisSong">
|
||||
<svg-icon
|
||||
icon-class="heart"
|
||||
:style="{
|
||||
|
@ -78,7 +78,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { isLoggedIn } from "@/utils/auth";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
import ArtistsInLine from "@/components/ArtistsInLine.vue";
|
||||
import ExplicitSymbol from "@/components/ExplicitSymbol.vue";
|
||||
|
@ -93,6 +93,7 @@ export default {
|
|||
return { focus: false, trackStyle: {} };
|
||||
},
|
||||
computed: {
|
||||
...mapState(["accountLogin"]),
|
||||
imgUrl() {
|
||||
if (this.track.al !== undefined) return this.track.al.picUrl;
|
||||
if (this.track.album !== undefined) return this.track.album.picUrl;
|
||||
|
@ -127,9 +128,6 @@ export default {
|
|||
if (this.isPlaying) trackClass.push("playing");
|
||||
return trackClass;
|
||||
},
|
||||
isLoggedIn() {
|
||||
return isLoggedIn();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
goToAlbum() {
|
||||
|
@ -161,7 +159,7 @@ button {
|
|||
.svg-icon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
color: #335eea;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.92);
|
||||
|
@ -182,12 +180,16 @@ button {
|
|||
border-radius: 8px;
|
||||
margin: 0 20px 0 10px;
|
||||
width: 12px;
|
||||
color: rgba(0, 0, 0, 0.58);
|
||||
color: var(--color-text);
|
||||
cursor: default;
|
||||
span {
|
||||
opacity: 0.58;
|
||||
}
|
||||
}
|
||||
|
||||
.explicit-symbol {
|
||||
color: rgba(0, 0, 0, 0.28);
|
||||
opacity: 0.28;
|
||||
color: var(--color-text);
|
||||
.svg-icon {
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
@ -223,7 +225,7 @@ button {
|
|||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
color: var(--color-text);
|
||||
cursor: default;
|
||||
padding-right: 16px;
|
||||
display: -webkit-box;
|
||||
|
@ -235,13 +237,14 @@ button {
|
|||
margin-right: 2px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.72);
|
||||
opacity: 0.72;
|
||||
}
|
||||
}
|
||||
.artist {
|
||||
margin-top: 2px;
|
||||
font-size: 13px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
color: var(--color-text);
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
|
@ -249,7 +252,7 @@ button {
|
|||
a {
|
||||
span {
|
||||
margin-right: 3px;
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
opacity: 0.8;
|
||||
}
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
|
@ -262,7 +265,8 @@ button {
|
|||
flex: 1;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
color: var(--color-text);
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
|
@ -276,10 +280,12 @@ button {
|
|||
justify-content: flex-end;
|
||||
margin-right: 10px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
opacity: 0.88;
|
||||
color: var(--color-text);
|
||||
}
|
||||
&:hover {
|
||||
transition: all 0.3s;
|
||||
background: #f5f5f7;
|
||||
background: var(--color-secondary-bg);
|
||||
}
|
||||
}
|
||||
.track.disable {
|
||||
|
@ -292,7 +298,7 @@ button {
|
|||
.time,
|
||||
.no,
|
||||
.featured {
|
||||
color: rgba(0, 0, 0, 0.28) !important;
|
||||
opacity: 0.28 !important;
|
||||
}
|
||||
&:hover {
|
||||
background: none;
|
||||
|
@ -327,24 +333,22 @@ button {
|
|||
}
|
||||
|
||||
.track.playing {
|
||||
background: #eaeffd;
|
||||
color: #335eea;
|
||||
background: var(--color-primary-bg);
|
||||
color: var(--color-primary);
|
||||
.title,
|
||||
.album {
|
||||
color: #335eea;
|
||||
.album,
|
||||
.time {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
.title .featured,
|
||||
.artist {
|
||||
color: #335eea;
|
||||
.artist,
|
||||
.explicit-symbol {
|
||||
color: var(--color-primary);
|
||||
opacity: 0.88;
|
||||
}
|
||||
.no span {
|
||||
color: #335eea;
|
||||
color: var(--color-primary);
|
||||
opacity: 0.78;
|
||||
}
|
||||
.explicit-symbol {
|
||||
color: #335eea;
|
||||
opacity: 0.88;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -108,5 +108,11 @@ export default {
|
|||
high: "High",
|
||||
lossless: "Lossless",
|
||||
},
|
||||
appearance: {
|
||||
text: "Appearance",
|
||||
auto: "Auto",
|
||||
light: "Light",
|
||||
dark: "Dark",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -6,9 +6,6 @@ export default {
|
|||
library: "资料库",
|
||||
search: "搜索",
|
||||
},
|
||||
footer: {
|
||||
settings: "设置",
|
||||
},
|
||||
home: {
|
||||
recommendPlaylist: "推荐歌单",
|
||||
recommendArtist: "推荐歌手",
|
||||
|
@ -34,7 +31,7 @@ export default {
|
|||
albums: "专辑",
|
||||
withAlbums: "张专辑",
|
||||
artist: "歌手",
|
||||
videos: "个视频",
|
||||
videos: "个MV",
|
||||
},
|
||||
album: {
|
||||
released: "发行于",
|
||||
|
@ -103,7 +100,7 @@ export default {
|
|||
songs: "首歌",
|
||||
},
|
||||
settings: {
|
||||
settings: "选项",
|
||||
settings: "设置",
|
||||
logout: "登出",
|
||||
language: "语言",
|
||||
musicQuality: {
|
||||
|
@ -113,5 +110,11 @@ export default {
|
|||
high: "极高",
|
||||
lossless: "无损",
|
||||
},
|
||||
appearance: {
|
||||
text: "外观",
|
||||
auto: "自动",
|
||||
light: "浅色",
|
||||
dark: "深色",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ import "@/assets/icons";
|
|||
import "@/utils/filters";
|
||||
import { initMediaSession } from "@/utils/mediaSession";
|
||||
import "./registerServiceWorker";
|
||||
import { dailyTask } from "@/utils/common";
|
||||
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { Vue as VueIntegration } from "@sentry/integrations";
|
||||
|
@ -23,7 +24,6 @@ Vue.config.productionTip = false;
|
|||
initMediaSession();
|
||||
|
||||
if (process.env.VUE_APP_ENABLE_SENTRY === "true") {
|
||||
console.log("VUE_APP_ENABLE_SENTRY");
|
||||
Sentry.init({
|
||||
dsn:
|
||||
"https://30aaa25152974f48971912a394ab6bc3@o436528.ingest.sentry.io/5477409",
|
||||
|
@ -41,6 +41,8 @@ if (process.env.VUE_APP_ENABLE_SENTRY === "true") {
|
|||
});
|
||||
}
|
||||
|
||||
dailyTask();
|
||||
|
||||
new Vue({
|
||||
i18n,
|
||||
store,
|
||||
|
|
|
@ -3,7 +3,7 @@ import VueRouter from "vue-router";
|
|||
import store from "@/store";
|
||||
import NProgress from "nprogress";
|
||||
import "@/assets/css/nprogress.css";
|
||||
import Cookies from "js-cookie";
|
||||
import { isLooseLoggedIn } from "@/utils/auth";
|
||||
|
||||
NProgress.configure({ showSpinner: false, trickleSpeed: 100 });
|
||||
|
||||
|
@ -12,7 +12,7 @@ const routes = [
|
|||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: () => import("@/views/home"),
|
||||
component: () => import("@/views/home.vue"),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
|
@ -20,32 +20,32 @@ const routes = [
|
|||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
component: () => import("@/views/login"),
|
||||
component: () => import("@/views/login.vue"),
|
||||
},
|
||||
{
|
||||
path: "/login/username",
|
||||
name: "loginUsername",
|
||||
component: () => import("@/views/loginUsername"),
|
||||
component: () => import("@/views/loginUsername.vue"),
|
||||
},
|
||||
{
|
||||
path: "/login/account",
|
||||
name: "loginAccount",
|
||||
component: () => import("@/views/loginAccount"),
|
||||
component: () => import("@/views/loginAccount.vue"),
|
||||
},
|
||||
{
|
||||
path: "/playlist/:id",
|
||||
name: "playlist",
|
||||
component: () => import("@/views/playlist"),
|
||||
component: () => import("@/views/playlist.vue"),
|
||||
},
|
||||
{
|
||||
path: "/album/:id",
|
||||
name: "album",
|
||||
component: () => import("@/views/album"),
|
||||
component: () => import("@/views/album.vue"),
|
||||
},
|
||||
{
|
||||
path: "/artist/:id",
|
||||
name: "artist",
|
||||
component: () => import("@/views/artist"),
|
||||
component: () => import("@/views/artist.vue"),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
|
@ -53,12 +53,12 @@ const routes = [
|
|||
{
|
||||
path: "/mv/:id",
|
||||
name: "mv",
|
||||
component: () => import("@/views/mv"),
|
||||
component: () => import("@/views/mv.vue"),
|
||||
},
|
||||
{
|
||||
path: "/next",
|
||||
name: "next",
|
||||
component: () => import("@/views/next"),
|
||||
component: () => import("@/views/next.vue"),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
|
@ -66,17 +66,17 @@ const routes = [
|
|||
{
|
||||
path: "/search",
|
||||
name: "search",
|
||||
component: () => import("@/views/search"),
|
||||
component: () => import("@/views/search.vue"),
|
||||
},
|
||||
{
|
||||
path: "/new-album",
|
||||
name: "newAlbum",
|
||||
component: () => import("@/views/newAlbum"),
|
||||
component: () => import("@/views/newAlbum.vue"),
|
||||
},
|
||||
{
|
||||
path: "/explore",
|
||||
name: "explore",
|
||||
component: () => import("@/views/explore"),
|
||||
component: () => import("@/views/explore.vue"),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
|
@ -84,7 +84,7 @@ const routes = [
|
|||
{
|
||||
path: "/library",
|
||||
name: "library",
|
||||
component: () => import("@/views/library"),
|
||||
component: () => import("@/views/library.vue"),
|
||||
meta: {
|
||||
requireLogin: true,
|
||||
keepAlive: true,
|
||||
|
@ -93,7 +93,7 @@ const routes = [
|
|||
{
|
||||
path: "/library/liked-songs",
|
||||
name: "likedSongs",
|
||||
component: () => import("@/views/playlist"),
|
||||
component: () => import("@/views/playlist.vue"),
|
||||
meta: {
|
||||
requireLogin: true,
|
||||
},
|
||||
|
@ -101,7 +101,7 @@ const routes = [
|
|||
{
|
||||
path: "/settings",
|
||||
name: "settings",
|
||||
component: () => import("@/views/settings"),
|
||||
component: () => import("@/views/settings.vue"),
|
||||
},
|
||||
];
|
||||
const router = new VueRouter({
|
||||
|
@ -116,17 +116,15 @@ const router = new VueRouter({
|
|||
});
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
// 需要登录的逻辑
|
||||
if (to.meta.requireLogin) {
|
||||
if (store.state.settings.user.nickname === undefined) {
|
||||
next({ path: "/login" });
|
||||
}
|
||||
if (
|
||||
Cookies.get("MUSIC_U") === undefined &&
|
||||
Cookies.get("loginMode") === "account"
|
||||
) {
|
||||
next({ path: "/login" });
|
||||
} else {
|
||||
if (isLooseLoggedIn()) {
|
||||
next();
|
||||
} else {
|
||||
next({ path: "/login" });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { updateMediaSessionMetaData } from "@/utils/mediaSession";
|
||||
import { getTrackDetail, scrobble, getMP3 } from "@/api/track";
|
||||
import { isLoggedIn } from "@/utils/auth";
|
||||
import { isAccountLoggedIn } from "@/utils/auth";
|
||||
import { updateHttps } from "@/utils/common";
|
||||
|
||||
export default {
|
||||
|
@ -41,8 +41,7 @@ export default {
|
|||
dispatch("nextTrack");
|
||||
});
|
||||
}
|
||||
|
||||
if (isLoggedIn) {
|
||||
if (isAccountLoggedIn()) {
|
||||
getMP3(track.id).then((data) => {
|
||||
// 未知情况下会没有返回数据导致报错,增加防范逻辑
|
||||
if (data.data[0]) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import mutations from "./mutations";
|
|||
import actions from "./actions";
|
||||
import initState from "./initState";
|
||||
import { Howl, Howler } from "howler";
|
||||
import { changeAppearance } from "@/utils/common";
|
||||
|
||||
if (localStorage.getItem("appVersion") === null) {
|
||||
localStorage.setItem("player", JSON.stringify(initState.player));
|
||||
|
@ -45,4 +46,13 @@ if ([undefined, null].includes(store.state.settings.lang)) {
|
|||
localStorage.setItem("settings", JSON.stringify(store.state.settings));
|
||||
}
|
||||
|
||||
changeAppearance(store.state.settings.appearance);
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", () => {
|
||||
if (store.state.settings.appearance === "auto") {
|
||||
changeAppearance(store.state.settings.appearance);
|
||||
}
|
||||
});
|
||||
|
||||
export default store;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
const initState = {
|
||||
howler: null,
|
||||
accountLogin: false,
|
||||
usernameLogin: false,
|
||||
liked: {
|
||||
songs: [],
|
||||
},
|
||||
|
@ -85,7 +87,11 @@ const initState = {
|
|||
id: 0,
|
||||
},
|
||||
lang: null,
|
||||
appearance: "auto",
|
||||
musicQuality: 320000,
|
||||
showGithubIcon: true,
|
||||
showPlaylistsByAppleMusic: true,
|
||||
lastRefreshCookieDate: 0,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -81,6 +81,16 @@ export default {
|
|||
return track;
|
||||
});
|
||||
},
|
||||
updateAccountLogin(state, status) {
|
||||
state.accountLogin = status;
|
||||
},
|
||||
updateUsernameLogin(state, status) {
|
||||
state.usernameLogin = status;
|
||||
},
|
||||
updateLogout() {
|
||||
this.commit("updateAccountLogin", false);
|
||||
this.commit("updateUsernameLogin", false);
|
||||
},
|
||||
updateUser(state, user) {
|
||||
state.settings.user = user;
|
||||
},
|
||||
|
@ -106,4 +116,7 @@ export default {
|
|||
changeMusicQuality(state, value) {
|
||||
state.settings.musicQuality = value;
|
||||
},
|
||||
updateSettings(state, { key, value }) {
|
||||
state.settings[key] = value;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
export default {
|
||||
howler: null,
|
||||
accountLogin: false,
|
||||
usernameLogin: false,
|
||||
liked: {
|
||||
songs: [],
|
||||
},
|
||||
|
|
|
@ -4,10 +4,38 @@ import store from "@/store";
|
|||
|
||||
export function doLogout() {
|
||||
logout();
|
||||
// 移除前端本地用来认证登录的字段
|
||||
Cookies.remove("loginMode");
|
||||
// 网易云的接口会自动移除该 cookies
|
||||
// Cookies.remove("MUSIC_U");
|
||||
// 更新状态仓库中的用户信息
|
||||
store.commit("updateUser", { id: 0 });
|
||||
// 更新状态仓库中的登录状态
|
||||
store.commit("updateLogout");
|
||||
}
|
||||
|
||||
// MUSIC_U 只有在账户登录的情况下才有
|
||||
export function isLoggedIn() {
|
||||
return Cookies.get("MUSIC_U") !== undefined ? true : false;
|
||||
}
|
||||
|
||||
// 账号登录
|
||||
export function isAccountLoggedIn() {
|
||||
return (
|
||||
Cookies.get("MUSIC_U") !== undefined &&
|
||||
Cookies.get("loginMode") === "account"
|
||||
);
|
||||
}
|
||||
|
||||
// 用户名搜索(用户数据为只读)
|
||||
export function isUsernameLoggedIn() {
|
||||
return (
|
||||
Cookies.get("MUSIC_U") === undefined &&
|
||||
Cookies.get("loginMode") === "username"
|
||||
);
|
||||
}
|
||||
|
||||
// 账户登录或者用户名搜索都判断为登录,宽松检查
|
||||
export function isLooseLoggedIn() {
|
||||
return isAccountLoggedIn() || isUsernameLoggedIn();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { isLoggedIn } from "./auth";
|
||||
import { isAccountLoggedIn } from "./auth";
|
||||
import { refreshCookie } from "@/api/auth";
|
||||
import { dailySignin } from "@/api/user";
|
||||
import dayjs from "dayjs";
|
||||
import store from "@/store";
|
||||
|
||||
export function isTrackPlayable(track) {
|
||||
|
@ -7,7 +10,7 @@ export function isTrackPlayable(track) {
|
|||
reason: "",
|
||||
};
|
||||
if (track.fee === 1 || track.privilege?.fee === 1) {
|
||||
if (isLoggedIn && store.state.settings.user.vipType === 11) {
|
||||
if (isAccountLoggedIn() && store.state.settings.user.vipType === 11) {
|
||||
result.playable = true;
|
||||
} else {
|
||||
result.playable = false;
|
||||
|
@ -75,3 +78,32 @@ export function updateHttps(url) {
|
|||
if (!url) return "";
|
||||
return url.replace(/^http:/, "https:");
|
||||
}
|
||||
|
||||
export function dailyTask() {
|
||||
let lastDate = store.state.settings.lastRefreshCookieDate;
|
||||
if (
|
||||
isAccountLoggedIn() &&
|
||||
(lastDate === undefined || lastDate !== dayjs().date())
|
||||
) {
|
||||
console.log("execute dailyTask");
|
||||
store.commit("updateSettings", {
|
||||
key: "lastRefreshCookieDate",
|
||||
value: dayjs().date(),
|
||||
});
|
||||
refreshCookie();
|
||||
dailySignin(0);
|
||||
dailySignin(1);
|
||||
}
|
||||
}
|
||||
|
||||
export function changeAppearance(appearance) {
|
||||
if (appearance === "auto" || appearance === undefined) {
|
||||
appearance = window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
}
|
||||
document.body.setAttribute("data-theme", appearance);
|
||||
document
|
||||
.querySelector('meta[name="theme-color"]')
|
||||
.setAttribute("content", appearance === "dark" ? "#222" : "#fff");
|
||||
}
|
||||
|
|
|
@ -60,8 +60,8 @@
|
|||
More by
|
||||
<router-link :to="`/artist/${album.artist.id}`"
|
||||
>{{ album.artist.name }}
|
||||
</router-link></div
|
||||
>
|
||||
</router-link>
|
||||
</div>
|
||||
<div>
|
||||
<CoverRow
|
||||
type="album"
|
||||
|
@ -200,6 +200,7 @@ export default {
|
|||
justify-content: center;
|
||||
flex: 1;
|
||||
margin-left: 56px;
|
||||
color: var(--color-text);
|
||||
.title {
|
||||
font-size: 56px;
|
||||
font-weight: 700;
|
||||
|
@ -208,7 +209,7 @@ export default {
|
|||
}
|
||||
.artist {
|
||||
font-size: 18px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
margin-top: 24px;
|
||||
a {
|
||||
font-weight: 600;
|
||||
|
@ -216,13 +217,13 @@ export default {
|
|||
}
|
||||
.date-and-count {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.description {
|
||||
user-select: none;
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
margin-top: 24px;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
|
@ -230,8 +231,8 @@ export default {
|
|||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
transition: color 0.3s;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
transition: opacity 0.3s;
|
||||
opacity: 0.88;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +282,8 @@ export default {
|
|||
}
|
||||
|
||||
.explicit-symbol {
|
||||
color: rgba(0, 0, 0, 0.28);
|
||||
opacity: 0.28;
|
||||
color: var(--color-text);
|
||||
margin-right: 4px;
|
||||
.svg-icon {
|
||||
margin-bottom: -3px;
|
||||
|
@ -292,22 +294,25 @@ export default {
|
|||
margin-top: 36px;
|
||||
margin-bottom: 36px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.48);
|
||||
opacity: 0.48;
|
||||
color: var(--color-text);
|
||||
div {
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.album-time {
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
}
|
||||
}
|
||||
|
||||
.more-by {
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||
border-top: 1px solid rgba(128, 128, 128, 0.18);
|
||||
|
||||
padding-top: 22px;
|
||||
.section-title {
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,6 +195,7 @@ export default {
|
|||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 72px;
|
||||
color: var(--color-text);
|
||||
img {
|
||||
height: 192px;
|
||||
width: 192px;
|
||||
|
@ -209,13 +210,13 @@ export default {
|
|||
|
||||
.artist {
|
||||
font-size: 18px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.statistics {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
|
@ -234,12 +235,14 @@ export default {
|
|||
.section-title {
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 16px;
|
||||
margin-top: 46px;
|
||||
}
|
||||
|
||||
.latest-release {
|
||||
color: var(--color-text);
|
||||
.release {
|
||||
display: flex;
|
||||
}
|
||||
|
@ -258,17 +261,16 @@ export default {
|
|||
.name {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.date {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.78);
|
||||
opacity: 0.78;
|
||||
}
|
||||
.type {
|
||||
margin-top: 2px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,11 +283,12 @@ export default {
|
|||
margin-top: 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.78);
|
||||
opacity: 0.78;
|
||||
color: var(--color-secondary);
|
||||
font-weight: 600;
|
||||
&:hover {
|
||||
background: #f5f5f7;
|
||||
color: rgba(0, 0, 0, 0.96);
|
||||
opacity: 1;
|
||||
// background: var(--color-primary-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ export default {
|
|||
|
||||
<style lang="scss" scoped>
|
||||
h1 {
|
||||
color: var(--color-text);
|
||||
font-size: 56px;
|
||||
}
|
||||
.buttons {
|
||||
|
@ -178,19 +179,18 @@ h1 {
|
|||
font-weight: 600;
|
||||
font-size: 18px;
|
||||
border-radius: 10px;
|
||||
color: rgb(0, 0, 0);
|
||||
background-color: #f5f5f7;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
background-color: var(--color-secondary-bg);
|
||||
color: var(--color-secondary);
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(51, 94, 234, 0.1);
|
||||
color: #335eea;
|
||||
background-color: var(--color-primary-bg);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
.button.active {
|
||||
background-color: rgba(51, 94, 234, 0.1);
|
||||
color: #335eea;
|
||||
background-color: var(--color-primary-bg);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.playlists {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="home" v-show="show">
|
||||
<div class="index-row">
|
||||
<div class="index-row" v-if="settings.showPlaylistsByAppleMusic !== false">
|
||||
<div class="title"> by Apple Music </div>
|
||||
<CoverRow
|
||||
:type="'playlist'"
|
||||
|
@ -54,7 +54,7 @@
|
|||
:color="'grey'"
|
||||
@click.native="goTo('/settings')"
|
||||
>
|
||||
{{ $t("footer.settings") }}
|
||||
{{ $t("settings.settings") }}
|
||||
</ButtonTwoTone>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -66,6 +66,8 @@ import { toplistOfArtists } from "@/api/artist";
|
|||
import { byAppleMusic } from "@/utils/staticPlaylist";
|
||||
import { newAlbums } from "@/api/album";
|
||||
import NProgress from "nprogress";
|
||||
import { mapState } from "vuex";
|
||||
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
|
||||
|
@ -88,6 +90,7 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["settings"]),
|
||||
byAppleMusic() {
|
||||
return byAppleMusic;
|
||||
},
|
||||
|
@ -158,40 +161,11 @@ export default {
|
|||
margin-bottom: 20px;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
|
||||
color: var(--color-text);
|
||||
a {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
margin: 12px 12px 24px 12px;
|
||||
.text {
|
||||
width: 208px;
|
||||
margin-top: 8px;
|
||||
.name {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
line-height: 20px;
|
||||
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
.info {
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
line-height: 18px;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
// margin-top: 4px;
|
||||
}
|
||||
opacity: 0.68;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
import { mapState } from "vuex";
|
||||
import { getTrackDetail, getLyric } from "@/api/track";
|
||||
import { userDetail, userPlaylist } from "@/api/user";
|
||||
import { randomNum } from "@/utils/common";
|
||||
import { randomNum, dailyTask } from "@/utils/common";
|
||||
import { getPlaylistDetail } from "@/api/playlist";
|
||||
import { playPlaylistByID } from "@/utils/play";
|
||||
import NProgress from "nprogress";
|
||||
|
@ -98,6 +98,7 @@ export default {
|
|||
},
|
||||
activated() {
|
||||
this.loadData();
|
||||
dailyTask();
|
||||
},
|
||||
computed: {
|
||||
...mapState(["settings"]),
|
||||
|
@ -185,6 +186,7 @@ export default {
|
|||
<style lang="scss" scoped>
|
||||
h1 {
|
||||
font-size: 42px;
|
||||
color: var(--color-text);
|
||||
.head {
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
|
@ -219,25 +221,21 @@ h1 {
|
|||
transition: all 0.4s;
|
||||
box-sizing: border-box;
|
||||
|
||||
background: #eaeffd;
|
||||
// background: linear-gradient(-30deg, #60a6f7, #4364f7, #0052d4);
|
||||
// color: white;
|
||||
// background: linear-gradient(149.46deg, #450af5, #8e8ee5 99.16%);
|
||||
background: var(--color-primary-bg);
|
||||
|
||||
.bottom {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: var(--color-primary);
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #335eea;
|
||||
}
|
||||
.sub-title {
|
||||
font-size: 15px;
|
||||
margin-top: 2px;
|
||||
color: #335eea;
|
||||
}
|
||||
|
||||
button {
|
||||
|
@ -247,16 +245,14 @@ h1 {
|
|||
align-items: center;
|
||||
height: 44px;
|
||||
width: 44px;
|
||||
// background: rgba(255, 255, 255, 1);
|
||||
background: #335eea;
|
||||
background: var(--color-primary);
|
||||
border-radius: 50%;
|
||||
transition: 0.2s;
|
||||
box-shadow: 0 6px 12px -4px rgba(0, 0, 0, 0.2);
|
||||
cursor: default;
|
||||
|
||||
.svg-icon {
|
||||
// color: #3f63f5;
|
||||
color: #eaeffd;
|
||||
color: var(--color-primary-bg);
|
||||
margin-left: 4px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
|
@ -276,7 +272,8 @@ h1 {
|
|||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-size: 14px;
|
||||
color: rgba(51, 94, 234, 0.88);
|
||||
opacity: 0.88;
|
||||
color: var(--color-primary);
|
||||
p {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
@ -286,7 +283,8 @@ h1 {
|
|||
.playlists {
|
||||
margin-top: 54px;
|
||||
.title {
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
color: var(--color-text);
|
||||
opacity: 0.88;
|
||||
margin-bottom: 8px;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
|
|
|
@ -112,9 +112,9 @@ export default {
|
|||
NProgress.done();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateUser", "updateUserInfo"]),
|
||||
...mapMutations(["updateUser", "updateUserInfo", "updateAccountLogin"]),
|
||||
afterLogin() {
|
||||
// Cookies.set("MUSIC_U", true, { expires: 3650 });
|
||||
this.updateAccountLogin(true);
|
||||
Cookies.set("loginMode", "account", { expires: 3650 });
|
||||
userPlaylist({
|
||||
uid: this.$store.state.settings.user.userId,
|
||||
|
@ -127,18 +127,34 @@ export default {
|
|||
this.$router.push({ path: "/library" });
|
||||
});
|
||||
},
|
||||
validatePhone() {
|
||||
if (
|
||||
this.countryCode === "" ||
|
||||
this.phone === "" ||
|
||||
this.password === ""
|
||||
) {
|
||||
alert("国家区号、手机或密码不正确");
|
||||
this.processing = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
validateEmail() {
|
||||
const emailReg = /^[A-Za-z0-9]+([_][A-Za-z0-9]+)*@([A-Za-z0-9]+\.)+[A-Za-z]{2,6}$/;
|
||||
if (
|
||||
this.email === "" ||
|
||||
this.password === "" ||
|
||||
!emailReg.test(this.email)
|
||||
) {
|
||||
alert("邮箱或密码不正确");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
login() {
|
||||
this.processing = true;
|
||||
if (this.mode === "phone") {
|
||||
if (
|
||||
this.countryCode === "" ||
|
||||
this.phone === "" ||
|
||||
this.password === ""
|
||||
) {
|
||||
alert("国家区号、手机或密码不正确");
|
||||
this.processing = false;
|
||||
return;
|
||||
}
|
||||
this.processing = this.validatePhone();
|
||||
loginWithPhone({
|
||||
countrycode: this.countryCode.replace("+", "").replace(/\s/g, ""),
|
||||
phone: this.phoneNumber.replace(/\s/g, ""),
|
||||
|
@ -156,16 +172,7 @@ export default {
|
|||
alert(error);
|
||||
});
|
||||
} else {
|
||||
let emailReg = /^[A-Za-z0-9]+([_][A-Za-z0-9]+)*@([A-Za-z0-9]+\.)+[A-Za-z]{2,6}$/;
|
||||
if (
|
||||
this.email === "" ||
|
||||
this.password === "" ||
|
||||
!emailReg.test(this.email)
|
||||
) {
|
||||
alert("邮箱或密码不正确");
|
||||
this.processing = false;
|
||||
return;
|
||||
}
|
||||
this.processing = this.validateEmail();
|
||||
loginWithEmail({
|
||||
email: this.email.replace(/\s/g, ""),
|
||||
password: "fakePassword",
|
||||
|
@ -199,6 +206,7 @@ export default {
|
|||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
margin-bottom: 48px;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.section-1 {
|
||||
|
@ -209,11 +217,6 @@ export default {
|
|||
height: 64px;
|
||||
margin: 20px;
|
||||
}
|
||||
.svg-icon {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
color: rgba(82, 82, 82, 0.28);
|
||||
}
|
||||
}
|
||||
|
||||
.section-2 {
|
||||
|
@ -226,12 +229,13 @@ export default {
|
|||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 16px;
|
||||
color: var(--color-text);
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 46px;
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
background: var(--color-secondary-bg);
|
||||
border-radius: 8px;
|
||||
width: 300px;
|
||||
}
|
||||
|
@ -258,7 +262,12 @@ export default {
|
|||
width: 100%;
|
||||
font-weight: 600;
|
||||
margin-top: -1px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
color: var(--color-text);
|
||||
opacity: 0.38;
|
||||
}
|
||||
|
||||
input#countryCode {
|
||||
|
@ -269,10 +278,10 @@ export default {
|
|||
}
|
||||
|
||||
.active {
|
||||
background: #eaeffd;
|
||||
background: var(--color-primary-bg);
|
||||
input,
|
||||
.svg-icon {
|
||||
color: #335eea;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -283,8 +292,8 @@ export default {
|
|||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
background-color: rgba(51, 94, 234, 0.1);
|
||||
color: #335eea;
|
||||
background-color: var(--color-primary-bg);
|
||||
color: var(--color-primary);
|
||||
border-radius: 8px;
|
||||
margin-top: 24px;
|
||||
transition: 0.2s;
|
||||
|
@ -304,17 +313,19 @@ export default {
|
|||
a {
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
color: var(--color-text);
|
||||
opacity: 0.68;
|
||||
}
|
||||
}
|
||||
|
||||
.notice {
|
||||
width: 300px;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.18);
|
||||
border-top: 1px solid rgba(128, 128, 128);
|
||||
margin-top: 48px;
|
||||
padding-top: 12px;
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.48);
|
||||
color: var(--color-text);
|
||||
opacity: 0.48;
|
||||
}
|
||||
|
||||
@keyframes loading {
|
||||
|
@ -339,7 +350,7 @@ button.loading {
|
|||
.loading span {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: #335eea;
|
||||
background-color: var(--color-primary);
|
||||
border-radius: 50%;
|
||||
margin: 0 2px;
|
||||
animation: loading 1.4s infinite both;
|
||||
|
|
|
@ -41,8 +41,9 @@
|
|||
<ButtonTwoTone
|
||||
@click.native="confirm"
|
||||
v-show="activeUser.nickname !== undefined"
|
||||
>{{ $t("login.confirm") }}</ButtonTwoTone
|
||||
>
|
||||
{{ $t("login.confirm") }}
|
||||
</ButtonTwoTone>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -73,7 +74,7 @@ export default {
|
|||
NProgress.done();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateUser", "updateUserInfo"]),
|
||||
...mapMutations(["updateUser", "updateUserInfo", "updateUsernameLogin"]),
|
||||
search() {
|
||||
if (!this.keyword) return;
|
||||
search({ keywords: this.keyword, limit: 9, type: 1002 }).then((data) => {
|
||||
|
@ -83,6 +84,7 @@ export default {
|
|||
},
|
||||
confirm() {
|
||||
this.updateUser(this.activeUser);
|
||||
this.updateUsernameLogin(true);
|
||||
Cookies.set("loginMode", "username", { expires: 3650 });
|
||||
userPlaylist({
|
||||
uid: this.activeUser.userId,
|
||||
|
@ -105,6 +107,7 @@ export default {
|
|||
<style lang="scss" scoped>
|
||||
.login {
|
||||
display: flex;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -119,7 +122,7 @@ export default {
|
|||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
color: rgba(0, 0, 0, 0.78);
|
||||
opacity: 0.78;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,13 +133,13 @@ export default {
|
|||
height: 48px;
|
||||
border-radius: 11px;
|
||||
width: 326px;
|
||||
background: #eaeffd;
|
||||
background: var(--color-primary-bg);
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
color: #335eea;
|
||||
color: var(--color-primary);
|
||||
margin: {
|
||||
left: 12px;
|
||||
right: 8px;
|
||||
|
@ -151,9 +154,10 @@ export default {
|
|||
width: 115%;
|
||||
font-weight: 600;
|
||||
margin-top: -1px;
|
||||
color: #335eea;
|
||||
color: var(--color-primary);
|
||||
&::placeholder {
|
||||
color: #335eeac4;
|
||||
color: var(--color-primary);
|
||||
opacity: 0.78;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,15 +189,15 @@ export default {
|
|||
margin-left: 12px;
|
||||
}
|
||||
&:hover {
|
||||
background: #f5f5f7;
|
||||
background: var(--color-secondary-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.user.active {
|
||||
transition: 0.2s;
|
||||
background: #eaeffd;
|
||||
.name {
|
||||
color: #335eea;
|
||||
background: var(--color-primary-bg);
|
||||
.nickname {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -127,19 +127,20 @@ export default {
|
|||
|
||||
.video-info {
|
||||
margin-top: 12px;
|
||||
color: var(--color-text);
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.artist {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
margin-top: 2px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.info {
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
margin-top: 12px;
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +150,8 @@ export default {
|
|||
.section-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
color: var(--color-text);
|
||||
opacity: 0.88;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -106,5 +106,6 @@ h1 {
|
|||
margin-top: 36px;
|
||||
margin-bottom: 18px;
|
||||
cursor: default;
|
||||
color: var(--color-text);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
</ButtonTwoTone>
|
||||
<ButtonTwoTone
|
||||
v-if="
|
||||
isLoggedIn && playlist.creator.userId !== settings.user.userId
|
||||
accountLogin && playlist.creator.userId !== settings.user.userId
|
||||
"
|
||||
shape="round"
|
||||
:iconClass="playlist.subscribed ? 'heart-solid' : 'heart'"
|
||||
|
@ -92,7 +92,6 @@ import NProgress from "nprogress";
|
|||
import { getPlaylistDetail, subscribePlaylist } from "@/api/playlist";
|
||||
import { playAList } from "@/utils/play";
|
||||
import { getTrackDetail } from "@/api/track";
|
||||
import { isLoggedIn } from "@/utils/auth";
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
|
@ -132,10 +131,7 @@ export default {
|
|||
window.removeEventListener("scroll", this.handleScroll, true);
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player", "settings"]),
|
||||
isLoggedIn() {
|
||||
return isLoggedIn();
|
||||
},
|
||||
...mapState(["player", "settings", "accountLogin"]),
|
||||
isLikeSongsPage() {
|
||||
return this.$route.name === "likedSongs";
|
||||
},
|
||||
|
@ -230,20 +226,24 @@ export default {
|
|||
.title {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text);
|
||||
}
|
||||
.artist {
|
||||
font-size: 18px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
color: var(--color-text);
|
||||
margin-top: 24px;
|
||||
}
|
||||
.date-and-count {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
color: var(--color-text);
|
||||
margin-top: 2px;
|
||||
}
|
||||
.description {
|
||||
font-size: 14px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
color: var(--color-text);
|
||||
margin-top: 24px;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
|
@ -251,8 +251,8 @@ export default {
|
|||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
transition: color 0.3s;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
transition: opacity 0.3s;
|
||||
opacity: 0.88;
|
||||
}
|
||||
}
|
||||
.buttons {
|
||||
|
@ -303,6 +303,7 @@ export default {
|
|||
.user-info {
|
||||
h1 {
|
||||
font-size: 42px;
|
||||
color: var(--color-text);
|
||||
.avatar {
|
||||
height: 44px;
|
||||
margin-right: 12px;
|
||||
|
|
|
@ -192,15 +192,17 @@ export default {
|
|||
h1 {
|
||||
margin-top: -10px;
|
||||
margin-bottom: 0;
|
||||
color: var(--color-text);
|
||||
span {
|
||||
color: rgba(0, 0, 0, 0.58);
|
||||
opacity: 0.58;
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
opacity: 0.88;
|
||||
color: var(--color-text);
|
||||
margin-bottom: 16px;
|
||||
margin-top: 46px;
|
||||
}
|
||||
|
@ -219,6 +221,7 @@ h1 {
|
|||
padding-right: 48px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
.artist {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -236,6 +239,7 @@ h1 {
|
|||
|
||||
.albums-list {
|
||||
display: flex;
|
||||
color: var(--color-text);
|
||||
.album {
|
||||
img {
|
||||
height: 128px;
|
||||
|
@ -249,7 +253,6 @@ h1 {
|
|||
.name {
|
||||
margin-top: 6px;
|
||||
font-weight: 600;
|
||||
color: rgba(0, 0, 0, 0.88);
|
||||
font-size: 14px;
|
||||
width: 128px;
|
||||
display: -webkit-box;
|
||||
|
@ -259,7 +262,7 @@ h1 {
|
|||
}
|
||||
.artist {
|
||||
font-size: 12px;
|
||||
color: rgba(0, 0, 0, 0.68);
|
||||
opacity: 0.68;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user