use the new add_field() method to define fields

This commit is contained in:
Romain Bignon 2010-10-08 13:43:23 +02:00
commit 92c6507f71
14 changed files with 133 additions and 178 deletions

View file

@ -268,7 +268,6 @@ class AuMBackend(BaseBackend, ICapMessages, ICapMessagesPost, ICapDating, ICapCh
contact = Contact(_id, profile.get_name(), s) contact = Contact(_id, profile.get_name(), s)
contact.status_msg = u'%s old' % profile.table['details']['old'] contact.status_msg = u'%s old' % profile.table['details']['old']
contact.summary = profile.description contact.summary = profile.description
contact.avatar = None
for photo in profile.photos: for photo in profile.photos:
contact.set_photo(photo.split('/')[-1], url=photo, thumbnail_url=photo.replace('image', 'thumb1_')) contact.set_photo(photo.split('/')[-1], url=photo, thumbnail_url=photo.replace('image', 'thumb1_'))
contact.profile = [] contact.profile = []

View file

@ -15,6 +15,8 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from datetime import datetime
import re import re
from logging import warning from logging import warning
@ -26,7 +28,7 @@ class Message(object):
self.browser = browser self.browser = browser
self.board = board self.board = board
self.filename = filename self.filename = filename
self.datetime = 0 self.datetime = datetime.now()
self.url = url self.url = url
self.author = u'' self.author = u''
self.text = u'' self.text = u''

View file

@ -18,6 +18,7 @@
from __future__ import with_statement from __future__ import with_statement
from weboob.capabilities.geolocip import ICapGeolocIp, IpLocation from weboob.capabilities.geolocip import ICapGeolocIp, IpLocation
from weboob.capabilities.base import NotAvailable
from weboob.tools.backend import BaseBackend from weboob.tools.backend import BaseBackend
from weboob.tools.browser import BaseBrowser from weboob.tools.browser import BaseBrowser
@ -66,5 +67,8 @@ class GeolocIpBackend(BaseBackend, ICapGeolocIp):
iploc.lg = float(tab['lg']) iploc.lg = float(tab['lg'])
iploc.host = tab['host'] iploc.host = tab['host']
iploc.tld = tab['tld'] iploc.tld = tab['tld']
iploc.isp = tab['fai'] if 'fai' in tab:
iploc.isp = tab['fai']
else:
iploc.isp = NotAvailable
return iploc return iploc

View file

@ -36,11 +36,11 @@ class OuiFMBackend(BaseBackend, ICapRadio):
LICENSE = 'GPLv3' LICENSE = 'GPLv3'
BROWSER = OuiFMBrowser BROWSER = OuiFMBrowser
_RADIOS = {'general': (u'OUÏ FM', u'OUI FM', 'http://ouifm.ice.infomaniak.ch/ouifm-high.mp3'), _RADIOS = {'general': (u'OUÏ FM', u'OUI FM', u'http://ouifm.ice.infomaniak.ch/ouifm-high.mp3'),
'alternatif': (u'OUÏ FM Alternatif', u'OUI FM - L\'Alternative Rock', 'http://ouifm.ice.infomaniak.ch/ouifm2.mp3'), 'alternatif': (u'OUÏ FM Alternatif', u'OUI FM - L\'Alternative Rock', u'http://ouifm.ice.infomaniak.ch/ouifm2.mp3'),
'collector': (u'OUÏ FM Collector', u'OUI FM - Classic Rock', 'http://ouifm.ice.infomaniak.ch/ouifm3.mp3'), 'collector': (u'OUÏ FM Collector', u'OUI FM - Classic Rock', u'http://ouifm.ice.infomaniak.ch/ouifm3.mp3'),
'blues': (u'OUÏ FM Blues', u'OUI FM - Blues', 'http://ouifm.ice.infomaniak.ch/ouifm4.mp3'), 'blues': (u'OUÏ FM Blues', u'OUI FM - Blues', u'http://ouifm.ice.infomaniak.ch/ouifm4.mp3'),
'inde': (u'OUÏ FM Indé', u'OUI FM - Rock Indé', 'http://ouifm.ice.infomaniak.ch/ouifm5.mp3'), 'inde': (u'OUÏ FM Indé', u'OUI FM - Rock Indé', u'http://ouifm.ice.infomaniak.ch/ouifm5.mp3'),
} }
def iter_radios(self): def iter_radios(self):
@ -70,7 +70,7 @@ class OuiFMBackend(BaseBackend, ICapRadio):
radio.current = current radio.current = current
stream = Stream(0) stream = Stream(0)
stream.title = '128kbits/s' stream.title = u'128kbits/s'
stream.url = url stream.url = url
radio.streams = [stream] radio.streams = [stream]
return radio return radio

View file

@ -31,4 +31,4 @@ class PlayerPage(BasePage):
_radio = '_%s' % radio _radio = '_%s' % radio
title = select(self.document.getroot(), 'div#titre%s' % _radio, 1).text.strip() title = select(self.document.getroot(), 'div#titre%s' % _radio, 1).text.strip()
artist = select(self.document.getroot(), 'div#artiste%s' % _radio, 1).text.strip() artist = select(self.document.getroot(), 'div#artiste%s' % _radio, 1).text.strip()
return artist, title return unicode(artist), unicode(title)

View file

@ -17,9 +17,7 @@
import sys import sys
if sys.version_info[:2] <= (2, 5): from datetime import datetime
from weboob.tools.property import property
from .base import IBaseCap, CapBaseObject from .base import IBaseCap, CapBaseObject
@ -29,68 +27,33 @@ __all__ = ['Account', 'AccountNotFound', 'NotEnoughMoney', 'ICapBank', 'Operatio
class AccountNotFound(Exception): class AccountNotFound(Exception):
pass pass
class NotEnoughMoney(Exception): class NotEnoughMoney(Exception):
pass pass
class Account(CapBaseObject): class Account(CapBaseObject):
FIELDS = ('label', 'balance', 'coming')
def __init__(self): def __init__(self):
CapBaseObject.__init__(self, 0) CapBaseObject.__init__(self, 0)
self.label = '' self.add_field('label', (str,unicode))
self._balance = 0.0 self.add_field('balance', float)
self._coming = 0.0 self.add_field('coming', float)
self.link_id = '' self.add_field('link_id', (str,unicode))
@property
def balance(self):
return self._balance
@balance.setter
def balance(self, value):
self._balance = float(value)
@property
def coming(self):
return self._coming
@coming.setter
def coming(self, value):
self._coming = float(value)
def __repr__(self): def __repr__(self):
return u"<Account id='%s' label='%s'>" % (self.id, self.label) return u"<Account id='%s' label='%s'>" % (self.id, self.label)
class Operation(CapBaseObject): class Operation(CapBaseObject):
FIELDS = ('date', 'label', 'amount')
def __init__(self, id): def __init__(self, id):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.date = None self.add_field('date', (str,unicode,datetime))
self._label = u'' self.add_field('label', unicode)
self._amount = 0.0 self.add_field('amount', float)
def __repr__(self): def __repr__(self):
return "<Operation date='%s' label='%s' amount=%s>" % (self.date, self.label, self.amount) return "<Operation date='%s' label='%s' amount=%s>" % (self.date, self.label, self.amount)
@property
def label(self):
return self._label
@label.setter
def label(self, value):
self._label = unicode(value)
@property
def amount(self):
return self._amount
@amount.setter
def amount(self, value):
self._amount = float(value)
class ICapBank(IBaseCap): class ICapBank(IBaseCap):
def iter_accounts(self): def iter_accounts(self):
raise NotImplementedError() raise NotImplementedError()
@ -103,6 +66,6 @@ class ICapBank(IBaseCap):
def iter_history(self, id): def iter_history(self, id):
raise NotImplementedError() raise NotImplementedError()
def transfer(self, id_from, id_to, amount): def transfer(self, id_from, id_to, amount):
raise NotImplementedError() raise NotImplementedError()

View file

@ -29,14 +29,15 @@ class ChatException(Exception):
class ChatMessage(CapBaseObject): class ChatMessage(CapBaseObject):
FIELDS = ('id_from', 'id_to', 'date', 'message')
def __init__(self, id_from, id_to, message, date=None): def __init__(self, id_from, id_to, message, date=None):
CapBaseObject.__init__(self, '%s.%s' % (id_from, id_to)) CapBaseObject.__init__(self, '%s.%s' % (id_from, id_to))
self.id_from = id_from self.add_field('id_from', (str,unicode), id_from)
self.id_to = id_to self.add_field('id_to', (str,unicode), id_to)
self.message = message self.add_field('message', (str,unicode), message)
self.date = datetime.datetime.utcnow() if date is None else date self.add_field('date', datetime.datetime, date)
if self.date is None:
self.date = datetime.datetime.utcnow()
class ICapChat(IBaseCap): class ICapChat(IBaseCap):

View file

@ -36,11 +36,11 @@ class ProfileNode(object):
class ContactPhoto(CapBaseObject): class ContactPhoto(CapBaseObject):
def __init__(self, name): def __init__(self, name):
CapBaseObject.__init__(self, name) CapBaseObject.__init__(self, name)
self.name = name #useless, but keep compatibility self.add_field('name', (str,unicode), name)
self.url = u'' self.add_field('url', (str,unicode))
self.data = '' self.add_field('data', str)
self.thumbnail_url = u'' self.add_field('thumbnail_url', (str,unicode))
self.thumbnail_data = u'' self.add_field('thumbnail_data', (str,unicode))
def __iscomplete__(self): def __iscomplete__(self):
return (self.data and (not self.thumbnail_url or self.thumbnail_data)) return (self.data and (not self.thumbnail_url or self.thumbnail_data))
@ -49,11 +49,11 @@ class ContactPhoto(CapBaseObject):
return self.url return self.url
def __repr__(self): def __repr__(self):
return u'<ContactPhoto "%s" data=%do tndata=%do>' % (self.name, len(self.data), len(self.thumbnail_data)) return u'<ContactPhoto "%s" data=%do tndata=%do>' % (self.id,
len(self.data) if self.data else 0,
len(self.thumbnail_data) if self.thumbnail_data else 0)
class Contact(CapBaseObject): class Contact(CapBaseObject):
FIELDS = ('name', 'status', 'status_msg', 'summary', 'avatar', 'photos', 'profile')
STATUS_ONLINE = 0x001 STATUS_ONLINE = 0x001
STATUS_AWAY = 0x002 STATUS_AWAY = 0x002
STATUS_OFFLINE = 0x004 STATUS_OFFLINE = 0x004
@ -61,13 +61,12 @@ class Contact(CapBaseObject):
def __init__(self, id, name, status): def __init__(self, id, name, status):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.name = name self.add_field('name', (str,unicode), name)
self.status = status self.add_field('status', int, status)
self.status_msg = NotLoaded self.add_field('status_msg', (str,unicode))
self.summary = NotLoaded self.add_field('summary', (str,unicode))
self.avatar = NotLoaded self.add_field('photos', dict, OrderedDict())
self.photos = OrderedDict() self.add_field('profile', list)
self.profile = NotLoaded
def set_photo(self, name, **kwargs): def set_photo(self, name, **kwargs):
if not name in self.photos: if not name in self.photos:

View file

@ -19,23 +19,23 @@
from .base import IBaseCap, CapBaseObject from .base import IBaseCap, CapBaseObject
__all__ = ('IpLocation', 'ICapGeolocIp') __all__ = ['IpLocation', 'ICapGeolocIp']
class IpLocation(CapBaseObject): class IpLocation(CapBaseObject):
FIELDS = ('city', 'region', 'zipcode', 'country', 'lt', 'lg', 'host', 'tls', 'isp')
def __init__(self, ipaddr): def __init__(self, ipaddr):
CapBaseObject.__init__(self, ipaddr) CapBaseObject.__init__(self, ipaddr)
self.ipaddr = ipaddr self.ipaddr = ipaddr
self.city = None self.add_field('city', (str,unicode))
self.region = None self.add_field('region', (str,unicode))
self.zipcode = None self.add_field('zipcode', (str,unicode))
self.country = None self.add_field('country', (str,unicode))
self.lt = None self.add_field('lt', float)
self.lg = None self.add_field('lg', float)
self.host = None self.add_field('host', (str,unicode))
self.tld = None self.add_field('tld', (str,unicode))
self.isp = None self.add_field('isp', (str,unicode))
class ICapGeolocIp(IBaseCap): class ICapGeolocIp(IBaseCap):
def get_location(self, ipaddr): def get_location(self, ipaddr):

View file

@ -31,8 +31,6 @@ class Message(CapBaseObject):
IS_ACCUSED = 0x004 # The receiver has read this message IS_ACCUSED = 0x004 # The receiver has read this message
IS_NOT_ACCUSED = 0x008 # The receiver has not read this message IS_NOT_ACCUSED = 0x008 # The receiver has not read this message
FIELDS = ('thread', 'title', 'sender', 'receiver', 'date', 'parent', 'content', 'signature', 'children', 'flags')
def __init__(self, thread, id, def __init__(self, thread, id,
title=NotLoaded, title=NotLoaded,
sender=NotLoaded, sender=NotLoaded,
@ -44,10 +42,16 @@ class Message(CapBaseObject):
children=NotLoaded, children=NotLoaded,
flags=0): flags=0):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.thread = thread self.add_field('thread', Thread, thread)
self.title = title self.add_field('title', (str,unicode), title)
self.sender = sender self.add_field('sender', (str,unicode), sender)
self.receiver = receiver self.add_field('receiver', (str,unicode), receiver)
self.add_field('date', datetime.datetime, date)
self.add_field('parent', Message, parent)
self.add_field('content', (str,unicode), content)
self.add_field('signature', (str,unicode), signature)
self.add_field('children', list, children)
self.add_field('flags', int, flags)
if date is None: if date is None:
date = datetime.datetime.utcnow() date = datetime.datetime.utcnow()
@ -59,11 +63,6 @@ class Message(CapBaseObject):
self.parent = NotLoaded self.parent = NotLoaded
self._parent_id = parent self._parent_id = parent
self.content = content
self.signature = signature
self.children = children
self.flags = flags
@property @property
def date_int(self): def date_int(self):
return int(time.strftime('%Y%m%d%H%M%S', self.date.timetuple())) return int(time.strftime('%Y%m%d%H%M%S', self.date.timetuple()))
@ -92,15 +91,13 @@ class Message(CapBaseObject):
return result.encode('utf-8') return result.encode('utf-8')
class Thread(CapBaseObject): class Thread(CapBaseObject):
FIELDS = ('root', 'title', 'date', 'nb_messages', 'nb_unread')
def __init__(self, id): def __init__(self, id):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.root = NotLoaded self.add_field('root', Message)
self.title = NotLoaded self.add_field('title', (str,unicode))
self.date = NotLoaded self.add_field('date', datetime.datetime)
self.nb_messages = NotLoaded self.add_field('nb_messages', int)
self.nb_unread = NotLoaded self.add_field('nb_unread', int)
def iter_all_messages(self): def iter_all_messages(self):
if self.root: if self.root:

View file

@ -16,19 +16,17 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from .base import IBaseCap, NotLoaded, CapBaseObject from .base import IBaseCap, CapBaseObject
__all__ = ['Emission', 'Stream', 'Radio', 'ICapRadio'] __all__ = ['Emission', 'Stream', 'Radio', 'ICapRadio']
class Emission(CapBaseObject): class Emission(CapBaseObject):
FIELDS = ('artist', 'title')
def __init__(self, id): def __init__(self, id):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.artist = NotLoaded self.add_field('artist', unicode)
self.title = NotLoaded self.add_field('title', unicode)
def __iscomplete__(self): def __iscomplete__(self):
# This volatile information may be reloaded everytimes. # This volatile information may be reloaded everytimes.
@ -38,12 +36,10 @@ class Emission(CapBaseObject):
return u'%s - %s' % (self.artist, self.title) return u'%s - %s' % (self.artist, self.title)
class Stream(CapBaseObject): class Stream(CapBaseObject):
FIELDS = ('title', 'url')
def __init__(self, id): def __init__(self, id):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.title = NotLoaded self.add_field('title', unicode)
self.url = NotLoaded self.add_field('url', unicode)
def __unicode__(self): def __unicode__(self):
return u'%s (%s)' % (self.title, self.url) return u'%s (%s)' % (self.title, self.url)
@ -52,14 +48,12 @@ class Stream(CapBaseObject):
return self.__unicode__() return self.__unicode__()
class Radio(CapBaseObject): class Radio(CapBaseObject):
FIELDS = ('title', 'description', 'current', 'streams')
def __init__(self, id): def __init__(self, id):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.title = NotLoaded self.add_field('title', unicode)
self.description = NotLoaded self.add_field('description', unicode)
self.streams = NotLoaded self.add_field('current', Emission)
self.current = NotLoaded self.add_field('streams', list)
class ICapRadio(IBaseCap): class ICapRadio(IBaseCap):
def iter_radios(self): def iter_radios(self):

View file

@ -15,6 +15,7 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from datetime import datetime
from .base import IBaseCap, CapBaseObject, NotLoaded from .base import IBaseCap, CapBaseObject, NotLoaded
@ -23,21 +24,18 @@ __all__ = ['ICapTorrent', 'Torrent']
class Torrent(CapBaseObject): class Torrent(CapBaseObject):
FIELDS = ('name', 'size', 'date', 'url', 'seeders', 'leechers', 'files', 'description')
def __init__(self, id, name, date=NotLoaded, size=NotLoaded, url=NotLoaded, def __init__(self, id, name, date=NotLoaded, size=NotLoaded, url=NotLoaded,
seeders=NotLoaded, leechers=NotLoaded, files=NotLoaded, seeders=NotLoaded, leechers=NotLoaded, files=NotLoaded,
description=NotLoaded): description=NotLoaded):
CapBaseObject.__init__(self, id) CapBaseObject.__init__(self, id)
self.name = name self.add_field('name', (str,unicode), name)
self.date = date self.add_field('size', (int,long,float), size)
self.size = size self.add_field('date', datetime, date)
self.url = url self.add_field('url', (str,unicode), url)
self.seeders = seeders self.add_field('seeders', int, seeders)
self.leechers = leechers self.add_field('leechers', int, leechers)
self.files = files self.add_field('files', list, files)
self.description = description self.add_field('description', (str,unicode), description)
class ICapTorrent(IBaseCap): class ICapTorrent(IBaseCap):
def iter_torrents(self, pattern): def iter_torrents(self, pattern):

View file

@ -16,7 +16,7 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from datetime import time from datetime import time, datetime
from .base import IBaseCap, CapBaseObject from .base import IBaseCap, CapBaseObject
@ -24,6 +24,31 @@ from .base import IBaseCap, CapBaseObject
__all__ = ['Departure', 'ICapTravel', 'Station'] __all__ = ['Departure', 'ICapTravel', 'Station']
class Station(CapBaseObject):
def __init__(self, id, name):
CapBaseObject.__init__(self, id)
self.add_field('name', (str,unicode), name)
def __repr__(self):
return "<Station id=%r name=%r>" % (self.id, self.name)
class Departure(CapBaseObject):
def __init__(self, id, _type, _time):
CapBaseObject.__init__(self, id)
self.add_field('type', (str,unicode), _type)
self.add_field('time', datetime, _time)
self.add_field('departure_station', (str,unicode))
self.add_field('arrival_station', (str,unicode))
self.add_field('late', time, time())
self.add_field('information', (str,unicode))
self.add_field('plateform', (str,unicode))
def __repr__(self):
return u"<Departure id=%r type=%r time=%r departure=%r arrival=%r>" % (
self.id, self.type, self.time.strftime('%H:%M'), self.departure_station, self.arrival_station)
class ICapTravel(IBaseCap): class ICapTravel(IBaseCap):
def iter_station_search(self, pattern): def iter_station_search(self, pattern):
""" """
@ -43,33 +68,3 @@ class ICapTravel(IBaseCap):
@return [iter] result of Departure objects @return [iter] result of Departure objects
""" """
raise NotImplementedError() raise NotImplementedError()
class Station(CapBaseObject):
FIELDS = ('name',)
def __init__(self, id, name):
CapBaseObject.__init__(self, id)
self.name = name
def __repr__(self):
return "<Station id=%r name=%r>" % (self.id, self.name)
class Departure(CapBaseObject):
FIELDS = ('type', 'time', 'departure_station', 'arrival_station', 'late', 'information', 'plateform')
def __init__(self, id, _type, _time):
CapBaseObject.__init__(self, id)
self.type = _type
self.time = _time
self.departure_station = u''
self.arrival_station = u''
self.late = time()
self.information = u''
self.plateform = u''
def __repr__(self):
return u"<Departure id=%r type=%r time=%r departure=%r arrival=%r>" % (
self.id, self.type, self.time.strftime('%H:%M'), self.departure_station, self.arrival_station)

View file

@ -16,7 +16,9 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from .base import IBaseCap, NotLoaded, CapBaseObject from datetime import datetime, timedelta
from .base import IBaseCap, CapBaseObject, NotLoaded
__all__ = ['BaseVideo', 'ICapVideo'] __all__ = ['BaseVideo', 'ICapVideo']
@ -25,8 +27,8 @@ __all__ = ['BaseVideo', 'ICapVideo']
class VideoThumbnail(CapBaseObject): class VideoThumbnail(CapBaseObject):
def __init__(self, url): def __init__(self, url):
CapBaseObject.__init__(self, url) CapBaseObject.__init__(self, url)
self.url = url.replace(' ', '%20') self.add_field('url', (unicode,str), url.replace(' ', '%20'))
self.data = NotLoaded self.add_field('data', str)
def __str__(self): def __str__(self):
return self.url return self.url
@ -39,22 +41,23 @@ class VideoThumbnail(CapBaseObject):
class BaseVideo(CapBaseObject): class BaseVideo(CapBaseObject):
FIELDS = ('title', 'url', 'author', 'duration', 'date', 'rating', 'rating_max', 'thumbnail', 'nsfw')
def __init__(self, _id, title=NotLoaded, url=NotLoaded, author=NotLoaded, duration=NotLoaded, date=NotLoaded, def __init__(self, _id, title=NotLoaded, url=NotLoaded, author=NotLoaded, duration=NotLoaded, date=NotLoaded,
rating=NotLoaded, rating_max=NotLoaded, thumbnail=NotLoaded, thumbnail_url=None, nsfw=False): rating=NotLoaded, rating_max=NotLoaded, thumbnail=NotLoaded, thumbnail_url=None, nsfw=False):
CapBaseObject.__init__(self, unicode(_id)) CapBaseObject.__init__(self, unicode(_id))
self.title = title
self.url = url self.add_field('title', (str,unicode), title)
self.author = author self.add_field('url', (str,unicode), url)
self.duration = duration self.add_field('author', (str,unicode), author)
self.date = date self.add_field('duration', (int,long,timedelta), duration)
self.rating = rating self.add_field('date', datetime, date)
self.rating_max = rating_max self.add_field('rating', (int,long,float), rating)
self.thumbnail = thumbnail self.add_field('rating_max', (int,long,float), rating_max)
self.add_field('thumbnail', VideoThumbnail, thumbnail)
self.add_field('nsfw', bool, nsfw)
# XXX remove this and fix all backends
if thumbnail_url is not None and self.thumbnail is NotLoaded: if thumbnail_url is not None and self.thumbnail is NotLoaded:
self.thumbnail = VideoThumbnail(thumbnail_url) self.thumbnail = VideoThumbnail(thumbnail_url)
self.nsfw = nsfw
@classmethod @classmethod
def id2url(cls, _id): def id2url(cls, _id):