forked from platypush/platypush
Support for subtitles in new media webplugin - WIP
This commit is contained in:
parent
17de2a194c
commit
cf23e2fc72
18 changed files with 234 additions and 25 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -6,4 +6,4 @@
|
||||||
url = https://github.com/BlackLight/platypush.wiki.git
|
url = https://github.com/BlackLight/platypush.wiki.git
|
||||||
[submodule "platypush/backend/http/static/flag-icons"]
|
[submodule "platypush/backend/http/static/flag-icons"]
|
||||||
path = platypush/backend/http/static/flag-icons
|
path = platypush/backend/http/static/flag-icons
|
||||||
url = https://github.com/lipis/flag-icon-css.git
|
url = git@github.com:BlackLight/flag-icon-css.git
|
||||||
|
|
|
@ -14,6 +14,14 @@
|
||||||
.item-info {
|
.item-info {
|
||||||
font-size: 1.15em;
|
font-size: 1.15em;
|
||||||
letter-spacing: .02em;
|
letter-spacing: .02em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $default-hover-fg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
@import 'webpanel/plugins/media/results';
|
@import 'webpanel/plugins/media/results';
|
||||||
@import 'webpanel/plugins/media/controls';
|
@import 'webpanel/plugins/media/controls';
|
||||||
@import 'webpanel/plugins/media/info';
|
@import 'webpanel/plugins/media/info';
|
||||||
|
@import 'webpanel/plugins/media/subs';
|
||||||
|
|
||||||
.media-plugin {
|
.media-plugin {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -34,8 +34,8 @@
|
||||||
|
|
||||||
&:nth-child(odd) { background: rgba(255, 255, 255, 0.0); }
|
&:nth-child(odd) { background: rgba(255, 255, 255, 0.0); }
|
||||||
&:nth-child(even) { background: $default-bg-3; }
|
&:nth-child(even) { background: $default-bg-3; }
|
||||||
&:hover { background: $hover-bg !important; }
|
&:hover { background: $hover-bg; }
|
||||||
&.selected { background: $selected-bg !important; }
|
&.selected { background: $selected-bg; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
.media-plugin {
|
||||||
|
#media-subs {
|
||||||
|
.body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.subs-container {
|
||||||
|
.loading, .no-results {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3rem;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subs {
|
||||||
|
.list {
|
||||||
|
max-height: 50vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: .75em .5em;
|
||||||
|
border-bottom: $default-border-2;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:nth-child(odd) { background: rgba(255, 255, 255, 0.0); }
|
||||||
|
&:nth-child(even) { background: $default-bg-3; }
|
||||||
|
&.selected { background: $selected-bg; }
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $hover-bg;
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
position: relative;
|
||||||
|
padding: 1.5rem 0;
|
||||||
|
height: $subs-control-height;
|
||||||
|
|
||||||
|
button {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
margin-right: 1rem;
|
||||||
|
border: $default-border-2;
|
||||||
|
box-shadow: $btn-default-shadow;
|
||||||
|
|
||||||
|
&:hover:not([disabled]) {
|
||||||
|
box-shadow: $btn-hover-default-shadow;
|
||||||
|
color: $default-hover-fg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,3 +13,7 @@ $result-item-icon: #444;
|
||||||
$devices-dropdown-z-index: 2;
|
$devices-dropdown-z-index: 2;
|
||||||
$devices-dropdown-refresh-fg: #666;
|
$devices-dropdown-refresh-fg: #666;
|
||||||
|
|
||||||
|
$subs-control-height: 4rem;
|
||||||
|
$btn-default-shadow: 2px 2px 2px #ddd;
|
||||||
|
$btn-hover-default-shadow: 3px 3px 3px #ddd;
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c8031a673e8428b842199c0dcf66d12b6ed1d1d6
|
Subproject commit c0465f4f9ddfee44ad601e906ab541ac0ca4c57d
|
|
@ -19,7 +19,7 @@ MediaHandlers.file = Vue.extend({
|
||||||
{
|
{
|
||||||
text: 'Play with subtitles',
|
text: 'Play with subtitles',
|
||||||
iconClass: 'fas fa-closed-captioning',
|
iconClass: 'fas fa-closed-captioning',
|
||||||
action: this.searchSubtiles,
|
action: this.searchSubtitles,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -84,8 +84,23 @@ MediaHandlers.file = Vue.extend({
|
||||||
this.bus.$emit('info', (await this.getMetadata(item)));
|
this.bus.$emit('info', (await this.getMetadata(item)));
|
||||||
},
|
},
|
||||||
|
|
||||||
searchSubtitles: function(item) {
|
infoLoad: function(url) {
|
||||||
|
if (!this.matchesUrl(url))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.info(url);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
searchSubtitles: function(item) {
|
||||||
|
this.bus.$emit('search-subs', item);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created: function() {
|
||||||
|
const self = this;
|
||||||
|
setTimeout(() => {
|
||||||
|
self.infoLoadWatch = self.bus.$on('info-load', this.infoLoad);
|
||||||
|
}, 1000);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,10 @@ Vue.component('media', {
|
||||||
loading: false,
|
loading: false,
|
||||||
item: {},
|
item: {},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
subsModal: {
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -104,8 +108,9 @@ Vue.component('media', {
|
||||||
item = await this.startStreaming(item.url);
|
item = await this.startStreaming(item.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = await this.selectedDevice.play(item.url);
|
let status = await this.selectedDevice.play(item.url, item.subtitles);
|
||||||
|
|
||||||
|
this.subsModal.visible = false;
|
||||||
this.onStatusUpdate({
|
this.onStatusUpdate({
|
||||||
device: this.selectedDevice,
|
device: this.selectedDevice,
|
||||||
status: status,
|
status: status,
|
||||||
|
@ -172,6 +177,14 @@ Vue.component('media', {
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
searchSubs: function(item) {
|
||||||
|
if (typeof item === 'string')
|
||||||
|
item = {url: item};
|
||||||
|
|
||||||
|
this.subsModal.visible = true;
|
||||||
|
this.$refs.subs.search(item);
|
||||||
|
},
|
||||||
|
|
||||||
selectDevice: async function(device) {
|
selectDevice: async function(device) {
|
||||||
this.selectedDevice = device;
|
this.selectedDevice = device;
|
||||||
let status = await this.selectedDevice.status();
|
let status = await this.selectedDevice.status();
|
||||||
|
@ -254,6 +267,7 @@ Vue.component('media', {
|
||||||
this.bus.$on('results-ready', this.onResultsReady);
|
this.bus.$on('results-ready', this.onResultsReady);
|
||||||
this.bus.$on('status-update', this.onStatusUpdate);
|
this.bus.$on('status-update', this.onStatusUpdate);
|
||||||
this.bus.$on('start-streaming', this.startStreaming);
|
this.bus.$on('start-streaming', this.startStreaming);
|
||||||
|
this.bus.$on('search-subs', this.searchSubs);
|
||||||
|
|
||||||
setInterval(this.timerFunc, 1000);
|
setInterval(this.timerFunc, 1000);
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,13 @@ MediaPlayers.browser = Vue.extend({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
subFormats: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return ['vtt'];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'Browser',
|
default: 'Browser',
|
||||||
|
|
|
@ -15,6 +15,13 @@ MediaPlayers.chromecast = Vue.extend({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
subFormats: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return ['vtt'];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
device: {
|
device: {
|
||||||
type: null,
|
type: null,
|
||||||
address: null,
|
address: null,
|
||||||
|
|
|
@ -16,6 +16,13 @@ MediaPlayers.local = Vue.extend({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
subFormats: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return ['srt'];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
device: {
|
device: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
|
@ -46,10 +53,10 @@ MediaPlayers.local = Vue.extend({
|
||||||
return await request(this.pluginPrefix.concat('.status'));
|
return await request(this.pluginPrefix.concat('.status'));
|
||||||
},
|
},
|
||||||
|
|
||||||
play: async function(resource) {
|
play: async function(resource, subtitles=undefined) {
|
||||||
return await request(
|
return await request(
|
||||||
this.pluginPrefix.concat('.play'),
|
this.pluginPrefix.concat('.play'),
|
||||||
{resource: resource}
|
{resource: resource, subtitles: subtitles}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
45
platypush/backend/http/static/js/plugins/media/subs.js
Normal file
45
platypush/backend/http/static/js/plugins/media/subs.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
Vue.component('media-subs', {
|
||||||
|
template: '#tmpl-media-subs',
|
||||||
|
props: {
|
||||||
|
bus: { type: Object },
|
||||||
|
subFormats: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
media: {},
|
||||||
|
items: [],
|
||||||
|
selectedItem: undefined,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
search: async function(media) {
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
this.media = media;
|
||||||
|
this.selectedItem = undefined;
|
||||||
|
this.items = await request('media.subtitles.get_subtitles', {resource: this.media.url});
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
play: async function() {
|
||||||
|
let args = {link: this.selectedItem.SubDownloadLink};
|
||||||
|
|
||||||
|
if (this.media.url && this.media.url.startsWith('file://'))
|
||||||
|
args.media_resource = this.media.url;
|
||||||
|
|
||||||
|
if (this.subFormats.indexOf('srt') < 0)
|
||||||
|
args.convert_to_vtt = true;
|
||||||
|
|
||||||
|
this.media.subtitles = (await request('media.subtitles.download', args)).filename;
|
||||||
|
this.bus.$emit('play', this.media);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div class="col-3 item-container">
|
<div class="col-3 item-container">
|
||||||
<div class="item-info">
|
<div class="item-info">
|
||||||
<span v-text="status.title" v-if="status.title"></span>
|
<span v-text="status.title"
|
||||||
|
@click="bus.$emit('info-load', status.url)"
|
||||||
|
v-if="status.title"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
{% include 'plugins/media/results.html' %}
|
{% include 'plugins/media/results.html' %}
|
||||||
{% include 'plugins/media/item.html' %}
|
{% include 'plugins/media/item.html' %}
|
||||||
{% include 'plugins/media/info.html' %}
|
{% include 'plugins/media/info.html' %}
|
||||||
|
{% include 'plugins/media/subs.html' %}
|
||||||
|
|
||||||
{% for script in utils.search_directory(static_folder + '/js/plugins/media/handlers', 'js', recursive=True) %}
|
{% for script in utils.search_directory(static_folder + '/js/plugins/media/handlers', 'js', recursive=True) %}
|
||||||
<script type="application/javascript" src="{{ url_for('static', filename='js/plugins/media/handlers/' + script) }}"></script>
|
<script type="application/javascript" src="{{ url_for('static', filename='js/plugins/media/handlers/' + script) }}"></script>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='flag-icons/css/flag-icon.css') }}">
|
||||||
|
|
||||||
<script type="text/x-template" id="tmpl-media">
|
<script type="text/x-template" id="tmpl-media">
|
||||||
<div class="plugin media-plugin">
|
<div class="plugin media-plugin">
|
||||||
<div class="search">
|
<div class="search">
|
||||||
|
@ -38,10 +40,17 @@
|
||||||
v-if="selectedDevice && status[selectedDevice.type] && status[selectedDevice.type][selectedDevice.name] && (status[selectedDevice.type][selectedDevice.name].state === 'play' || status[selectedDevice.type][selectedDevice.name].state === 'pause')">
|
v-if="selectedDevice && status[selectedDevice.type] && status[selectedDevice.type][selectedDevice.name] && (status[selectedDevice.type][selectedDevice.name].state === 'play' || status[selectedDevice.type][selectedDevice.name].state === 'pause')">
|
||||||
</media-controls>
|
</media-controls>
|
||||||
|
|
||||||
<modal id="media-info" title="Media info" v-model="infoModal.visible" ref="modalInfo">
|
<modal id="media-info" title="Media info" v-model="infoModal.visible">
|
||||||
<div class="loading" v-if="infoModal.loading">Loading</div>
|
<div class="loading" v-if="infoModal.loading">Loading</div>
|
||||||
<media-info :bus="bus" :item="infoModal.item" v-else></media-info>
|
<media-info :bus="bus" :item="infoModal.item" v-else></media-info>
|
||||||
</modal>
|
</modal>
|
||||||
|
|
||||||
|
<modal id="media-subs" title="Subtitles" v-model="subsModal.visible">
|
||||||
|
<media-subs :bus="bus"
|
||||||
|
:subFormats="selectedDevice ? selectedDevice.subFormats : []"
|
||||||
|
ref="subs">
|
||||||
|
</media-subs>
|
||||||
|
</modal>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
34
platypush/backend/http/templates/plugins/media/subs.html
Normal file
34
platypush/backend/http/templates/plugins/media/subs.html
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<script type="application/javascript" src="{{ url_for('static', filename='js/plugins/media/subs.js') }}"></script>
|
||||||
|
|
||||||
|
<script type="text/x-template" id="tmpl-media-subs">
|
||||||
|
<div class="subs-container">
|
||||||
|
<div class="loading" v-if="loading">Loading</div>
|
||||||
|
<div class="no-results" v-else-if="!Object.keys(items).length">No results</div>
|
||||||
|
|
||||||
|
<div class="subs" v-else>
|
||||||
|
<div class="list">
|
||||||
|
<div class="sub"
|
||||||
|
:class="{selected: selectedItem && selectedItem.SubDownloadLink === item.SubDownloadLink}"
|
||||||
|
@click="selectedItem = item"
|
||||||
|
v-for="item in items"
|
||||||
|
:key="item.SubDownloadLink">
|
||||||
|
<div class="col-1 icon">
|
||||||
|
<i class="fa fa-hdd" v-if="item.IsLocal"></i>
|
||||||
|
<i :class="'flag-icon flag-icon-' + item.ISO639" v-else></i>
|
||||||
|
</div>
|
||||||
|
<div class="col-11 title" v-text="item.SubFileName"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<button type="button"
|
||||||
|
class="btn-default"
|
||||||
|
@click="play"
|
||||||
|
:disabled="!selectedItem">
|
||||||
|
Select and play
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
|
@ -4,9 +4,8 @@ import requests
|
||||||
import tempfile
|
import tempfile
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from platypush.message.response import Response
|
|
||||||
from platypush.plugins import Plugin, action
|
from platypush.plugins import Plugin, action
|
||||||
from platypush.utils import find_files_by_ext, get_mime_type
|
from platypush.utils import find_files_by_ext
|
||||||
|
|
||||||
|
|
||||||
class MediaSubtitlesPlugin(Plugin):
|
class MediaSubtitlesPlugin(Plugin):
|
||||||
|
@ -20,7 +19,7 @@ class MediaSubtitlesPlugin(Plugin):
|
||||||
* **requests** (``pip install requests``)
|
* **requests** (``pip install requests``)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, username, password, language=None, *args, **kwargs):
|
def __init__(self, username, password, language=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param username: Your OpenSubtitles username
|
:param username: Your OpenSubtitles username
|
||||||
:type username: str
|
:type username: str
|
||||||
|
@ -36,7 +35,7 @@ class MediaSubtitlesPlugin(Plugin):
|
||||||
|
|
||||||
from pythonopensubtitles.opensubtitles import OpenSubtitles
|
from pythonopensubtitles.opensubtitles import OpenSubtitles
|
||||||
|
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
self._ost = OpenSubtitles()
|
self._ost = OpenSubtitles()
|
||||||
self._token = self._ost.login(username, password)
|
self._token = self._ost.login(username, password)
|
||||||
|
@ -52,7 +51,6 @@ class MediaSubtitlesPlugin(Plugin):
|
||||||
raise AttributeError('{} is neither a string nor a list'.format(
|
raise AttributeError('{} is neither a string nor a list'.format(
|
||||||
language))
|
language))
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_subtitles(self, resource, language=None):
|
def get_subtitles(self, resource, language=None):
|
||||||
"""
|
"""
|
||||||
|
@ -73,7 +71,7 @@ class MediaSubtitlesPlugin(Plugin):
|
||||||
|
|
||||||
resource = os.path.abspath(os.path.expanduser(resource))
|
resource = os.path.abspath(os.path.expanduser(resource))
|
||||||
if not os.path.isfile(resource):
|
if not os.path.isfile(resource):
|
||||||
return (None, '{} is not a valid file'.format(resource))
|
return None, '{} is not a valid file'.format(resource)
|
||||||
|
|
||||||
file = resource
|
file = resource
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
|
@ -117,7 +115,6 @@ class MediaSubtitlesPlugin(Plugin):
|
||||||
finally:
|
finally:
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def download(self, link, media_resource=None, path=None, convert_to_vtt=False):
|
def download(self, link, media_resource=None, path=None, convert_to_vtt=False):
|
||||||
"""
|
"""
|
||||||
|
@ -154,7 +151,6 @@ class MediaSubtitlesPlugin(Plugin):
|
||||||
return {'filename': link}
|
return {'filename': link}
|
||||||
|
|
||||||
gzip_content = requests.get(link).content
|
gzip_content = requests.get(link).content
|
||||||
f = None
|
|
||||||
|
|
||||||
if not path and media_resource:
|
if not path and media_resource:
|
||||||
if media_resource.startswith('file://'):
|
if media_resource.startswith('file://'):
|
||||||
|
@ -199,7 +195,7 @@ class MediaSubtitlesPlugin(Plugin):
|
||||||
try:
|
try:
|
||||||
webvtt.read(filename)
|
webvtt.read(filename)
|
||||||
return filename
|
return filename
|
||||||
except Exception as e:
|
except Exception:
|
||||||
webvtt.from_srt(filename).save()
|
webvtt.from_srt(filename).save()
|
||||||
return '.'.join(filename.split('.')[:-1]) + '.vtt'
|
return '.'.join(filename.split('.')[:-1]) + '.vtt'
|
||||||
|
|
||||||
|
|
|
@ -384,7 +384,7 @@ class MediaVlcPlugin(MediaPlugin):
|
||||||
else:
|
else:
|
||||||
status['state'] = PlayerState.STOP.value
|
status['state'] = PlayerState.STOP.value
|
||||||
|
|
||||||
status['url'] = self._player.get_media().get_mrl() if self._player.get_media() else None
|
status['url'] = urllib.parse.unquote(self._player.get_media().get_mrl()) if self._player.get_media() else None
|
||||||
status['position'] = float(self._player.get_time()/1000) if self._player.get_time() is not None else None
|
status['position'] = float(self._player.get_time()/1000) if self._player.get_time() is not None else None
|
||||||
|
|
||||||
media = self._player.get_media()
|
media = self._player.get_media()
|
||||||
|
@ -393,7 +393,7 @@ class MediaVlcPlugin(MediaPlugin):
|
||||||
status['seekable'] = status['duration'] is not None
|
status['seekable'] = status['duration'] is not None
|
||||||
status['fullscreen'] = self._player.get_fullscreen()
|
status['fullscreen'] = self._player.get_fullscreen()
|
||||||
status['mute'] = self._player.audio_get_mute()
|
status['mute'] = self._player.audio_get_mute()
|
||||||
status['path'] = urllib.parse.unquote(status['url'])
|
status['path'] = status['url']
|
||||||
status['pause'] = status['state'] == PlayerState.PAUSE.value
|
status['pause'] = status['state'] == PlayerState.PAUSE.value
|
||||||
status['percent_pos'] = self._player.get_position()*100
|
status['percent_pos'] = self._player.get_position()*100
|
||||||
status['filename'] = urllib.parse.unquote(status['url']).split('/')[-1]
|
status['filename'] = urllib.parse.unquote(status['url']).split('/')[-1]
|
||||||
|
|
Loading…
Reference in a new issue