class FavouriteItem(TracklistItemMixin, Base): __acl__ = (Allow( Parent, Create, Fields('favourite_id', 'favourite_provider_id', 'account_id', 'account_provider_id', 'track_id', 'track_provider_id')), Allow(Owner, Read, Fields('id', 'track_id', 'track_provider_id')), Allow(Owner, Delete), Allow(Parent, Query, Fields('favourite'))) __table_args__ = (sql.PrimaryKeyConstraint('id'), sql.ForeignKeyConstraint( ['favourite_provider_id', 'favourite_id'], ['favourite.provider_id', 'favourite.id']), sql.ForeignKeyConstraint( ['account_id', 'account_provider_id'], ['account.id', 'account.provider_id']), sql.ForeignKeyConstraint(['track_provider_id'], ['provider.id'])) provider_id = orm.synonym('favourite_provider_id') favourite_id = sql.Column(sql.String(96), nullable=False) favourite_provider_id = sql.Column(sql.String(16), nullable=False) favourite = orm.relation('Favourite', back_populates='items') parent = orm.synonym('favourite')
class Session(Base): __acl__ = ( Allow(Owner, Create, Fields( 'account_id', 'account_provider_id', 'system', 'browser', 'screen' )), Allow(Owner, Read, Fields()), Deny() ) __table_args__ = ( sql.PrimaryKeyConstraint( 'id'), sql.ForeignKeyConstraint( ['account_id', 'account_provider_id'], ['account.id', 'account.provider_id']) ) id = sql.Column(sql.String(64), default=functools.partial(gen_token, 64)) account_id = sql.Column(sql.String(32), nullable=False) account_provider_id = sql.Column(sql.String(16), nullable=False) account = orm.relation( 'Account', back_populates='sessions', uselist=False, single_parent=True) parent = orm.synonym('account') system = sql.Column(sql.String(64), nullable=False) browser = sql.Column(sql.String(64), nullable=False) screen = sql.Column(sql.String(32), nullable=False)
class Token(Base): __acl__ = ( Allow(Everyone, Create, Fields()), Allow(Everyone, Read, Fields( 'id', 'claimed' )), Allow(Everyone, Update, Fields( 'claimed', 'account_id', 'account_provider_id' )) ) __table_args__ = ( sql.PrimaryKeyConstraint( 'id'), sql.ForeignKeyConstraint( ['account_id', 'account_provider_id'], ['account.id', 'account.provider_id']) ) id = sql.Column(sql.String(16), default=functools.partial(gen_token, 6)) claimed = sql.Column(sql.Boolean, default=False) account_provider_id = sql.Column(sql.String(16)) account_id = sql.Column(sql.String(32)) account = orm.relation( 'Account', single_parent=True) parent = orm.synonym('account')
class Provider(Base): __acl__ = (Allow(Everyone, Read, Fields('id', 'client_id')), Allow(Everyone, Query, Fields('id'))) __table_args__ = (sql.PrimaryKeyConstraint('id'), ) id = sql.Column(sql.String(12)) provider_id = orm.synonym('id') @property def client_id(self): if self.id in opt.options['providers']: return opt.options[self.id]['api_key']
class Image(Base): __acl__ = (Allow( Everyone, Read, Fields('id', 'small', 'medium', 'large', 'created', 'updated')), Deny()) __table_args__ = (sql.PrimaryKeyConstraint('id'), ) id = sql.Column(sql.Integer) small = sql.Column(sql.String(256)) medium = sql.Column(sql.String(256)) large = sql.Column(sql.String(256), nullable=False) def copy(self): return Image(small=self.small, medium=self.medium, large=self.large) @classmethod def from_soundcloud(cls, url): if isinstance(url, str): return cls(small=url, medium=url.replace('large', 't300x300'), large=url.replace('large', 't500x500')) @classmethod def from_youtube(cls, thumbnails): if isinstance(thumbnails, dict): return cls(small=thumbnails.get('default', {}).get('url'), medium=thumbnails.get('medium', {}).get('url'), large=thumbnails.get('high', {}).get('url'))
class TrackComment(Transient): __acl__ = ( Allow(Everyone, Read, Fields( 'id', 'provider_id', 'account.id', 'account.provider_id', 'account.title', 'account.image.small', 'account.image.medium', 'account.image.large', 'body', 'timestamp', 'track_id', 'track_provider_id', 'created' )), ) id = None provider_id = None account = None body = None timestamp = None track_id = None track_provider_id = None
class Favourite(TracklistMixin, Base): __acl__ = (Allow( Owner, Read, Fields('id', 'provider_id', 'account_id', 'account_provider_id')), ) account = orm.relation('Account', back_populates='favourite', viewonly=True) items = orm.relation('FavouriteItem', cascade='all, delete-orphan', order_by='FavouriteItem.created', single_parent=True)
class Image(Base): __acl__ = (Allow( Everyone, Read, Fields('id', 'small', 'medium', 'large', 'created', 'updated')), Deny()) __table_args__ = (sql.PrimaryKeyConstraint('id'), ) id = sql.Column(sql.Integer) small = sql.Column(sql.String(256)) medium = sql.Column(sql.String(256)) large = sql.Column(sql.String(256), nullable=False) def copy(self): return Image(small=self.small, medium=self.medium, large=self.large)
class User(Base): __acl__ = (Allow( Child, Read, Fields('id', 'provider_id', 'accounts.id', 'accounts.provider_id', 'accounts.connected', 'accounts.favourite_id', 'accounts.image.id', 'accounts.image.small', 'accounts.image.medium', 'accounts.image.large', 'accounts.title', 'created', 'updated')), ) __table_args__ = (sql.PrimaryKeyConstraint('id'), ) id = sql.Column(sql.Integer) provider_id = 'cloudplayer' accounts = orm.relation('Account', back_populates='user', uselist=True, single_parent=True, cascade='all, delete-orphan') children = orm.synonym('accounts')
class Track(Transient): __acl__ = (Allow( Everyone, Read, Fields('id', 'provider_id', 'account.id', 'account.provider_id', 'account.title', 'account.image.small', 'account.image.medium', 'account.image.large', 'aspect_ratio', 'duration', 'favourite_count', 'image.small', 'image.medium', 'image.large', 'play_count', 'title', 'created')), ) id = None provider_id = None account = None aspect_ratio = None duration = None favourite_count = None image = None play_count = None title = None
class Playlist(TracklistMixin, Base): __acl__ = ( Allow(Owner, Create, Fields( 'provider_id', 'account_id', 'account_provider_id', 'description', 'public', 'title' )), Allow(Owner, Read, Fields( 'id', 'provider_id', 'account_id', 'account_provider_id', 'description', 'follower_count', 'image.id', 'image.small', 'image.medium', 'image.large', 'public', 'title', 'created', 'updated' )), Allow(Owner, Update, Fields( 'description', 'public', 'title' )), Allow(Owner, Delete), Allow(Owner, Query, Fields( 'id', 'provider_id', 'account_id', 'account_provider_id' )), Deny() ) __channel__ = ( 'playlist.{provider_id}.{id}', ) __fields__ = ( 'id', 'provider_id', 'account_id', 'account_provider_id', 'description', 'follower_count', 'image.id', 'image.small', 'image.medium', 'image.large', 'public', 'title', 'created', 'updated' ) @declared_attr def __table_args__(cls): return super().__table_args__ + ( sql.ForeignKeyConstraint( ['image_id'], ['image.id']), ) account = orm.relation( 'Account', back_populates='playlists', cascade='all', viewonly=True) parent = orm.synonym('account') items = orm.relation( 'PlaylistItem', cascade='all, delete-orphan', order_by='PlaylistItem.rank', single_parent=True) description = sql.Column(sql.Unicode(5120), nullable=True) follower_count = sql.Column(sql.Integer, default=0) public = sql.Column(sql.Boolean, default=False) title = sql.Column(sql.Unicode(256), nullable=False) image_id = sql.Column(sql.Integer) image = orm.relation( 'Image', cascade='all, delete-orphan', single_parent=True, uselist=False)
class Track(Transient): __acl__ = ( Allow(Everyone, Read, Fields( 'id', 'provider_id', 'account.id', 'account.provider_id', 'account.title', 'account.image.small', 'account.image.medium', 'account.image.large', 'aspect_ratio', 'duration', 'favourite_count', 'image.small', 'image.medium', 'image.large', 'play_count', 'title', 'created' )), ) id = None provider_id = None account = None aspect_ratio = None duration = None favourite_count = None image = None play_count = None title = None @classmethod def from_provider(cls, provider_id, track): if provider_id == 'soundcloud': return cls.from_soundcloud(track) elif provider_id == 'youtube': return cls.from_youtube(track) else: raise ValueError('unsupported provider') @classmethod def from_soundcloud(cls, track): user = track['user'] artist = Account( id=user['id'], provider_id='soundcloud', title=user['username'], image=Image.from_soundcloud(user.get('avatar_url'))) return cls( id=track['id'], provider_id='soundcloud', account=artist, aspect_ratio=1.0, duration=int(track['duration'] / 1000.0), favourite_count=track.get('favoritings_count', 0), image=Image.from_soundcloud(track.get('artwork_url')), play_count=track.get('playback_count', 0), title=track['title'], created=datetime.datetime.strptime( track['created_at'], '%Y/%m/%d %H:%M:%S %z')) @classmethod def from_youtube(cls, track): snippet = track['snippet'] player = track['player'] statistics = track['statistics'] duration = isodate.parse_duration(track['contentDetails']['duration']) artist = Account( id=snippet['channelId'], provider_id='youtube', image=None, title=snippet['channelTitle']) return cls( id=track['id'], provider_id='youtube', account=artist, aspect_ratio=( float(player['embedHeight']) / float(player['embedWidth'])), duration=int(duration.total_seconds()), favourite_count=statistics.get('likeCount', 0), image=Image.from_youtube(snippet.get('thumbnails')), play_count=statistics.get('viewCount', 0), title=snippet['title'], created=datetime.datetime.strptime( snippet['publishedAt'], '%Y-%m-%dT%H:%M:%S.%fZ'))
class Account(Base): __acl__ = (Allow( Owner, Read, Fields('id', 'provider_id', 'user_id', 'connected', 'favourite_id', 'image.id', 'image.small', 'image.medium', 'image.large', 'title', 'created', 'updated')), Allow(Owner, Update, Fields('image', 'title')), Allow( Everyone, Read, Fields('id', 'provider_id', 'image.id', 'image.small', 'image.medium', 'image.large', 'title')), Allow(Everyone, Query, Fields('id', 'provider_id', 'title')), Deny()) __fields__ = ('id', 'provider_id', 'user_id', 'connected', 'favourite_id', 'image_id', 'title', 'created', 'updated') __channel__ = ('account.{provider_id}.{id}', ) __table_args__ = (sql.PrimaryKeyConstraint('id', 'provider_id'), sql.ForeignKeyConstraint(['provider_id'], ['provider.id']), sql.ForeignKeyConstraint(['user_id'], ['user.id']), sql.ForeignKeyConstraint(['image_id'], ['image.id'])) id = sql.Column(sql.String(32)) account_id = orm.synonym('id') provider_id = sql.Column(sql.String(16), nullable=False) provider = orm.relation('Provider', cascade=None, uselist=False, viewonly=True) account_provider_id = orm.synonym('provider_id') user_id = sql.Column(sql.Integer, nullable=False) user = orm.relation('User', back_populates='accounts', uselist=False, viewonly=True) parent = orm.synonym('user') sessions = orm.relation('Session', back_populates='account', cascade='all, delete-orphan', single_parent=True, uselist=True) image_id = sql.Column(sql.Integer) image = orm.relation('Image', cascade='all, delete-orphan', single_parent=True, uselist=False) @property def favourite_id(self): if self.favourite: return self.favourite.id favourite = orm.relation('Favourite', back_populates='account', cascade='all, delete-orphan', single_parent=True, uselist=False) playlists = orm.relation('Playlist', back_populates='account', cascade='all, delete-orphan', single_parent=True, uselist=True) title = sql.Column('title', sql.Unicode(64)) access_token = sql.Column(sql.String(256)) refresh_token = sql.Column(sql.String(256)) token_expiration = sql.Column(sql.DateTime()) @property def connected(self): return self.provider_id == 'cloudplayer' or all( [self.access_token, self.refresh_token])