Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
birk
madek-broadcaster
Commits
54b45e10
Commit
54b45e10
authored
Feb 15, 2017
by
birk
Browse files
Refactoring of caching media files - half way done.
parent
34ff2df9
Changes
4
Hide whitespace changes
Inline
Side-by-side
player/content/api.py
View file @
54b45e10
...
...
@@ -255,7 +255,7 @@ class ApiClient(object):
return
c
async
def
get_media_entries
(
self
,
path_
,
limit_
=
None
,
meta_data_white_list_
=
None
):
async
def
get_media_entries
(
self
,
path_
,
limit_
=
None
,
meta_data_white_list_
=
None
,
preload_media_
=
False
):
"""
Requests media entries based on a complete api-path.
"""
...
...
@@ -273,7 +273,9 @@ class ApiClient(object):
for
i
in
roa
[
'collection'
][
'relations'
].
items
():
if
i
[
1
][
'name'
]
==
'Media-Entry'
:
path_
=
i
[
1
][
'href'
]
task
=
asyncio
.
ensure_future
(
self
.
get_media_entry
(
path_
,
meta_data_white_list_
=
meta_data_white_list_
))
task
=
asyncio
.
ensure_future
(
self
.
get_media_entry
(
path_
,
meta_data_white_list_
=
meta_data_white_list_
,
preload_media_
=
preload_media_
))
tasks
.
append
(
task
)
if
tasks
.
__len__
()
>=
limit
:
ready
=
True
...
...
@@ -290,7 +292,7 @@ class ApiClient(object):
return
media_entries
async
def
get_media_entry
(
self
,
path_
=
None
,
id_
=
None
,
meta_data_white_list_
=
None
):
async
def
get_media_entry
(
self
,
path_
=
None
,
id_
=
None
,
meta_data_white_list_
=
None
,
preload_media_
=
False
):
cr
=
ApiClient
.
complete
(
path_
,
id_
,
'media-entry'
)
j
=
await
self
.
send_request
(
cr
.
path
)
if
j
:
...
...
@@ -308,9 +310,9 @@ class ApiClient(object):
if
'media-file'
in
roa
[
'relations'
]:
mf
=
await
self
.
get_media_file
(
roa
[
'relations'
][
'media-file'
][
'href'
])
if
mf
:
m
.
set_
media_file
(
mf
)
# TODO: Decide whether or not to cache the media file
await
self
.
cache_media_file
(
m
)
m
.
set_
file_data
(
mf
)
if
preload_media_
:
await
self
.
cache_media_file
(
m
)
else
:
# a media entry without media files is invalid
print
(
'No MediaFile for MediaEntry {}'
.
format
(
m
.
id
))
...
...
@@ -415,16 +417,8 @@ class ApiClient(object):
return
None
async
def
cache_media_file
(
self
,
media_entry_
):
bytes
=
await
self
.
send_request
(
media_entry_
.
get_media_url
)
if
media_entry_
.
is_image
:
with
tempfile
.
NamedTemporaryFile
(
suffix
=
'.jpg'
)
as
cache_file
:
cache_file
.
write
(
bytes
)
media_entry_
.
set_image
(
pyglet
.
image
.
load
(
cache_file
.
name
))
elif
media_entry_
.
is_video
:
t
=
tempfile
.
NamedTemporaryFile
(
suffix
=
'.mp4'
)
t
.
write
(
bytes
)
media_entry_
.
set_video
(
t
)
return
None
# TODO: this is not asynched yet
file
=
MediaFile
(
media_entry_
)
async
def
get_preview
(
self
,
path
):
j
=
await
self
.
send_request
(
path
)
...
...
player/content/mediaentry.py
View file @
54b45e10
...
...
@@ -3,6 +3,7 @@ import random
from
tempfile
import
NamedTemporaryFile
import
pyglet
import
requests
from
content.apidata
import
ApiData
from
system.config
import
Config
...
...
@@ -10,6 +11,11 @@ from system.config import Config
class
MediaEntryData
(
ApiData
):
IMAGE
=
'image'
VIDEO
=
'video'
AUDIO
=
'audio'
DOCUMENT
=
'document'
# static shortcuts for the return values of self.orientation
LANDSCAPE
=
-
1
SQUARE
=
0
...
...
@@ -40,7 +46,8 @@ class MediaEntryData(ApiData):
self
.
uuid
=
None
self
.
is_published
=
None
self
.
responsible_user_id
=
None
self
.
media_file
=
None
self
.
file_data
=
None
self
.
file
=
None
self
.
image
=
None
self
.
video
=
None
if
Config
().
dev_mode
:
...
...
@@ -48,8 +55,15 @@ class MediaEntryData(ApiData):
else
:
self
.
duration
=
random
.
randint
(
30
,
40
)
def
set_media_file
(
self
,
media_file_
):
self
.
media_file
=
media_file_
def
set_file_data
(
self
,
file_data_
):
self
.
file_data
=
file_data_
def
set_file
(
self
,
file_
):
self
.
file
=
file_
self
.
file
.
push_handlers
(
on_cached
=
self
.
on_file_cached
)
def
on_file_cached
(
self
,
file_
):
pass
def
parse_data
(
self
,
json_
:
dict
):
self
.
uuid
=
json_
[
'id'
]
...
...
@@ -60,25 +74,25 @@ class MediaEntryData(ApiData):
@
property
def
media_type
(
self
):
if
self
.
media_file
and
self
.
media_file
.
media_type
:
return
self
.
media_file
.
media_type
if
self
.
file_data
and
self
.
file_data
.
media_type
:
return
self
.
file_data
.
media_type
return
None
@
property
def
is_image
(
self
):
return
self
.
media_type
==
'image'
return
self
.
media_type
==
MediaEntryData
.
IMAGE
@
property
def
is_video
(
self
):
return
self
.
media_type
==
'video'
return
self
.
media_type
==
MediaEntryData
.
VIDEO
@
property
def
is_audio
(
self
):
return
self
.
media_type
==
'audio'
return
self
.
media_type
==
MediaEntryData
.
AUDIO
@
property
def
is_document
(
self
):
return
self
.
media_type
==
'document'
return
self
.
media_type
==
MediaEntryData
.
DOCUMENT
@
property
def
orientation
(
self
):
...
...
@@ -87,41 +101,38 @@ class MediaEntryData(ApiData):
"""
w
=
0
h
=
0
if
self
.
media_file
and
self
.
media_file
.
get_preview
():
if
self
.
file_data
and
self
.
file_data
.
get_preview
():
# TODO: Preview width and height are not trustworthy ...
w
=
self
.
media_file
.
get_preview
().
width
h
=
self
.
media_file
.
get_preview
().
height
w
=
self
.
file_data
.
get_preview
().
width
h
=
self
.
file_data
.
get_preview
().
height
return
MediaEntryData
.
get_orientation
(
w
,
h
)
@
property
def
get_media
_url
(
self
):
def
file
_url
(
self
):
# TODO: Decide which data stream should be shown.
if
self
.
media_file
and
len
(
self
.
media_file
.
previews
)
>
0
:
return
self
.
media_file
.
get_preview
().
data_stream
if
self
.
file_data
and
len
(
self
.
file_data
.
previews
)
>
0
:
return
self
.
file_data
.
get_preview
().
data_stream
return
None
@
property
def
get_media_filename
(
self
):
if
self
.
media_file
and
len
(
self
.
media_file
.
previews
)
>
0
:
return
self
.
media_file
.
get_preview
().
filename
return
None
@
property
def
media_file_id
(
self
):
if
self
.
media_file
and
len
(
self
.
media_file
.
previews
)
>
0
:
return
self
.
media_file
.
get_preview
().
media_file_id
return
None
# @property
# def media_file_id(self):
# if self.file_data and len(self.file_data.previews) > 0:
# return self.file_data.get_preview().media_file_id
# return None
@
property
def
media_width_height
(
self
):
if
self
.
media_file
and
len
(
self
.
media_file
.
previews
)
>
0
:
return
self
.
media_file
.
get_preview
().
width_height
def
width_height
(
self
):
# Check first the actual size of the loaded file and then as a fallback the values from the API.
if
self
.
file
and
self
.
file
.
width
and
self
.
file
.
height
:
return
self
.
file
.
width
,
self
.
file
.
height
elif
self
.
file_data
and
len
(
self
.
file_data
.
previews
)
>
0
:
return
self
.
file_data
.
get_preview
().
width_height
return
None
,
None
def
set_image
(
self
,
image_
:
pyglet
.
image
.
AbstractImage
):
self
.
image
=
image_
if
self
.
media_file
and
self
.
media_file
.
get_preview
():
self
.
media_file
.
get_preview
().
set_size
(
self
.
image
.
width
,
self
.
image
.
height
)
if
self
.
file_data
and
self
.
file_data
.
get_preview
():
self
.
file_data
.
get_preview
().
set_size
(
self
.
image
.
width
,
self
.
image
.
height
)
def
set_video
(
self
,
video_
:
NamedTemporaryFile
):
self
.
video
=
video_
...
...
@@ -133,14 +144,113 @@ class MediaEntryData(ApiData):
self
.
_source
=
None
def
set_media_size
(
self
,
width_
,
height_
):
if
self
.
media_file
and
self
.
media_file
.
get_preview
():
self
.
media_file
.
get_preview
().
set_size
(
width_
,
height_
)
if
self
.
file_data
and
self
.
file_data
.
get_preview
():
self
.
file_data
.
get_preview
().
set_size
(
width_
,
height_
)
def
__str__
(
self
):
s
=
'MediaEntryData {}'
.
format
(
self
.
uuid
)
return
s
class
MediaFile
(
pyglet
.
event
.
EventDispatcher
):
__SUFFIXES
=
{
MediaEntryData
.
IMAGE
:
'.jpg'
,
MediaEntryData
.
VIDEO
:
'.mp4'
,
MediaEntryData
.
AUDIO
:
'.mp3'
,
MediaEntryData
.
DOCUMENT
:
'.jpg'
}
def
__init__
(
self
,
entry_
:
MediaEntryData
):
super
(
MediaFile
,
self
).
__init__
()
self
.
__entry
=
entry_
self
.
__temp
=
None
self
.
__image_source
=
None
self
.
__video_source
=
None
self
.
__video_player
=
None
entry_
.
set_file
(
self
)
def
cache
(
self
):
if
self
.
__temp
:
# TODO: clean up
pass
self
.
__temp
=
NamedTemporaryFile
(
suffix
=
self
.
__suffix
,
delete
=
False
)
w
=
None
h
=
None
d
=
None
response
=
requests
.
get
(
'{}{}'
.
format
(
Config
().
server
,
self
.
__entry
.
file_url
),
stream
=
True
,
auth
=
Config
().
api_auth
)
for
block
in
response
.
iter_content
(
1024
):
self
.
__temp
.
write
(
block
)
if
self
.
__entry
.
media_type
==
MediaEntryData
.
IMAGE
:
self
.
__image_source
=
pyglet
.
image
.
load
(
self
.
__temp
.
name
)
w
,
h
=
self
.
__image_source
.
width
,
self
.
__image_source
.
height
self
.
dispatch_event
(
'on_cached'
,
self
)
def
play
(
self
):
if
not
self
.
__temp
:
self
.
cache
()
if
self
.
__entry
.
media_type
==
MediaEntryData
.
IMAGE
:
pass
elif
self
.
__entry
.
media_type
==
MediaEntryData
.
VIDEO
:
if
not
self
.
__video_source
:
self
.
__video_source
=
pyglet
.
media
.
load
(
self
.
__temp
.
name
)
if
not
self
.
__video_player
:
self
.
__video_player
=
self
.
__video_source
.
play
()
self
.
__video_player
.
eos_action
=
self
.
__video_player
.
EOS_PAUSE
@
self
.
__video_player
.
event
def
on_eos
():
self
.
on_video_end
(
self
)
def
stop
(
self
):
# TODO: Stop the video
pass
def
delete
(
self
):
# TODO: Delete the file
pass
@
property
def
width
(
self
):
if
self
.
__image_source
:
return
self
.
__image_source
.
width
# TODO: Do I have to do the same for video?
return
None
@
property
def
height
(
self
):
if
self
.
__image_source
:
return
self
.
__image_source
.
height
# TODO: Do I have to do the same for video?
return
None
@
property
def
texture
(
self
):
if
self
.
__entry
.
media_type
==
MediaEntryData
.
IMAGE
:
if
not
self
.
__image_source
:
return
None
return
self
.
__image_source
.
get_texture
()
elif
self
.
__entry
.
media_type
==
MediaEntryData
.
VIDEO
:
if
not
self
.
__video_player
:
return
None
return
self
.
__video_player
.
get_texture
()
return
None
@
property
def
player
(
self
):
if
self
.
__entry
.
media_type
==
MediaEntryData
.
VIDEO
:
if
not
self
.
__video_player
:
self
.
play
()
return
self
.
__video_player
return
None
def
on_video_end
(
self
):
pass
@
property
def
__suffix
(
self
):
if
self
.
__entry
.
media_type
in
MediaFile
.
__SUFFIXES
:
return
MediaFile
.
__SUFFIXES
[
self
.
__entry
.
media_type
]
return
None
MediaFile
.
register_event_type
(
'on_cached'
)
class
MediaFileData
():
def
__init__
(
self
,
server_
:
str
,
json_
:
dict
):
self
.
id
=
json_
[
'id'
]
...
...
@@ -157,7 +267,7 @@ class MediaFileData():
def
add_preview
(
self
,
preview_
):
# TODO: Remove once the API delivers this for MediaFile.
if
self
.
media_type
is
None
or
self
.
media_type
is
'image'
:
if
self
.
media_type
is
None
or
self
.
media_type
is
MediaEntryData
.
IMAGE
:
self
.
media_type
=
preview_
.
media_type
self
.
previews
.
append
(
preview_
)
...
...
@@ -180,13 +290,13 @@ class MediaFileData():
document_extensions
=
[
'.pdf'
,
'.doc'
,
'.docx'
,
'.txt'
,
'.ai'
]
filename
,
file_extension
=
os
.
path
.
splitext
(
self
.
filename
)
if
file_extension
.
lower
()
in
image_extensions
:
return
'image'
return
MediaEntryData
.
IMAGE
elif
file_extension
.
lower
()
in
video_extensions
:
return
'video'
return
MediaEntryData
.
VIDEO
elif
file_extension
.
lower
()
in
sound_extensions
:
return
'sound'
return
MediaEntryData
.
SOUND
elif
file_extension
.
lower
()
in
document_extensions
:
return
'document'
return
MediaEntryData
.
DOCUMENT
print
(
'#### unrecognized file extension: {} ####'
.
format
(
file_extension
))
return
None
...
...
player/content/program.py
View file @
54b45e10
...
...
@@ -38,7 +38,7 @@ class Program(EventDispatcher):
self
.
__index
=
None
self
.
_playlist
=
[]
playlist
=
[]
for
m
in
await
self
.
_api
.
get_media_entries
(
self
.
start_url
,
limit
,
self
.
_meta_data_white_list
):
for
m
in
await
self
.
_api
.
get_media_entries
(
self
.
start_url
,
limit
,
self
.
_meta_data_white_list
,
preload_media_
):
# only use images and videos
if
m
.
is_image
or
m
.
is_video
:
playlist
.
append
(
m
)
...
...
player/display/mediadisplay.py
View file @
54b45e10
...
...
@@ -4,6 +4,7 @@ import pyglet
import
requests
import
sys
from
content.mediaentry
import
MediaFile
from
system.config
import
Config
...
...
@@ -20,13 +21,13 @@ class MediaDisplay(pyglet.event.EventDispatcher):
self
.
index
=
index_
self
.
screen
=
screen_
self
.
texture
=
None
self
.
player
=
None
# for videos
#
self.player = None # for videos
self
.
area
=
None
self
.
visible
=
False
def
fin
d_position
(
self
):
def
de
fin
e_area
(
self
):
# Looks for a suitable position on the screen
w
,
h
=
self
.
media_entry
.
media_
width_height
w
,
h
=
self
.
media_entry
.
width_height
if
w
and
h
:
# First init the are with the original size ...
self
.
area
=
Area
(
0
,
0
,
w
,
h
)
...
...
@@ -36,20 +37,18 @@ class MediaDisplay(pyglet.event.EventDispatcher):
def
show
(
self
):
# Called when the content appears on the screen.
self
.
find_position
()
if
self
.
media_entry
.
is_image
:
self
.
texture
=
self
.
media_entry
.
image
.
get_texture
()
elif
self
.
media_entry
.
is_video
:
print
(
'video {}'
.
format
(
self
.
media_entry
.
video
.
name
))
self
.
player
=
pyglet
.
media
.
load
(
self
.
media_entry
.
video
.
name
).
play
()
self
.
texture
=
self
.
player
.
get_texture
()
# self.player.eos_action = self.player.EOS_PAUSE
# @self.player.event
# def on_eos():
# self.on_video_end(self)
if
not
self
.
media_entry
.
file
or
not
self
.
media_entry
.
file
.
texture
:
file
=
MediaFile
(
self
.
media_entry
)
file
.
cache
()
self
.
media_entry
.
file
.
play
()
if
self
.
media_entry
.
is_video
:
@
self
.
media_entry
.
file
.
player
.
event
def
on_eos
():
self
.
on_video_end
(
self
)
self
.
texture
=
self
.
media_entry
.
file
.
texture
pyglet
.
clock
.
schedule_once
(
self
.
on_timer_end
,
self
.
media_entry
.
duration
)
self
.
set_width_height
(
self
.
area
.
width
,
self
.
area
.
height
)
self
.
define_area
(
)
self
.
visible
=
True
self
.
dispatch_event
(
'on_play'
,
self
)
...
...
@@ -59,12 +58,12 @@ class MediaDisplay(pyglet.event.EventDispatcher):
if
self
.
texture
:
self
.
texture
.
blit
(
a
.
x
,
a
.
y
,
0
,
a
.
width
,
a
.
height
)
elif
self
.
media_entry
.
is_video
:
if
self
.
player
:
if
self
.
texture
:
self
.
texture
.
blit
(
a
.
x
,
a
.
y
,
0
,
a
.
width
,
a
.
height
)
def
on_video_end
(
self
):
print
(
'on video end ...'
)
self
.
player
.
stop
()
# TODO: Do I need this here?
def
on_timer_end
(
self
,
seconds_
):
# timer used for still images
...
...
@@ -72,26 +71,19 @@ class MediaDisplay(pyglet.event.EventDispatcher):
def
on_content_end
(
self
):
# print('content end %s' % self.screen.index)
if
self
.
media_entry
.
video
and
type
(
self
.
media_entry
.
video
)
is
tempfile
.
NamedTemporaryFile
:
self
.
media_entry
.
video
.
close
()
self
.
media_entry
.
video
=
None
# TODO: stop video and clear cache file
# if self.media_entry.video and type(self.media_entry.video) is tempfile.NamedTemporaryFile:
# self.media_entry.video.close()
# self.media_entry.video = None
self
.
dispatch_event
(
'on_end'
,
self
,
self
.
screen
)
def
hide
(
self
):
# Called when the content disappears from the screen.
if
self
.
media_entry
.
is_video
:
self
.
player
.
pause
()
self
.
player
.
pop_handlers
()
#
if self.media_entry.is_video:
#
self.player.pause()
#
self.player.pop_handlers()
self
.
visible
=
False
def
set_width_height
(
self
,
width_
,
height_
):
if
self
.
media_entry
.
is_image
:
self
.
texture
.
width
=
width_
self
.
texture
.
height
=
height_
elif
self
.
media_entry
.
is_video
:
self
.
player
.
width
=
width_
self
.
player
.
height
=
height_
MediaDisplay
.
register_event_type
(
'on_play'
)
MediaDisplay
.
register_event_type
(
'on_end'
)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment