# -*- coding: utf-8 -*-
# Licensed under the MIT license
# http://opensource.org/licenses/mit-license.php
# Copyright 2018, Pol Canelles <canellestudi@gmail.com>
'''
Backend models for BackendItem
------------------------------
Backend items to be used directly or subclassed. This classes inherits from
:class:`~coherence.backend.BackendItem`. This classes should cover the most
basic needs for different types of media and goes one step further from the
:mod:`~coherence.backend` by initializing the corresponding DIDLLite object.
* For video backends:
- :class:`BackendVideoItem`: item representing a video resource
* For audio backends:
- :class:`BackendAudioItem`: item representing a audio resource
- :class:`BackendMusicTrackItem`: item representing an audio resource
* For image/photo backends:
- :class:`BackendImageItem`: item representing a image resource
- :class:`BackendPhotoItem`: item representing a photo resource
* For create a custom backend:
- If the items described above does not meet your needs, you can subclass
them or you may use the base class :class:`BackendBaseItem`, used to
develop all those backend items described above.
.. note::
To write this module, some of the the old backends has been taken
as a reference:
- :mod:`~coherence.backends.appletrailers_storage`
- :mod:`~coherence.backends.banshee_storage`
- :mod:`~coherence.backends.fs_storage`
.. warning:: Be aware that we use super to initialize all the classes of this
module in order to have a better MRO class resolution...so...take
it into account if you inherit from one of this classes.
.. versionadded:: 0.8.3
'''
from coherence.upnp.core.utils import ReverseProxyUriResource
from coherence.upnp.core import DIDLLite
from coherence.backend import BackendItem
[docs]class BackendBaseItem(BackendItem):
'''
This class is intended to be used as a base class for creating a custom
backend item. It has the ability to support proxy or non-proxy items by
using the property proxy_cls.
.. warning:: ReverseProxyUriResource does not support https connections,
so...better stick to non-proxy if the target resource is in a
secure connection until... we grant support for https
connections.
'''
is_proxy = False
'''If the item should be considered a ReverseProxyUriResource. This
property is automatically set when the item is initialized'''
location = None
'''Represents a file path of our media file, or alternatively a FilePath or
a ReverseProxyResource object. It will be set automatically based on the
value of the class :attr:`proxy_cls` (if the property :attr:`is_proxy`
equals to True).'''
proxy_cls = ReverseProxyUriResource
'''Define a class inherited from
:class:`~coherence.upnp.core.utils.ReverseProxyUriResource`. This property
will only be used if the property :attr:`is_proxy` equals True.
.. warning:: ReverseProxyResource does not support https. If your
resources point to a secure site, it's recommended to
not enable the :attr:`BackendBaseStore.proxy` (disabled
by default)
'''
item = None
'''Define the initialized :attr:`item_cls`. It will be set when the class
:class:`BackendBaseItem` is initialized based on the attribute
:attr:`item_cls`'''
item_cls = DIDLLite.Item
'''Define an atomic object from :class:`~coherence.upnp.core.DIDLLite.Item`
to be used to initialize the :attr:`item`'''
mimetype = ''
'''The mimetype of your item'''
def __init__(self, parent_id, item_id, urlbase, **kwargs):
super(BackendBaseItem, self).__init__()
self.id = item_id
self.parent_id = parent_id
self.name = self.title = \
kwargs.get('title',
kwargs.get('name',
'My Backend Item'))
self.http_url = kwargs.get('url', None)
if len(urlbase) and urlbase[-1] != '/':
urlbase += '/'
self.url = urlbase + str(self.id)
if 'is_proxy' in kwargs:
self.is_proxy = kwargs['is_proxy']
if 'mimetype' in kwargs:
self.mimetype = kwargs['mimetype']
if self.is_proxy and self.proxy_cls is not None:
self.location = self.proxy_cls(self.http_url)
elif self.is_proxy:
self.warning('BackendBaseItem was unable to create a Proxy '
'location, falling back to non proxy...')
self.is_proxy = False
self.item = self.item_cls(
self.id, self.parent_id, self.name)
self.item.attachments = {}
self.item.title = self.title
[docs] def get_name(self):
return self.title
[docs] def get_children(self, start=0, request_count=0):
return []
[docs] def get_child_count(self):
return 0
[docs] def get_path(self):
if self.is_proxy:
return self.location
if self.http_url:
return self.http_url
return self.url
def __repr__(self):
return \
f'<BackendBaseItem {self.id} {self.title}' \
f' [parent id: {self.parent_id}]>'
[docs]class BackendVideoItem(BackendBaseItem):
'''
This Represents a Backend Video Item.
'''
item_cls = DIDLLite.VideoItem
def __init__(self, parent_id, item_id, urlbase, **kwargs):
super(BackendVideoItem, self).__init__(
parent_id, item_id, urlbase, **kwargs)
self.director = kwargs.get('director', None)
self.actors = kwargs.get('actors', [])
self.genres = kwargs.get('genres', [])
self.description = kwargs.get('description', None)
self.image = kwargs.get('image', None)
self.item.director = self.director
self.item.actors = self.actors
self.item.genres = self.genres
self.item.description = self.description
self.item.albumArtURI = self.image
def __repr__(self):
return \
f'<BackendVideoItem{self.id} title="{self.title}" ' \
f'genres="{", ".join(self.genres)}" director="{self.director}">'
[docs]class BackendAudioItem(BackendBaseItem):
'''
This Represents an Audio Item. It supports those properties:
- :attr:`artist`: The name of the artist
- :attr:`album`: an instance of a
:class:`~coherence.backends.models.containers.BackendMusicAlbum`
- :attr:`genre`: The music genre for the audio
- :attr:`playlist`: Playlist
'''
item_cls = DIDLLite.AudioItem
def __init__(self, parent_id, item_id, urlbase, **kwargs):
super(BackendAudioItem, self).__init__(
parent_id, item_id, urlbase, **kwargs)
self.artist = kwargs.get('artist', None)
self.album = kwargs.get('album', None)
self.genre = kwargs.get('genre', None)
self.image = kwargs.get('image', None)
self.playlist = kwargs.get('playlist', None)
self.item.artist = self.artist
self.item.album = self.album
self.item.genre = self.genre
self.item.playlist = self.playlist
self.item.albumArtURI = self.image
def __repr__(self):
album = 'None' if not self.album else self.album.title
return \
f'<BackendAudioItem{self.id} title="{self.title}" ' \
f'album={self.album}" genre="{self.genre}" ' \
f'artist="{self.artist}" path="{self.get_path()}">'
[docs]class BackendMusicTrackItem(BackendAudioItem):
'''
This is like :class:`BackendAudioItem` but with a track number added.
'''
item_cls = DIDLLite.MusicTrack
def __init__(self, parent_id, item_id, urlbase, **kwargs):
super(BackendMusicTrackItem, self).__init__(
parent_id, item_id, urlbase, **kwargs)
self.track_number = kwargs.get('track_number', 1)
self.item.originalTrackNumber = self.track_number
def __repr__(self):
album = 'None' if not self.album else self.album.title
return \
f'<BackendMusicTrackItem{self.id} title="{self.title}" ' \
f'track="{self.track_number}" album={album}" ' \
f'genre="{self.genre}" artist="{self.artist}" ' \
f'path="{self.get_path()}">'
[docs]class BackendImageItem(BackendBaseItem):
'''
This Represents a Backend Image Item.
'''
item_cls = DIDLLite.ImageItem
mimetype = ''
def __init__(self, parent_id, item_id, urlbase, **kwargs):
super(BackendImageItem, self).__init__(
parent_id, item_id, urlbase, **kwargs)
self.artist = kwargs.get('artist', None)
self.rating = kwargs.get('rating', None)
self.publisher = kwargs.get('publisher', None)
self.rights = kwargs.get('rights', None)
self.item.artist = self.artist
self.item.rating = self.rating
self.item.publisher = self.publisher
self.item.rights = self.rights
def __repr__(self):
return \
f'<BackendImageItem {self.id} artist="{self.artist}" ' \
f'rating="{self.rating}" publisher="{self.publisher}">'
[docs]class BackendPhotoItem(BackendImageItem):
'''
This Represents a Backend Photo Item. Iis like :class:`BackendImageItem`
but with additional attribute added :attr:`album`.
'''
item_cls = DIDLLite.Photo
def __init__(self, parent_id, item_id, urlbase, **kwargs):
super(BackendPhotoItem, self).__init__(
parent_id, item_id, urlbase, **kwargs)
self.album = kwargs.get('album', None)
self.item.album = self.album
def __repr__(self):
return \
f'<BackendPhotoItem {self.id} artist="{self.artist}" ' \
f'album="{self.album}" rating="{self.rating}">'