Skip to content

Commit

Permalink
✨ feat: 播放模式支持点击切换
Browse files Browse the repository at this point in the history
  • Loading branch information
imsyy committed Jan 10, 2024
1 parent 309c323 commit a57a18b
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 56 deletions.
59 changes: 27 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
- 本项目采用 [Vue 3](https://cn.vuejs.org/) 全家桶和 [Naïve UI](https://www.naiveui.com/) 组件库及 [Electron](https://www.electronjs.org/zh/docs/latest/) 开发
- 支持网页端与客户端,由于设备有限,目前仅适配 `Win`,其他平台可自行解决兼容性后进行构建
- 仅对移动端做了基础适配,**不保证功能全部可用**

> 请注意,本程序不打算开发移动端,也不会对移动端进行完美适配,仅保证基础可用性
- 欢迎各位大佬 `Star` 😍

## 👀 Demo
Expand All @@ -30,38 +32,31 @@

## 🎉 功能

- 支持扫码登录
- 支持手机号登录
- 自动进行每日签到及云贝签到
- 封面主题色自适应
- 本地歌曲管理及分类(建议先使用 [音乐标签](https://www.cnblogs.com/vinlxc/p/11347744.html) 进行匹配后再使用)
- **支持播放部分无版权歌曲(可能会与原曲不匹配,客户端独占功能)**
- 下载歌曲(最高支持 Hi-Res)
- 新建歌单及歌单编辑
- 收藏 / 取消收藏歌单或歌手
- 每日推荐歌曲
- 私人 FM
- 云盘音乐上传
- 云盘内歌曲播放
- 云盘内歌曲纠正
- 云盘歌曲删除
- 支持逐字歌词
- 歌词滚动以及歌词翻译
- MV 与视频播放
- 音乐频谱显示( 暂时去除,还待完善 )
- 音乐渐入渐出
- 支持 PWA
- 支持评论区及评论点赞
- 明暗模式自动 / 手动切换
- ~~移动端基础适配~~
- ~~`i18n` 支持~~

#### 待办

- [ ] 完善音乐频谱
- [ ] 添加桌面歌词
- [ ] 多种布局方式
- [ ] 发表评论
- ✨ 支持扫码登录
- 📱 支持手机号登录
- 📅 自动进行每日签到及云贝签到
- 🎨 封面主题色自适应
- 📁 本地歌曲管理及分类(建议先使用 [音乐标签](https://www.cnblogs.com/vinlxc/p/11347744.html) 进行匹配后再使用)
- 🎵 **支持播放部分无版权歌曲(可能会与原曲不匹配,客户端独占功能)**
- ⬇️ 下载歌曲(最高支持 Hi-Res)
- ➕ 新建歌单及歌单编辑
- ❤️ 收藏 / 取消收藏歌单或歌手
- 🎶 每日推荐歌曲
- 📻 私人 FM
- ☁️ 云盘音乐上传
- 📂 云盘内歌曲播放
- 🔄 云盘内歌曲纠正
- 🗑️ 云盘歌曲删除
- 📝 支持逐字歌词
- 🔄 歌词滚动以及歌词翻译
- 📹 MV 与视频播放
- 🎶 音乐频谱显示
- ⏭️ 音乐渐入渐出
- 🔄 支持 PWA
- 💬 支持评论区及评论点赞
- 🌓 明暗模式自动 / 手动切换
- 📱 移动端基础适配
- ~~🌐 `i18n` 支持~~

## 🖼️ Screenshots

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"home": "https://imsyy.top",
"github": "https://github.com/imsyy/SPlayer",
"repository": "github:imsyy/SPlayer",
"license": "AGPL-3.0",
"license-file": "LICENSE",
"engines": {
"node": ">=18.16.0",
"npm": ">=9.6.7",
Expand Down
13 changes: 13 additions & 0 deletions src/api/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,19 @@ export const getSearchSuggest = (keywords, mobile = false) => {
});
};

/**
* 默认搜索关键词
*/
export const getSearchDefault = () => {
return axios({
method: "GET",
url: "/search/default",
params: {
timestamp: new Date().getTime(),
},
});
};

/**
* 搜索结果
* @param {string} keywords - 搜索关键词
Expand Down
56 changes: 34 additions & 22 deletions src/components/Player/MainControl.vue
Original file line number Diff line number Diff line change
Expand Up @@ -221,22 +221,25 @@
trigger="hover"
@select="playModeChange"
>
<div class="mode hidden" @click.stop @dblclick.stop>
<n-icon size="22">
<SvgIcon
:icon="
playHeartbeatMode
? 'heartbit'
: playSongMode === 'normal'
? 'repeat-list'
: playSongMode === 'random'
? 'shuffle'
: 'repeat-song'
"
isSpecial
/>
</n-icon>
</div>
<n-icon
class="mode hidden"
size="22"
@click.stop="playModeChange(false)"
@dblclick.stop
>
<SvgIcon
:icon="
playHeartbeatMode
? 'heartbit'
: playSongMode === 'normal'
? 'repeat-list'
: playSongMode === 'random'
? 'shuffle'
: 'repeat-song'
"
isSpecial
/>
</n-icon>
</n-dropdown>
<!-- 倍速 -->
<n-popover :show-arrow="false" trigger="hover" placement="top-end" raw>
Expand Down Expand Up @@ -390,16 +393,16 @@ const renderIcon = (icon, isSpecial = false) => {
// 播放模式数据
const playModeOptions = ref([
{
label: "列表循环",
key: "normal",
icon: renderIcon("repeat-list", true),
},
{
label: "单曲循环",
key: "repeat",
icon: renderIcon("repeat-song", true),
},
{
label: "列表循环",
key: "normal",
icon: renderIcon("repeat-list", true),
},
{
label: "随机播放",
key: "random",
Expand Down Expand Up @@ -504,6 +507,11 @@ const changePlayIndexDebounce = debounce(async (type, id) => {
// 播放模式切换
const playModeChange = (mode) => {
const modeMap = {
normal: "random",
random: "shuffle",
shuffle: "normal",
};
// 关闭心动模式
if (playHeartbeatMode.value) {
playHeartbeatMode.value = false;
Expand All @@ -513,7 +521,11 @@ const playModeChange = (mode) => {
playListOld.value = [];
}
// 切换模式
playSongMode.value = mode;
if (mode) {
playSongMode.value = mode;
} else {
playSongMode.value = modeMap[playSongMode.value] || "normal";
}
};
// 音量条鼠标滚动
Expand Down
42 changes: 40 additions & 2 deletions src/components/Search/SearchInp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
v-model:value="searchInputValue"
:class="searchInputFocus ? 'input focus' : 'input'"
:input-props="{ autoComplete: false }"
:placeholder="searchPlaceholder"
:allow-input="noSideSpace"
placeholder="搜索音乐 / 视频"
round
clearable
@focus="searchInputToFocus"
Expand Down Expand Up @@ -43,6 +43,7 @@
import { storeToRefs } from "pinia";
import { useRouter } from "vue-router";
import { getSongDetail } from "@/api/song";
import { getSearchDefault } from "@/api/search";
import { siteData, siteStatus, musicData } from "@/stores";
import { addSongToNext, initPlayer } from "@/utils/Player";
import formatData from "@/utils/formatData";
Expand All @@ -55,8 +56,12 @@ const { searchHistory } = storeToRefs(data);
const { playSongData } = storeToRefs(music);
const { searchInputFocus } = storeToRefs(status);
// 搜索框数据
const searchInpRef = ref(null);
const searchInputValue = ref("");
const searchInterval = ref(null);
const searchRealkeyword = ref(null);
const searchPlaceholder = ref("搜索音乐 / 视频");
// 搜索框输入限制
const noSideSpace = (value) => !value.startsWith(" ");
Expand All @@ -80,6 +85,25 @@ const setSearchHistory = (name) => {
}
};
// 更换搜索框关键词
const updatePlaceholder = async () => {
try {
const result = await getSearchDefault();
searchPlaceholder.value = result.data.showKeyword;
searchRealkeyword.value = result.data.realkeyword;
} catch (error) {
console.error("搜索关键词获取失败:", error);
searchPlaceholder.value = "搜索音乐 / 视频";
}
};
// 更新搜索框关键词
const changePlaceholder = () => {
updatePlaceholder();
// 5分钟
searchInterval.value = setInterval(updatePlaceholder, 5 * 60 * 1000);
};
// 关闭搜索
const closeSearch = () => {
// 取消聚焦状态
Expand Down Expand Up @@ -107,9 +131,15 @@ const toPlaySong = async (id) => {
// 前往搜索
const toSearch = (val, type = "song") => {
if (!val) return false;
// 未输入内容且不存在推荐
if (!val && searchPlaceholder.value === "搜索音乐 / 视频") return false;
if (!val && searchPlaceholder.value !== "搜索音乐 / 视频" && searchRealkeyword.value) {
val = searchRealkeyword.value?.trim();
}
// 取消聚焦状态
closeSearch();
// 更新推荐
updatePlaceholder();
// 触发测试
if (Number(val) === 114514) return router.push("/test");
// 判断类型
Expand Down Expand Up @@ -161,6 +191,14 @@ const toSearch = (val, type = "song") => {
break;
}
};
onMounted(() => {
changePlaceholder();
});
onBeforeUnmount(() => {
clearInterval(searchInterval.value);
});
</script>
<style lang="scss" scoped>
Expand Down
5 changes: 5 additions & 0 deletions src/utils/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,11 @@ const getPlaySongName = () => {
return songName + " - " + songArtist;
};

/**
* 播放所有歌曲
* @param {Array} playlist - 包含歌曲信息的数组
* @param {string} mode - 播放模式
*/
export const playAllSongs = async (playlist, mode = "normal") => {
try {
// pinia
Expand Down

0 comments on commit a57a18b

Please sign in to comment.