Compare commits

...

4 Commits

Author SHA1 Message Date
advplyr 86809dcc62 Update audio player to pass chapterInfo to media session API 2025-01-01 09:02:31 -06:00
advplyr 9fa00a1904 Fix Share media player not using media session API #3768 2025-01-01 08:55:40 -06:00
advplyr 1c2ee09f18 Fix user stats heatmap to use range of currently showing data only 2024-12-31 17:41:09 -06:00
advplyr ee310d967e Merge pull request #3766 from advplyr/remove-old-playlist
Remove old Playlist object + remove unnecessary toasts
2024-12-31 17:26:26 -06:00
3 changed files with 138 additions and 38 deletions
+15 -7
View File
@@ -374,19 +374,27 @@ export default {
return return
} }
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Session_API
if ('mediaSession' in navigator) { if ('mediaSession' in navigator) {
var coverImageSrc = this.$store.getters['globals/getLibraryItemCoverSrc'](this.streamLibraryItem, '/Logo.png', true) const chapterInfo = []
const artwork = [ if (this.chapters.length) {
{ this.chapters.forEach((chapter) => {
src: coverImageSrc chapterInfo.push({
} title: chapter.title,
] startTime: chapter.start
})
})
}
navigator.mediaSession.metadata = new MediaMetadata({ navigator.mediaSession.metadata = new MediaMetadata({
title: this.title, title: this.title,
artist: this.playerHandler.displayAuthor || this.mediaMetadata.authorName || 'Unknown', artist: this.playerHandler.displayAuthor || this.mediaMetadata.authorName || 'Unknown',
album: this.mediaMetadata.seriesName || '', album: this.mediaMetadata.seriesName || '',
artwork artwork: [
{
src: this.$store.getters['globals/getLibraryItemCoverSrc'](this.streamLibraryItem, '/Logo.png', true)
}
]
}) })
console.log('Set media session metadata', navigator.mediaSession.metadata) console.log('Set media session metadata', navigator.mediaSession.metadata)
+30 -30
View File
@@ -193,46 +193,46 @@ export default {
buildData() { buildData() {
this.data = [] this.data = []
var maxValue = 0 let maxValue = 0
var minValue = 0 let minValue = 0
Object.values(this.daysListening).forEach((val) => {
if (val > maxValue) maxValue = val
if (!minValue || val < minValue) minValue = val
})
const range = maxValue - minValue + 0.01
const dates = []
for (let i = 0; i < this.daysToShow + 1; i++) { for (let i = 0; i < this.daysToShow + 1; i++) {
const col = Math.floor(i / 7)
const row = i % 7
const date = i === 0 ? this.firstWeekStart : this.$addDaysToDate(this.firstWeekStart, i) const date = i === 0 ? this.firstWeekStart : this.$addDaysToDate(this.firstWeekStart, i)
const dateString = this.$formatJsDate(date, 'yyyy-MM-dd') const dateString = this.$formatJsDate(date, 'yyyy-MM-dd')
const datePretty = this.$formatJsDate(date, 'MMM d, yyyy') const dateObj = {
const monthString = this.$formatJsDate(date, 'MMM') col: Math.floor(i / 7),
const value = this.daysListening[dateString] || 0 row: i % 7,
const x = col * 13 date,
const y = row * 13 dateString,
datePretty: this.$formatJsDate(date, 'MMM d, yyyy'),
monthString: this.$formatJsDate(date, 'MMM'),
dayOfMonth: Number(dateString.split('-').pop()),
yearString: dateString.split('-').shift(),
value: this.daysListening[dateString] || 0
}
dates.push(dateObj)
var bgColor = this.bgColors[0] if (dateObj.value) {
var outlineColor = this.outlineColors[0] if (dateObj.value > maxValue) maxValue = dateObj.value
if (value) { if (!minValue || dateObj.value < minValue) minValue = dateObj.value
}
}
const range = maxValue - minValue + 0.01
for (const dateObj of dates) {
let bgColor = this.bgColors[0]
let outlineColor = this.outlineColors[0]
if (dateObj.value) {
outlineColor = this.outlineColors[1] outlineColor = this.outlineColors[1]
var percentOfAvg = (value - minValue) / range const percentOfAvg = (dateObj.value - minValue) / range
var bgIndex = Math.floor(percentOfAvg * 4) + 1 const bgIndex = Math.floor(percentOfAvg * 4) + 1
bgColor = this.bgColors[bgIndex] || 'red' bgColor = this.bgColors[bgIndex] || 'red'
} }
this.data.push({ this.data.push({
date, ...dateObj,
dateString, style: `transform:translate(${dateObj.col * 13}px,${dateObj.row * 13}px);background-color:${bgColor};outline:1px solid ${outlineColor};outline-offset:-1px;`
datePretty,
monthString,
dayOfMonth: Number(dateString.split('-').pop()),
yearString: dateString.split('-').shift(),
value,
col,
row,
style: `transform:translate(${x}px,${y}px);background-color:${bgColor};outline:1px solid ${outlineColor};outline-offset:-1px;`
}) })
} }
+93 -1
View File
@@ -110,6 +110,84 @@ export default {
} }
}, },
methods: { methods: {
mediaSessionPlay() {
console.log('Media session play')
this.play()
},
mediaSessionPause() {
console.log('Media session pause')
this.pause()
},
mediaSessionStop() {
console.log('Media session stop')
this.pause()
},
mediaSessionSeekBackward() {
console.log('Media session seek backward')
this.jumpBackward()
},
mediaSessionSeekForward() {
console.log('Media session seek forward')
this.jumpForward()
},
mediaSessionSeekTo(e) {
console.log('Media session seek to', e)
if (e.seekTime !== null && !isNaN(e.seekTime)) {
this.seek(e.seekTime)
}
},
mediaSessionPreviousTrack() {
if (this.$refs.audioPlayer) {
this.$refs.audioPlayer.prevChapter()
}
},
mediaSessionNextTrack() {
if (this.$refs.audioPlayer) {
this.$refs.audioPlayer.nextChapter()
}
},
updateMediaSessionPlaybackState() {
if ('mediaSession' in navigator) {
navigator.mediaSession.playbackState = this.isPlaying ? 'playing' : 'paused'
}
},
setMediaSession() {
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Session_API
if ('mediaSession' in navigator) {
const chapterInfo = []
if (this.chapters.length > 0) {
this.chapters.forEach((chapter) => {
chapterInfo.push({
title: chapter.title,
startTime: chapter.start
})
})
}
navigator.mediaSession.metadata = new MediaMetadata({
title: this.mediaItemShare.playbackSession.displayTitle || 'No title',
artist: this.mediaItemShare.playbackSession.displayAuthor || 'Unknown',
artwork: [
{
src: this.coverUrl
}
],
chapterInfo
})
console.log('Set media session metadata', navigator.mediaSession.metadata)
navigator.mediaSession.setActionHandler('play', this.mediaSessionPlay)
navigator.mediaSession.setActionHandler('pause', this.mediaSessionPause)
navigator.mediaSession.setActionHandler('stop', this.mediaSessionStop)
navigator.mediaSession.setActionHandler('seekbackward', this.mediaSessionSeekBackward)
navigator.mediaSession.setActionHandler('seekforward', this.mediaSessionSeekForward)
navigator.mediaSession.setActionHandler('seekto', this.mediaSessionSeekTo)
navigator.mediaSession.setActionHandler('previoustrack', this.mediaSessionSeekBackward)
navigator.mediaSession.setActionHandler('nexttrack', this.mediaSessionSeekForward)
} else {
console.warn('Media session not available')
}
},
async coverImageLoaded(e) { async coverImageLoaded(e) {
if (!this.playbackSession.coverPath) return if (!this.playbackSession.coverPath) return
const fac = new FastAverageColor() const fac = new FastAverageColor()
@@ -126,8 +204,19 @@ export default {
}) })
}, },
playPause() { playPause() {
if (this.isPlaying) {
this.pause()
} else {
this.play()
}
},
play() {
if (!this.localAudioPlayer || !this.hasLoaded) return if (!this.localAudioPlayer || !this.hasLoaded) return
this.localAudioPlayer.playPause() this.localAudioPlayer.play()
},
pause() {
if (!this.localAudioPlayer || !this.hasLoaded) return
this.localAudioPlayer.pause()
}, },
jumpForward() { jumpForward() {
if (!this.localAudioPlayer || !this.hasLoaded) return if (!this.localAudioPlayer || !this.hasLoaded) return
@@ -213,6 +302,7 @@ export default {
} else { } else {
this.stopPlayInterval() this.stopPlayInterval()
} }
this.updateMediaSessionPlaybackState()
}, },
playerTimeUpdate(time) { playerTimeUpdate(time) {
this.setCurrentTime(time) this.setCurrentTime(time)
@@ -276,6 +366,8 @@ export default {
this.localAudioPlayer.on('timeupdate', this.playerTimeUpdate.bind(this)) this.localAudioPlayer.on('timeupdate', this.playerTimeUpdate.bind(this))
this.localAudioPlayer.on('error', this.playerError.bind(this)) this.localAudioPlayer.on('error', this.playerError.bind(this))
this.localAudioPlayer.on('finished', this.playerFinished.bind(this)) this.localAudioPlayer.on('finished', this.playerFinished.bind(this))
this.setMediaSession()
}, },
beforeDestroy() { beforeDestroy() {
window.removeEventListener('resize', this.resize) window.removeEventListener('resize', this.resize)