mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-12 12:21:34 +00:00
first_progress
This commit is contained in:
parent
09d7880779
commit
2d10669700
15 changed files with 643 additions and 108 deletions
|
|
@ -1,40 +1,35 @@
|
||||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
|
||||||
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
|
// README at: https://github.com/devcontainers/templates/tree/main/src/javascript-node
|
||||||
{
|
{
|
||||||
"name": "Audiobookshelf",
|
"name": "Audiobookshelf",
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
|
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
|
||||||
// Append -bullseye or -buster to pin to an OS version.
|
// Append -bullseye or -buster to pin to an OS version.
|
||||||
// Use -bullseye variants on local arm64/Apple Silicon.
|
// Use -bullseye variants on local arm64/Apple Silicon.
|
||||||
"args": {
|
"args": {
|
||||||
"VARIANT": "20"
|
"VARIANT": "20"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mounts": [
|
"mounts": ["source=abs-server-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume", "source=abs-client-node_modules,target=${containerWorkspaceFolder}/client/node_modules,type=volume"],
|
||||||
"source=abs-server-node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume",
|
// Features to add to the dev container. More info: https://containers.dev/features.
|
||||||
"source=abs-client-node_modules,target=${containerWorkspaceFolder}/client/node_modules,type=volume"
|
// "features": {},
|
||||||
],
|
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||||
// Features to add to the dev container. More info: https://containers.dev/features.
|
//"forwardPorts": [
|
||||||
// "features": {},
|
// 3000,
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
// 3333
|
||||||
"forwardPorts": [
|
//],
|
||||||
3000,
|
"runArgs": ["--network=host"],
|
||||||
3333
|
// Use 'postCreateCommand' to run commands after the container is created.
|
||||||
],
|
"postCreateCommand": "sh .devcontainer/post-create.sh",
|
||||||
// Use 'postCreateCommand' to run commands after the container is created.
|
// Configure tool-specific properties.
|
||||||
"postCreateCommand": "sh .devcontainer/post-create.sh",
|
"customizations": {
|
||||||
// Configure tool-specific properties.
|
// Configure properties specific to VS Code.
|
||||||
"customizations": {
|
"vscode": {
|
||||||
// Configure properties specific to VS Code.
|
// Add the IDs of extensions you want installed when the container is created.
|
||||||
"vscode": {
|
"extensions": ["dbaeumer.vscode-eslint", "octref.vetur"]
|
||||||
// Add the IDs of extensions you want installed when the container is created.
|
}
|
||||||
"extensions": [
|
}
|
||||||
"dbaeumer.vscode-eslint",
|
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
||||||
"octref.vetur"
|
// "remoteUser": "root"
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
|
|
||||||
// "remoteUser": "root"
|
|
||||||
}
|
}
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
<div v-if="isChromecastInitialized" class="w-6 min-w-6 h-6 ml-2 mr-1 sm:mx-2 cursor-pointer">
|
<div v-if="isChromecastInitialized" class="w-6 min-w-6 h-6 ml-2 mr-1 sm:mx-2 cursor-pointer">
|
||||||
<google-cast-launcher></google-cast-launcher>
|
<google-cast-launcher></google-cast-launcher>
|
||||||
</div>
|
</div>
|
||||||
|
<ui-dlna-dropdown class="mr-2" />
|
||||||
<widgets-notification-widget class="hidden md:block" />
|
<widgets-notification-widget class="hidden md:block" />
|
||||||
|
|
||||||
<nuxt-link v-if="currentLibrary" to="/config/stats" class="hover:text-gray-200 cursor-pointer w-8 h-8 hidden sm:flex items-center justify-center mx-1">
|
<nuxt-link v-if="currentLibrary" to="/config/stats" class="hover:text-gray-200 cursor-pointer w-8 h-8 hidden sm:flex items-center justify-center mx-1">
|
||||||
|
|
@ -155,6 +155,7 @@ export default {
|
||||||
isChromecastInitialized() {
|
isChromecastInitialized() {
|
||||||
return this.$store.state.globals.isChromecastInitialized
|
return this.$store.state.globals.isChromecastInitialized
|
||||||
},
|
},
|
||||||
|
|
||||||
isHttps() {
|
isHttps() {
|
||||||
return location.protocol === 'https:' || process.env.NODE_ENV === 'development'
|
return location.protocol === 'https:' || process.env.NODE_ENV === 'development'
|
||||||
},
|
},
|
||||||
|
|
|
||||||
95
client/components/ui/DlnaDropdown.vue
Normal file
95
client/components/ui/DlnaDropdown.vue
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
<template>
|
||||||
|
<div class="max-w-52" v-click-outside="clickOutsideObj" v-if="has_devices">
|
||||||
|
<button type="button" :disabled="disabled" aria-haspopup="listbox" :aria-expanded="showMenu" @click.stop.prevent="clickShowMenu">
|
||||||
|
<div class="flex">
|
||||||
|
<span class="hidden sm:block truncate">
|
||||||
|
<span v-show="has_devices" class="material-icons-outlined text-2xl text-opacity-50" v-bind:class="{ 'icon-blue': has_device }"> cast </span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<transition name="menu">
|
||||||
|
<ul v-show="showMenu" class="absolute z-10 -mt-px w-full min-w-48 bg-primary border border-black-200 shadow-lg rounded-b-md py-1 overflow-auto focus:outline-none sm:text-sm DlnaDropdownMenu" tabindex="-1" role="listbox">
|
||||||
|
<template v-for="device in get_devices">
|
||||||
|
<li :key="device.host" class="text-gray-400 hover:text-white relative py-2 cursor-pointer hover:bg-black-400" v-bind:class="{ 'bg-black-600': get_device == device.host }" role="option" tabindex="0" @keydown.enter="selectDevice(device.host)" @click="selectDevice(device.host)">
|
||||||
|
<div class="flex items-center px-2">
|
||||||
|
<span class="font-normal block truncate font-sans text-sm">{{ device.name }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
</ul>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
clickOutsideObj: {
|
||||||
|
handler: this.clickedOutside,
|
||||||
|
events: ['mousedown'],
|
||||||
|
isActive: true
|
||||||
|
},
|
||||||
|
showMenu: false,
|
||||||
|
disabled: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickShowMenu() {
|
||||||
|
if (this.disabled) return
|
||||||
|
this.showMenu = !this.showMenu
|
||||||
|
},
|
||||||
|
clickedOutside() {
|
||||||
|
this.showMenu = false
|
||||||
|
},
|
||||||
|
selectDevice(device) {
|
||||||
|
if (this.selectedDevice == device) {
|
||||||
|
this.$store.commit('globals/setDlnaDevice', '')
|
||||||
|
this.selectedDevice = ''
|
||||||
|
} else {
|
||||||
|
this.selectedDevice = device
|
||||||
|
this.$store.commit('globals/setDlnaDevice', device)
|
||||||
|
this.$root.socket.emit('test')
|
||||||
|
}
|
||||||
|
this.showMenu = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
has_device() {
|
||||||
|
return Boolean(this.$store.getters['globals/getDLNAdevice'])
|
||||||
|
},
|
||||||
|
has_devices() {
|
||||||
|
return Boolean(this.$store.getters['globals/getDLNAdevices'])
|
||||||
|
},
|
||||||
|
get_device() {
|
||||||
|
return this.$store.getters['globals/getDLNAdevice']
|
||||||
|
},
|
||||||
|
get_devices() {
|
||||||
|
return this.$store.getters['globals/getDLNAdevices']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$axios
|
||||||
|
.$get('/api/dlna/devices')
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('failed to fetch DLNA devices', error)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
this.$store.commit('globals/setDlnaDevices', response)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.DlnaDropdownMenu {
|
||||||
|
max-height: calc(100vh - 75px);
|
||||||
|
max-width: 100pt;
|
||||||
|
}
|
||||||
|
.icon-blue {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
88
client/players/DLNAPlayer.js
Normal file
88
client/players/DLNAPlayer.js
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
import EventEmitter from 'events'
|
||||||
|
|
||||||
|
export default class DLNAPlayer extends EventEmitter {
|
||||||
|
constructor(ctx) {
|
||||||
|
super()
|
||||||
|
|
||||||
|
this.ctx = ctx
|
||||||
|
this.player = null
|
||||||
|
this.playerController = null
|
||||||
|
|
||||||
|
this.libraryItem = null
|
||||||
|
this.audioTracks = []
|
||||||
|
this.currentTrackIndex = 0
|
||||||
|
this.isHlsTranscode = null
|
||||||
|
this.currentTime = 0
|
||||||
|
this.playWhenReady = false
|
||||||
|
this.defaultPlaybackRate = 1
|
||||||
|
|
||||||
|
// TODO: Use canDisplayType on receiver to check mime types
|
||||||
|
this.playableMimeTypes = ['audio/flac', 'audio/mpeg', 'audio/mp4', 'audio/ogg', 'audio/aac', 'audio/x-ms-wma', 'audio/x-aiff', 'audio/webm']
|
||||||
|
|
||||||
|
this.coverUrl = ''
|
||||||
|
this.castPlayerState = 'IDLE'
|
||||||
|
|
||||||
|
// Supported audio codecs for chromecast
|
||||||
|
|
||||||
|
this.supportedAudioCodecs = ['opus', 'mp3', 'aac', 'flac', 'webma', 'wav']
|
||||||
|
|
||||||
|
this.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentTrack() {
|
||||||
|
return this.audioTracks[this.currentTrackIndex] || {}
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.ctx.$root.socket.on('test', this.destroy)
|
||||||
|
//this.player = this.ctx.$root.castPlayer
|
||||||
|
}
|
||||||
|
|
||||||
|
evtMediaInfoChanged() {}
|
||||||
|
|
||||||
|
destroy() {}
|
||||||
|
|
||||||
|
async set(libraryItem, tracks, isHlsTranscode, startTime, playWhenReady = false) {
|
||||||
|
this.libraryItem = libraryItem
|
||||||
|
this.audioTracks = tracks
|
||||||
|
this.isHlsTranscode = isHlsTranscode
|
||||||
|
this.playWhenReady = playWhenReady
|
||||||
|
this.currentTime = startTime
|
||||||
|
console.log('Tracks: ')
|
||||||
|
console.log(tracks.find((at) => at.startOffset <= startTime && at.startOffset + at.duration > startTime))
|
||||||
|
var coverImg = this.ctx.$store.getters['globals/getLibraryItemCoverSrc'](libraryItem)
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
this.coverUrl = coverImg
|
||||||
|
} else {
|
||||||
|
this.coverUrl = `${window.location.origin}${coverImg}`
|
||||||
|
}
|
||||||
|
this.ctx.$root.socket.emit('dlna_start', this.audioTracks)
|
||||||
|
}
|
||||||
|
|
||||||
|
resetStream(startTime) {}
|
||||||
|
|
||||||
|
playPause() {}
|
||||||
|
|
||||||
|
play() {}
|
||||||
|
|
||||||
|
pause() {}
|
||||||
|
|
||||||
|
getCurrentTime() {
|
||||||
|
//var currentTrackOffset = this.currentTrack.startOffset || 0
|
||||||
|
return 0 //this.player ? currentTrackOffset + this.player.currentTime : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
getDuration() {
|
||||||
|
if (!this.audioTracks.length) return 0
|
||||||
|
var lastTrack = this.audioTracks[this.audioTracks.length - 1]
|
||||||
|
return lastTrack.startOffset + lastTrack.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
setPlaybackRate(playbackRate) {
|
||||||
|
this.defaultPlaybackRate = playbackRate
|
||||||
|
}
|
||||||
|
|
||||||
|
async seek(time, playWhenReady) {}
|
||||||
|
|
||||||
|
setVolume(volume) {}
|
||||||
|
}
|
||||||
|
|
@ -113,7 +113,6 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
this.isHlsTranscode = isHlsTranscode
|
this.isHlsTranscode = isHlsTranscode
|
||||||
this.playWhenReady = playWhenReady
|
this.playWhenReady = playWhenReady
|
||||||
this.startTime = startTime
|
this.startTime = startTime
|
||||||
|
|
||||||
if (this.hlsInstance) {
|
if (this.hlsInstance) {
|
||||||
this.destroyHlsInstance()
|
this.destroyHlsInstance()
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +146,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
timeoutRetry: {
|
timeoutRetry: {
|
||||||
maxNumRetry: 4,
|
maxNumRetry: 4,
|
||||||
retryDelayMs: 0,
|
retryDelayMs: 0,
|
||||||
maxRetryDelayMs: 0,
|
maxRetryDelayMs: 0
|
||||||
},
|
},
|
||||||
errorRetry: {
|
errorRetry: {
|
||||||
maxNumRetry: 8,
|
maxNumRetry: 8,
|
||||||
|
|
@ -160,7 +159,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
}
|
}
|
||||||
return retry
|
return retry
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +193,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
|
|
||||||
setDirectPlay() {
|
setDirectPlay() {
|
||||||
// Set initial track and track time offset
|
// Set initial track and track time offset
|
||||||
var trackIndex = this.audioTracks.findIndex(t => this.startTime >= t.startOffset && this.startTime < (t.startOffset + t.duration))
|
var trackIndex = this.audioTracks.findIndex((t) => this.startTime >= t.startOffset && this.startTime < t.startOffset + t.duration)
|
||||||
this.currentTrackIndex = trackIndex >= 0 ? trackIndex : 0
|
this.currentTrackIndex = trackIndex >= 0 ? trackIndex : 0
|
||||||
|
|
||||||
this.loadCurrentTrack()
|
this.loadCurrentTrack()
|
||||||
|
|
@ -270,7 +269,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
// Seeking Direct play
|
// Seeking Direct play
|
||||||
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
||||||
// Change Track
|
// Change Track
|
||||||
var trackIndex = this.audioTracks.findIndex(t => time >= t.startOffset && time < (t.startOffset + t.duration))
|
var trackIndex = this.audioTracks.findIndex((t) => time >= t.startOffset && time < t.startOffset + t.duration)
|
||||||
if (trackIndex >= 0) {
|
if (trackIndex >= 0) {
|
||||||
this.startTime = time
|
this.startTime = time
|
||||||
this.currentTrackIndex = trackIndex
|
this.currentTrackIndex = trackIndex
|
||||||
|
|
@ -293,7 +292,6 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
this.player.volume = volume
|
this.player.volume = volume
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
isValidDuration(duration) {
|
isValidDuration(duration) {
|
||||||
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import LocalVideoPlayer from './LocalVideoPlayer'
|
||||||
import CastPlayer from './CastPlayer'
|
import CastPlayer from './CastPlayer'
|
||||||
import AudioTrack from './AudioTrack'
|
import AudioTrack from './AudioTrack'
|
||||||
import VideoTrack from './VideoTrack'
|
import VideoTrack from './VideoTrack'
|
||||||
|
import DLNAPlayer from './DLNAPlayer'
|
||||||
|
|
||||||
export default class PlayerHandler {
|
export default class PlayerHandler {
|
||||||
constructor(ctx) {
|
constructor(ctx) {
|
||||||
|
|
@ -32,14 +33,17 @@ export default class PlayerHandler {
|
||||||
get isCasting() {
|
get isCasting() {
|
||||||
return this.ctx.$store.state.globals.isCasting
|
return this.ctx.$store.state.globals.isCasting
|
||||||
}
|
}
|
||||||
|
get get_Dlna() {
|
||||||
|
return this.ctx.$store.state.globals.dlnaDevice
|
||||||
|
}
|
||||||
get libraryItemId() {
|
get libraryItemId() {
|
||||||
return this.libraryItem ? this.libraryItem.id : null
|
return this.libraryItem ? this.libraryItem.id : null
|
||||||
}
|
}
|
||||||
get isPlayingCastedItem() {
|
get isPlayingCastedItem() {
|
||||||
return this.libraryItem && (this.player instanceof CastPlayer)
|
return this.libraryItem && this.player instanceof CastPlayer
|
||||||
}
|
}
|
||||||
get isPlayingLocalItem() {
|
get isPlayingLocalItem() {
|
||||||
return this.libraryItem && (this.player instanceof LocalAudioPlayer)
|
return this.libraryItem && this.player instanceof LocalAudioPlayer
|
||||||
}
|
}
|
||||||
get userToken() {
|
get userToken() {
|
||||||
return this.ctx.$store.getters['user/getToken']
|
return this.ctx.$store.getters['user/getToken']
|
||||||
|
|
@ -49,7 +53,7 @@ export default class PlayerHandler {
|
||||||
}
|
}
|
||||||
get episode() {
|
get episode() {
|
||||||
if (!this.episodeId) return null
|
if (!this.episodeId) return null
|
||||||
return this.libraryItem.media.episodes.find(ep => ep.id === this.episodeId)
|
return this.libraryItem.media.episodes.find((ep) => ep.id === this.episodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
setSessionId(sessionId) {
|
setSessionId(sessionId) {
|
||||||
|
|
@ -66,7 +70,7 @@ export default class PlayerHandler {
|
||||||
this.playWhenReady = playWhenReady
|
this.playWhenReady = playWhenReady
|
||||||
this.initialPlaybackRate = this.isMusic ? 1 : playbackRate
|
this.initialPlaybackRate = this.isMusic ? 1 : playbackRate
|
||||||
|
|
||||||
this.startTimeOverride = (startTimeOverride == null || isNaN(startTimeOverride)) ? undefined : Number(startTimeOverride)
|
this.startTimeOverride = startTimeOverride == null || isNaN(startTimeOverride) ? undefined : Number(startTimeOverride)
|
||||||
|
|
||||||
if (!this.player) this.switchPlayer(playWhenReady)
|
if (!this.player) this.switchPlayer(playWhenReady)
|
||||||
else this.prepare()
|
else this.prepare()
|
||||||
|
|
@ -86,6 +90,22 @@ export default class PlayerHandler {
|
||||||
this.player = new CastPlayer(this.ctx)
|
this.player = new CastPlayer(this.ctx)
|
||||||
this.setPlayerListeners()
|
this.setPlayerListeners()
|
||||||
|
|
||||||
|
if (this.libraryItem) {
|
||||||
|
// libraryItem was already loaded - prepare for cast
|
||||||
|
this.playWhenReady = playWhenReady
|
||||||
|
this.prepare()
|
||||||
|
}
|
||||||
|
} else if (this.get_Dlna) {
|
||||||
|
console.log('[PlayerHandler] Switching to DLNA player')
|
||||||
|
this.stopPlayInterval()
|
||||||
|
this.playerStateChange('LOADING')
|
||||||
|
this.startTime = this.player ? this.player.getCurrentTime() : this.startTime
|
||||||
|
if (this.player) {
|
||||||
|
this.player.destroy()
|
||||||
|
}
|
||||||
|
this.player = new DLNAPlayer(this.ctx)
|
||||||
|
this.setPlayerListeners()
|
||||||
|
|
||||||
if (this.libraryItem) {
|
if (this.libraryItem) {
|
||||||
// libraryItem was already loaded - prepare for cast
|
// libraryItem was already loaded - prepare for cast
|
||||||
this.playWhenReady = playWhenReady
|
this.playWhenReady = playWhenReady
|
||||||
|
|
@ -127,7 +147,7 @@ export default class PlayerHandler {
|
||||||
|
|
||||||
playerError() {
|
playerError() {
|
||||||
// Switch to HLS stream on error
|
// Switch to HLS stream on error
|
||||||
if (!this.isCasting && (this.player instanceof LocalAudioPlayer)) {
|
if (!this.isCasting && this.player instanceof LocalAudioPlayer) {
|
||||||
console.log(`[PlayerHandler] Audio player error switching to HLS stream`)
|
console.log(`[PlayerHandler] Audio player error switching to HLS stream`)
|
||||||
this.prepare(true)
|
this.prepare(true)
|
||||||
}
|
}
|
||||||
|
|
@ -199,15 +219,17 @@ export default class PlayerHandler {
|
||||||
forceTranscode,
|
forceTranscode,
|
||||||
forceDirectPlay: this.isCasting || this.isVideo // TODO: add transcode support for chromecast
|
forceDirectPlay: this.isCasting || this.isVideo // TODO: add transcode support for chromecast
|
||||||
}
|
}
|
||||||
|
console.log('Payload:', payload)
|
||||||
const path = this.episodeId ? `/api/items/${this.libraryItem.id}/play/${this.episodeId}` : `/api/items/${this.libraryItem.id}/play`
|
const path = this.episodeId ? `/api/items/${this.libraryItem.id}/play/${this.episodeId}` : `/api/items/${this.libraryItem.id}/play`
|
||||||
const session = await this.ctx.$axios.$post(path, payload).catch((error) => {
|
const session = await this.ctx.$axios.$post(path, payload).catch((error) => {
|
||||||
console.error('Failed to start stream', error)
|
console.error('Failed to start stream', error)
|
||||||
})
|
})
|
||||||
|
console.log(session)
|
||||||
this.prepareSession(session)
|
this.prepareSession(session)
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareOpenSession(session, playbackRate) { // Session opened on init socket
|
prepareOpenSession(session, playbackRate) {
|
||||||
|
// Session opened on init socket
|
||||||
if (!this.player) this.switchPlayer() // Must set player first for open sessions
|
if (!this.player) this.switchPlayer() // Must set player first for open sessions
|
||||||
|
|
||||||
this.libraryItem = session.libraryItem
|
this.libraryItem = session.libraryItem
|
||||||
|
|
@ -241,14 +263,14 @@ export default class PlayerHandler {
|
||||||
|
|
||||||
this.player.set(this.libraryItem, videoTrack, this.isHlsTranscode, this.startTime, this.playWhenReady)
|
this.player.set(this.libraryItem, videoTrack, this.isHlsTranscode, this.startTime, this.playWhenReady)
|
||||||
} else {
|
} else {
|
||||||
var audioTracks = session.audioTracks.map(at => new AudioTrack(at, this.userToken))
|
var audioTracks = session.audioTracks.map((at) => new AudioTrack(at, this.userToken))
|
||||||
|
|
||||||
this.ctx.playerLoading = true
|
this.ctx.playerLoading = true
|
||||||
this.isHlsTranscode = true
|
this.isHlsTranscode = true
|
||||||
if (session.playMethod === this.ctx.$constants.PlayMethod.DIRECTPLAY) {
|
if (session.playMethod === this.ctx.$constants.PlayMethod.DIRECTPLAY) {
|
||||||
this.isHlsTranscode = false
|
this.isHlsTranscode = false
|
||||||
}
|
}
|
||||||
|
console.log('blub', audioTracks)
|
||||||
this.player.set(this.libraryItem, audioTracks, this.isHlsTranscode, this.startTime, this.playWhenReady)
|
this.player.set(this.libraryItem, audioTracks, this.isHlsTranscode, this.startTime, this.playWhenReady)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,7 +317,7 @@ export default class PlayerHandler {
|
||||||
const currentTime = this.player.getCurrentTime()
|
const currentTime = this.player.getCurrentTime()
|
||||||
this.ctx.setCurrentTime(currentTime)
|
this.ctx.setCurrentTime(currentTime)
|
||||||
|
|
||||||
const exactTimeElapsed = ((Date.now() - lastTick) / 1000)
|
const exactTimeElapsed = (Date.now() - lastTick) / 1000
|
||||||
lastTick = Date.now()
|
lastTick = Date.now()
|
||||||
this.listeningTimeSinceSync += exactTimeElapsed
|
this.listeningTimeSinceSync += exactTimeElapsed
|
||||||
const TimeToWaitBeforeSync = this.lastSyncTime > 0 ? 10 : 20
|
const TimeToWaitBeforeSync = this.lastSyncTime > 0 ? 10 : 20
|
||||||
|
|
@ -340,17 +362,20 @@ export default class PlayerHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.listeningTimeSinceSync = 0
|
this.listeningTimeSinceSync = 0
|
||||||
this.ctx.$axios.$post(`/api/session/${this.currentSessionId}/sync`, syncData, { timeout: 9000 }).then(() => {
|
this.ctx.$axios
|
||||||
this.failedProgressSyncs = 0
|
.$post(`/api/session/${this.currentSessionId}/sync`, syncData, { timeout: 9000 })
|
||||||
}).catch((error) => {
|
.then(() => {
|
||||||
console.error('Failed to update session progress', error)
|
|
||||||
// After 4 failed sync attempts show an alert toast
|
|
||||||
this.failedProgressSyncs++
|
|
||||||
if (this.failedProgressSyncs >= 4) {
|
|
||||||
this.ctx.showFailedProgressSyncs()
|
|
||||||
this.failedProgressSyncs = 0
|
this.failedProgressSyncs = 0
|
||||||
}
|
})
|
||||||
})
|
.catch((error) => {
|
||||||
|
console.error('Failed to update session progress', error)
|
||||||
|
// After 4 failed sync attempts show an alert toast
|
||||||
|
this.failedProgressSyncs++
|
||||||
|
if (this.failedProgressSyncs >= 4) {
|
||||||
|
this.ctx.showFailedProgressSyncs()
|
||||||
|
this.failedProgressSyncs = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
stopPlayInterval() {
|
stopPlayInterval() {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ export const state = () => ({
|
||||||
selectedRawCoverUrl: null,
|
selectedRawCoverUrl: null,
|
||||||
isCasting: false, // Actively casting
|
isCasting: false, // Actively casting
|
||||||
isChromecastInitialized: false, // Script loadeds
|
isChromecastInitialized: false, // Script loadeds
|
||||||
|
dlnaDevice: '',
|
||||||
|
dlnaDevices: [],
|
||||||
showBatchQuickMatchModal: false,
|
showBatchQuickMatchModal: false,
|
||||||
dateFormats: [
|
dateFormats: [
|
||||||
{
|
{
|
||||||
|
|
@ -118,6 +120,12 @@ export const getters = {
|
||||||
},
|
},
|
||||||
getIsBatchSelectingMediaItems: (state) => {
|
getIsBatchSelectingMediaItems: (state) => {
|
||||||
return state.selectedMediaItems.length
|
return state.selectedMediaItems.length
|
||||||
|
},
|
||||||
|
getDLNAdevice: (state) => {
|
||||||
|
return state.dlnaDevice
|
||||||
|
},
|
||||||
|
getDLNAdevices: (state) => {
|
||||||
|
return state.dlnaDevices
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,5 +229,17 @@ export const mutations = {
|
||||||
} else if (selected && !isAlreadySelected) {
|
} else if (selected && !isAlreadySelected) {
|
||||||
state.selectedMediaItems.push(item)
|
state.selectedMediaItems.push(item)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
setDlnaDevices(state, val){
|
||||||
|
state.dlnaDevices = val
|
||||||
|
for (var device in devices){
|
||||||
|
if (device.host == state.dlnaDevice){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.dlnaDevice = ''
|
||||||
|
},
|
||||||
|
setDlnaDevice(state, val){
|
||||||
|
state.dlnaDevice = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,33 +32,33 @@ export const state = () => ({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
getServerSetting: state => key => {
|
getServerSetting: (state) => (key) => {
|
||||||
if (!state.serverSettings) return null
|
if (!state.serverSettings) return null
|
||||||
return state.serverSettings[key]
|
return state.serverSettings[key]
|
||||||
},
|
},
|
||||||
getLibraryItemIdStreaming: state => {
|
getLibraryItemIdStreaming: (state) => {
|
||||||
return state.streamLibraryItem?.id || null
|
return state.streamLibraryItem?.id || null
|
||||||
},
|
},
|
||||||
getIsStreamingFromDifferentLibrary: (state, getters, rootState) => {
|
getIsStreamingFromDifferentLibrary: (state, getters, rootState) => {
|
||||||
if (!state.streamLibraryItem) return false
|
if (!state.streamLibraryItem) return false
|
||||||
return state.streamLibraryItem.libraryId !== rootState.libraries.currentLibraryId
|
return state.streamLibraryItem.libraryId !== rootState.libraries.currentLibraryId
|
||||||
},
|
},
|
||||||
getIsMediaStreaming: state => (libraryItemId, episodeId) => {
|
getIsMediaStreaming: (state) => (libraryItemId, episodeId) => {
|
||||||
if (!state.streamLibraryItem) return null
|
if (!state.streamLibraryItem) return null
|
||||||
if (!episodeId) return state.streamLibraryItem.id == libraryItemId
|
if (!episodeId) return state.streamLibraryItem.id == libraryItemId
|
||||||
return state.streamLibraryItem.id == libraryItemId && state.streamEpisodeId == episodeId
|
return state.streamLibraryItem.id == libraryItemId && state.streamEpisodeId == episodeId
|
||||||
},
|
},
|
||||||
getIsMediaQueued: state => (libraryItemId, episodeId) => {
|
getIsMediaQueued: (state) => (libraryItemId, episodeId) => {
|
||||||
return state.playerQueueItems.some(i => {
|
return state.playerQueueItems.some((i) => {
|
||||||
if (!episodeId) return i.libraryItemId === libraryItemId
|
if (!episodeId) return i.libraryItemId === libraryItemId
|
||||||
return i.libraryItemId === libraryItemId && i.episodeId === episodeId
|
return i.libraryItemId === libraryItemId && i.episodeId === episodeId
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
getBookshelfView: state => {
|
getBookshelfView: (state) => {
|
||||||
if (!state.serverSettings || isNaN(state.serverSettings.bookshelfView)) return Constants.BookshelfView.STANDARD
|
if (!state.serverSettings || isNaN(state.serverSettings.bookshelfView)) return Constants.BookshelfView.STANDARD
|
||||||
return state.serverSettings.bookshelfView
|
return state.serverSettings.bookshelfView
|
||||||
},
|
},
|
||||||
getHomeBookshelfView: state => {
|
getHomeBookshelfView: (state) => {
|
||||||
if (!state.serverSettings || isNaN(state.serverSettings.homeBookshelfView)) return Constants.BookshelfView.STANDARD
|
if (!state.serverSettings || isNaN(state.serverSettings.homeBookshelfView)) return Constants.BookshelfView.STANDARD
|
||||||
return state.serverSettings.homeBookshelfView
|
return state.serverSettings.homeBookshelfView
|
||||||
}
|
}
|
||||||
|
|
@ -69,17 +69,20 @@ export const actions = {
|
||||||
const updatePayload = {
|
const updatePayload = {
|
||||||
...payload
|
...payload
|
||||||
}
|
}
|
||||||
return this.$axios.$patch('/api/settings', updatePayload).then((result) => {
|
return this.$axios
|
||||||
if (result.success) {
|
.$patch('/api/settings', updatePayload)
|
||||||
commit('setServerSettings', result.serverSettings)
|
.then((result) => {
|
||||||
return true
|
if (result.success) {
|
||||||
} else {
|
commit('setServerSettings', result.serverSettings)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Failed to update server settings', error)
|
||||||
return false
|
return false
|
||||||
}
|
})
|
||||||
}).catch((error) => {
|
|
||||||
console.error('Failed to update server settings', error)
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
checkForUpdate({ commit }) {
|
checkForUpdate({ commit }) {
|
||||||
const VERSION_CHECK_BUFF = 1000 * 60 * 5 // 5 minutes
|
const VERSION_CHECK_BUFF = 1000 * 60 * 5 // 5 minutes
|
||||||
|
|
@ -180,7 +183,7 @@ export const mutations = {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
addItemToQueue(state, item) {
|
addItemToQueue(state, item) {
|
||||||
const exists = state.playerQueueItems.some(i => {
|
const exists = state.playerQueueItems.some((i) => {
|
||||||
if (!i.episodeId) return i.libraryItemId === item.libraryItemId
|
if (!i.episodeId) return i.libraryItemId === item.libraryItemId
|
||||||
return i.libraryItemId === item.libraryItemId && i.episodeId === item.episodeId
|
return i.libraryItemId === item.libraryItemId && i.episodeId === item.episodeId
|
||||||
})
|
})
|
||||||
|
|
@ -235,5 +238,6 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
setInnerModalOpen(state, val) {
|
setInnerModalOpen(state, val) {
|
||||||
state.innerModalOpen = val
|
state.innerModalOpen = val
|
||||||
}
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
250
package-lock.json
generated
250
package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"cookie-parser": "^1.4.6",
|
"cookie-parser": "^1.4.6",
|
||||||
|
"dlnacasts": "^0.1.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-session": "^1.17.3",
|
"express-session": "^1.17.3",
|
||||||
"graceful-fs": "^4.2.10",
|
"graceful-fs": "^4.2.10",
|
||||||
|
|
@ -1096,6 +1097,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-from": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
|
||||||
|
},
|
||||||
"node_modules/bytes": {
|
"node_modules/bytes": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||||
|
|
@ -1385,6 +1391,52 @@
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/concat-stream": {
|
||||||
|
"version": "1.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||||
|
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||||
|
"engines": [
|
||||||
|
"node >= 0.8"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-from": "^1.0.0",
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"readable-stream": "^2.2.2",
|
||||||
|
"typedarray": "^0.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/concat-stream/node_modules/isarray": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
|
||||||
|
},
|
||||||
|
"node_modules/concat-stream/node_modules/readable-stream": {
|
||||||
|
"version": "2.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||||
|
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/concat-stream/node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"node_modules/concat-stream/node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/console-control-strings": {
|
"node_modules/console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||||
|
|
@ -1448,6 +1500,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/core-util-is": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
|
},
|
||||||
"node_modules/cors": {
|
"node_modules/cors": {
|
||||||
"version": "2.8.5",
|
"version": "2.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||||
|
|
@ -1494,6 +1551,17 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/decompress-response": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-response": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/deep-eql": {
|
"node_modules/deep-eql": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
|
||||||
|
|
@ -1568,6 +1636,33 @@
|
||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dlnacasts": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dlnacasts/-/dlnacasts-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-JsNDoe2UbFzsXRdOHmGK8JO1SR/3Dj7J9LCmTgo35ppYQ0dR2O+oe8T2kABBF4+Qas4auaILQ4rul+LWMhtEdw==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^2.1.3",
|
||||||
|
"mime": "^1.3.4",
|
||||||
|
"node-ssdp": "^2.7.1",
|
||||||
|
"run-parallel": "^1.1.6",
|
||||||
|
"simple-get": "^2.1.0",
|
||||||
|
"thunky": "^0.1.0",
|
||||||
|
"upnp-mediarenderer-client": "^1.2.2",
|
||||||
|
"xml2js": "^0.4.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dlnacasts/node_modules/xml2js": {
|
||||||
|
"version": "0.4.23",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
|
||||||
|
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
|
||||||
|
"dependencies": {
|
||||||
|
"sax": ">=0.6.0",
|
||||||
|
"xmlbuilder": "~11.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dom-serializer": {
|
"node_modules/dom-serializer": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||||
|
|
@ -1643,6 +1738,22 @@
|
||||||
"integrity": "sha512-T5q3pjQon853xxxHUq3ZP68ZpvJHuSMY2+BZaW3QzjS4HvNuvsMmZ/+lU+nCrftre1jFZ+OSlExynXWBihnXzw==",
|
"integrity": "sha512-T5q3pjQon853xxxHUq3ZP68ZpvJHuSMY2+BZaW3QzjS4HvNuvsMmZ/+lU+nCrftre1jFZ+OSlExynXWBihnXzw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/elementtree": {
|
||||||
|
"version": "0.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz",
|
||||||
|
"integrity": "sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"sax": "1.1.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/elementtree/node_modules/sax": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg=="
|
||||||
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
|
@ -3061,6 +3172,14 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mimic-response": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||||
|
|
@ -3475,6 +3594,14 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/network-address": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/network-address/-/network-address-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-Q6878fmvItA1mE7H9Il46lONgFgTzX2f98zkS0c2YlkCACzNjwvum/8Kq693IQpxe9zy+w+Zm/4p0wQreLEtZw==",
|
||||||
|
"bin": {
|
||||||
|
"network-address": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nise": {
|
"node_modules/nise": {
|
||||||
"version": "5.1.5",
|
"version": "5.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz",
|
||||||
|
|
@ -3661,6 +3788,23 @@
|
||||||
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
"integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/node-ssdp": {
|
||||||
|
"version": "2.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-ssdp/-/node-ssdp-2.9.1.tgz",
|
||||||
|
"integrity": "sha512-yGUSsm7HKxcv1XU0X6BIMWaOl/SaXqrIhwZCdklmAzwjG6qt+hnJwzs+VigCuRMP+jhSyoVBvHnoc95VgxbcuQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^2.2.0",
|
||||||
|
"ip": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-ssdp/node_modules/ip": {
|
||||||
|
"version": "1.1.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz",
|
||||||
|
"integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ=="
|
||||||
|
},
|
||||||
"node_modules/node-tone": {
|
"node_modules/node-tone": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-tone/-/node-tone-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-tone/-/node-tone-1.0.1.tgz",
|
||||||
|
|
@ -4121,6 +4265,11 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/process-nextick-args": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
|
},
|
||||||
"node_modules/process-on-spawn": {
|
"node_modules/process-on-spawn": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz",
|
||||||
|
|
@ -4184,6 +4333,25 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/queue-microtask": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/random-bytes": {
|
"node_modules/random-bytes": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||||
|
|
@ -4312,6 +4480,28 @@
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/run-parallel": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"queue-microtask": "^1.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/safe-buffer": {
|
"node_modules/safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
|
@ -4564,6 +4754,35 @@
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-concat": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/simple-get": {
|
||||||
|
"version": "2.8.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz",
|
||||||
|
"integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==",
|
||||||
|
"dependencies": {
|
||||||
|
"decompress-response": "^3.3.0",
|
||||||
|
"once": "^1.3.1",
|
||||||
|
"simple-concat": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/simple-update-notifier": {
|
"node_modules/simple-update-notifier": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
|
||||||
|
|
@ -4975,6 +5194,11 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/thunky": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-vquTt/sKNzFqFK8DKLg33U7deg93WKYH4CE2Ul9hOyMCfm7VXgM7GJQRpPAgnmgnrf407Fcq8TQVEKlbavAu+A=="
|
||||||
|
},
|
||||||
"node_modules/to-fast-properties": {
|
"node_modules/to-fast-properties": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||||
|
|
@ -5056,6 +5280,11 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/typedarray": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
|
||||||
|
},
|
||||||
"node_modules/typedarray-to-buffer": {
|
"node_modules/typedarray-to-buffer": {
|
||||||
"version": "3.1.5",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||||
|
|
@ -5138,6 +5367,27 @@
|
||||||
"browserslist": ">= 4.21.0"
|
"browserslist": ">= 4.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/upnp-device-client": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/upnp-device-client/-/upnp-device-client-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-5BcYJJU5wXR6xGko/UuLSavybAA0sZx17Hka4ikOXwA9Ze3fiExmgUDytAXE5qjdbKzARl0lOLC3hPSUwAa3eQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"concat-stream": "^1.4.8",
|
||||||
|
"debug": "^2.1.3",
|
||||||
|
"elementtree": "~0.1.6",
|
||||||
|
"network-address": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/upnp-mediarenderer-client": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/upnp-mediarenderer-client/-/upnp-mediarenderer-client-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-F+C3Yceoz0j3ZWEchz5tpaOEqkbpObRUmeuPGc9+2u2YvC1CDbXGQ6mjbM10MDhnUJ0tTWYTufpj6xsWctnULw==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^2.1.3",
|
||||||
|
"elementtree": "^0.1.6",
|
||||||
|
"upnp-device-client": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
|
|
||||||
10
package.json
10
package.json
|
|
@ -52,7 +52,8 @@
|
||||||
"socket.io": "^4.5.4",
|
"socket.io": "^4.5.4",
|
||||||
"sqlite3": "^5.1.6",
|
"sqlite3": "^5.1.6",
|
||||||
"ssrf-req-filter": "^1.1.0",
|
"ssrf-req-filter": "^1.1.0",
|
||||||
"xml2js": "^0.5.0"
|
"xml2js": "^0.5.0",
|
||||||
|
"dlnacasts": "^0.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"chai": "^4.3.10",
|
"chai": "^4.3.10",
|
||||||
|
|
@ -60,5 +61,12 @@
|
||||||
"nodemon": "^2.0.20",
|
"nodemon": "^2.0.20",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"sinon": "^17.0.1"
|
"sinon": "^17.0.1"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"dlnacasts": {
|
||||||
|
"upnp-mediarenderer-client":{
|
||||||
|
"typescript": "git+https://github.com/kontiko/node-upnp-device-client-sonos-support.git"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,11 @@ const RssFeedManager = require('./managers/RssFeedManager')
|
||||||
const CronManager = require('./managers/CronManager')
|
const CronManager = require('./managers/CronManager')
|
||||||
const ApiCacheManager = require('./managers/ApiCacheManager')
|
const ApiCacheManager = require('./managers/ApiCacheManager')
|
||||||
const BinaryManager = require('./managers/BinaryManager')
|
const BinaryManager = require('./managers/BinaryManager')
|
||||||
|
<<<<<<< Updated upstream
|
||||||
const ShareManager = require('./managers/ShareManager')
|
const ShareManager = require('./managers/ShareManager')
|
||||||
|
=======
|
||||||
|
const DLNAManager = require('./managers/DLNAManager')
|
||||||
|
>>>>>>> Stashed changes
|
||||||
const LibraryScanner = require('./scanner/LibraryScanner')
|
const LibraryScanner = require('./scanner/LibraryScanner')
|
||||||
|
|
||||||
//Import the main Passport and Express-Session library
|
//Import the main Passport and Express-Session library
|
||||||
|
|
@ -77,6 +81,7 @@ class Server {
|
||||||
this.cronManager = new CronManager(this.podcastManager)
|
this.cronManager = new CronManager(this.podcastManager)
|
||||||
this.apiCacheManager = new ApiCacheManager()
|
this.apiCacheManager = new ApiCacheManager()
|
||||||
this.binaryManager = new BinaryManager()
|
this.binaryManager = new BinaryManager()
|
||||||
|
this.DLNAManager = new DLNAManager()
|
||||||
|
|
||||||
// Routers
|
// Routers
|
||||||
this.apiRouter = new ApiRouter(this)
|
this.apiRouter = new ApiRouter(this)
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,23 @@ class SocketAuthority {
|
||||||
*/
|
*/
|
||||||
getUsersOnline() {
|
getUsersOnline() {
|
||||||
const onlineUsersMap = {}
|
const onlineUsersMap = {}
|
||||||
Object.values(this.clients).filter(c => c.user).forEach(client => {
|
Object.values(this.clients)
|
||||||
if (onlineUsersMap[client.user.id]) {
|
.filter((c) => c.user)
|
||||||
onlineUsersMap[client.user.id].connections++
|
.forEach((client) => {
|
||||||
} else {
|
if (onlineUsersMap[client.user.id]) {
|
||||||
onlineUsersMap[client.user.id] = {
|
onlineUsersMap[client.user.id].connections++
|
||||||
...client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions),
|
} else {
|
||||||
connections: 1
|
onlineUsersMap[client.user.id] = {
|
||||||
|
...client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions),
|
||||||
|
connections: 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
|
||||||
return Object.values(onlineUsersMap)
|
return Object.values(onlineUsersMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientsForUser(userId) {
|
getClientsForUser(userId) {
|
||||||
return Object.values(this.clients).filter(c => c.user && c.user.id === userId)
|
return Object.values(this.clients).filter((c) => c.user && c.user.id === userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -81,10 +83,8 @@ class SocketAuthority {
|
||||||
close(callback) {
|
close(callback) {
|
||||||
Logger.info('[SocketAuthority] Shutting down')
|
Logger.info('[SocketAuthority] Shutting down')
|
||||||
// This will close all open socket connections, and also close the underlying http server
|
// This will close all open socket connections, and also close the underlying http server
|
||||||
if (this.io)
|
if (this.io) this.io.close(callback)
|
||||||
this.io.close(callback)
|
else callback()
|
||||||
else
|
|
||||||
callback()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(Server) {
|
initialize(Server) {
|
||||||
|
|
@ -93,7 +93,7 @@ class SocketAuthority {
|
||||||
this.io = new SocketIO.Server(this.Server.server, {
|
this.io = new SocketIO.Server(this.Server.server, {
|
||||||
cors: {
|
cors: {
|
||||||
origin: '*',
|
origin: '*',
|
||||||
methods: ["GET", "POST"]
|
methods: ['GET', 'POST']
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -113,6 +113,9 @@ class SocketAuthority {
|
||||||
// Scanning
|
// Scanning
|
||||||
socket.on('cancel_scan', (libraryId) => this.cancelScan(libraryId))
|
socket.on('cancel_scan', (libraryId) => this.cancelScan(libraryId))
|
||||||
|
|
||||||
|
//DLNA
|
||||||
|
|
||||||
|
socket.on('dlna_start', (data) => this.Server.DLNAManager.start_playback(socket.id, data))
|
||||||
// Logs
|
// Logs
|
||||||
socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
|
socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
|
||||||
socket.on('remove_log_listener', () => Logger.removeSocketListener(socket.id))
|
socket.on('remove_log_listener', () => Logger.removeSocketListener(socket.id))
|
||||||
|
|
|
||||||
14
server/controllers/DLNAController.js
Normal file
14
server/controllers/DLNAController.js
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
class DLNAController {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
async get_Devices(req, res) {
|
||||||
|
var count = 0
|
||||||
|
const players = await this.DLNAManager.Client.players
|
||||||
|
|
||||||
|
return res.status(200).send(players)
|
||||||
|
}
|
||||||
|
middleware(req, res, next) {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = new DLNAController()
|
||||||
15
server/managers/DLNAManager.js
Normal file
15
server/managers/DLNAManager.js
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
class DLNAManager {
|
||||||
|
constructor() {
|
||||||
|
console.log('It worked')
|
||||||
|
this.Client = require('dlnacasts')()
|
||||||
|
this.Client.on('update', function (player) {
|
||||||
|
console.log('all players: ', this.players)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
start_playback(id, data) {
|
||||||
|
console.log(id, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = DLNAManager
|
||||||
|
|
@ -30,8 +30,12 @@ const ToolsController = require('../controllers/ToolsController')
|
||||||
const RSSFeedController = require('../controllers/RSSFeedController')
|
const RSSFeedController = require('../controllers/RSSFeedController')
|
||||||
const CustomMetadataProviderController = require('../controllers/CustomMetadataProviderController')
|
const CustomMetadataProviderController = require('../controllers/CustomMetadataProviderController')
|
||||||
const MiscController = require('../controllers/MiscController')
|
const MiscController = require('../controllers/MiscController')
|
||||||
|
<<<<<<< Updated upstream
|
||||||
const ShareController = require('../controllers/ShareController')
|
const ShareController = require('../controllers/ShareController')
|
||||||
|
|
||||||
|
=======
|
||||||
|
const DLNAController = require('../controllers/DLNAController')
|
||||||
|
>>>>>>> Stashed changes
|
||||||
const Author = require('../objects/entities/Author')
|
const Author = require('../objects/entities/Author')
|
||||||
const Series = require('../objects/entities/Series')
|
const Series = require('../objects/entities/Series')
|
||||||
|
|
||||||
|
|
@ -52,6 +56,7 @@ class ApiRouter {
|
||||||
this.notificationManager = Server.notificationManager
|
this.notificationManager = Server.notificationManager
|
||||||
this.emailManager = Server.emailManager
|
this.emailManager = Server.emailManager
|
||||||
this.apiCacheManager = Server.apiCacheManager
|
this.apiCacheManager = Server.apiCacheManager
|
||||||
|
this.DLNAManager = Server.DLNAManager
|
||||||
|
|
||||||
this.router = express()
|
this.router = express()
|
||||||
this.router.disable('x-powered-by')
|
this.router.disable('x-powered-by')
|
||||||
|
|
@ -311,12 +316,15 @@ class ApiRouter {
|
||||||
this.router.post('/custom-metadata-providers', CustomMetadataProviderController.middleware.bind(this), CustomMetadataProviderController.create.bind(this))
|
this.router.post('/custom-metadata-providers', CustomMetadataProviderController.middleware.bind(this), CustomMetadataProviderController.create.bind(this))
|
||||||
this.router.delete('/custom-metadata-providers/:id', CustomMetadataProviderController.middleware.bind(this), CustomMetadataProviderController.delete.bind(this))
|
this.router.delete('/custom-metadata-providers/:id', CustomMetadataProviderController.middleware.bind(this), CustomMetadataProviderController.delete.bind(this))
|
||||||
|
|
||||||
|
<<<<<<< Updated upstream
|
||||||
//
|
//
|
||||||
// Share routes
|
// Share routes
|
||||||
//
|
//
|
||||||
this.router.post('/share/mediaitem', ShareController.createMediaItemShare.bind(this))
|
this.router.post('/share/mediaitem', ShareController.createMediaItemShare.bind(this))
|
||||||
this.router.delete('/share/mediaitem/:id', ShareController.deleteMediaItemShare.bind(this))
|
this.router.delete('/share/mediaitem/:id', ShareController.deleteMediaItemShare.bind(this))
|
||||||
|
|
||||||
|
=======
|
||||||
|
>>>>>>> Stashed changes
|
||||||
//
|
//
|
||||||
// Misc Routes
|
// Misc Routes
|
||||||
//
|
//
|
||||||
|
|
@ -337,6 +345,12 @@ class ApiRouter {
|
||||||
this.router.post('/watcher/update', MiscController.updateWatchedPath.bind(this))
|
this.router.post('/watcher/update', MiscController.updateWatchedPath.bind(this))
|
||||||
this.router.get('/stats/year/:year', MiscController.getAdminStatsForYear.bind(this))
|
this.router.get('/stats/year/:year', MiscController.getAdminStatsForYear.bind(this))
|
||||||
this.router.get('/logger-data', MiscController.getLoggerData.bind(this))
|
this.router.get('/logger-data', MiscController.getLoggerData.bind(this))
|
||||||
|
|
||||||
|
//
|
||||||
|
//DLNA Routes
|
||||||
|
//
|
||||||
|
|
||||||
|
this.router.get('/dlna/devices', DLNAController.middleware.bind(this), DLNAController.get_Devices.bind(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue