This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
appcat
/
sonist
Archived
1
0
Fork 0

引入ID3读写模块

2.x
宇天 2020-11-18 18:32:20 +08:00
parent ea4bdddffa
commit 2f746df5fd
7 changed files with 269 additions and 225 deletions

View File

@ -16,6 +16,7 @@
"dependencies": { "dependencies": {
"crypto.js": "^2.0.2", "crypto.js": "^2.0.2",
"iofs": "^1.5.1", "iofs": "^1.5.1",
"music-metadata": "^7.5.0",
"sqlite3": "^5.0.0" "sqlite3": "^5.0.0"
}, },
"devDependencies": { "devDependencies": {

File diff suppressed because one or more lines are too long

View File

@ -5,199 +5,210 @@
* @date 2018/12/16 17:15:07 * @date 2018/12/16 17:15:07
*/ */
@import './var.scss';
@import "./var.scss";
.app { .app {
position:relative; position: relative;
display:flex;flex-direction:column; display: flex;
width:100%;height:100%; flex-direction: column;
background:rgba(0, 0, 0, .3); width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
// //
.title-bar { .title-bar {
position:relative; position: relative;
display:flex; display: flex;
align-items:center; align-items: center;
z-index:9; z-index: 9;
height:26px; height: 26px;
.btn-box { .btn-box {
display:inline-flex;; display: inline-flex;
width:auto;height:12px;padding:0 8px; width: auto;
height: 12px;
padding: 0 8px;
.item { .item {
display:inline-flex; display: inline-flex;
width:12px;height:12px; width: 12px;
margin:0 3px; height: 12px;
background:url(/images/btn-grey.svg) no-repeat;background-size:cover; margin: 0 3px;
background: url(/images/btn-grey.svg) no-repeat;
background-size: cover;
} }
&.focus { &.focus {
.quit {background-image:url(/images/btn-close.svg);} .quit {
.min {background-image:url(/images/btn-mini.svg);} background-image: url(/images/btn-close.svg);
}
.min {
background-image: url(/images/btn-mini.svg);
}
// .max {background-image:url(/images/btn-maxi.svg);} // .max {background-image:url(/images/btn-maxi.svg);}
} }
&:hover { &:hover {
.quit {background-image:url(/images/btn-close_a.svg);} .quit {
.min {background-image:url(/images/btn-mini_a.svg);} background-image: url(/images/btn-close_a.svg);
}
.min {
background-image: url(/images/btn-mini_a.svg);
}
// .max {background-image:url(/images/btn-maxi_a.svg);} // .max {background-image:url(/images/btn-maxi_a.svg);}
} }
} }
} }
.main-body { .main-body {
overflow:hidden; overflow: hidden;
flex:1; flex: 1;
display: flex; display: flex;
justify-content:space-between; justify-content: space-between;
.aside { .aside {
width:180px; width: 180px;
height:100%; height: 100%;
padding:0 16px; padding: 0 16px;
line-height:2; line-height: 2;
fieldset { fieldset {
border:0; border: 0;
color:#ebebeb; color: #ebebeb;
font-size:12px; font-size: 12px;
legend { legend {
font-size:18px; font-size: 18px;
background:linear-gradient(to bottom,#58ffdf 50%, #459888); background: linear-gradient(to bottom, #58ffdf 50%, #459888);
background-clip:text; background-clip: text;
color:transparent; color: transparent;
} }
.item { .item {
padding-left:12px; padding-left: 12px;
line-height:1.75; line-height: 1.75;
} }
button { button {
width:42px;height:16px; width: 42px;
margin-left:12px; height: 16px;
font-size:10px; margin-left: 12px;
border:0; font-size: 10px;
border-radius:9px; border: 0;
background:nth($cb, 1); border-radius: 9px;
color:#fff; background: nth($cb, 1);
color: #fff;
} }
} }
} }
.song-box { .song-box {
width:618px; width: 618px;
.preview { .preview {
position:relative; position: relative;
display:flex; display: flex;
align-items:center; align-items: center;
width:100%; width: 100%;
height:99px; height: 99px;
padding-bottom:16px; padding-bottom: 16px;
border-bottom:1px solid rgba(200, 200, 200, .1); border-bottom: 1px solid rgba(200, 200, 200, 0.1);
.album { .album {
width:80px;height:80px; width: 80px;
img {width:100%;height:100%;} height: 80px;
img {
width: 100%;
height: 100%;
}
} }
.info { .info {
display:flex; display: flex;
flex-direction:column; flex-direction: column;
justify-content:center; justify-content: center;
width:320px; width: 320px;
margin-left:32px; margin-left: 32px;
strong { strong {
height:36px; height: 36px;
font-size:18px; font-size: 18px;
font-weight: normal; font-weight: normal;
} }
cite { cite {
font-size:12px; font-size: 12px;
font-style:normal; font-style: normal;
}
p {
font-size: 12px;
color: #bdbdbd;
} }
p {font-size:12px;color:#bdbdbd;}
} }
.duration {
position:absolute;
right:32px;
top:16px;
font-size:12px;
color:#bdbdbd;
}
.total { .total {
position:absolute; position: absolute;
right:32px; right: 32px;
bottom:16px; bottom: 16px;
font-size:16px; font-size: 16px;
font-weight:bold; font-weight: bold;
font-family:Raleway; font-family: Raleway;
} }
} }
.scroll-box { .scroll-box {
width:100%; width: 100%;
height:269px; height: 269px;
padding:16px 6px; padding: 16px 6px;
border-top:1px solid rgba(32, 32, 32, .1); border-top: 1px solid rgba(32, 32, 32, 0.1);
} }
.list { .list {
height:237px; height: 237px;
font-size:12px; font-size: 12px;
.item { .item {
display:flex; display: flex;
align-items:center; align-items: center;
height:26px; height: 26px;
padding:0 12px; padding: 0 12px;
border-radius:13px; border-radius: 13px;
.idx { .idx {
position:relative; position: relative;
width:64px; width: 64px;
padding-left:16px; padding-left: 16px;
font-size:12px; font-size: 12px;
font-family:Raleway; font-family: Raleway;
} }
.name { .name {
overflow:hidden; flex: 1;
flex:1;
} }
.artist { .artist {
overflow:hidden; width: 128px;
width:128px; margin-left: 12px;
margin-left:12px;
} }
.duration { .duration {
width:42px; width: 42px;
margin-left:12px; margin-left: 12px;
} }
&.on { &.on {
color:#feac23; color: #feac23;
font-size:14px; font-size: 14px;
.idx::before { .idx::before {
position:absolute; position: absolute;
left:0;top:3px; left: 0;
font-size:10px; top: 3px;
content:""; font-size: 10px;
content: '';
} }
} }
&.active, &:hover { &.active,
color:#58ffdf; &:hover {
color: #58ffdf;
background: rgba(29, 77, 68, 0.15); background: rgba(29, 77, 68, 0.15);
} }
} }
@ -205,189 +216,195 @@
} }
} }
.play-bar { .play-bar {
height:66px;width:100%; height: 66px;
background:rgba(255, 255, 255, .25); width: 100%;
color:#fff; background: rgba(255, 255, 255, 0.25);
color: #fff;
.stat-bar { .stat-bar {
display:flex; display: flex;
align-items:center; align-items: center;
justify-content:space-between; justify-content: space-between;
height:20px; height: 20px;
color: #ebebeb; color: #ebebeb;
.time { .time {
width:42px; width: 42px;
margin:0 6px; margin: 0 6px;
text-align:center; text-align: center;
font-size:12px; font-size: 12px;
} }
.progress { .progress {
flex:1; flex: 1;
display:flex; display: flex;
align-items: flex-start; align-items: flex-start;
height:3px; height: 3px;
background: #b2cfe3; background: #b2cfe3;
} }
.thumb { .thumb {
width:8%; width: 8%;
height:3px; height: 3px;
background:#58ffdf; background: #58ffdf;
} }
} }
.ctrl-box { .ctrl-box {
display:flex; display: flex;
align-items:center; align-items: center;
height:42px; height: 42px;
.holder { .holder {
flex:1; flex: 1;
} }
.info { .info {
display:flex; display: flex;
flex-direction:column; flex-direction: column;
justify-content:center; justify-content: center;
width:320px; width: 320px;
height:42px; height: 42px;
padding-left:12px; padding-left: 12px;
line-height:1.25; line-height: 1.25;
strong { strong {
font-size:14px; font-size: 14px;
font-weight: 500; font-weight: 500;
} }
cite { cite {
font-size:12px; font-size: 12px;
font-style:normal; font-style: normal;
color:#aeaeae; color: #aeaeae;
} }
} }
.play-btn { .play-btn {
display:flex; display: flex;
align-items:center; align-items: center;
justify-content:space-between; justify-content: space-between;
width:120px; width: 120px;
height:42px; height: 42px;
margin-left:32px; margin-left: 32px;
.item { .item {
width:22px;height:22px; width: 22px;
background-repeat:no-repeat; height: 22px;
background-size:cover; background-repeat: no-repeat;
transition:background .1s ease-in-out; background-size: cover;
cursor:pointer; transition: background 0.1s ease-in-out;
cursor: pointer;
&.prev { &.prev {
background-image:url(/images/ctrl/prev.png); background-image: url(/images/ctrl/prev.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/prev_a.png); &:active {
background-image: url(/images/ctrl/prev_a.png);
} }
} }
&.on,&.off { &.on,
width:42px;height:42px; &.off {
width: 42px;
height: 42px;
} }
&.on { &.on {
background-image:url(/images/ctrl/play.png); background-image: url(/images/ctrl/play.png);
animation:round 2s linear infinite; animation: round 2s linear infinite;
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/play_a.png); &:active {
background-image: url(/images/ctrl/play_a.png);
} }
} }
&.off { &.off {
background-image:url(/images/ctrl/pause.png); background-image: url(/images/ctrl/pause.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/pause_a.png); &:active {
background-image: url(/images/ctrl/pause_a.png);
} }
} }
&.next { &.next {
background-image:url(/images/ctrl/next.png); background-image: url(/images/ctrl/next.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/next_a.png); &:active {
background-image: url(/images/ctrl/next_a.png);
} }
} }
} }
} }
.play-action { .play-action {
display:flex; display: flex;
align-items:center; align-items: center;
justify-content:space-between; justify-content: space-between;
width:64px; width: 64px;
height:22px; height: 22px;
margin-right:16px; margin-right: 16px;
.item { .item {
width:22px;height:22px; width: 22px;
background-repeat:no-repeat; height: 22px;
background-size:cover; background-repeat: no-repeat;
transition:background .1s ease-in-out; background-size: cover;
cursor:pointer; transition: background 0.1s ease-in-out;
cursor: pointer;
&.volume { &.volume {
background-image:url(/images/ctrl/volume.png); background-image: url(/images/ctrl/volume.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/volume_a.png); &:active {
background-image: url(/images/ctrl/volume_a.png);
} }
} }
&.mute { &.mute {
background-image:url(/images/ctrl/mute.png); background-image: url(/images/ctrl/mute.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/mute_a.png); &:active {
background-image: url(/images/ctrl/mute_a.png);
} }
} }
&.single { &.single {
background-image:url(/images/ctrl/single.png); background-image: url(/images/ctrl/single.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/single_a.png); &:active {
background-image: url(/images/ctrl/single_a.png);
} }
} }
&.all { &.all {
background-image:url(/images/ctrl/all.png); background-image: url(/images/ctrl/all.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/all_a.png); &:active {
background-image: url(/images/ctrl/all_a.png);
} }
} }
&.rand { &.rand {
background-image:url(/images/ctrl/rand.png); background-image: url(/images/ctrl/rand.png);
&:hover,&:active { &:hover,
background-image:url(/images/ctrl/rand_a.png); &:active {
background-image: url(/images/ctrl/rand_a.png);
} }
} }
} }
} }
} }
} }
} }
@keyframes round { @keyframes round {
from { from {
transform:rotate(0); transform: rotate(0);
} }
to { to {
transform:rotate(360deg); transform: rotate(360deg);
} }
} }

View File

@ -47,19 +47,19 @@
<p>经典咏流传第三季 第7期</p> <p>经典咏流传第三季 第7期</p>
</div> </div>
<span class="duration">98:54</span> <span class="total" :text="list.size()"></span>
<span class="total">118</span>
</div> </div>
<div class="scroll-box"> <div class="scroll-box">
<wc-scroll class="list"> <wc-scroll class="list">
<section
<section class="item" :for="i it in list"> class="item"
:class="{on: curr === i}"
:for="i it in list">
<span class="idx" :text="i + 1"></span> <span class="idx" :text="i + 1"></span>
<span class="name" :text="it.name"></span> <span class="name text-ell" :text="it.name"></span>
<span class="artist" :text="it.artist"></span> <span class="artist text-ell" :text="it.artist"></span>
<span class="duration" :text="it.duration"></span> <span class="duration" :text="it.duration"></span>
</section> </section>
</wc-scroll> </wc-scroll>
</div> </div>
</div> </div>

View File

@ -8,7 +8,8 @@ import Anot from '/js/lib/anot.js'
import '/js/lib/scroll/index.js' import '/js/lib/scroll/index.js'
import app from '/js/lib/socket.js' import app from '/js/lib/socket.js'
// const {} from '' // const id3 = require('jsmediatags')
const id3 = require('music-metadata')
Anot({ Anot({
$id: 'app', $id: 'app',
@ -16,13 +17,22 @@ Anot({
isplaying: true, isplaying: true,
playmode: 1, playmode: 1,
mute: false, mute: false,
curr: 2,
list: [] list: []
}, },
mounted() { async mounted() {
var list = app.dispatch('scan-dir', { path: '/Volumes/extends/music' }) var list = app.dispatch('scan-dir', { path: '/Volumes/extends/music' })
this.list = list this.list = list
console.log(list)
for (let it of this.list) {
let { album, artist, title, duration } = await this.getID3(it.path)
it.name = title || it.name
it.artist = artist || '未知歌手'
it.album = album
it.duration = Anot.filters.time(duration)
}
}, },
methods: { methods: {
play() { play() {
@ -37,6 +47,15 @@ Anot({
}, },
toggleMute() { toggleMute() {
this.mute = !this.mute this.mute = !this.mute
},
getID3(file) {
return id3.parseFile(file).then(res => {
let {
common: { album, artist, title },
format: { duration }
} = res
return { album, artist, title, duration: ~~duration }
})
} }
} }
}) })

View File

@ -19,7 +19,8 @@ CREATE TABLE IF NOT EXISTS "songs" (
"name" char(128) NOT NULL, "name" char(128) NOT NULL,
"album" char(128) NOT NULL, "album" char(128) NOT NULL,
"cover" char(256) NOT NULL, "cover" char(256) NOT NULL,
"lrc" text NOT NULL, "path" char(256) NOT NULL,
"lrc" text NOT NULL
) )
` `
// 歌曲和播放列表的关系表(多对多) // 歌曲和播放列表的关系表(多对多)

View File

@ -7,6 +7,7 @@
const { app, ipcMain, globalShortcut: GS } = require('electron') const { app, ipcMain, globalShortcut: GS } = require('electron')
const path = require('path') const path = require('path')
const fs = require('iofs') const fs = require('iofs')
const sec = require('crypto.js')
const Shortcut = require('./shortcut') const Shortcut = require('./shortcut')
const Sqlite = require('./db') const Sqlite = require('./db')
@ -91,7 +92,12 @@ ipcMain.on('app', (ev, conn) => {
}) })
.map(it => { .map(it => {
var { ext, name } = path.parse(it) var { ext, name } = path.parse(it)
return { uuid: '', ext, name, path: it } var buf = fs.origin.createReadStream(it, {
start: 0,
end: 256,
encoding: 'base64'
})
return { name, path: it, artist: '', album: '', duration: '00:00' }
}) })
ev.returnValue = list ev.returnValue = list
} else { } else {