Skip to content

Commit

Permalink
new feature: DLNA casting
Browse files Browse the repository at this point in the history
- tested working on LG WebOS (B9)
- todo: subtitles
- todo: cast local files
  • Loading branch information
vankasteelj committed Nov 10, 2024
1 parent 0ba61fe commit bcf53cf
Show file tree
Hide file tree
Showing 10 changed files with 368 additions and 14 deletions.
15 changes: 10 additions & 5 deletions app/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -750,30 +750,35 @@
overflow-y: scroll;
}

#details-loading .player {
#details-loading .player,
#details-loading .dlnaplayer {
font-size: 20px;
height: 20%;
user-select: none;
}

#details-loading .player .control .fa {
#details-loading .player .control .fa,
#details-loading .dlnaplayer .control .fa {
background-color: transparent;
color: #2b678f;
cursor: pointer;
padding: 10px;
transition: all .5s;
}

#details-loading .player .control .fa:hover {
#details-loading .player .control .fa:hover,
#details-loading .dlnaplayer .control .fa:hover {
background-color: #2b678f;
color: #fafafa;
}

#details-loading .player .control .fa-font-small:before {
#details-loading .player .control .fa-font-small:before,
#details-loading .dlnaplayer .control .fa-font-small:before {
font-size: 12px;
}

#details-loading .player .control .separator {
#details-loading .player .control .separator,
#details-loading .dlnaplayer .control .separator {
padding: 0 30px;
}

Expand Down
14 changes: 14 additions & 0 deletions app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,19 @@ <h4><i18n>My most active day is:</i18n></h4>
<div class="action">
<input type="text" id="localip-input" readonly placeholder="127.0.0.1"/>
</div>
</div>
<div class="option">
<div class="text i18n" title="Cast to DLNA devices on your local network">
<i18n>DLNA casting</i18n>
</div>
<div class="action">
<i18n>no</i18n>&nbsp;
<label class="switch">
<input id="allow_dlnacasting" type="checkbox">
<span class="slider round"></span>
</label>
&nbsp;<i18n>yes</i18n>
</div>
</div>
<div class="option">
<div class="text i18n" title="Other devices on your local network using this application will be able to see, search and play your local Movies and Shows collection">
Expand Down Expand Up @@ -1329,6 +1342,7 @@ <h3><i18n>Plugins tester</i18n></h3>
<script src="js/lib/network.js" type="application/javascript"></script>
<script src="js/lib/images.js" type="application/javascript"></script>
<script src="js/lib/player.js" type="application/javascript"></script>
<script src="js/lib/cast.js" type="application/javascript"></script>
<script src="js/lib/search.js" type="application/javascript"></script>
<script src="js/lib/plugins.js" type="application/javascript"></script>
<script src="js/lib/streamer.js" type="application/javascript"></script>
Expand Down
1 change: 1 addition & 0 deletions app/js/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const Nodempv2 = require('node-mpv-2')
const Trakttv = require('trakt.tv')
const Opensubtitles = require('opensubtitles.com')
const Webtorrent = require('webtorrent')
const Dlnacasts = require('dlnacasts2')

const PKJSON = require('../package.json')
const countryList = require('../app/js/vendor/ISO3166-1.alpha2.json')
Expand Down
80 changes: 80 additions & 0 deletions app/js/lib/cast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
'use strict'

const Cast = {
clients: {
dlna: Dlnacasts()
},
activePlayer: undefined,
players: [],
scan: () => {
// DLNA
Cast.clients.dlna = Dlnacasts()
Cast.clients.dlna.on('update', player => {
//console.info('Found DLNA Device: %s at %s', player.name, player.host)
let exists = false
for (const i in Cast.players) {
if (Cast.players[i].name === player.name) {
exists = true
console.info('Updating the available players list with %s (%s)', player.name, player.host)
Cast.players[i] = {
name: player.name,
url: player.host,
player: player
}
}
}

if (!exists) {
console.info('Adding %s (%s) to the list of available players', player.name, player.host)
Cast.players.push({
name: player.name,
url: player.host,
player: player
})
}
})

console.info('Scanning for DLNA devices...')
Cast.clients.dlna.update()
},
cast: (name, title, url, subtitle) => {
if (Cast.activePlayer) Cast.activePlayer.stop()

for (const i in Cast.players) {
if (Cast.players[i].name === name) {
const player = Cast.players[i].player
let media = {
title: title,
dlnaFeatures: 'DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01100000000000000000000000000000'
}
if (subtitle) media.subtitte = [subtitle]
player.play(url, media, (err, status) => {
if (err) {
Cast.activePlayer = undefined
} else {
Cast.activePlayer = player
}
})
}
}
},
play: () => {
if (Cast.activePlayer) {
console.info('DLNA: play (%s)', Cast.activePlayer.name)
Cast.activePlayer.play()
}
},
pause: () => {
if (Cast.activePlayer) {
console.info('DLNA: pause (%s)', Cast.activePlayer.name)
Cast.activePlayer.pause()
}
},
stop: () => {
if (Cast.activePlayer) {
console.info('DLNA: stop (%s)', Cast.activePlayer.name)
Cast.activePlayer.stop()
Cast.activePlayer = undefined
}
}
}
36 changes: 36 additions & 0 deletions app/js/main/details.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ const Details = {
$(`#${Details.from}`).show()
window.scrollTo(0, (Details.fromScroll || 0))
$('#details').hide()
Cast.stop()
},

local: {
Expand Down Expand Up @@ -674,6 +675,26 @@ const Details = {
})
},

keepWatchingDlna: (player) => {
if (Details.from === 'locals') {
$('#keepWatching .message').text(i18n.__('DLNA casting is not allowed on local files')).css('color', '#933')
$('#keepWatching .casting .logo').removeClass('fa-feed').addClass('fa-warning')
$('#keepWatching .casting').show()
$('#keepWatching .selector').hide()
return
}

$('#keepWatching .message').text(i18n.__('Currently casting to %s', player.name))
$('#keepWatching .ip').text(player.ip)
$('#keepWatching .casting').show()
$('#keepWatching .selector').hide()

const title = $('#details-metadata .titles').text().replace(/\W+/g, ' ')
const url = Streamer.streaminfo.url.replace('127.0.0.1', DB.sync.get('localip'))
const subtitle = undefined // todo
Cast.cast(player.name, title, url, subtitle)
},

keepWatchingPopup: () => {
Player.mpv.pause()

Expand All @@ -683,6 +704,7 @@ const Details = {
$('#keepWatching .casting').hide()
$('#keepWatching .selector').show()

// add peers
for (const i in Network.peers) {
const item = `<div class="peer" onClick="Details.keepWatchingOn(Network.peers[${i}])">` +
`<span class="name">${Network.peers[i].name}</span>` +
Expand All @@ -691,6 +713,15 @@ const Details = {
'</div>'
$('#keepWatching .selector .list').append(item)
}

// add dlna
for (const i in Cast.players) {
const item = `<div class="peer" onClick="Details.keepWatchingDlna(Cast.players[${i}])">` +
`<span class="name">${Cast.players[i].name}</span>` +
`<span class="ip">${Cast.players[i].url}</span>` +
`</div>`
$('#keepWatching .selector .list').append(item)
}
$('#keepWatching').show()
},

Expand All @@ -703,6 +734,11 @@ const Details = {
if (DB.sync.get('localsharing') && DB.sync.get('localplayback') && Network.peers.length) {
$('#cast .peers').show()
}

// dlna casting
if (DB.sync.get('dlnacasting') && Cast.players.length) {
$('#cast .peers').show()
}
},

openFileSelector: (files) => {
Expand Down
13 changes: 13 additions & 0 deletions app/js/utils/boot.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,12 @@ const Boot = {
$('#settings .resumeplayback').show()
}

// allow DLNA search
if (DB.sync.get('dlnacasting')) {
document.querySelector('#allow_dlnacasting').checked = true
Cast.scan()
}

// allow direct playback feature on local network
if (DB.sync.get('localplayback')) {
document.querySelector('#allow_resumeplayback').checked = true
Expand Down Expand Up @@ -350,6 +356,13 @@ const Boot = {
}
})

document.querySelector('#allow_dlnacasting').addEventListener('click', (evt) => {
DB.sync.store(evt.target.checked, 'dlnacasting')
if (evt.target.checked) {
Cast.scan()
}
})

document.querySelector('#allow_resumeplayback').addEventListener('click', (evt) => {
DB.sync.store(evt.target.checked, 'localplayback')
Network.disconnect()
Expand Down
5 changes: 4 additions & 1 deletion app/localization/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,8 @@
"Activate the feature and display a 'Rate and review' popup after watching a movie or a show": "Activer la fonctionnalité pour afficher une fenêtre 'Notez et commentez' après avoir regardé un film ou une série",
"Default: 55": "Par défaut : 55",
"Pin this": "Epingler",
"Game-show": "Jeu télévisé"
"Game-show": "Jeu télévisé",
"DLNA casting": "DLNA casting",
"Cast to DLNA devices on your local network": "Caster via DLNA sur vos périphériques connectés au réseau local",
"DLNA casting is not allowed on local files": "Caster via DLNA n'est pas autorisé avec des fichiers locaux"
}
2 changes: 2 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ const sd = (fix) => {
'whealth',
'readdirp',
'Webtorrent',
'Dlnacasts',
'Opensubtitles',
'langs',
'Trakttv',
Expand All @@ -445,6 +446,7 @@ const sd = (fix) => {
'Local',
'Network',
'Player',
'Cast',
'Plugins',
'Profiles',
'Search',
Expand Down
Loading

0 comments on commit bcf53cf

Please sign in to comment.