Compare commits

..

No commits in common. "master" and "v0.3.3" have entirely different histories.

186 changed files with 9439 additions and 20120 deletions

View file

@ -1,16 +0,0 @@
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.github
.gitignore
README.md
LICENSE
.vscode
dist
dist_electron
build
images
script

View file

@ -1,7 +1,5 @@
VUE_APP_NETEASE_API_URL=/api
VUE_APP_NETEASE_API_URL=http://127.0.0.1:3000
VUE_APP_ELECTRON_API_URL=/api
VUE_APP_ELECTRON_API_URL_DEV=http://127.0.0.1:10754
VUE_APP_LASTFM_API_KEY=09c55292403d961aa517ff7f5e8a3d9c
VUE_APP_LASTFM_API_SHARED_SECRET=307c9fda32b3904e53654baff215cb67
DEV_SERVER_PORT=20201
VUE_APP_ELECTRON_API_URL_DEV=http://127.0.0.1:3000
VUE_APP_ENABLE_SENTRY=false
DEV_SERVER_PORT=20201

4
.envrc
View file

@ -1,4 +0,0 @@
source_url "https://raw.githubusercontent.com/cachix/devenv/82c0147677e510b247d8b9165c54f73d32dfd899/direnvrc" "sha256-7u4iDd1nZpxL4tCzmPG0dQgC5V+/44Ba+tHkPob1v2k="
export NIXPKGS_ALLOW_INSECURE=1
use devenv

7
.gitattributes vendored
View file

@ -1,7 +0,0 @@
* text eol=lf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.mp3 binary
*.icns binary
*.gif binary

View file

@ -1,15 +1,6 @@
name: Release
name: Build/release
env:
YARN_INSTALL_NOPT: yarn add --ignore-platform --ignore-optional
on:
push:
branches:
- master
tags:
- v*
workflow_dispatch:
on: [push, pull_request]
jobs:
release:
@ -17,75 +8,19 @@ jobs:
strategy:
matrix:
os: [macos-latest, windows-latest, ubuntu-22.04]
os: [macos-latest, windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v3
with:
submodules: "recursive"
uses: actions/checkout@v2
- name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v3
uses: actions/setup-node@v1
with:
node-version: 16
cache: 'yarn'
- name: Install RPM & Pacman (on Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update &&
sudo apt-get install --no-install-recommends -y rpm &&
sudo apt-get install --no-install-recommends -y libarchive-tools &&
sudo apt-get install --no-install-recommends -y libopenjp2-tools
- name: Install Snapcraft (on Ubuntu)
uses: samuelmeuli/action-snapcraft@v1
if: startsWith(matrix.os, 'ubuntu')
with:
snapcraft_token: ${{ secrets.snapcraft_token }}
- id: get_unm_version
name: Get the installed UNM version
run: |
yarn --ignore-optional
unm_version=$(node -e "console.log(require('./node_modules/@unblockneteasemusic/rust-napi/package.json').version)")
echo "::set-output name=unmver::${unm_version}"
shell: bash
- name: Install UNM dependencies for Windows
if: runner.os == 'Windows'
run: |
${{ env.YARN_INSTALL_NOPT }} \
@unblockneteasemusic/rust-napi-win32-x64-msvc@${{steps.get_unm_version.outputs.unmver}}
shell: bash
- name: Install UNM dependencies for macOS
if: runner.os == 'macOS'
run: |
${{ env.YARN_INSTALL_NOPT }} \
@unblockneteasemusic/rust-napi-darwin-x64@${{steps.get_unm_version.outputs.unmver}} \
@unblockneteasemusic/rust-napi-darwin-arm64@${{steps.get_unm_version.outputs.unmver}} \
dmg-license
shell: bash
- name: Install UNM dependencies for Linux
if: runner.os == 'Linux'
run: |
${{ env.YARN_INSTALL_NOPT }} \
@unblockneteasemusic/rust-napi-linux-x64-gnu@${{steps.get_unm_version.outputs.unmver}} \
@unblockneteasemusic/rust-napi-linux-arm64-gnu@${{steps.get_unm_version.outputs.unmver}} \
@unblockneteasemusic/rust-napi-linux-arm-gnueabihf@${{steps.get_unm_version.outputs.unmver}}
shell: bash
node-version: 12.16.3
- name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1.6.0
env:
VUE_APP_NETEASE_API_URL: /api
VUE_APP_ELECTRON_API_URL: /api
VUE_APP_ELECTRON_API_URL_DEV: http://127.0.0.1:10754
VUE_APP_LASTFM_API_KEY: 09c55292403d961aa517ff7f5e8a3d9c
VUE_APP_LASTFM_API_SHARED_SECRET: 307c9fda32b3904e53654baff215cb67
uses: samuelmeuli/action-electron-builder@v1
with:
# GitHub token, automatically provided to the action
# (No need to define this secret in the repo settings)
@ -97,20 +32,14 @@ jobs:
use_vue_cli: true
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v2
with:
name: YesPlayMusic-mac
path: dist_electron/*-universal.dmg
path: dist_electron/*.dmg
if-no-files-found: ignore
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v2
with:
name: YesPlayMusic-win
path: dist_electron/*Setup*.exe
if-no-files-found: ignore
- uses: actions/upload-artifact@v3
with:
name: YesPlayMusic-linux
path: dist_electron/*.AppImage
path: dist_electron/*.exe
if-no-files-found: ignore

View file

@ -1,48 +0,0 @@
name: Upstream Sync
permissions:
contents: write
issues: write
actions: write
on:
schedule:
- cron: '0 * * * *' # every hour
workflow_dispatch:
jobs:
sync_latest_from_upstream:
name: Sync latest commits from upstream repo
runs-on: ubuntu-latest
if: ${{ github.event.repository.fork }}
steps:
- uses: actions/checkout@v4
- name: Clean issue notice
uses: actions-cool/issues-helper@v3
with:
actions: 'close-issues'
labels: '🚨 Sync Fail'
- name: Sync upstream changes
id: sync
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4
with:
upstream_sync_repo: qier222/YesPlayMusic
upstream_sync_branch: master
target_sync_branch: master
target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set
test_mode: false
- name: Sync check
if: failure()
uses: actions-cool/issues-helper@v3
with:
actions: 'create-issue'
title: '🚨 同步失败 | Sync Fail'
labels: '🚨 Sync Fail'
body: |
Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork.
由于上游仓库的 workflow 文件变更,导致 GitHub 自动暂停了本次自动更新,你需要手动 Sync Fork 一次。

16
.gitignore vendored
View file

@ -1,6 +1,8 @@
.DS_Store
node_modules
/dist
dist_electron
Icon?
# local env files
.env
@ -23,21 +25,9 @@ pnpm-debug.log*
*.sw?
.vercel
/netease_api
#Electron-builder output
/dist_electron
NeteaseCloudMusicApi-master
NeteaseCloudMusicApi-master.zip
# Local Netlify folder
.netlify
vercel.json
# Devenv
.devenv*
devenv.local.nix
# direnv
.direnv
# pre-commit
.pre-commit-config.yaml

4
.npmrc Normal file
View file

@ -0,0 +1,4 @@
# 如果发现 npm / yarn 安装太慢,可以解除注释
# registry=https://registry.npm.taobao.org/
# ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron
# phantomjs_cdnurl=https://npm.taobao.org/dist/phantomjs

1
.nvmrc
View file

@ -1 +0,0 @@
14

View file

@ -1,3 +1,5 @@
build
coverage
dist
netease_api

View file

@ -3,9 +3,10 @@
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"singleQuote": false,
"jsxSingleQuote": true,
"arrowParens": "avoid",
"jsxBracketSameLine": false,
"arrowParens": "always",
"endOfLine": "lf",
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "strict"

View file

@ -1,25 +0,0 @@
FROM node:16.13.1-alpine as build
ENV VUE_APP_NETEASE_API_URL=/api
WORKDIR /app
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories &&\
apk add --no-cache python3 make g++ git
COPY package.json yarn.lock ./
RUN yarn install
COPY . .
RUN yarn config set electron_mirror https://npmmirror.com/mirrors/electron/ && \
yarn build
FROM nginx:1.20.2-alpine as app
COPY --from=build /app/package.json /usr/local/lib/
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories &&\
apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.14/main libuv \
&& apk add --no-cache --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.14/main nodejs npm \
&& npm i -g $(awk -F \" '{if($2=="NeteaseCloudMusicApi") print $2"@"$4}' /usr/local/lib/package.json) \
&& rm -f /usr/local/lib/package.json
COPY --from=build /app/docker/nginx.conf.example /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
CMD nginx ; exec npx NeteaseCloudMusicApi

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2020-2023 qier222
Copyright (c) 2020 qier222
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.

204
README.md
View file

@ -8,221 +8,69 @@
<p align="center">
高颜值的第三方网易云播放器
<br />
<a href="https://music.ineko.cc" target="blank"><strong>🌎 访问DEMO</strong></a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="#%EF%B8%8F-安装" target="blank"><strong>📦️ 下载安装包</strong></a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="https://t.me/yesplaymusic" target="blank"><strong>💬 加入交流群</strong></a>
<a href="https://music.qier222.com" target="blank"><strong>🌎 访问DEMO</strong></a>&nbsp;&nbsp;|&nbsp;&nbsp;
<a href="#%EF%B8%8F-安装" target="blank"><strong>📦️ 下载安装包</strong></a>
<br />
<br />
</p>
</p>
[![Library][library-screenshot]](https://music.ineko.cc)
## 全新版本
全新2.0 Alpha测试版已发布欢迎前往 [Releases](https://github.com/qier222/YesPlayMusic/releases) 页面下载。
当前版本将会进入维护模式除重大bug修复外不会再更新新功能。
[![Library][library-screenshot]](https://music.qier222.com)
## ✨ 特性
- ✅ 使用 Vue.js 全家桶开发
- 🔴 网易云账号登录(扫码/手机/邮箱登录)
- 📺 支持 MV 播放
- 🔴 网易云账号登录
- 📺 MV 播放
- 📃 支持歌词显示
- 📻 支持私人 FM / 每日推荐歌曲
- 🚫🤝 无任何社交功能
- 🌎️ 海外用户可直接播放(需要登录网易云账号)
- 🔐 支持 [UnblockNeteaseMusic](https://github.com/UnblockNeteaseMusic/server#音源清单),自动使用[各类音源](https://github.com/UnblockNeteaseMusic/server#音源清单)替换变灰歌曲链接 (网页版不支持)
- 「各类音源」指默认启用的音源。
- YouTube 音源需自行安装 `yt-dlp`
- 🔐 支持 [UnblockNeteaseMusic](https://github.com/nondanee/UnblockNeteaseMusic),自动使用 QQ/酷狗/酷我音源替换变灰歌曲链接 (网页版不支持)
- ⏭️ 支持 MediaSession API可以使用系统快捷键操作上一首下一首
- ✔️ 每日自动签到(手机端和电脑端同时签到)
- 🌚 Light/Dark Mode 自动切换
- 👆 支持 Touch Bar
- 🖥️ 支持 PWA可在 Chrome/Edge 里点击地址栏右边的 安装到电脑
- 🟥 支持 Last.fm Scrobble
- ☁️ 支持音乐云盘
- ⌨️ 自定义快捷键和全局快捷键
- 🎧 支持 Mpris
- 🙉 支持显示歌曲和专辑的 Explicit 标志
- 🛠 更多特性开发中
## 📦️ 安装
Electron 版本由 [@hawtim](https://github.com/hawtim) 和 [@qier222](https://github.com/qier222) 适配并维护,支持 macOS、Windows、Linux。
访问本项目的 [Releases](https://github.com/qier222/YesPlayMusic/releases)
页面下载安装包。
访问本项目的 [Releases](https://github.com/qier222/YesPlayMusic/releases) 页面下载安装包,或者访问 [镜像下载站 (大陆访问更快)](https://dl.qier222.com/YesPlayMusic/) 下载。
- macOS 用户可以通过 Homebrew 来安装:`brew install --cask yesplaymusic`
## ⚙️ 部署至服务器
- Windows 用户可以通过 Scoop 来安装:`scoop install extras/yesplaymusic`
## ⚙️ 部署至 Vercel
除了下载安装包使用,你还可以将本项目部署到 Vercel 或你的服务器上。下面是部署到 Vercel 的方法。
本项目的 Demo (https://music.qier222.com) 就是部署在 Vercel 上的网站。
[![Powered by Vercel](https://www.datocms-assets.com/31049/1618983297-powered-by-vercel.svg)](https://vercel.com/?utm_source=ohmusic&utm_campaign=oss)
1. 部署网易云 API详情参见 [Binaryify/NeteaseCloudMusicApi](https://neteasecloudmusicapi.vercel.app/#/?id=%e5%ae%89%e8%a3%85)
。你也可以将 API 部署到 Vercel。
2. 点击本仓库右上角的 Fork复制本仓库到你的 GitHub 账号。
3. 点击仓库的 Add File选择 Create new file输入 `vercel.json`,将下面的内容复制粘贴到文件中,并将 `https://your-netease-api.example.com` 替换为你刚刚部署的网易云 API 地址:
```json
{
"rewrites": [
{
"source": "/api/:match*",
"destination": "https://your-netease-api.example.com/:match*"
}
]
}
```
4. 打开 [Vercel.com](https://vercel.com),使用 GitHub 登录。
5. 点击 Import Git Repository 并选择你刚刚复制的仓库并点击 Import。
6. 点击 PERSONAL ACCOUNT 旁边的 Select。
7. 点击 Environment Variables填写 Name 为 `VUE_APP_NETEASE_API_URL`Value 为 `/api`,点击 Add。最后点击底部的 Deploy 就可以部署到
Vercel 了。
## ⚙️ 部署到自己的服务器
除了部署到 Vercel你还可以部署到自己的服务器上
除了下载安装包使用,你还可以将本项目部署到你的服务器上。
1. 部署网易云 API详情参见 [Binaryify/NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi)
2. 克隆本仓库
```sh
git clone --recursive https://github.com/qier222/YesPlayMusic.git
git clone https://github.com/qier222/YesPlayMusic.git
```
3. 安装依赖
```sh
yarn install
```
4. (可选)使用 Nginx 反向代理 API将 API 路径映射为 `/api`,如果 API 和网页不在同一个域名下的话(跨域),会有一些 bug。
5. 复制 `/.env.example` 文件为 `/.env`,修改里面 `VUE_APP_NETEASE_API_URL` 的值为网易云 API 地址。本地开发的话可以填写 API 地址为 `http://localhost:3000`YesPlayMusic 地址为 `http://localhost:8080`。如果你使用了反向代理 API可以填写 API 地址为 `/api`
4. 复制 `/.env.example` 文件为 `/.env`,修改里面 `VUE_APP_NETEASE_API_URL` 的值为网易云 API 地址。本地开发的话可以填写 API 地址为 `http://localhost:3000`YesPlayMusic 地址为 `http://localhost:8080`
```
VUE_APP_NETEASE_API_URL=http://localhost:3000
```
6. 编译打包
5. 编译打包
```sh
yarn run build
```
7. 将 `/dist` 目录下的文件上传到你的 Web 服务器
## ⚙️ 宝塔面板 docker应用商店 部署
1. 安装宝塔面板,前往[宝塔面板官网](https://www.bt.cn/new/download.html) ,选择正式版的脚本下载安装。
2. 安装后登录宝塔面板,在左侧导航栏中点击 Docker首次进入会提示安装Docker服务点击立即安装按提示完成安装
3. 安装完成后在应用商店中找到YesPlayMusic点击安装配置域名、端口等基本信息即可完成安装。
4. 安装后在浏览器输入上一步骤设置的域名即可访问。
## ⚙️ Docker 部署
1. 构建 Docker Image
```sh
docker build -t yesplaymusic .
```
2. 启动 Docker Container
```sh
docker run -d --name YesPlayMusic -p 80:80 yesplaymusic
```
3. Docker Compose 启动
```sh
docker-compose up -d
```
YesPlayMusic 地址为 `http://localhost`
## ⚙️ 部署至 Replit
1. 新建 Repl选择 Bash 模板
2. 在 Replit shell 中运行以下命令
```sh
bash <(curl -s -L https://raw.githubusercontent.com/qier222/YesPlayMusic/main/install-replit.sh)
```
3. 首次运行成功后,只需点击绿色按钮 `Run` 即可再次运行
4. 由于 replit 个人版限制内存为 1G教育版为 3G构建过程中可能会失败请再次运行上述命令或运行以下命令
```sh
cd /home/runner/${REPL_SLUG}/music && yarn install && yarn run build
```
## 👷‍♂️ 打包客户端
如果在 Release 页面没有找到适合你的设备的安装包的话,你可以根据下面的步骤来打包自己的客户端。
1. 打包 Electron 需要用到 Node.js 和 Yarn。可前往 [Node.js 官网](https://nodejs.org/zh-cn/) 下载安装包。安装 Node.js
后可在终端里执行 `npm install -g yarn` 来安装 Yarn。
2. 使用 `git clone --recursive https://github.com/qier222/YesPlayMusic.git` 克隆本仓库到本地。
3. 使用 `yarn install` 安装项目依赖。
4. 复制 `/.env.example` 文件为 `/.env`
5. 选择下列表格的命令来打包适合的你的安装包,打包出来的文件在 `/dist_electron` 目录下。了解更多信息可访问 [electron-builder 文档](https://www.electron.build/cli)
| 命令 | 说明 |
| ------------------------------------------ | ------------------------- |
| `yarn electron:build --windows nsis:ia32` | Windows 32 位 |
| `yarn electron:build --windows nsis:arm64` | Windows ARM |
| `yarn electron:build --linux deb:armv7l` | Debian armv7l树莓派等 |
| `yarn electron:build --macos dir:arm64` | macOS ARM |
## :computer: 配置开发环境
本项目由 [NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi) 提供 API。
运行本项目
```shell
# 安装依赖
yarn install
# 创建本地环境变量
cp .env.example .env
# 运行(网页端)
yarn serve
# 运行electron
yarn electron:serve
```
本地运行 NeteaseCloudMusicApi或者将 API [部署至 Vercel](#%EF%B8%8F-部署至-vercel)
```shell
# 运行 API (默认 3000 端口)
yarn netease_api:run
```
6. 将 `/dist` 目录下的文件上传到你的 Web 服务器
## ☑️ Todo
@ -238,8 +86,6 @@ yarn netease_api:run
## 灵感来源
API 源代码来自 [Binaryify/NeteaseCloudMusicApi](https://github.com/Binaryify/NeteaseCloudMusicApi)
- [Apple Music](https://music.apple.com)
- [YouTube Music](https://music.youtube.com)
- [Spotify](https://www.spotify.com)
@ -247,14 +93,12 @@ API 源代码来自 [Binaryify/NeteaseCloudMusicApi](https://github.com/Binaryif
## 🖼️ 截图
![lyrics][lyrics-screenshot]
![library-dark][library-dark-screenshot]
![album][album-screenshot]
![home-2][home-2-screenshot]
![artist][artist-screenshot]
![search][search-screenshot]
![home][home-screenshot]
![explore][explore-screenshot]
[![artist][artist-screenshot]](https://music.qier222.com)
[![album][album-screenshot]](https://music.qier222.com)
[![playlist][playlist-screenshot]](https://music.qier222.com)
[![explore][explore-screenshot]](https://music.qier222.com)
[![search][search-screenshot]](https://music.qier222.com)
[![home][home-screenshot]](https://music.qier222.com)
<!-- MARKDOWN LINKS & IMAGES -->
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
@ -263,8 +107,6 @@ API 源代码来自 [Binaryify/NeteaseCloudMusicApi](https://github.com/Binaryif
[artist-screenshot]: images/artist.png
[explore-screenshot]: images/explore.png
[home-screenshot]: images/home.png
[home-2-screenshot]: images/home-2.png
[lyrics-screenshot]: images/lyrics.png
[library-screenshot]: images/library.png
[library-dark-screenshot]: images/library-dark.png
[playlist-screenshot]: images/playlist.png
[search-screenshot]: images/search.png

View file

@ -1,11 +1,7 @@
module.exports = {
presets: [
[
'@vue/cli-plugin-babel/preset',
{
useBuiltIns: 'usage',
shippedProposals: true,
},
],
presets: ["@vue/cli-plugin-babel/preset"],
plugins: [
"@babel/plugin-proposal-nullish-coalescing-operator",
"@babel/plugin-proposal-optional-chaining",
],
};

View file

@ -1,132 +0,0 @@
{
"nodes": {
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1730412360,
"owner": "cachix",
"repo": "devenv",
"rev": "45847cb1f14a6d8cfa86ea943703c54a8798ae7e",
"type": "github"
},
"original": {
"dir": "src/modules",
"owner": "cachix",
"repo": "devenv",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1730272153,
"owner": "nixos",
"repo": "nixpkgs",
"rev": "2d2a9ddbe3f2c00747398f3dc9b05f7f2ebb0f53",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1730327045,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "080166c15633801df010977d9d7474b4a6c549d7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nodejs16": {
"locked": {
"lastModified": 1700230496,
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a71323f68d4377d12c04a5410e214495ec598d4c",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nixpkgs",
"rev": "a71323f68d4377d12c04a5410e214495ec598d4c",
"type": "github"
}
},
"pre-commit-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1730302582,
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "af8a16fe5c264f5e9e18bcee2859b40a656876cf",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"nixpkgs": "nixpkgs",
"nodejs16": "nodejs16",
"pre-commit-hooks": "pre-commit-hooks"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,53 +0,0 @@
{ pkgs, lib, config, inputs, ... }:
let
nodejs16 = import inputs.nodejs16 { system = pkgs.stdenv.system; };
in
{
# https://devenv.sh/basics/
env.GREET = "devenv";
# https://devenv.sh/packages/
packages = [ pkgs.git ] ++ lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin.apple_sdk; [
frameworks.AppKit
]);
# https://devenv.sh/languages/
languages.javascript.enable = true;
languages.javascript.package = nodejs16.pkgs.nodejs_16;
languages.javascript.corepack.enable = true;
# languages.rust.enable = true;
# https://devenv.sh/processes/
# processes.cargo-watch.exec = "cargo-watch";
# https://devenv.sh/services/
# services.postgres.enable = true;
# https://devenv.sh/scripts/
scripts.hello.exec = ''
echo hello from $GREET
'';
enterShell = ''
hello
git --version
'';
# https://devenv.sh/tasks/
# tasks = {
# "myproj:setup".exec = "mytool build";
# "devenv:enterShell".after = [ "myproj:setup" ];
# };
# https://devenv.sh/tests/
enterTest = ''
echo "Running tests"
git --version | grep --color=auto "${pkgs.git.version}"
'';
# https://devenv.sh/pre-commit-hooks/
# pre-commit.hooks.shellcheck.enable = true;
# See full reference at https://devenv.sh/reference/options/
}

View file

@ -1,19 +0,0 @@
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:nixos/nixpkgs/nixpkgs-unstable
nodejs16:
url: github:nixos/nixpkgs/a71323f68d4377d12c04a5410e214495ec598d4c
# https://github.com/cachix/devenv/issues/792#issuecomment-2043166453
impure: true
# If you're using non-OSS software, you can set allowUnfree to true.
# allowUnfree: true
# If you're willing to use a package that's vulnerable
# permittedInsecurePackages:
# - "openssl-1.1.1w"
# If you have more than one devenv you can merge them
#imports:
# - ./backend

View file

@ -1,39 +0,0 @@
services:
YesPlayMusic:
build:
context: .
image: yesplaymusic
container_name: YesPlayMusic
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./docker/nginx.conf.example:/etc/nginx/conf.d/default.conf:ro
ports:
- 80:80
restart: always
depends_on:
- UnblockNeteaseMusic
environment:
- NODE_TLS_REJECT_UNAUTHORIZED=0
networks:
my_network:
UnblockNeteaseMusic:
image: pan93412/unblock-netease-music-enhanced
command: -o kugou kuwo migu bilibili pyncmd -p 80:443 -f 45.127.129.53 -e -
# environment:
# JSON_LOG: true
# LOG_LEVEL: debug
networks:
my_network:
aliases:
- music.163.com
- interface.music.163.com
- interface3.music.163.com
- interface.music.163.com.163jiasu.com
- interface3.music.163.com.163jiasu.com
restart: always
networks:
my_network:
driver: bridge

View file

@ -1,28 +0,0 @@
server {
gzip on;
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location @rewrites {
rewrite ^(.*)$ /index.html last;
}
location /api/ {
proxy_buffers 16 32k;
proxy_buffer_size 128k;
proxy_busy_buffers_size 128k;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $remote_addr;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000/;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 804 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

After

Width:  |  Height:  |  Size: 730 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 389 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

BIN
images/playlist.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 1 MiB

Before After
Before After

View file

@ -1,28 +0,0 @@
#!/usr/bin/bash
# 初始化 .replit 和 replit.nix
if [[ $1 == i ]];then
echo -e 'run = ["bash", "main.sh"]\n\nentrypoint = "main.sh"' >.replit
echo -e "{ pkgs }: {\n\t\tdeps = [\n\t\t\tpkgs.nodejs-16_x\n\t\t\tpkgs.yarn\n\t\t\tpkgs.bashInteractive\n\t\t];\n}" > replit.nix
exit
fi
# 安装
if [[ ! -d api ]];then
mkdir api
git clone https://github.com/Binaryify/NeteaseCloudMusicApi ./api && \
cd api && npm install && cd ..
fi
if [[ ! -d music ]];then
mkdir music
git clone https://github.com/qier222/YesPlayMusic ./music && \
cd music && cp .env.example .env && npm install --force && npm run build && cd ..
fi
# 启动
PID=`ps -ef | grep npm | awk '{print $2}' | sed '$d'`
if [[ ! -z ${PID} ]];then echo $PID | xargs kill;fi
nohup bash -c 'cd api && PORT=35216 node app.js' > api.log 2>&1
nohup bash -c 'npx serve music/dist/' > music.log 2>&1

View file

@ -7,8 +7,7 @@
},
"target": "ES6",
"module": "commonjs",
"allowSyntheticDefaultImports": true,
"jsx": "preserve"
"allowSyntheticDefaultImports": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]

View file

@ -1,9 +1,9 @@
{
"name": "yesplaymusic",
"version": "0.4.9",
"name": "YesPlayMusic",
"version": "0.3.3",
"private": true,
"description": "A third party music player for Netease Music",
"author": "qier222<qier222@outlook.com>",
"description": "A third party music application for Netease Music",
"author": "hawtim<hawtimzhang@gmail.com>",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
@ -18,68 +18,57 @@
"electron:publish": "vue-cli-service electron:build -mwl -p always",
"postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps",
"prettier": "npx prettier --write ./src",
"netease_api:run": "npx NeteaseCloudMusicApi"
"prettier": "npx prettier --write ./src ./script",
"netease_api:run": "cd ./netease_api && npm run start",
"netease_api:pull": "node script/pull.js",
"netease_api:install": "cd ./netease_api && npm install",
"netease_api:setup": "npm run netease_api:pull && npm run netease_api:install"
},
"main": "background.js",
"engines": {
"node": "14 || 16"
},
"dependencies": {
"@unblockneteasemusic/rust-napi": "^0.4.0",
"NeteaseCloudMusicApi": "^4.23.3",
"axios": "^0.26.1",
"@njzy/unblockneteasemusic": "^0.25.3",
"axios": "^0.21.0",
"big-integer": "^1.6.48",
"change-case": "^4.1.2",
"cli-color": "^2.0.0",
"color": "^4.2.3",
"core-js": "^3.6.5",
"crypto-js": "^4.0.0",
"dayjs": "^1.8.36",
"dexie": "^3.0.3",
"discord-rich-presence": "^0.0.8",
"electron": "^13.6.7",
"electron-builder": "^23.0.0",
"electron-context-menu": "^3.1.2",
"electron": "11.0.2",
"electron-context-menu": "^2.3.0",
"electron-debug": "^3.1.0",
"electron-devtools-installer": "^3.2",
"electron-icon-builder": "^2.0.1",
"electron-is-dev": "^2.0.0",
"electron-devtools-installer": "^3.1.1",
"electron-icon-builder": "^1.0.2",
"electron-is-dev": "^1.2.0",
"electron-log": "^4.3.0",
"electron-store": "^8.0.1",
"electron-updater": "^5.0.1",
"esbuild": "^0.20.1",
"esbuild-loader": "^4.0.3",
"electron-store": "^6.0.1",
"electron-updater": "^4.3.5",
"express": "^4.17.1",
"express-fileupload": "^1.2.0",
"express-http-proxy": "^1.6.2",
"extract-zip": "^2.0.1",
"howler": "^2.2.3",
"howler": "^2.2.0",
"js-cookie": "^2.2.1",
"jsbi": "^4.1.0",
"localforage": "^1.9.0",
"lodash": "^4.17.20",
"md5": "^2.3.0",
"mpris-service": "^2.1.2",
"music-metadata": "^7.5.3",
"node-vibrant": "^3.2.1-alpha.1",
"nprogress": "^0.2.0",
"pac-proxy-agent": "^4.1.0",
"plyr": "^3.6.2",
"qrcode": "^1.4.4",
"prettier": "2.1.2",
"register-service-worker": "^1.7.1",
"svg-sprite-loader": "^6.0.11",
"svg-sprite-loader": "^5.0.0",
"tunnel": "^0.0.6",
"vscode-codicons": "^0.0.17",
"vue": "^2.6.11",
"vue-clipboard2": "^0.3.1",
"vue-gtag": "1",
"vue-analytics": "^5.22.1",
"vue-electron": "^1.0.6",
"vue-i18n": "^8.22.0",
"vue-router": "^3.4.3",
"vue-slider-component": "^3.2.5",
"vuex": "^3.4.0",
"x11": "^2.3.0"
"vuex": "^3.4.0"
},
"devDependencies": {
"@types/node": "^17.0.0",
"@sentry/browser": "^5.27.0",
"@sentry/integrations": "^5.27.0",
"@sentry/tracing": "^5.27.0",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-pwa": "~4.5.0",
@ -87,21 +76,13 @@
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^7.9.0",
"eslint-plugin-vue": "^6.2.2",
"husky": "^4.3.0",
"prettier": "2.5.1",
"sass": "^1.26.11",
"sass-loader": "^10.0.2",
"vue-cli-plugin-electron-builder": "~2.1.1",
"vue-cli-plugin-electron-builder": "~2.0.0-rc.4",
"vue-template-compiler": "^2.6.11"
},
"resolutions": {
"icon-gen": "3.0.0",
"degenerator": "2.2.0",
"electron-builder": "^23.0.0"
},
"eslintConfig": {
"root": true,
"env": {
@ -110,8 +91,6 @@
},
"extends": [
"plugin:vue/essential",
"plugin:vue/recommended",
"plugin:prettier/recommended",
"eslint:recommended"
],
"parserOptions": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 816 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 855 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -1,25 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="referrer" content="no-referrer" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="referrer" content="no-referrer" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View file

@ -1,2 +1,2 @@
User-agent: *
Disallow: /
Disallow:

View file

@ -1,7 +0,0 @@
commit_template: 'style: with ${restyler.name}'
restylers:
- prettier
- prettier-json
- prettier-markdown
- prettier-yaml
- whitespace

103
script/pull.js Normal file
View file

@ -0,0 +1,103 @@
// node module
const fs = require("fs");
const https = require("https");
const resolve = require("path").resolve;
const join = require("path").resolve;
const extract = require("extract-zip");
// 函数参数
const dest = resolve(__dirname, "../");
const fileName = "NeteaseCloudMusicApi-master.zip";
const options = {
hostname: "github.91chifun.workers.dev",
path: `//https://github.com/Binaryify/NeteaseCloudMusicApi/archive/master.zip`,
};
// 完整的流程控制
/**
* 1. 检查本地文件是否已有
* 2. 下载默认/指定版本的 zip 压缩包等待下载
* 3. 解压缩
* 4. 进入目录安装依赖 npm install
*/
function fix2(number) {
return number.toFixed(2);
}
async function download(options, fileName, callback) {
return await new Promise((resolve, reject) => {
const destPath = join(__dirname, "../" + fileName);
// Check if exist
if (fs.existsSync(destPath)) return resolve(destPath);
const file = fs.createWriteStream(destPath);
const request = https.get(options, (res) => {
let len = res.headers && parseInt(res.headers["content-length"], 10);
let cur = 0;
// 1048576 - bytes in 1Megabyte
const MEGA = 1048576;
let total = 0;
if (len) {
total = len / MEGA;
}
if (!len) {
console.log(
"Downloading, but can not get content-length, please be patient."
);
}
res.on("data", (chunk) => {
if (len) {
cur += chunk.length;
console.log(
`Downloading ${fix2((100.0 * cur) / len)}% ${fix2(
cur / MEGA
)}/${fix2(total)}mb`
);
}
});
res.on("end", () => {
callback("Downloading complete!");
});
res.pipe(file);
file.on("finish", () => {
file.close(() => {
callback("File wrote complete!");
resolve(destPath);
});
});
file.on("error", (err) => {
fs.unlink(destPath);
reject(err);
});
request.on("error", (err) => {
console.log("Error: " + err.message);
});
});
});
}
async function unzip(source, target) {
try {
await extract(source, {
dir: target,
});
console.log("Extraction complete");
return true;
} catch (err) {
// handle any errors
if (err.message === "end of central directory record signature not found") {
console.log("Not a full_downloaded zip file, removed!");
fs.unlinkSync(source);
}
return false;
}
}
// Download process
download(options, fileName, (text) => {
console.log(text);
}).then((path) => {
console.log(path);
// Unzip process
return unzip(path, dest);
});

View file

@ -1,43 +1,39 @@
<template>
<div id="app" :class="{ 'user-select-none': userSelectNone }">
<Scrollbar v-show="!showLyrics" ref="scrollbar" />
<Navbar v-show="showNavbar" ref="navbar" />
<main
ref="main"
:style="{ overflow: enableScrolling ? 'auto' : 'hidden' }"
@scroll="handleScroll"
>
<div id="app">
<Navbar ref="navbar" />
<main v-show="!this.$store.state.showLyrics">
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</main>
<transition name="slide-up">
<Player v-if="enablePlayer" v-show="showPlayer" ref="player" />
</transition>
<Player
v-if="this.$store.state.player.enabled"
ref="player"
v-show="showPlayer"
/></transition>
<Toast />
<ModalAddTrackToPlaylist v-if="isAccountLoggedIn" />
<ModalNewPlaylist v-if="isAccountLoggedIn" />
<transition v-if="enablePlayer" name="slide-up">
<Lyrics v-show="showLyrics" />
<transition name="slide-up" v-if="this.$store.state.player.enabled">
<Lyrics v-show="this.$store.state.showLyrics" />
</transition>
</div>
</template>
<script>
import ModalAddTrackToPlaylist from './components/ModalAddTrackToPlaylist.vue';
import ModalNewPlaylist from './components/ModalNewPlaylist.vue';
import Scrollbar from './components/Scrollbar.vue';
import Navbar from './components/Navbar.vue';
import Player from './components/Player.vue';
import Toast from './components/Toast.vue';
import { ipcRenderer } from './electron/ipcRenderer';
import { isAccountLoggedIn, isLooseLoggedIn } from '@/utils/auth';
import Lyrics from './views/lyrics.vue';
import { mapState } from 'vuex';
import ModalAddTrackToPlaylist from "./components/ModalAddTrackToPlaylist.vue";
import ModalNewPlaylist from "./components/ModalNewPlaylist.vue";
import Navbar from "./components/Navbar.vue";
import Player from "./components/Player.vue";
import Toast from "./components/Toast.vue";
import { ipcRenderer } from "./electron/ipcRenderer";
import { isAccountLoggedIn } from "@/utils/auth";
import Lyrics from "./views/lyrics.vue";
export default {
name: 'App',
name: "App",
components: {
Navbar,
Player,
@ -45,104 +41,163 @@ export default {
ModalAddTrackToPlaylist,
ModalNewPlaylist,
Lyrics,
Scrollbar,
},
data() {
return {
isElectron: process.env.IS_ELECTRON, // true || undefined
userSelectNone: false,
};
},
computed: {
...mapState(['showLyrics', 'settings', 'player', 'enableScrolling']),
isAccountLoggedIn() {
return isAccountLoggedIn();
},
showPlayer() {
return (
[
'mv',
'loginUsername',
'login',
'loginAccount',
'lastfmCallback',
].includes(this.$route.name) === false
["mv", "loginUsername", "login", "loginAccount"].includes(
this.$route.name
) === false
);
},
enablePlayer() {
return this.player.enabled && this.$route.name !== 'lastfmCallback';
},
showNavbar() {
return this.$route.name !== 'lastfmCallback';
},
},
created() {
if (this.isElectron) ipcRenderer(this);
window.addEventListener('keydown', this.handleKeydown);
this.fetchData();
if (this.isElectron) {
ipcRenderer(this);
}
window.addEventListener("keydown", this.handleKeydown);
},
methods: {
handleKeydown(e) {
if (e.code === 'Space') {
if (e.target.tagName === 'INPUT') return false;
if (this.$route.name === 'mv') return false;
if (e.code === "Space") {
if (e.target.tagName === "INPUT") return false;
if (this.$route.name === "mv") return false;
e.preventDefault();
this.player.playOrPause();
this.$refs.player.play();
}
},
fetchData() {
if (!isLooseLoggedIn()) return;
this.$store.dispatch('fetchLikedSongs');
this.$store.dispatch('fetchLikedSongsWithDetails');
this.$store.dispatch('fetchLikedPlaylist');
if (isAccountLoggedIn()) {
this.$store.dispatch('fetchLikedAlbums');
this.$store.dispatch('fetchLikedArtists');
this.$store.dispatch('fetchLikedMVs');
this.$store.dispatch('fetchCloudDisk');
}
},
handleScroll() {
this.$refs.scrollbar.handleScroll();
},
},
};
</script>
<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);
--color-primary-bg-for-transparent: rgba(189, 207, 255, 0.28);
--color-secondary-bg-for-transparent: rgba(209, 209, 214, 0.28);
}
[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: rgba(34, 34, 34, 0.86);
--color-primary-bg-for-transparent: rgba(255, 255, 255, 0.12);
--color-secondary-bg-for-transparent: rgba(255, 255, 255, 0.08);
}
#app {
width: 100%;
transition: all 0.4s;
}
#app,
input {
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;
}
body {
background-color: var(--color-body-bg);
}
html {
overflow-y: overlay;
min-width: 768px;
}
main {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
overflow: auto;
padding: 64px 10vw 96px 10vw;
box-sizing: border-box;
scrollbar-width: none; // firefox
margin-top: 84px;
margin-bottom: 96px;
padding: {
right: 10vw;
left: 10vw;
}
}
@media (max-width: 1336px) {
main {
padding: 64px 5vw 96px 5vw;
padding: 0 5vw;
}
}
main::-webkit-scrollbar {
width: 0px;
select,
button {
font-family: inherit;
}
button {
background: none;
border: none;
cursor: pointer;
}
input,
button {
&:focus {
outline: none;
}
}
a {
color: inherit;
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
/* Let's get this party started */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
border-left: 1px solid rgba(128, 128, 128, 0.18);
background: var(--color-body-bg);
}
::-webkit-scrollbar-thumb {
-webkit-border-radius: 10px;
border-radius: 10px;
background: rgba(128, 128, 128, 0.38);
}
[data-theme="dark"] ::-webkit-scrollbar-thumb {
background: var(--color-secondary-bg);
}
.slide-up-enter-active,
.slide-up-leave-active {
transition: transform 0.4s;
transition: all 0.4s;
}
.slide-up-enter,
.slide-up-leave-to {
.slide-up-enter, .slide-up-leave-to /* .fade-leave-active below version 2.1.8 */ {
transform: translateY(100%);
}
[data-electron="yes"] {
button,
.navigation-links a,
.playlist-info .description {
cursor: default !important;
}
}
</style>

View file

@ -1,6 +1,5 @@
import request from '@/utils/request';
import { mapTrackPlayableStatus } from '@/utils/common';
import { cacheAlbum, getAlbumFromCache } from '@/utils/db';
import request from "@/utils/request";
import { mapTrackPlayableStatus } from "@/utils/common";
/**
* 获取专辑内容
@ -8,23 +7,15 @@ import { cacheAlbum, getAlbumFromCache } from '@/utils/db';
* @param {number} id
*/
export function getAlbum(id) {
const fetchLatest = () => {
return request({
url: '/album',
method: 'get',
params: {
id,
},
}).then(data => {
cacheAlbum(id, data);
data.songs = mapTrackPlayableStatus(data.songs);
return data;
});
};
fetchLatest();
return getAlbumFromCache(id).then(result => {
return result ?? fetchLatest();
return request({
url: "/album",
method: "get",
params: {
id,
},
}).then((data) => {
data.songs = mapTrackPlayableStatus(data.songs);
return data;
});
}
@ -41,8 +32,8 @@ export function getAlbum(id) {
*/
export function newAlbums(params) {
return request({
url: '/album/new',
method: 'get',
url: "/album/new",
method: "get",
params,
});
}
@ -55,8 +46,8 @@ export function newAlbums(params) {
*/
export function albumDynamicDetail(id) {
return request({
url: '/album/detail/dynamic',
method: 'get',
url: "/album/detail/dynamic",
method: "get",
params: { id, timestamp: new Date().getTime() },
});
}
@ -72,8 +63,8 @@ export function albumDynamicDetail(id) {
*/
export function likeAAlbum(params) {
return request({
url: '/album/sub',
method: 'post',
url: "/album/sub",
method: "post",
params,
});
}

View file

@ -1,7 +1,5 @@
import request from '@/utils/request';
import { mapTrackPlayableStatus } from '@/utils/common';
import { isAccountLoggedIn } from '@/utils/auth';
import { getTrackDetail } from '@/api/track';
import request from "@/utils/request";
import { mapTrackPlayableStatus } from "@/utils/common";
/**
* 获取歌手单曲
@ -10,19 +8,13 @@ import { getTrackDetail } from '@/api/track';
*/
export function getArtist(id) {
return request({
url: '/artists',
method: 'get',
url: "/artists",
method: "get",
params: {
id,
timestamp: new Date().getTime(),
},
}).then(async data => {
if (!isAccountLoggedIn()) {
const trackIDs = data.hotSongs.map(t => t.id);
const tracks = await getTrackDetail(trackIDs.join(','));
data.hotSongs = tracks.songs;
return data;
}
}).then((data) => {
data.hotSongs = mapTrackPlayableStatus(data.hotSongs);
return data;
});
@ -41,8 +33,8 @@ export function getArtist(id) {
*/
export function getArtistAlbum(params) {
return request({
url: '/artist/album',
method: 'get',
url: "/artist/album",
method: "get",
params,
});
}
@ -58,14 +50,12 @@ export function getArtistAlbum(params) {
* @param {number=} type
*/
export function toplistOfArtists(type = null) {
let params = {};
if (type) {
params.type = type;
}
return request({
url: '/toplist/artist',
method: 'get',
params,
url: "/toplist/artist",
method: "get",
params: {
type,
},
});
}
/**
@ -77,8 +67,8 @@ export function toplistOfArtists(type = null) {
*/
export function artistMv(params) {
return request({
url: '/artist/mv',
method: 'get',
url: "/artist/mv",
method: "get",
params,
});
}
@ -94,8 +84,8 @@ export function artistMv(params) {
*/
export function followAArtist(params) {
return request({
url: '/artist/sub',
method: 'post',
url: "/artist/sub",
method: "post",
params,
});
}
@ -108,8 +98,8 @@ export function followAArtist(params) {
*/
export function similarArtists(id) {
return request({
url: '/simi/artist',
method: 'post',
url: "/simi/artist",
method: "post",
params: { id },
});
}

View file

@ -1,4 +1,4 @@
import request from '@/utils/request';
import request from "@/utils/request";
/**
* 手机登录
@ -14,12 +14,11 @@ import request from '@/utils/request';
*/
export function loginWithPhone(params) {
return request({
url: '/login/cellphone',
method: 'post',
url: "/login/cellphone",
method: "post",
params,
});
}
/**
* 邮箱登录
* - email: 163 网易邮箱
@ -32,60 +31,12 @@ export function loginWithPhone(params) {
*/
export function loginWithEmail(params) {
return request({
url: '/login',
method: 'post',
url: "/login",
method: "post",
params,
});
}
/**
* 二维码key生成接口
*/
export function loginQrCodeKey() {
return request({
url: '/login/qr/key',
method: 'get',
params: {
timestamp: new Date().getTime(),
},
});
}
/**
* 二维码生成接口
* 说明: 调用此接口传入上一个接口生成的key可生成二维码图片的base64和二维码信息,
* 可使用base64展示图片,或者使用二维码信息内容自行使用第三方二维码生产库渲染二维码
* @param {Object} params
* @param {string} params.key
* @param {string=} params.qrimg 传入后会额外返回二维码图片base64编码
*/
export function loginQrCodeCreate(params) {
return request({
url: '/login/qr/create',
method: 'get',
params: {
...params,
timestamp: new Date().getTime(),
},
});
}
/**
* 二维码检测扫码状态接口
* 说明: 轮询此接口可获取二维码扫码状态,800为二维码过期,801为等待扫码,802为待确认,803为授权登录成功(803状态码下会返回cookies)
* @param {string} key
*/
export function loginQrCodeCheck(key) {
return request({
url: '/login/qr/check',
method: 'get',
params: {
key,
timestamp: new Date().getTime(),
},
});
}
/**
* 刷新登录
* 说明 : 调用此接口 , 可刷新登录状态
@ -93,8 +44,8 @@ export function loginQrCodeCheck(key) {
*/
export function refreshCookie() {
return request({
url: '/login/refresh',
method: 'post',
url: "/login/refresh",
method: "post",
});
}
@ -104,7 +55,7 @@ export function refreshCookie() {
*/
export function logout() {
return request({
url: '/logout',
method: 'post',
url: "/logout",
method: "post",
});
}

View file

@ -1,80 +0,0 @@
// Last.fm API documents 👉 https://www.last.fm/api
import axios from 'axios';
import md5 from 'crypto-js/md5';
const apiKey = process.env.VUE_APP_LASTFM_API_KEY;
const apiSharedSecret = process.env.VUE_APP_LASTFM_API_SHARED_SECRET;
const baseUrl = window.location.origin;
const url = 'https://ws.audioscrobbler.com/2.0/';
const sign = params => {
const sortParamsKeys = Object.keys(params).sort();
const sortedParams = sortParamsKeys.reduce((acc, key) => {
acc[key] = params[key];
return acc;
}, {});
let signature = '';
for (const [key, value] of Object.entries(sortedParams)) {
signature += `${key}${value}`;
}
return md5(signature + apiSharedSecret).toString();
};
export function auth() {
const url = process.env.IS_ELECTRON
? `https://www.last.fm/api/auth/?api_key=${apiKey}&cb=${baseUrl}/#/lastfm/callback`
: `https://www.last.fm/api/auth/?api_key=${apiKey}&cb=${baseUrl}/lastfm/callback`;
window.open(url);
}
export function authGetSession(token) {
const signature = md5(
`api_key${apiKey}methodauth.getSessiontoken${token}${apiSharedSecret}`
).toString();
return axios({
url,
method: 'GET',
params: {
method: 'auth.getSession',
format: 'json',
api_key: apiKey,
api_sig: signature,
token,
},
});
}
export function trackUpdateNowPlaying(params) {
params.api_key = apiKey;
params.method = 'track.updateNowPlaying';
params.sk = JSON.parse(localStorage.getItem('lastfm'))['key'];
const signature = sign(params);
return axios({
url,
method: 'POST',
params: {
...params,
api_sig: signature,
format: 'json',
},
});
}
export function trackScrobble(params) {
params.api_key = apiKey;
params.method = 'track.scrobble';
params.sk = JSON.parse(localStorage.getItem('lastfm'))['key'];
const signature = sign(params);
return axios({
url,
method: 'POST',
params: {
...params,
api_sig: signature,
format: 'json',
},
});
}

View file

@ -1,4 +1,4 @@
import request from '@/utils/request';
import request from "@/utils/request";
/**
* 获取 mv 数据
@ -9,8 +9,8 @@ import request from '@/utils/request';
*/
export function mvDetail(mvid) {
return request({
url: '/mv/detail',
method: 'get',
url: "/mv/detail",
method: "get",
params: {
mvid,
timestamp: new Date().getTime(),
@ -30,8 +30,8 @@ export function mvDetail(mvid) {
*/
export function mvUrl(params) {
return request({
url: '/mv/url',
method: 'get',
url: "/mv/url",
method: "get",
params,
});
}
@ -43,8 +43,8 @@ export function mvUrl(params) {
*/
export function simiMv(mvid) {
return request({
url: '/simi/mv',
method: 'get',
url: "/simi/mv",
method: "get",
params: { mvid },
});
}
@ -62,8 +62,8 @@ export function simiMv(mvid) {
export function likeAMV(params) {
params.timestamp = new Date().getTime();
return request({
url: '/mv/sub',
method: 'post',
url: "/mv/sub",
method: "post",
params,
});
}

View file

@ -1,5 +1,5 @@
import request from '@/utils/request';
import { mapTrackPlayableStatus } from '@/utils/common';
import request from "@/utils/request";
import { mapTrackPlayableStatus } from "@/utils/common";
/**
* 搜索
@ -18,33 +18,12 @@ import { mapTrackPlayableStatus } from '@/utils/common';
*/
export function search(params) {
return request({
url: '/search',
method: 'get',
url: "/search",
method: "get",
params,
}).then(data => {
}).then((data) => {
if (data.result?.song !== undefined)
data.result.song.songs = mapTrackPlayableStatus(data.result.song.songs);
return data;
});
}
export function personalFM() {
return request({
url: '/personal_fm',
method: 'get',
params: {
timestamp: new Date().getTime(),
},
});
}
export function fmTrash(id) {
return request({
url: '/fm_trash',
method: 'post',
params: {
timestamp: new Date().getTime(),
id,
},
});
}

View file

@ -1,5 +1,5 @@
import request from '@/utils/request';
import { mapTrackPlayableStatus } from '@/utils/common';
import request from "@/utils/request";
import { mapTrackPlayableStatus } from "@/utils/common";
/**
* 推荐歌单
@ -11,8 +11,8 @@ import { mapTrackPlayableStatus } from '@/utils/common';
*/
export function recommendPlaylist(params) {
return request({
url: '/personalized',
method: 'get',
url: "/personalized",
method: "get",
params,
});
}
@ -24,12 +24,9 @@ export function recommendPlaylist(params) {
*/
export function dailyRecommendPlaylist(params) {
return request({
url: '/recommend/resource',
method: 'get',
params: {
params,
timestamp: Date.now(),
},
url: "/recommend/resource",
method: "get",
params,
});
}
/**
@ -46,16 +43,14 @@ export function getPlaylistDetail(id, noCache = false) {
let params = { id };
if (noCache) params.timestamp = new Date().getTime();
return request({
url: '/playlist/detail',
method: 'get',
url: "/playlist/detail",
method: "get",
params,
}).then(data => {
if (data.playlist) {
data.playlist.tracks = mapTrackPlayableStatus(
data.playlist.tracks,
data.privileges || []
);
}
}).then((data) => {
data.playlist.tracks = mapTrackPlayableStatus(
data.playlist.tracks,
data.privileges || []
);
return data;
});
}
@ -72,8 +67,8 @@ export function getPlaylistDetail(id, noCache = false) {
*/
export function highQualityPlaylist(params) {
return request({
url: '/top/playlist/highquality',
method: 'get',
url: "/top/playlist/highquality",
method: "get",
params,
});
}
@ -91,8 +86,8 @@ export function highQualityPlaylist(params) {
*/
export function topPlaylist(params) {
return request({
url: '/top/playlist',
method: 'get',
url: "/top/playlist",
method: "get",
params,
});
}
@ -103,8 +98,8 @@ export function topPlaylist(params) {
*/
export function playlistCatlist() {
return request({
url: '/playlist/catlist',
method: 'get',
url: "/playlist/catlist",
method: "get",
});
}
@ -114,8 +109,8 @@ export function playlistCatlist() {
*/
export function toplists() {
return request({
url: '/toplist',
method: 'get',
url: "/toplist",
method: "get",
});
}
@ -131,8 +126,8 @@ export function toplists() {
export function subscribePlaylist(params) {
params.timestamp = new Date().getTime();
return request({
url: '/playlist/subscribe',
method: 'post',
url: "/playlist/subscribe",
method: "post",
params,
});
}
@ -145,8 +140,8 @@ export function subscribePlaylist(params) {
*/
export function deletePlaylist(id) {
return request({
url: '/playlist/delete',
method: 'post',
url: "/playlist/delete",
method: "post",
params: { id },
});
}
@ -165,8 +160,8 @@ export function deletePlaylist(id) {
export function createPlaylist(params) {
params.timestamp = new Date().getTime();
return request({
url: '/playlist/create',
method: 'post',
url: "/playlist/create",
method: "post",
params,
});
}
@ -183,47 +178,8 @@ export function createPlaylist(params) {
export function addOrRemoveTrackFromPlaylist(params) {
params.timestamp = new Date().getTime();
return request({
url: '/playlist/tracks',
method: 'post',
params,
});
}
/**
* 每日推荐歌曲
* 说明 : 调用此接口 , 可获得每日推荐歌曲 ( 需要登录 )
* @param {Object} params
* @param {string} params.op
* @param {string} params.pid
*/
export function dailyRecommendTracks() {
return request({
url: '/recommend/songs',
method: 'get',
params: { timestamp: new Date().getTime() },
}).then(result => {
result.data.dailySongs = mapTrackPlayableStatus(
result.data.dailySongs,
result.data.privileges
);
return result;
});
}
/**
* 心动模式/智能播放
* 说明 : 登录后调用此接口 , 可获取心动模式/智能播放列表 必选参数 : id : 歌曲 id
* - id : 歌曲 id
* - pid : 歌单 id
* - sid : 要开始播放的歌曲的 id (可选参数)
* @param {Object} params
* @param {number=} params.id
* @param {number=} params.pid
*/
export function intelligencePlaylist(params) {
return request({
url: '/playmode/intelligence/list',
method: 'get',
url: "/playlist/tracks",
method: "post",
params,
});
}

View file

@ -1,13 +1,6 @@
import store from '@/store';
import request from '@/utils/request';
import { mapTrackPlayableStatus } from '@/utils/common';
import {
cacheTrackDetail,
getTrackDetailFromCache,
cacheLyric,
getLyricFromCache,
} from '@/utils/db';
import store from "@/store";
import request from "@/utils/request";
import { mapTrackPlayableStatus } from "@/utils/common";
/**
* 获取音乐 url
* 说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口, 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url,
@ -15,85 +8,51 @@ import {
* @param {string} id - 音乐的 id例如 id=405998841,33894312
*/
export function getMP3(id) {
const getBr = () => {
// 当返回的 quality >= 400000时就会优先返回 hi-res
const quality = store.state.settings?.musicQuality ?? '320000';
return quality === 'flac' ? '350000' : quality;
};
let br =
store.state.settings?.musicQuality !== undefined
? store.state.settings.musicQuality
: 320000;
return request({
url: '/song/url',
method: 'get',
url: "/song/url",
method: "get",
params: {
id,
br: getBr(),
br,
},
});
}
/**
* 获取歌曲详情
* 说明 : 调用此接口 , 传入音乐 id(支持多个 id, , 隔开), 可获得歌曲详情(注意:歌曲封面现在需要通过专辑内容接口获取)
* @param {string} ids - 音乐 id, 例如 ids=405998841,33894312
*/
export function getTrackDetail(ids) {
const fetchLatest = () => {
return request({
url: '/song/detail',
method: 'get',
params: {
ids,
},
}).then(data => {
data.songs.map(song => {
const privileges = data.privileges.find(t => t.id === song.id);
cacheTrackDetail(song, privileges);
});
data.songs = mapTrackPlayableStatus(data.songs, data.privileges);
return data;
});
};
fetchLatest();
let idsInArray = [String(ids)];
if (typeof ids === 'string') {
idsInArray = ids.split(',');
}
return getTrackDetailFromCache(idsInArray).then(result => {
if (result) {
result.songs = mapTrackPlayableStatus(result.songs, result.privileges);
}
return result ?? fetchLatest();
return request({
url: "/song/detail",
method: "get",
params: {
ids,
},
}).then((data) => {
data.songs = mapTrackPlayableStatus(data.songs, data.privileges);
return data;
});
}
/**
* 获取歌词
* 说明 : 调用此接口 , 传入音乐 id 可获得对应音乐的歌词 ( 不需要登录 )
* @param {number} id - 音乐 id
*/
export function getLyric(id) {
const fetchLatest = () => {
return request({
url: '/lyric',
method: 'get',
params: {
id,
},
}).then(result => {
cacheLyric(id, result);
return result;
});
};
fetchLatest();
return getLyricFromCache(id).then(result => {
return result ?? fetchLatest();
return request({
url: "/lyric",
method: "get",
params: {
id,
},
});
}
/**
* 新歌速递
* 说明 : 调用此接口 , 可获取新歌速递
@ -101,14 +60,13 @@ export function getLyric(id) {
*/
export function topSong(type) {
return request({
url: '/top/song',
method: 'get',
url: "/top/song",
method: "get",
params: {
type,
},
});
}
/**
* 喜欢音乐
* 说明 : 调用此接口 , 传入音乐 id, 可喜欢该音乐
@ -121,8 +79,8 @@ export function topSong(type) {
export function likeATrack(params) {
params.timestamp = new Date().getTime();
return request({
url: '/like',
method: 'get',
url: "/like",
method: "get",
params,
});
}
@ -141,8 +99,8 @@ export function likeATrack(params) {
export function scrobble(params) {
params.timestamp = new Date().getTime();
return request({
url: '/scrobble',
method: 'get',
url: "/scrobble",
method: "get",
params,
});
}

View file

@ -1,4 +1,4 @@
import request from '@/utils/request';
import request from "@/utils/request";
/**
* 获取用户详情
@ -8,25 +8,10 @@ import request from '@/utils/request';
*/
export function userDetail(uid) {
return request({
url: '/user/detail',
method: 'get',
url: "/user/detail",
method: "get",
params: {
uid,
timestamp: new Date().getTime(),
},
});
}
/**
* 获取账号详情
* 说明 : 登录后调用此接口 ,可获取用户账号信息
*/
export function userAccount() {
return request({
url: '/user/account',
method: 'get',
params: {
timestamp: new Date().getTime(),
},
});
}
@ -44,25 +29,8 @@ export function userAccount() {
*/
export function userPlaylist(params) {
return request({
url: '/user/playlist',
method: 'get',
params,
});
}
/**
* 获取用户播放记录
* 说明 : 登录后调用此接口 , 传入用户 id, 可获取用户播放记录
* - uid : 用户 id
* - type : type=1 时只返回 weekData, type=0 时返回 allData
* @param {Object} params
* @param {number} params.uid
* @param {number} params.type
*/
export function userPlayHistory(params) {
return request({
url: '/user/record',
method: 'get',
url: "/user/playlist",
method: "get",
params,
});
}
@ -75,8 +43,8 @@ export function userPlayHistory(params) {
*/
export function userLikedSongsIDs(uid) {
return request({
url: '/likelist',
method: 'get',
url: "/likelist",
method: "get",
params: {
uid,
timestamp: new Date().getTime(),
@ -92,8 +60,8 @@ export function userLikedSongsIDs(uid) {
*/
export function dailySignin(type = 0) {
return request({
url: '/daily_signin',
method: 'post',
url: "/daily_signin",
method: "post",
params: {
type,
timestamp: new Date().getTime(),
@ -104,18 +72,17 @@ export function dailySignin(type = 0) {
/**
* 获取收藏的专辑需要登录
* 说明 : 调用此接口可获取到用户收藏的专辑
* - limit : 返回数量 , 默认为 25
* - offset : 偏移数量用于分页 , :( 页数 -1)*25, 其中 25 limit 的值 , 默认为 0
* - limit : 返回数量 , 默认为 30
* - offset : 偏移数量用于分页 , :( 页数 -1)*30, 其中 30 limit 的值 , 默认为 0
* @param {Object} params
* @param {number} params.limit
* @param {number=} params.offset
*/
export function likedAlbums(params) {
export function likedAlbums() {
return request({
url: '/album/sublist',
method: 'get',
url: "/album/sublist",
method: "get",
params: {
limit: params.limit,
timestamp: new Date().getTime(),
},
});
@ -125,12 +92,11 @@ export function likedAlbums(params) {
* 获取收藏的歌手需要登录
* 说明 : 调用此接口可获取到用户收藏的歌手
*/
export function likedArtists(params) {
export function likedArtists() {
return request({
url: '/artist/sublist',
method: 'get',
url: "/artist/sublist",
method: "get",
params: {
limit: params.limit,
timestamp: new Date().getTime(),
},
});
@ -140,82 +106,12 @@ export function likedArtists(params) {
* 获取收藏的MV需要登录
* 说明 : 调用此接口可获取到用户收藏的MV
*/
export function likedMVs(params) {
export function likedMVs() {
return request({
url: '/mv/sublist',
method: 'get',
params: {
limit: params.limit,
timestamp: new Date().getTime(),
},
});
}
/**
* 上传歌曲到云盘需要登录
*/
export function uploadSong(file) {
let formData = new FormData();
formData.append('songFile', file);
return request({
url: '/cloud',
method: 'post',
url: "/mv/sublist",
method: "get",
params: {
timestamp: new Date().getTime(),
},
data: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
timeout: 200000,
}).catch(error => {
alert(`上传失败Error: ${error}`);
});
}
/**
* 获取云盘歌曲需要登录
* 说明 : 登录后调用此接口 , 可获取云盘数据 , 获取的数据没有对应 url, 需要再调用一 /song/url 获取 url
* - limit : 返回数量 , 默认为 200
* - offset : 偏移数量用于分页 , :( 页数 -1)*200, 其中 200 limit 的值 , 默认为 0
* @param {Object} params
* @param {number} params.limit
* @param {number=} params.offset
*/
export function cloudDisk(params = {}) {
params.timestamp = new Date().getTime();
return request({
url: '/user/cloud',
method: 'get',
params,
});
}
/**
* 获取云盘歌曲详情需要登录
*/
export function cloudDiskTrackDetail(id) {
return request({
url: '/user/cloud/detail',
method: 'get',
params: {
timestamp: new Date().getTime(),
id,
},
});
}
/**
* 删除云盘歌曲需要登录
* @param {Array} id
*/
export function cloudDiskTrackDelete(id) {
return request({
url: '/user/cloud/del',
method: 'get',
params: {
timestamp: new Date().getTime(),
id,
},
});
}

View file

@ -1,135 +0,0 @@
@font-face {
font-family: 'Barlow';
font-weight: normal;
src: url('~@/assets/fonts/Barlow-Regular.woff2') format('woff2'),
url('~@/assets/fonts/Barlow-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Barlow';
font-weight: medium;
src: url('~@/assets/fonts/Barlow-Medium.woff2') format('woff2'),
url('~@/assets/fonts/Barlow-Medium.ttf') format('truetype');
}
@font-face {
font-family: 'Barlow';
font-weight: 600;
src: url('~@/assets/fonts/Barlow-SemiBold.woff2') format('woff2'),
url('~@/assets/fonts/Barlow-SemiBold.ttf') format('truetype');
}
@font-face {
font-family: 'Barlow';
font-weight: bold;
src: url('~@/assets/fonts/Barlow-Bold.woff2') format('woff2'),
url('~@/assets/fonts/Barlow-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'Barlow';
font-weight: 800;
src: url('~@/assets/fonts/Barlow-ExtraBold.woff2') format('woff2'),
url('~@/assets/fonts/Barlow-ExtraBold.ttf') format('truetype');
}
@font-face {
font-family: 'Barlow';
font-weight: 900;
src: url('~@/assets/fonts/Barlow-Black.woff2') format('woff2'),
url('~@/assets/fonts/Barlow-Black.ttf') format('truetype');
}
: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);
--color-primary-bg-for-transparent: rgba(189, 207, 255, 0.28);
--color-secondary-bg-for-transparent: rgba(209, 209, 214, 0.28);
--html-overflow-y: overlay;
}
[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: rgba(34, 34, 34, 0.86);
--color-primary-bg-for-transparent: rgba(255, 255, 255, 0.12);
--color-secondary-bg-for-transparent: rgba(255, 255, 255, 0.08);
}
#app,
input {
font-family: 'Barlow', ui-sans-serif, system-ui, -apple-system,
BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei,
Source Han Sans SC, Noto Sans CJK SC, WenQuanYi Micro Hei, sans-serif,
microsoft uighur;
}
body {
background-color: var(--color-body-bg);
}
html {
overflow-y: var(--html-overflow-y);
min-width: 768px;
overscroll-behavior: none;
}
select,
button {
font-family: inherit;
}
button {
background: none;
border: none;
cursor: pointer;
user-select: none;
}
input,
button {
&:focus {
outline: none;
}
}
a {
color: inherit;
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
[data-electron='yes'] {
button,
.navigation-links a,
.playlist-info .description {
cursor: default !important;
}
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: transparent;
border-left: 1px solid rgba(128, 128, 128, 0.18);
background: var(--color-body-bg);
}
::-webkit-scrollbar-thumb {
-webkit-border-radius: 10px;
border-radius: 10px;
background: rgba(128, 128, 128, 0.38);
}
[data-theme='dark'] ::-webkit-scrollbar-thumb {
background: var(--color-secondary-bg);
}
.user-select-none {
user-select: none;
}

View file

@ -265,17 +265,17 @@ a.plyr__control::before {
display: none;
}
.plyr [data-plyr='airplay'],
.plyr [data-plyr='captions'],
.plyr [data-plyr='fullscreen'],
.plyr [data-plyr='pip'] {
.plyr [data-plyr="airplay"],
.plyr [data-plyr="captions"],
.plyr [data-plyr="fullscreen"],
.plyr [data-plyr="pip"] {
display: none;
}
.plyr--airplay-supported [data-plyr='airplay'],
.plyr--captions-enabled [data-plyr='captions'],
.plyr--fullscreen-enabled [data-plyr='fullscreen'],
.plyr--pip-supported [data-plyr='pip'] {
.plyr--airplay-supported [data-plyr="airplay"],
.plyr--captions-enabled [data-plyr="captions"],
.plyr--fullscreen-enabled [data-plyr="fullscreen"],
.plyr--pip-supported [data-plyr="pip"] {
display: inline-block;
}
@ -288,11 +288,11 @@ a.plyr__control::before {
transition: transform 0.3s ease;
}
.plyr__menu .plyr__control[aria-expanded='true'] svg {
.plyr__menu .plyr__control[aria-expanded="true"] svg {
transform: rotate(90deg);
}
.plyr__menu .plyr__control[aria-expanded='true'] .plyr__tooltip {
.plyr__menu .plyr__control[aria-expanded="true"] .plyr__tooltip {
display: none;
}
@ -327,7 +327,7 @@ a.plyr__control::before {
border: var(--plyr-menu-arrow-size, 4px) solid transparent;
border-top-color: rgba(255, 255, 255, 0.9);
border-top-color: var(--plyr-menu-background, rgba(255, 255, 255, 0.9));
content: '';
content: "";
height: 0;
position: absolute;
right: calc(((18px / 2) + calc(10px * 0.7)) - (4px / 2));
@ -341,18 +341,18 @@ a.plyr__control::before {
width: 0;
}
.plyr__menu__container [role='menu'] {
.plyr__menu__container [role="menu"] {
padding: calc(10px * 0.7);
padding: calc(var(--plyr-control-spacing, 10px) * 0.7);
}
.plyr__menu__container [role='menuitem'],
.plyr__menu__container [role='menuitemradio'] {
.plyr__menu__container [role="menuitem"],
.plyr__menu__container [role="menuitemradio"] {
margin-top: 2px;
}
.plyr__menu__container [role='menuitem']:first-child,
.plyr__menu__container [role='menuitemradio']:first-child {
.plyr__menu__container [role="menuitem"]:first-child,
.plyr__menu__container [role="menuitemradio"]:first-child {
margin-top: 0;
}
@ -386,7 +386,7 @@ a.plyr__control::before {
.plyr__menu__container .plyr__control::after {
border: 4px solid transparent;
border: var(--plyr-menu-item-arrow-size, 4px) solid transparent;
content: '';
content: "";
position: absolute;
top: 50%;
transform: translateY(-50%);
@ -441,7 +441,7 @@ a.plyr__control::before {
background: var(--plyr-menu-back-border-color, #dcdfe5);
box-shadow: 0 1px 0 #fff;
box-shadow: 0 1px 0 var(--plyr-menu-back-border-shadow-color, #fff);
content: '';
content: "";
height: 1px;
left: 0;
margin-top: calc(calc(10px * 0.7) / 2);
@ -457,19 +457,19 @@ a.plyr__control::before {
border-right-color: currentColor;
}
.plyr__menu__container .plyr__control[role='menuitemradio'] {
.plyr__menu__container .plyr__control[role="menuitemradio"] {
padding-left: calc(10px * 0.7);
padding-left: calc(var(--plyr-control-spacing, 10px) * 0.7);
}
.plyr__menu__container .plyr__control[role='menuitemradio']::after,
.plyr__menu__container .plyr__control[role='menuitemradio']::before {
.plyr__menu__container .plyr__control[role="menuitemradio"]::after,
.plyr__menu__container .plyr__control[role="menuitemradio"]::before {
border-radius: 100%;
}
.plyr__menu__container .plyr__control[role='menuitemradio']::before {
.plyr__menu__container .plyr__control[role="menuitemradio"]::before {
background: rgba(0, 0, 0, 0.1);
content: '';
content: "";
display: block;
flex-shrink: 0;
height: 16px;
@ -479,7 +479,7 @@ a.plyr__control::before {
width: 16px;
}
.plyr__menu__container .plyr__control[role='menuitemradio']::after {
.plyr__menu__container .plyr__control[role="menuitemradio"]::after {
background: #fff;
border: 0;
height: 6px;
@ -492,7 +492,7 @@ a.plyr__control::before {
}
.plyr__menu__container
.plyr__control[role='menuitemradio'][aria-checked='true']::before {
.plyr__control[role="menuitemradio"][aria-checked="true"]::before {
background: #00b3ff;
background: var(
--plyr-control-toggle-checked-background,
@ -501,14 +501,14 @@ a.plyr__control::before {
}
.plyr__menu__container
.plyr__control[role='menuitemradio'][aria-checked='true']::after {
.plyr__control[role="menuitemradio"][aria-checked="true"]::after {
opacity: 1;
transform: translateY(-50%) scale(1);
}
.plyr__menu__container
.plyr__control[role='menuitemradio'].plyr__tab-focus::before,
.plyr__menu__container .plyr__control[role='menuitemradio']:hover::before {
.plyr__control[role="menuitemradio"].plyr__tab-focus::before,
.plyr__menu__container .plyr__control[role="menuitemradio"]:hover::before {
background: rgba(35, 40, 47, 0.1);
}
@ -524,7 +524,7 @@ a.plyr__control::before {
pointer-events: none;
}
.plyr--full-ui input[type='range'] {
.plyr--full-ui input[type="range"] {
-webkit-appearance: none;
background: 0 0;
border: 0;
@ -547,7 +547,7 @@ a.plyr__control::before {
width: 100%;
}
.plyr--full-ui input[type='range']::-webkit-slider-runnable-track {
.plyr--full-ui input[type="range"]::-webkit-slider-runnable-track {
background: 0 0;
border: 0;
border-radius: calc(5px / 2);
@ -566,7 +566,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui input[type='range']::-webkit-slider-thumb {
.plyr--full-ui input[type="range"]::-webkit-slider-thumb {
background: #fff;
background: var(--plyr-range-thumb-background, #fff);
border: 0;
@ -596,7 +596,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui input[type='range']::-moz-range-track {
.plyr--full-ui input[type="range"]::-moz-range-track {
background: 0 0;
border: 0;
border-radius: calc(5px / 2);
@ -608,7 +608,7 @@ a.plyr__control::before {
user-select: none;
}
.plyr--full-ui input[type='range']::-moz-range-thumb {
.plyr--full-ui input[type="range"]::-moz-range-thumb {
background: #fff;
background: var(--plyr-range-thumb-background, #fff);
border: 0;
@ -628,7 +628,7 @@ a.plyr__control::before {
width: var(--plyr-range-thumb-height, 13px);
}
.plyr--full-ui input[type='range']::-moz-range-progress {
.plyr--full-ui input[type="range"]::-moz-range-progress {
background: currentColor;
border-radius: calc(5px / 2);
border-radius: calc(var(--plyr-range-track-height, 5px) / 2);
@ -636,7 +636,7 @@ a.plyr__control::before {
height: var(--plyr-range-track-height, 5px);
}
.plyr--full-ui input[type='range']::-ms-track {
.plyr--full-ui input[type="range"]::-ms-track {
background: 0 0;
border: 0;
border-radius: calc(5px / 2);
@ -650,7 +650,7 @@ a.plyr__control::before {
color: transparent;
}
.plyr--full-ui input[type='range']::-ms-fill-upper {
.plyr--full-ui input[type="range"]::-ms-fill-upper {
background: 0 0;
border: 0;
border-radius: calc(5px / 2);
@ -663,7 +663,7 @@ a.plyr__control::before {
user-select: none;
}
.plyr--full-ui input[type='range']::-ms-fill-lower {
.plyr--full-ui input[type="range"]::-ms-fill-lower {
background: 0 0;
border: 0;
border-radius: calc(5px / 2);
@ -677,7 +677,7 @@ a.plyr__control::before {
background: currentColor;
}
.plyr--full-ui input[type='range']::-ms-thumb {
.plyr--full-ui input[type="range"]::-ms-thumb {
background: #fff;
background: var(--plyr-range-thumb-background, #fff);
border: 0;
@ -698,20 +698,20 @@ a.plyr__control::before {
margin-top: 0;
}
.plyr--full-ui input[type='range']::-ms-tooltip {
.plyr--full-ui input[type="range"]::-ms-tooltip {
display: none;
}
.plyr--full-ui input[type='range']:focus {
.plyr--full-ui input[type="range"]:focus {
outline: 0;
}
.plyr--full-ui input[type='range']::-moz-focus-outer {
.plyr--full-ui input[type="range"]::-moz-focus-outer {
border: 0;
}
.plyr--full-ui
input[type='range'].plyr__tab-focus::-webkit-slider-runnable-track {
input[type="range"].plyr__tab-focus::-webkit-slider-runnable-track {
outline-color: #00b3ff;
outline-color: var(
--plyr-tab-focus-color,
@ -722,7 +722,7 @@ a.plyr__control::before {
outline-width: 3px;
}
.plyr--full-ui input[type='range'].plyr__tab-focus::-moz-range-track {
.plyr--full-ui input[type="range"].plyr__tab-focus::-moz-range-track {
outline-color: #00b3ff;
outline-color: var(
--plyr-tab-focus-color,
@ -733,7 +733,7 @@ a.plyr__control::before {
outline-width: 3px;
}
.plyr--full-ui input[type='range'].plyr__tab-focus::-ms-track {
.plyr--full-ui input[type="range"].plyr__tab-focus::-ms-track {
outline-color: #00b3ff;
outline-color: var(
--plyr-tab-focus-color,
@ -769,7 +769,7 @@ a.plyr__control::before {
}
.plyr__time + .plyr__time::before {
content: '\2044';
content: "\2044";
margin-right: 10px;
margin-right: var(--plyr-control-spacing, 10px);
}
@ -821,7 +821,7 @@ a.plyr__control::before {
var(--plyr-tooltip-background, rgba(255, 255, 255, 0.9));
bottom: calc(4px * -1);
bottom: calc(var(--plyr-tooltip-arrow-size, 4px) * -1);
content: '';
content: "";
height: 0;
left: 50%;
position: absolute;
@ -906,7 +906,7 @@ a.plyr__control::before {
position: relative;
}
.plyr__progress input[type='range'],
.plyr__progress input[type="range"],
.plyr__progress__buffer {
margin-left: calc(13px * -0.5);
margin-left: calc(var(--plyr-range-thumb-height, 13px) * -0.5);
@ -916,7 +916,7 @@ a.plyr__control::before {
width: calc(100% + var(--plyr-range-thumb-height, 13px));
}
.plyr__progress input[type='range'] {
.plyr__progress input[type="range"] {
position: relative;
z-index: 2;
}
@ -1024,7 +1024,7 @@ a.plyr__control::before {
width: 20%;
}
.plyr__volume input[type='range'] {
.plyr__volume input[type="range"] {
margin-left: calc(10px / 2);
margin-left: calc(var(--plyr-control-spacing, 10px) / 2);
margin-right: calc(10px / 2);
@ -1054,7 +1054,7 @@ a.plyr__control::before {
.plyr--audio .plyr__control.plyr__tab-focus,
.plyr--audio .plyr__control:hover,
.plyr--audio .plyr__control[aria-expanded='true'] {
.plyr--audio .plyr__control[aria-expanded="true"] {
background: #00b3ff;
background: var(
--plyr-audio-control-background-hover,
@ -1064,7 +1064,7 @@ a.plyr__control::before {
color: var(--plyr-audio-control-color-hover, #fff);
}
.plyr--full-ui.plyr--audio input[type='range']::-webkit-slider-runnable-track {
.plyr--full-ui.plyr--audio input[type="range"]::-webkit-slider-runnable-track {
background-color: rgba(193, 200, 209, 0.6);
background-color: var(
--plyr-audio-range-track-background,
@ -1072,7 +1072,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--audio input[type='range']::-moz-range-track {
.plyr--full-ui.plyr--audio input[type="range"]::-moz-range-track {
background-color: rgba(193, 200, 209, 0.6);
background-color: var(
--plyr-audio-range-track-background,
@ -1080,7 +1080,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--audio input[type='range']::-ms-track {
.plyr--full-ui.plyr--audio input[type="range"]::-ms-track {
background-color: rgba(193, 200, 209, 0.6);
background-color: var(
--plyr-audio-range-track-background,
@ -1088,7 +1088,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--audio input[type='range']:active::-webkit-slider-thumb {
.plyr--full-ui.plyr--audio input[type="range"]:active::-webkit-slider-thumb {
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
0 0 0 3px rgba(35, 40, 47, 0.1);
box-shadow: var(
@ -1100,7 +1100,7 @@ a.plyr__control::before {
var(--plyr-audio-range-thumb-active-shadow-color, rgba(35, 40, 47, 0.1));
}
.plyr--full-ui.plyr--audio input[type='range']:active::-moz-range-thumb {
.plyr--full-ui.plyr--audio input[type="range"]:active::-moz-range-thumb {
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
0 0 0 3px rgba(35, 40, 47, 0.1);
box-shadow: var(
@ -1112,7 +1112,7 @@ a.plyr__control::before {
var(--plyr-audio-range-thumb-active-shadow-color, rgba(35, 40, 47, 0.1));
}
.plyr--full-ui.plyr--audio input[type='range']:active::-ms-thumb {
.plyr--full-ui.plyr--audio input[type="range"]:active::-ms-thumb {
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
0 0 0 3px rgba(35, 40, 47, 0.1);
box-shadow: var(
@ -1207,7 +1207,7 @@ a.plyr__control::before {
.plyr--video .plyr__control.plyr__tab-focus,
.plyr--video .plyr__control:hover,
.plyr--video .plyr__control[aria-expanded='true'] {
.plyr--video .plyr__control[aria-expanded="true"] {
background: #00b3ff;
background: var(
--plyr-video-control-background-hover,
@ -1258,7 +1258,7 @@ a.plyr__control::before {
display: block;
}
.plyr--full-ui.plyr--video input[type='range']::-webkit-slider-runnable-track {
.plyr--full-ui.plyr--video input[type="range"]::-webkit-slider-runnable-track {
background-color: rgba(255, 255, 255, 0.25);
background-color: var(
--plyr-video-range-track-background,
@ -1266,7 +1266,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--video input[type='range']::-moz-range-track {
.plyr--full-ui.plyr--video input[type="range"]::-moz-range-track {
background-color: rgba(255, 255, 255, 0.25);
background-color: var(
--plyr-video-range-track-background,
@ -1274,7 +1274,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--video input[type='range']::-ms-track {
.plyr--full-ui.plyr--video input[type="range"]::-ms-track {
background-color: rgba(255, 255, 255, 0.25);
background-color: var(
--plyr-video-range-track-background,
@ -1282,7 +1282,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--video input[type='range']:active::-webkit-slider-thumb {
.plyr--full-ui.plyr--video input[type="range"]:active::-webkit-slider-thumb {
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
0 0 0 3px rgba(255, 255, 255, 0.5);
box-shadow: var(
@ -1297,7 +1297,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--video input[type='range']:active::-moz-range-thumb {
.plyr--full-ui.plyr--video input[type="range"]:active::-moz-range-thumb {
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
0 0 0 3px rgba(255, 255, 255, 0.5);
box-shadow: var(
@ -1312,7 +1312,7 @@ a.plyr__control::before {
);
}
.plyr--full-ui.plyr--video input[type='range']:active::-ms-thumb {
.plyr--full-ui.plyr--video input[type="range"]:active::-ms-thumb {
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
0 0 0 3px rgba(255, 255, 255, 0.5);
box-shadow: var(
@ -1713,7 +1713,7 @@ a.plyr__control::before {
var(--plyr-tooltip-background, rgba(255, 255, 255, 0.9));
bottom: calc(4px * -1);
bottom: calc(var(--plyr-tooltip-arrow-size, 4px) * -1);
content: '';
content: "";
height: 0;
left: 50%;
position: absolute;

View file

@ -89,7 +89,7 @@
}
.nyancat .vue-slider-dot-handle {
background: url('/img/logos/nyancat.gif');
background: url("/img/logos/nyancat.gif");
background-size: 36px;
width: 36px;
height: 24px;
@ -100,11 +100,6 @@
visibility: visible;
}
.nyancat-stop .vue-slider-dot-handle {
background-image: url('/img/logos/nyancat-stop.png');
transition: 300ms;
}
/* lyrics */
.lyrics-page .vue-slider-rail {
background-color: rgba(128, 128, 128, 0.18);
@ -126,19 +121,10 @@
display: none;
}
body[data-theme='dark'] .lyrics-page .vue-slider-process {
body[data-theme="dark"] .lyrics-page .vue-slider-process {
background-color: #fafafa;
}
body[data-theme='dark'] .lyrics-page .vue-slider-dot-handle {
background-color: #fff;
}
.lyrics-page[data-theme='dark'] .vue-slider-rail {
background-color: rgba(255, 255, 255, 0.18);
}
.lyrics-page[data-theme='dark'] .vue-slider-process,
.lyrics-page[data-theme='dark'] .vue-slider-dot-handle {
body[data-theme="dark"] .lyrics-page .vue-slider-dot-handle {
background-color: #fff;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1 +0,0 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 32 32" height="32px" id="Layer_1" version="1.1" viewBox="0 0 32 32" width="32px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M14.77,23.795L5.185,14.21c-0.879-0.879-0.879-2.317,0-3.195l0.8-0.801c0.877-0.878,2.316-0.878,3.194,0 l7.315,7.315l7.316-7.315c0.878-0.878,2.317-0.878,3.194,0l0.8,0.801c0.879,0.878,0.879,2.316,0,3.195l-9.587,9.585 c-0.471,0.472-1.104,0.682-1.723,0.647C15.875,24.477,15.243,24.267,14.77,23.795z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 666 B

View file

@ -1 +0,0 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="arrow-up" class="svg-inline--fa fa-arrow-up fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"></path></svg>

Before

Width:  |  Height:  |  Size: 487 B

View file

@ -1 +0,0 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 32 32" height="32px" id="Layer_1" version="1.1" viewBox="0 0 32 32" width="32px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M18.221,7.206l9.585,9.585c0.879,0.879,0.879,2.317,0,3.195l-0.8,0.801c-0.877,0.878-2.316,0.878-3.194,0 l-7.315-7.315l-7.315,7.315c-0.878,0.878-2.317,0.878-3.194,0l-0.8-0.801c-0.879-0.878-0.879-2.316,0-3.195l9.587-9.585 c0.471-0.472,1.103-0.682,1.723-0.647C17.115,6.524,17.748,6.734,18.221,7.206z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 668 B

View file

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="circle" class="svg-inline--fa fa-circle fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z"></path></svg>

After

Width:  |  Height:  |  Size: 301 B

View file

@ -1 +0,0 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="caret-down" class="svg-inline--fa fa-caret-down fa-w-10" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path fill="currentColor" d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"></path></svg>

Before

Width:  |  Height:  |  Size: 359 B

View file

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="expand-alt" class="svg-inline--fa fa-expand-alt fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M212.686 315.314L120 408l32.922 31.029c15.12 15.12 4.412 40.971-16.97 40.971h-112C10.697 480 0 469.255 0 456V344c0-21.382 25.803-32.09 40.922-16.971L72 360l92.686-92.686c6.248-6.248 16.379-6.248 22.627 0l25.373 25.373c6.249 6.248 6.249 16.378 0 22.627zm22.628-118.628L328 104l-32.922-31.029C279.958 57.851 290.666 32 312.048 32h112C437.303 32 448 42.745 448 56v112c0 21.382-25.803 32.09-40.922 16.971L376 152l-92.686 92.686c-6.248 6.248-16.379 6.248-22.627 0l-25.373-25.373c-6.249-6.248-6.249-16.378 0-22.627z"></path></svg>

After

Width:  |  Height:  |  Size: 749 B

View file

@ -1 +0,0 @@
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="radio-alt" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="svg-inline--fa fa-radio-alt fa-w-16 fa-7x"><path fill="currentColor" d="M209 368h-64a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16zm144 56a72 72 0 1 0-72-72 72.09 72.09 0 0 0 72 72zm96-296H212.5l288.83-81.21a16 16 0 0 0 11.07-19.74l-4.33-15.38A16 16 0 0 0 488.33.6L47.68 124.5A64 64 0 0 0 1 186.11V448a64 64 0 0 0 64 64h384a64 64 0 0 0 64-64V192a64 64 0 0 0-64-64zm16 320a16 16 0 0 1-16 16H65a16 16 0 0 1-16-16V256h416zM113 336h128a16 16 0 0 0 16-16v-16a16 16 0 0 0-16-16H113a16 16 0 0 0-16 16v16a16 16 0 0 0 16 16z" class=""></path></svg>

Before

Width:  |  Height:  |  Size: 733 B

View file

@ -1,3 +0,0 @@
<svg width="14" height="14" viewBox="0 0 14 14" data-darkreader-inline-fill="" xmlns="http://www.w3.org/2000/svg">
<path id="path" d="M1 11L3 11L3 13C3 13.55 3.45 14 4 14C4.55 14 5 13.55 5 13L5 10C5 9.45 4.55 9 4 9L1 9C0.45 9 0 9.45 0 10C0 10.55 0.45 11 1 11ZM11 3L11 1C11 0.45 10.55 0 10 0C9.45 0 9 0.45 9 1L9 4C9 4.54 9.45 5 10 5L13 5C13.55 5 14 4.54 14 4C14 3.45 13.55 3 13 3L11 3Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 396 B

View file

@ -1,3 +0,0 @@
<svg width="14" height="14" viewBox="0 0 14 14" data-darkreader-inline-fill="" xmlns="http://www.w3.org/2000/svg">
<path id="path" d="M1 9C0.45 9 0 9.45 0 10L0 13C0 13.55 0.45 14 1 14L4 14C4.55 14 5 13.55 5 13C5 12.45 4.55 12 4 12L2 12L2 10C2 9.45 1.55 9 1 9ZM9 1C9 1.54 9.45 2 10 2L12 2L12 4C12 4.54 12.45 5 13 5C13.55 5 14 4.54 14 4L14 1C14 0.45 13.55 0 13 0L10 0C9.45 0 9 0.45 9 1Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 396 B

View file

@ -1,7 +1,8 @@
import Vue from 'vue';
import SvgIcon from '@/components/SvgIcon';
import Vue from "vue";
import SvgIcon from "@/components/SvgIcon";
Vue.component('svg-icon', SvgIcon);
const requireAll = requireContext => requireContext.keys().map(requireContext);
const req = require.context('./', true, /\.svg$/);
Vue.component("svg-icon", SvgIcon);
const requireAll = (requireContext) =>
requireContext.keys().map(requireContext);
const req = require.context("./", true, /\.svg$/);
requireAll(req);

View file

@ -1 +0,0 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="sign-in-alt" class="svg-inline--fa fa-sign-in-alt fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M416 448h-84c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h84c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32h-84c-6.6 0-12-5.4-12-12V76c0-6.6 5.4-12 12-12h84c53 0 96 43 96 96v192c0 53-43 96-96 96zm-47-201L201 79c-15-15-41-4.5-41 17v96H24c-13.3 0-24 10.7-24 24v96c0 13.3 10.7 24 24 24h136v96c0 21.5 26 32 41 17l168-168c9.3-9.4 9.3-24.6 0-34z"></path></svg>

Before

Width:  |  Height:  |  Size: 579 B

View file

@ -1 +0,0 @@
<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg height="512px" id="Layer_1" style="enable-background:new 0 0 512 512;" version="1.1" viewBox="0 0 512 512" width="512px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M417.4,224H288V94.6c0-16.9-14.3-30.6-32-30.6c-17.7,0-32,13.7-32,30.6V224H94.6C77.7,224,64,238.3,64,256 c0,17.7,13.7,32,30.6,32H224v129.4c0,16.9,14.3,30.6,32,30.6c17.7,0,32-13.7,32-30.6V288h129.4c16.9,0,30.6-14.3,30.6-32 C448,238.3,434.3,224,417.4,224z"/></svg>

Before

Width:  |  Height:  |  Size: 618 B

View file

@ -1,2 +0,0 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="sort-amount-up" class="svg-inline--fa fa-sort-amount-up fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M304 416h-64a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h64a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM16 160h48v304a16 16 0 0 0 16 16h32a16 16 0 0 0 16-16V160h48c14.21 0 21.38-17.24 11.31-27.31l-80-96a16 16 0 0 0-22.62 0l-80 96C-5.35 142.74 1.77 160 16 160zm416 0H240a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h192a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm-64 128H240a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM496 32H240a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h256a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"></path></svg>

Before

Width:  |  Height:  |  Size: 784 B

View file

@ -1 +0,0 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="thumbs-down" class="svg-inline--fa fa-thumbs-down fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M0 56v240c0 13.255 10.745 24 24 24h80c13.255 0 24-10.745 24-24V56c0-13.255-10.745-24-24-24H24C10.745 32 0 42.745 0 56zm40 200c0-13.255 10.745-24 24-24s24 10.745 24 24-10.745 24-24 24-24-10.745-24-24zm272 256c-20.183 0-29.485-39.293-33.931-57.795-5.206-21.666-10.589-44.07-25.393-58.902-32.469-32.524-49.503-73.967-89.117-113.111a11.98 11.98 0 0 1-3.558-8.521V59.901c0-6.541 5.243-11.878 11.783-11.998 15.831-.29 36.694-9.079 52.651-16.178C256.189 17.598 295.709.017 343.995 0h2.844c42.777 0 93.363.413 113.774 29.737 8.392 12.057 10.446 27.034 6.148 44.632 16.312 17.053 25.063 48.863 16.382 74.757 17.544 23.432 19.143 56.132 9.308 79.469l.11.11c11.893 11.949 19.523 31.259 19.439 49.197-.156 30.352-26.157 58.098-59.553 58.098H350.723C358.03 364.34 384 388.132 384 430.548 384 504 336 512 312 512z"></path></svg>

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,3 @@
<svg fill="currentColor" viewBox="0 0 1024 500">
<path d="M152.1 236.2c-3.5-12.1-7.8-33.2-7.8-33.2h-.5s-4.3 21.1-7.8 33.2l-11.1 37.5H163zM616 96H336v320h280c13.3 0 24-10.7 24-24V120c0-13.3-10.7-24-24-24zm-24 120c0 6.6-5.4 12-12 12h-11.4c-6.9 23.6-21.7 47.4-42.7 69.9 8.4 6.4 17.1 12.5 26.1 18 5.5 3.4 7.3 10.5 4.1 16.2l-7.9 13.9c-3.4 5.9-10.9 7.8-16.7 4.3-12.6-7.8-24.5-16.1-35.4-24.9-10.9 8.7-22.7 17.1-35.4 24.9-5.8 3.5-13.3 1.6-16.7-4.3l-7.9-13.9c-3.2-5.6-1.4-12.8 4.2-16.2 9.3-5.7 18-11.7 26.1-18-7.9-8.4-14.9-17-21-25.7-4-5.7-2.2-13.6 3.7-17.1l6.5-3.9 7.3-4.3c5.4-3.2 12.4-1.7 16 3.4 5 7 10.8 14 17.4 20.9 13.5-14.2 23.8-28.9 30-43.2H412c-6.6 0-12-5.4-12-12v-16c0-6.6 5.4-12 12-12h64v-16c0-6.6 5.4-12 12-12h16c6.6 0 12 5.4 12 12v16h64c6.6 0 12 5.4 12 12zM0 120v272c0 13.3 10.7 24 24 24h280V96H24c-13.3 0-24 10.7-24 24zm58.9 216.1L116.4 167c1.7-4.9 6.2-8.1 11.4-8.1h32.5c5.1 0 9.7 3.3 11.4 8.1l57.5 169.1c2.6 7.8-3.1 15.9-11.4 15.9h-22.9a12 12 0 0 1-11.5-8.6l-9.4-31.9h-60.2l-9.1 31.8c-1.5 5.1-6.2 8.7-11.5 8.7H70.3c-8.2 0-14-8.1-11.4-15.9z"></path>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

Some files were not shown because too many files have changed in this diff Show more