Audio metadata

This commit is contained in:
DC
2016-03-22 03:37:27 -07:00
parent fc425e4221
commit fcf0e0d2fb
4 changed files with 82 additions and 4 deletions

View File

@@ -22,6 +22,7 @@
"hyperx": "^2.0.2", "hyperx": "^2.0.2",
"main-loop": "^3.2.0", "main-loop": "^3.2.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"musicmetadata": "^2.0.2",
"network-address": "^1.1.0", "network-address": "^1.1.0",
"prettier-bytes": "^1.0.1", "prettier-bytes": "^1.0.1",
"upload-element": "^1.0.1", "upload-element": "^1.0.1",
@@ -30,7 +31,6 @@
"winreg": "^1.0.1" "winreg": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
"appdmg": "^0.3.6",
"electron-osx-sign": "^0.3.0", "electron-osx-sign": "^0.3.0",
"electron-packager": "^5.0.0", "electron-packager": "^5.0.0",
"electron-prebuilt": "0.37.2", "electron-prebuilt": "0.37.2",
@@ -40,6 +40,9 @@
"rimraf": "^2.5.2", "rimraf": "^2.5.2",
"standard": "^6.0.5" "standard": "^6.0.5"
}, },
"optionalDependencies": {
"appdmg": "^0.3.6"
},
"homepage": "https://webtorrent.io", "homepage": "https://webtorrent.io",
"keywords": [ "keywords": [
"electron", "electron",

View File

@@ -730,6 +730,34 @@ body.drag .torrent-placeholder span {
font-weight: bold; font-weight: bold;
} }
/*
* AUDIO DETAILS
*/
.audio-metadata {
width: 500px;
max-width: 100%;
white-space: nowrap;
text-overflow: ellipsis;
align-self: center;
margin: 0 auto;
font-weight: bold;
font-size: 24px;
line-height: 2;
}
.audio-metadata .audio-title {
font-size: 32px;
}
.audio-metadata label {
display:inline-block;
width: 100px;
text-align: right;
font-weight: normal;
margin-right: 25px;
}
/* /*
* ERRORS * ERRORS
*/ */

View File

@@ -8,6 +8,7 @@ var EventEmitter = require('events')
var fs = require('fs') var fs = require('fs')
var mainLoop = require('main-loop') var mainLoop = require('main-loop')
var mkdirp = require('mkdirp') var mkdirp = require('mkdirp')
var musicmetadata = require('musicmetadata')
var networkAddress = require('network-address') var networkAddress = require('network-address')
var path = require('path') var path = require('path')
var remote = require('remote') var remote = require('remote')
@@ -609,7 +610,17 @@ function startServerFromReadyTorrent (torrent, index, cb) {
state.playing.infoHash = torrent.infoHash state.playing.infoHash = torrent.infoHash
state.playing.fileIndex = index state.playing.fileIndex = index
state.playing.type = TorrentPlayer.isVideo(file) ? 'video' : 'audio' state.playing.type = TorrentPlayer.isVideo(file) ? 'video' : 'audio'
state.playing.audioInfo = null
// if it's audio, parse out the metadata (artist, title, etc)
musicmetadata(file.createReadStream(), function (err, info) {
if (err) return
console.log('Got audio metadata for %s: %v', file.name, info)
state.playing.audioInfo = info
update()
})
// either way, start a streaming torrent-to-http server
var server = torrent.createServer() var server = torrent.createServer()
server.listen(0, function () { server.listen(0, function () {
var port = server.address().port var port = server.address().port

View File

@@ -21,6 +21,8 @@ function Player (state, dispatch) {
} }
function renderMedia (state, dispatch) { function renderMedia (state, dispatch) {
if (!state.server) return
// Unfortunately, play/pause can't be done just by modifying HTML. // Unfortunately, play/pause can't be done just by modifying HTML.
// Instead, grab the DOM node and play/pause it if necessary // Instead, grab the DOM node and play/pause it if necessary
var mediaType = state.playing.type /* 'audio' or 'video' */ var mediaType = state.playing.type /* 'audio' or 'video' */
@@ -57,8 +59,9 @@ function renderMedia (state, dispatch) {
// Show the media. // Show the media.
// Video fills the window, centered with black bars if necessary // Video fills the window, centered with black bars if necessary
// Audio gets a static poster image and a summary of the file metadata. // Audio gets a static poster image and a summary of the file metadata.
var isAudio = mediaType === 'audio'
var style = { var style = {
backgroundImage: mediaType === 'audio' ? cssBackgroundImagePoster(state) : '' backgroundImage: isAudio ? cssBackgroundImagePoster(state) : ''
} }
return hx` return hx`
<div <div
@@ -66,6 +69,7 @@ function renderMedia (state, dispatch) {
style=${style} style=${style}
onmousemove=${() => dispatch('mediaMouseMoved')}> onmousemove=${() => dispatch('mediaMouseMoved')}>
${mediaTag} ${mediaTag}
${renderAudioMetadata(state)}
</div> </div>
` `
@@ -86,6 +90,34 @@ function renderMedia (state, dispatch) {
} }
} }
function renderAudioMetadata (state) {
if (!state.playing.audioInfo) return
var info = state.playing.audioInfo
// Get audio track info
var title = info.title
if (!title) {
var torrentSummary = getPlayingTorrentSummary(state)
title = torrentSummary.files[state.playing.fileIndex].name
}
var artist = info.artist && info.artist[0]
var album = info.album
if (album && info.year && !album.includes(info.year)) {
album += ' (' + info.year + ')'
}
var track
if (info.track && info.track.no && info.track.of) {
track = info.track.no + ' of ' + info.track.of
}
// Show a small info box in the middle of the screen
var elems = [hx`<div class='audio-title'><label></label>${title}</div>`]
if (artist) elems.push(hx`<div class='audio-artist'><label>Artist</label>${artist}</div>`)
if (album) elems.push(hx`<div class='audio-album'><label>Album</label>${album}</div>`)
if (track) elems.push(hx`<div class='audio-track'><label>Track</label>${track}</div>`)
return hx`<div class='audio-metadata'>${elems}</div>`
}
function renderCastScreen (state, dispatch) { function renderCastScreen (state, dispatch) {
var isChromecast = state.playing.location.startsWith('chromecast') var isChromecast = state.playing.location.startsWith('chromecast')
var isAirplay = state.playing.location.startsWith('airplay') var isAirplay = state.playing.location.startsWith('airplay')
@@ -112,8 +144,7 @@ function renderCastScreen (state, dispatch) {
// Returns the CSS background-image string for a poster image + dark vignette // Returns the CSS background-image string for a poster image + dark vignette
function cssBackgroundImagePoster (state) { function cssBackgroundImagePoster (state) {
var infoHash = state.playing.infoHash var torrentSummary = getPlayingTorrentSummary(state)
var torrentSummary = state.saved.torrents.find((x) => x.infoHash === infoHash)
if (!torrentSummary || !torrentSummary.posterURL) return '' if (!torrentSummary || !torrentSummary.posterURL) return ''
var cleanURL = torrentSummary.posterURL.replace(/\\/g, '/') var cleanURL = torrentSummary.posterURL.replace(/\\/g, '/')
return 'radial-gradient(circle at center, ' + return 'radial-gradient(circle at center, ' +
@@ -121,6 +152,11 @@ function cssBackgroundImagePoster (state) {
`, url(${cleanURL})` `, url(${cleanURL})`
} }
function getPlayingTorrentSummary (state) {
var infoHash = state.playing.infoHash
return state.saved.torrents.find((x) => x.infoHash === infoHash)
}
function renderPlayerControls (state, dispatch) { function renderPlayerControls (state, dispatch) {
var positionPercent = 100 * state.playing.currentTime / state.playing.duration var positionPercent = 100 * state.playing.currentTime / state.playing.duration
var playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 8px)' } var playbackCursorStyle = { left: 'calc(' + positionPercent + '% - 8px)' }