Ejemplo n.º 1
0
    def handle(self, packet_msg):
        if not self.is_token_auth():
            return

        # Fetch all players. Use this to init client state
        if self.query == 'status_change':
            status = packet_msg.get('status')

            # Get previous player state from database
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=self.sock.uid).one()
            except NoResultFound:
                log.warn(u"Requested player %s was not found!", self.sock.uid)
                return
            finally:
                s.close()

            # Remote status == STOPPED => attempt to come up with a new source
            if status == 0:
                self.send_source(player)
            else:
                s = db_session()
                player.status = status
                s.add(player)
                s.commit()
                self.broadcast('player', {'state': player.serialize()},
                               query="change",
                               client_type='user',
                               avoid_self=False)
                s.close()
Ejemplo n.º 2
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        # Fetch all events. Use this to init client state
        if self.query == 'fetchall':
            s = db_session()
            if self.is_admin():
                events = [event.serialize() for event in s.query(Event).all()]
            else:
                events = [event.serialize() for event in s.query(Event).filter_by(visible=True).all()]
            s.close()
            self.send_message(events)
            log.info(u"[%s] Events fetched", self.sock.sid[0:6])
            return

        if self.query == 'add' and self.is_admin():
            s = db_session()
            event = Event(name=u'Event {}'.format(generate_session()[:4]), visible=False)
            s.add(event)
            s.commit()
            self.send_message(event.serialize())
            s.close()

            log.info(u"[%s] New event added", self.sock.sid[0:6])
            return

        if self.query == 'edit' and self.is_admin():
            event_id = packet_msg.get('id')
            name = packet_msg.get('name')
            visible = packet_msg.get('visible')

            # Get user
            s = db_session()
            try:
                event = s.query(Event).filter_by(id=event_id).one()
                event.name = name
                event.visible = visible
                s.add(event)
                s.commit()
                self.send_message(event.serialize())

                log.info(u"[%s] Event %d edited", event_id, self.sock.sid[0:6])
            except NoResultFound:
                log.info(u"[%s] error while editing event %d: no event found", event_id, self.sock.sid[0:6])
                return
            finally:
                s.close()
Ejemplo n.º 3
0
    def handle(self, packet_msg):
        username = packet_msg.get('username')
        password = packet_msg.get('password')
        password2 = packet_msg.get('password2')
        email = packet_msg.get('email', '')
        nickname = packet_msg.get('nickname')

        if not username or not password or not nickname or not password2:
            self.send_error('Fill all fields', 400)
            return

        if len(username) < 5 or len(username) > 32:
            self.send_error('Username should be between 5 and 32 characters long', 400)
            return

        if len(nickname) < 5 or len(nickname) > 32:
            self.send_error('Nickname should be between 5 and 32 characters long', 400)
            return

        if email and (len(email) < 3 or len(email) > 128):
            self.send_error('Email should be between 3 and 128 characters long', 400)
            return

        if len(password) < 8:
            self.send_error('Password should be at least 8 characters long', 400)
            return

        if password != password2:
            self.send_error('Passwords don\'t match!', 400)
            return

        # Make sure the nickname is not yet reserved
        s = db_session()
        try:
            s.query(User).filter_by(nickname=nickname).one()
            self.send_error('Nickname is already reserved', 405)
            s.close()
            return
        except NoResultFound:
            pass

        # Make sure the username is not yet reserved
        try:
            s.query(User).filter_by(username=username).one()
            self.send_error('Username is already reserved', 405)
            s.close()
            return
        except NoResultFound:
            pass

        pw_hash = pbkdf2_sha256.encrypt(password)
        user = User(username=username, password=pw_hash, email=email, nickname=nickname, level=USERLEVELS['user'])
        s.add(user)
        s.commit()
        s.close()

        # Send simple notification
        log.info(u"Registered new user %s.", username)
        self.send_message({})
Ejemplo n.º 4
0
 def handle_fetchall_sig(self):
     s = db_session()
     queues = [
         queue.serialize() for queue in s.query(SourceQueue).filter_by(
             user=self.sock.uid).all()
     ]
     s.close()
     self.send_message(queues, query="fetchall")
Ejemplo n.º 5
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        if self.query == 'fetch_most_received':
            # TODO: THIS IS BRUTEFORCE, MAKE A BETTER QUERY
            s = db_session()
            skips = s.query(Skip, Media,
                            User).filter(Media.id == Skip.media,
                                         User.id == Media.user).all()
            s.close()
            counts = {}
            names = {}
            for m in skips:
                if m[2].id not in counts:
                    counts[m[2].id] = 0
                    names[m[2].id] = m[2].nickname
                counts[m[2].id] += 1

            out = []
            k = 1
            for m in sorted(counts.iteritems(),
                            key=lambda x: x[1],
                            reverse=True):
                out.append({'number': k, 'amount': m[1], 'name': names[m[0]]})
                k += 1
            self.send_message(out)

        if self.query == 'fetch_most_given':
            s = db_session()
            skips = s.query(Skip.user, func.count(Skip.id).label('skips'), User)\
                .filter(User.id == Skip.user)\
                .group_by(Skip.user)\
                .order_by('skips desc').all()
            s.close()
            out = []
            k = 1
            for skip in skips:
                out.append({
                    'number': k,
                    'amount': skip[1],
                    'name': skip[2].nickname
                })
                k += 1
            self.send_message(out)
Ejemplo n.º 6
0
 def ensure_sourcequeue(self, player_id):
     s = db_session()
     try:
         r = s.query(SourceQueue).filter_by(user=self.sock.uid, target=player_id).one()
         return r.id
     except NoResultFound:
         sq = SourceQueue(user=self.sock.uid, target=player_id)
         s.add(sq)
         s.commit()
         return sq.id
     finally:
         s.close()
Ejemplo n.º 7
0
 def ensure_sourcequeue(self, player_id):
     s = db_session()
     try:
         r = s.query(SourceQueue).filter_by(user=self.sock.uid,
                                            target=player_id).one()
         return r.id
     except NoResultFound:
         sq = SourceQueue(user=self.sock.uid, target=player_id)
         s.add(sq)
         s.commit()
         return sq.id
     finally:
         s.close()
Ejemplo n.º 8
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return
        if not self.is_admin():
            return

        # Fetch all users
        if self.query == 'fetchall':
            s = db_session()
            users = [user.serialize() for user in s.query(User).all()]
            s.close()
            self.send_message(users)
            log.info(u"[%s] Users fetched", self.sock.sid[0:6])
            return

        # Edit a single user
        if self.query == 'edit':
            user_id = packet_msg.get('id')
            nickname = packet_msg.get('nickname')
            email = packet_msg.get('email')

            # Get user
            s = db_session()
            try:
                user = s.query(User).filter_by(id=user_id).one()
                user.nickname = nickname
                user.email = email
                s.add(user)
                s.commit()
                self.send_message(user.serialize())

                log.info(u"[%s] Player %d edited", user_id, self.sock.sid[0:6])
            except NoResultFound:
                log.info(
                    u"[%s] error while editing player %d: no player found",
                    user_id, self.sock.sid[0:6])
                return
            finally:
                s.close()
Ejemplo n.º 9
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        # Fetch all media entries
        if self.query == 'fetchall':
            player_id = packet_msg.get('player_id')
            if player_id:
                s = db_session()
                medias = [media.serialize()
                          for media in s.query(Media).filter(Media.queue == SourceQueue.id,
                                                             SourceQueue.target == player_id).order_by(Media.id.asc()).all()]
                s.close()
                self.send_message(medias)
Ejemplo n.º 10
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return
        if not self.is_admin():
            return

        # Fetch all users
        if self.query == 'fetchall':
            s = db_session()
            users = [user.serialize() for user in s.query(User).all()]
            s.close()
            self.send_message(users)
            log.info(u"[%s] Users fetched", self.sock.sid[0:6])
            return

        # Edit a single user
        if self.query == 'edit':
            user_id = packet_msg.get('id')
            nickname = packet_msg.get('nickname')
            email = packet_msg.get('email')

            # Get user
            s = db_session()
            try:
                user = s.query(User).filter_by(id=user_id).one()
                user.nickname = nickname
                user.email = email
                s.add(user)
                s.commit()
                self.send_message(user.serialize())

                log.info(u"[%s] Player %d edited", user_id, self.sock.sid[0:6])
            except NoResultFound:
                log.info(u"[%s] error while editing player %d: no player found", user_id, self.sock.sid[0:6])
                return
            finally:
                s.close()
Ejemplo n.º 11
0
def create_admin(_username, _password):
    settings.config_init()
    db_init(settings.DATABASE_CONFIG)
    pw_hash = pbkdf2_sha256.encrypt(_password)
    s = db_session()
    user = User(username=_username,
                nickname=_username,
                email="*****@*****.**",
                password=pw_hash,
                level=USERLEVELS['admin'])
    s.add(user)
    try:
        s.commit()
        print("User '{}' created.".format(_username))
    except IntegrityError:
        print("User {} already exists.".format(_username))
    finally:
        s.close()
Ejemplo n.º 12
0
def create_admin(_username, _password):
    settings.config_init()
    db_init(settings.DATABASE_CONFIG)
    pw_hash = pbkdf2_sha256.encrypt(_password)
    s = db_session()
    user = User(username=_username,
                nickname=_username,
                email="*****@*****.**",
                password=pw_hash,
                level=USERLEVELS['admin'])
    s.add(user)
    try:
        s.commit()
        print("User '{}' created.".format(_username))
    except IntegrityError:
        print("User {} already exists.".format(_username))
    finally:
        s.close()
Ejemplo n.º 13
0
    def handle(self, packet_msg):
        sid = packet_msg.get('sid')

        # Make sure we at least do get a sid (not empty string or stuff)
        if not sid:
            self.send_error("Invalid session", 403)
            log.info(u"Authentication failed")
            return

        # Attempt to find an active session and the attached user account
        user = None
        ses = None
        s = db_session()
        try:
            ses = s.query(Session).filter_by(key=sid).one()
            user = s.query(User).filter_by(id=ses.user).one()
        except NoResultFound:
            pass
        finally:
            s.close()

        # Session found with token.
        if ses and user:
            self.sock.sid = sid
            self.sock.uid = user.id
            self.sock.authenticated = True
            self.sock.level = user.level
            self.sock.client_type = 'user'

            # Send login success message
            self.send_message({
                'uid': self.sock.uid,
                'sid': self.sock.sid,
                'user': user.serialize()
            })
            log.info(u"[%s] Authenticated", sid[0:6])
            return

        # Error out
        self.send_error("Invalid session", 403)
        log.info(u"[%s] Authentication failed", sid[0:6])
Ejemplo n.º 14
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        # Remove session
        s = db_session()
        s.query(Session).filter_by(key=self.sock.sid).delete()
        s.commit()
        s.close()

        # Dump out log
        log.info(u"[%s] Logged out", self.sock.sid[0:6])

        # De-auth & clear session information
        self.sock.authenticated = False
        self.sock.sid = None
        self.sock.uid = None
        self.sock.level = 0

        # Send required skip count
        self.send_req_skip_count()
Ejemplo n.º 15
0
    exit(0)

if 'create_test_admin' in sys.argv:
    create_admin('admin', 'admin')
    exit(0)

if 'create_event' in sys.argv:
    settings.config_init()
    db_init(settings.DATABASE_CONFIG)

    if len(sys.argv) == 3:
        name = sys.argv[2]
    else:
        name = raw_input("Event name: ")

    s = db_session()
    event = Event(name=name, visible=True)
    s.add(event)
    s.commit()
    s.close()
    exit(0)

if 'list_events' in sys.argv:
    settings.config_init()
    db_init(settings.DATABASE_CONFIG)
    s = db_session()
    print("ID  Name")
    for event in s.query(Event).all():
        print("{:3} {}".format(event.id, event.name))
    s.close()
    exit(0)
Ejemplo n.º 16
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        # Fetch all queues. Use this to init client state
        if self.query == 'fetchall':
            self.handle_fetchall_sig()

        # Fetch a single queue (for refreshing)
        if self.query == 'fetchone':
            s = db_session()
            try:
                queue = s.query(SourceQueue).filter_by(
                    user=self.sock.uid).one().serialize()
                self.send_message(queue)
            except NoResultFound:
                self.send_error('No queue found', 404)
            finally:
                s.close()

        # Add new item to the queue. Log to DB, send signal
        if self.query == 'add':
            url = packet_msg.get('url')
            player_id = packet_msg.get('player_id')
            if not url or not player_id:
                self.send_error('Invalid input data', 500)
                return

            queue_id = self.ensure_sourcequeue(player_id)

            # Attempt to parse the url
            youtube_hash = self.get_youtube_code(url)
            other_url = None
            # if not youtube_hash:
            #     other_url = self.validate_other_url(url)

            # Error out if necessary
            if not youtube_hash and not other_url:
                self.send_error('Invalid URL', 500)
                return

            # First, attempt to find the source from database. If it exists, simply use that.
            s = db_session()
            found_src = None
            try:
                if youtube_hash:
                    found_src = s.query(Source).filter_by(
                        youtube_hash=youtube_hash).one()
                elif other_url:
                    found_src = s.query(Source).filter_by(
                        other_url=other_url).one()
            except NoResultFound:
                pass
            finally:
                s.close()

            # If the existing source entry belongs to current user, show error.
            # Don't let user post the same video again and again (rudimentary protection)
            if found_src:
                s = db_session()
                try:
                    player = s.query(Player).filter_by(id=player_id).one()
                except NoResultFound:
                    self.send_error('Invalid input data', 500)
                    return
                finally:
                    s.close()

                s = db_session()
                try:
                    res = s.query(Media)\
                        .filter(Media.user == self.sock.uid, Media.source == found_src.id, Media.queue == queue_id)\
                        .all()
                    for r in res:
                        if r.id > player.last:
                            self.send_error('Url is already in the queue', 500)
                            return
                except NoResultFound:
                    pass
                finally:
                    s.close()

            # First title and description for new video
            first_title = "Unknown"
            first_desc = ""
            first_duration = 0

            # If this is a youtube url, attempt to fetch information for it
            if youtube_hash:
                with youtube_dl.YoutubeDL({'logger': log}) as ydl:
                    try:
                        info = ydl.extract_info(
                            'http://www.youtube.com/watch?v=' + youtube_hash,
                            download=False)
                    except youtube_dl.DownloadError, e:
                        self.send_error(str(e), 500)
                        return

                # Check video duration
                if info['duration'] > settings.LIMIT_DURATION and not self.is_admin(
                ):
                    current_str = format_time_delta(info['duration'])
                    limit_str = format_time_delta(settings.LIMIT_DURATION)
                    self.send_error(
                        'Video is too long ({}). Current limit is {}.'.format(
                            current_str, limit_str), 500)
                    return

                # Use video desc and title
                first_duration = info['duration']
                first_title = info['title']
                first_desc = info['description']

            if found_src:
                # Add a new media entry
                s = db_session()
                media = Media(source=found_src.id,
                              user=self.sock.uid,
                              queue=queue_id)
                s.add(media)
                s.commit()
                s.close()

                # Inform playerdevices about this (in case they are waiting for news about new media)
                self.broadcast('playerdev', {},
                               query='poke',
                               client_type="token")
            else:
                # Okay, Let's save the first draft and then poke at the downloader with MQ message
                s = db_session()
                source = Source(
                    youtube_hash=youtube_hash if youtube_hash else '',
                    other_url=other_url if other_url else '',
                    title=first_title,
                    description=first_desc,
                    length_seconds=first_duration,
                )
                s.add(source)
                s.commit()
                media = Media(source=source.id,
                              user=self.sock.uid,
                              queue=queue_id)
                s.add(media)
                s.commit()

                # Send message to kick the downloader
                self.sock.mq.send_msg(self.sock.mq.KEY_DOWNLOAD, {
                    'source_id': source.id,
                    'no_limit': self.is_admin()
                })

                s.close()

            # Resend all queue data (for now)
            self.handle_fetchall_sig()
            self.send_message({})
            log.info("[%s] New media added to queue", self.sock.sid[0:6])
Ejemplo n.º 17
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        password = packet_msg.get('password')
        password2 = packet_msg.get('password2')
        email = packet_msg.get('email', '')
        nickname = packet_msg.get('nickname')

        if len(nickname) < 5 or len(nickname) > 32:
            self.send_error(
                'Nickname should be between 5 and 32 characters long', 400)
            return

        if email and len(email) > 0:
            if len(email) < 3 or len(email) > 128:
                self.send_error(
                    'Email should be between 3 and 128 characters long', 400)
                return

        if (password and len(password) > 0) or (password2
                                                and len(password2) > 0):
            if (password and len(password) < 8) or (password2
                                                    and len(password2) < 8):
                self.send_error(
                    'Password should be at least 8 characters long', 400)
                return

            if password != password2:
                self.send_error('Passwords don\'t match!', 400)
                return

        # Make sure the nickname is not yet reserved
        s = db_session()
        try:
            s.query(User).filter(User.nickname == nickname).filter(
                User.id != self.sock.uid).one()
            self.send_error('Nickname is already reserved', 405)
            return
        except NoResultFound:
            pass
        finally:
            s.close()

        # Get user
        try:
            user = s.query(User).filter_by(id=self.sock.uid).one()
            username = user.username

            user.nickname = nickname
            user.email = email
            if password:
                user.password = pbkdf2_sha256.encrypt(password)

            s.add(user)
            s.commit()

            self.send_message(message={'user': user.serialize()})
        except NoResultFound:
            log.warn(u"User %d not found.", self.sock.uid)
            return
        finally:
            s.close()

        # Send simple notification
        log.info(u"Updated profile for user %s.", username)
Ejemplo n.º 18
0
    def send_source(self, player):
        last_id = 0
        if player.last:
            last_id = player.last

        # Attempt to fetch the next available media for this player
        s = db_session()
        media = s.query(Media)\
            .filter(
                SourceQueue.target == self.sock.uid,
                Media.queue == SourceQueue.id,
                Media.id > last_id)\
            .filter(
                Source.id == Media.source,
                Source.status == MEDIASTATUS['finished']) \
            .order_by(Media.id.asc())\
            .first()

        # No result => bail.
        # Result => get source ref
        if not media:
            # No result, so leave remote status as-is (stopped) and set that to DB too.
            player.status = 0
            s.add(player)
            s.commit()

            # Announce playback status change for all users
            self.broadcast('player', {'state': player.serialize()},
                           query="change",
                           client_type='user',
                           avoid_self=False)

            # Send playback request. We will get status back later.
            self.send_message({'status': 0},
                              query='set_status',
                              target_uid=player.id)

            s.close()
            log.info(u"No media for player, staying as STOPPED.")
            return
        else:
            source = s.query(Source).filter_by(id=media.source).one()
        s.close()

        real_file = source.file_name

        # Send playback request. We will get status back later.
        self.send_message({'url': settings.SOURCE_URL + real_file},
                          query='source',
                          target_uid=player.id)

        # Some logging
        log.info(u"Player %s is playing %s", self.sock.uid, source.id)

        # Update last played media track to db
        s = db_session()
        player.last = media.id
        player.status = 1
        s.add(player)
        s.commit()

        # Announce playback status change for all users
        self.broadcast('player', {'state': player.serialize()},
                       query="change",
                       client_type='user',
                       avoid_self=False)

        s.close()
Ejemplo n.º 19
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        # Add new empty player
        if self.query == "add" and self.is_admin():
            event_id = packet_msg.get("event_id")

            s = db_session()
            player = Player(
                event=event_id, name=u"Player {}".format(generate_session()[:4]), token=generate_session()[:16]
            )
            s.add(player)
            s.commit()
            self.send_message(player.serialize(show_token=True))
            s.close()

            log.info(u"[%s] New player added", self.sock.sid[0:6])
            return

        if self.query == "edit" and self.is_admin():
            player_id = packet_msg.get("id")
            name = packet_msg.get("name")

            # Get user
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
                player.name = name
                s.add(player)
                s.commit()
                self.send_message(player.serialize(show_token=True))

                log.info(u"[%s] Player %d edited", player_id, self.sock.sid[0:6])
            except NoResultFound:
                log.info(u"[%s] error while editing player %d: no player found", player_id, self.sock.sid[0:6])
                return
            finally:
                s.close()

        # Fetch all players. Use this to init client state
        if self.query == "fetchall":
            s = db_session()
            players = [p.serialize(show_token=self.is_admin()) for p in s.query(Player).all()]
            s.close()
            self.send_message(players)
            return

        if self.query == "now_playing":
            player_id = packet_msg.get("player_id")

            # Make sure we have a valid player
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            self.send_message({"state": player.serialize()}, query="change")
            return

        # Request skip
        if self.query == "skip":
            player_id = packet_msg.get("player_id")

            # Make sure we have a valid player
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            # Add our own skip
            s = db_session()
            try:
                skip = Skip(user=self.sock.uid, player=player.id, media=player.last)
                s.add(skip)
                s.commit()
            except IntegrityError:
                log.debug(u"Hissatsu! Double skip!")
                return
            finally:
                s.close()

            log.info(u"User %s requested skipping media %s on player %s", self.sock.uid, player.last, player.id)

            # Broadcast skip count
            skips = s.query(Skip).filter_by(player=player.id, media=player.last).count()
            if skips >= self.get_req_skip_count():
                log.info(u"All skip votes gathered; skipping %d", player.last)
                PlayerDeviceHandler(self.sock, "playerdev", "status_change").send_source(player)
            else:
                self.broadcast(
                    "player",
                    {"count": skips},
                    query="current_skip_count",
                    req_auth=True,
                    avoid_self=False,
                    client_type="user",
                )

            # That's that.
            return

        if self.query == "get_media_skip_count":
            player_id = packet_msg.get("player_id")

            # Make sure we have a valid player
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            # Get current skip count for requested player
            skips = s.query(Skip).filter_by(player=player.id, media=player.last).count()
            self.send_message({"count": skips}, query="current_skip_count")
            return

        if self.query == "req_skip_count":
            self.send_req_skip_count()
            return

        if self.query == "pause" and self.is_admin():
            player_id = packet_msg.get("player_id")
            if player_id:
                log.info(u"ADMIN: Force status = 2 on player %d", player_id)
                self._send_message("playerdev", {"status": 2}, query="set_status", target_uid=player_id)
            return

        if self.query == "play" and self.is_admin():
            player_id = packet_msg.get("player_id")
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            if player.status > 0:
                log.info(u"ADMIN: Force status = 1 on player %d", player_id)
                self._send_message("playerdev", {"status": 1}, query="set_status", target_uid=player_id)
            else:
                PlayerDeviceHandler(self.sock, "playerdev", "status_change").send_source(player)
            return

        if self.query == "force_skip" and self.is_admin():
            player_id = packet_msg.get("player_id")
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            log.info(u"ADMIN: Force skipping on player %d", player_id)
            PlayerDeviceHandler(self.sock, "playerdev", "status_change").send_source(player)
            return

        # Maintenance mode, not stop (even if it is named so)
        if self.query == "stop" and self.is_admin():
            player_id = packet_msg.get("player_id")
            if player_id:
                log.info(u"ADMIN: Force status = 4 on player %d", player_id)
                self._send_message("playerdev", {"status": 4}, query="set_status", target_uid=player_id)
            return
Ejemplo n.º 20
0
    def handle(self, packet_msg):
        # If we are already authenticated, don't bother with this
        if self.sock.authenticated:
            return

        username = packet_msg.get('username', '')
        password = packet_msg.get('password', '')
        token = packet_msg.get('token')

        if token:
            s = db_session()
            try:
                player = s.query(Player).filter_by(token=token).one()
            except NoResultFound:
                self.send_error('Incorrect token', 401)
                log.info(u"Invalid token.")
                return
            finally:
                s.close()

            self.sock.authenticated = True
            self.sock.client_type = 'token'
            self.sock.uid = player.id
            self.sock.level = 0

            # Send login success message
            self.send_message({
                'name': player.name
            })

            log.info(u"[%s] Token logged in", token[0:6])
        else:
            s = db_session()
            try:
                user = s.query(User).filter_by(username=username).one()
            except NoResultFound:
                self.send_error('Incorrect username or password', 401)
                log.info(u"Invalid username or password.")
                return
            finally:
                s.close()

            # If user exists and password matches, pass onwards!
            if user and pbkdf2_sha256.verify(password, user.password):
                session_id = generate_session()

                # Add new session
                s = db_session()
                ses = Session(key=session_id, user=user.id)
                s.add(ses)
                s.commit()
                s.close()

                # Mark connection as authenticated, and save session id
                self.sock.sid = session_id
                self.sock.uid = user.id
                self.sock.authenticated = True
                self.sock.level = user.level
                self.sock.client_type = 'user'

                # Send login success message
                self.send_message({
                    'uid': self.sock.uid,
                    'sid': self.sock.sid,
                    'user': user.serialize()
                })

                # Send required skip count
                self.send_req_skip_count()

                # Dump out log
                log.info(u"[%s] Logged in", self.sock.sid[0:6])
            else:
                self.send_error('Incorrect username or password', 401)
                log.info(u"Invalid username or password.")
Ejemplo n.º 21
0
 def handle_fetchall_sig(self):
     s = db_session()
     queues = [queue.serialize() for queue in s.query(SourceQueue).filter_by(user=self.sock.uid).all()]
     s.close()
     self.send_message(queues, query="fetchall")
Ejemplo n.º 22
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        if self.query == 'fetch_ratings':
            s = db_session()
            # We probably _could_ combine these queries.
            # Count skips received by media posted by users
            skips_recv = s.query(User, Media, Skip, func.count()).\
                filter(Media.user == User.id).\
                filter(Media.id == Skip.media).\
                group_by(User.id)
            # Count skip requests issued by users
            skips_sent = s.query(User, Skip, func.count()).\
                filter(User.id == Skip.user).\
                group_by(User.id)
            # Count total posts by each user
            posts = s.query(User, Media, func.count()).\
                filter(Media.user == User.id).\
                group_by(User.id)
            s.close()
            names_by_id = {}        # relevant users
            skips_recv_by_id = {}   # # of skips received by userid's media
            skips_sent_by_id = {}   # skips sent per user id
            posts_by_id = {}        # posts per user id
            collated = []
            for s in skips_recv.all():
                user = s[0]
                userid = s[0].id
                if userid not in names_by_id:
                    names_by_id[userid] = user.username
                skips_recv_by_id[userid] = s[3]  # get value of func.count()
            for s in skips_sent.all():
                user = s[0]
                userid = user.id
                if userid not in names_by_id:
                    names_by_id[userid] = user.username
                skips_sent_by_id[userid] = s[2]
            for p in posts.all():
                user = p[0]
                userid = user.id
                if userid not in names_by_id:
                    names_by_id[userid] = user.username
                posts_by_id[userid] = p[2]
            for userid in names_by_id:
                name = names_by_id[userid]
                skips_recv = skips_recv_by_id.get(userid, 0)
                skips_sent = skips_sent_by_id.get(userid, 0)
                posts = posts_by_id.get(userid, 0)
                collated.append((
                    name, skips_recv, skips_sent,
                    posts, float(skips_recv) / posts if posts > 0 else 0))
            out = []
            k = 1
            for c in collated:
                out.append({
                    'number': k,
                    'name': c[0],
                    'skips_sent': c[1],
                    'skips_recv': c[2],
                    'posts': c[3],
                    'rating': c[4],
                })
                k += 1
            self.send_message(out)
Ejemplo n.º 23
0
    exit(0)

if 'create_test_admin' in sys.argv:
    create_admin('admin', 'admin')
    exit(0)

if 'create_event' in sys.argv:
    settings.config_init()
    db_init(settings.DATABASE_CONFIG)

    if len(sys.argv) == 3:
        name = sys.argv[2]
    else:
        name = raw_input("Event name: ")

    s = db_session()
    event = Event(name=name, visible=True)
    s.add(event)
    s.commit()
    s.close()
    exit(0)

if 'list_events' in sys.argv:
    settings.config_init()
    db_init(settings.DATABASE_CONFIG)
    s = db_session()
    print("ID  Name")
    for event in s.query(Event).all():
        print("{:3} {}".format(event.id, event.name))
    s.close()
    exit(0)
Ejemplo n.º 24
0
    def handle(self):
        """ Handle incoming messages from the websocket interface """
        try:
            for method_frame, properties, body in self.channel.consume(self.QUEUE_DOWNLOAD):
                data = json.loads(body)

                # Get DB entry for this source
                s = db_session()
                try:
                    source = s.query(Source).filter_by(id=data['source_id']).one()
                except NoResultFound:
                    s.close()
                    log.warn(u"Could not find source!")
                    self.channel.basic_ack(method_frame.delivery_tag)
                    continue

                # Update status
                s.add(source)
                source.status = MEDIASTATUS['fetching_metadata']
                s.commit()
                self.send_msg('status', {
                    'status': MEDIASTATUS['fetching_metadata'],
                    'source_id': source.id
                })

                # Check how we need to handle this
                if source.youtube_hash:
                    if data['no_limit']:
                        req_format = 'bestvideo[height <=? 720][fps <=? 30]+bestaudio[abr<=128]/best'
                    else:
                        req_format = 'bestvideo[height <=? 720][fps <=? 30][filesize<{}]+bestaudio[filesize<{}]/best'\
                            .format(settings.LIMIT_VIDEO_SIZE, settings.LIMIT_AUDIO_SIZE)

                    ydl_opts = {
                        'logger': log,
                        'cachedir': settings.TMP_DIR,
                        'format': req_format,
                        'outtmpl': '%(id)s.%(ext)s'
                    }

                    # Download information
                    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                        info = ydl.extract_info('http://www.youtube.com/watch?v=' + source.youtube_hash, download=False)
                        file_name = ydl.prepare_filename(info)

                    # Form a correct path to the file
                    file_path = os.path.join(settings.CACHE_DIR, file_name)
                    ydl_opts['outtmpl'] = file_path

                    # If we are in debug mode, also dump the file information as json
                    # if settings.DEBUG:
                    #     with open(os.path.join(settings.TMP_DIR, file_name)+'.json', 'wb') as f:
                    #         f.write(json.dumps(info))

                    # Update status
                    source.status = MEDIASTATUS['downloading']
                    source.length_seconds = info['duration']
                    source.file_ext = os.path.splitext(file_name)[1][1:]
                    source.file_name = file_name
                    source.mime_type = mimetypes.guess_type('file://'+file_path)[0]

                    # Save video and audio information
                    if 'requested_formats' in info:
                        v, a = info['requested_formats']
                        source.video_bitrate = int(v['tbr'])
                        source.video_codec = v['vcodec']
                        source.video_w = v['width']
                        source.video_h = v['height']
                        source.audio_bitrate = int(a.get('abr', 0))
                        source.audio_codec = a['acodec']
                    else:
                        source.video_codec = info['vcodec']
                        source.video_w = info['width']
                        source.video_h = info['height']
                        source.audio_codec = info['acodec']

                    # Dump to DB
                    s.add(source)
                    s.commit()
                    self.send_msg('single', source.serialize())

                    # Start downloading
                    log.info(u"Downloading %s to %s", source.youtube_hash, file_path)
                    try:
                        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                            ydl.download(['http://www.youtube.com/watch?v=' + source.youtube_hash])
                    except Exception, e:
                        source.status = MEDIASTATUS['error']
                        source.message = "DL Error"
                        s.add(source)
                        s.commit()
                        self.channel.basic_ack(method_frame.delivery_tag)
                        s.close()
                        log.info(u"Error while attempting to download: %s", str(e))
                        continue
                else:
                    log.warn(u"Cannot yet download other urls!")

                # Save everything and dequeue this entry
                log.info(u"Download finished.")
                source.status = MEDIASTATUS['finished']
                source.message = 'Video downloaded successfully.'
                s.add(source)
                s.commit()
                self.send_msg('status', {
                    'status': MEDIASTATUS['finished'],
                    'source_id': source.id,
                    'message': source.message
                })

                # Finish up
                s.close()
                self.channel.basic_ack(method_frame.delivery_tag)
                log.info(u"Tag %s marked done.", method_frame.delivery_tag)

        except KeyboardInterrupt:
            return
Ejemplo n.º 25
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        # Fetch all queues. Use this to init client state
        if self.query == 'fetchall':
            self.handle_fetchall_sig()

        # Fetch a single queue (for refreshing)
        if self.query == 'fetchone':
            s = db_session()
            try:
                queue = s.query(SourceQueue).filter_by(user=self.sock.uid).one().serialize()
                self.send_message(queue)
            except NoResultFound:
                self.send_error('No queue found', 404)
            finally:
                s.close()

        # Add new item to the queue. Log to DB, send signal
        if self.query == 'add':
            url = packet_msg.get('url')
            player_id = packet_msg.get('player_id')
            if not url or not player_id:
                self.send_error('Invalid input data', 500)
                return

            queue_id = self.ensure_sourcequeue(player_id)

            # Attempt to parse the url
            youtube_hash = self.get_youtube_code(url)
            other_url = None
            # if not youtube_hash:
            #     other_url = self.validate_other_url(url)

            # Error out if necessary
            if not youtube_hash and not other_url:
                self.send_error('Invalid URL', 500)
                return

            # First, attempt to find the source from database. If it exists, simply use that.
            s = db_session()
            found_src = None
            try:
                if youtube_hash:
                    found_src = s.query(Source).filter_by(youtube_hash=youtube_hash).one()
                elif other_url:
                    found_src = s.query(Source).filter_by(other_url=other_url).one()
            except NoResultFound:
                pass
            finally:
                s.close()

            # If the existing source entry belongs to current user, show error.
            # Don't let user post the same video again and again (rudimentary protection)
            if found_src:
                s = db_session()
                try:
                    player = s.query(Player).filter_by(id=player_id).one()
                except NoResultFound:
                    self.send_error('Invalid input data', 500)
                    return
                finally:
                    s.close()

                s = db_session()
                try:
                    res = s.query(Media)\
                        .filter(Media.user == self.sock.uid, Media.source == found_src.id, Media.queue == queue_id)\
                        .all()
                    for r in res:
                        if r.id > player.last:
                            self.send_error('Url is already in the queue', 500)
                            return
                except NoResultFound:
                    pass
                finally:
                    s.close()

            # First title and description for new video
            first_title = "Unknown"
            first_desc = ""
            first_duration = 0

            # If this is a youtube url, attempt to fetch information for it
            if youtube_hash:
                with youtube_dl.YoutubeDL({'logger': log}) as ydl:
                    try:
                        info = ydl.extract_info('http://www.youtube.com/watch?v=' + youtube_hash, download=False)
                    except youtube_dl.DownloadError, e:
                        self.send_error(str(e), 500)
                        return

                # Check video duration
                if info['duration'] > settings.LIMIT_DURATION and not self.is_admin():
                    current_str = format_time_delta(info['duration'])
                    limit_str = format_time_delta(settings.LIMIT_DURATION)
                    self.send_error('Video is too long ({}). Current limit is {}.'
                                    .format(current_str, limit_str), 500)
                    return

                # Use video desc and title
                first_duration = info['duration']
                first_title = info['title']
                first_desc = info['description']

            if found_src:
                # Add a new media entry
                s = db_session()
                media = Media(
                    source=found_src.id,
                    user=self.sock.uid,
                    queue=queue_id
                )
                s.add(media)
                s.commit()
                s.close()

                # Inform playerdevices about this (in case they are waiting for news about new media)
                self.broadcast('playerdev', {}, query='poke', client_type="token")
            else:
                # Okay, Let's save the first draft and then poke at the downloader with MQ message
                s = db_session()
                source = Source(
                    youtube_hash=youtube_hash if youtube_hash else '',
                    other_url=other_url if other_url else '',
                    title=first_title,
                    description=first_desc,
                    length_seconds=first_duration,
                )
                s.add(source)
                s.commit()
                media = Media(
                    source=source.id,
                    user=self.sock.uid,
                    queue=queue_id
                )
                s.add(media)
                s.commit()

                # Send message to kick the downloader
                self.sock.mq.send_msg(self.sock.mq.KEY_DOWNLOAD, {
                    'source_id': source.id,
                    'no_limit': self.is_admin()
                })

                s.close()

            # Resend all queue data (for now)
            self.handle_fetchall_sig()
            self.send_message({})
            log.info("[%s] New media added to queue", self.sock.sid[0:6])
Ejemplo n.º 26
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        # Add new empty player
        if self.query == 'add' and self.is_admin():
            event_id = packet_msg.get('event_id')

            s = db_session()
            player = Player(
                event=event_id,
                name=u'Player {}'.format(generate_session()[:4]),
                token=generate_session()[:16])
            s.add(player)
            s.commit()
            self.send_message(player.serialize(show_token=True))
            s.close()

            log.info(u"[%s] New player added", self.sock.sid[0:6])
            return

        if self.query == 'edit' and self.is_admin():
            player_id = packet_msg.get('id')
            name = packet_msg.get('name')

            # Get user
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
                player.name = name
                s.add(player)
                s.commit()
                self.send_message(player.serialize(show_token=True))

                log.info(u"[%s] Player %d edited", player_id, self.sock.sid[0:6])
            except NoResultFound:
                log.info(u"[%s] error while editing player %d: no player found", player_id, self.sock.sid[0:6])
                return
            finally:
                s.close()

        # Fetch all players. Use this to init client state
        if self.query == 'fetchall':
            s = db_session()
            players = [p.serialize(show_token=self.is_admin()) for p in s.query(Player).all()]
            s.close()
            self.send_message(players)
            return

        if self.query == 'now_playing':
            player_id = packet_msg.get('player_id')

            # Make sure we have a valid player
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            self.send_message({'state': player.serialize()}, query='change')
            return

        # Request skip
        if self.query == 'skip':
            player_id = packet_msg.get('player_id')

            # Make sure we have a valid player
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            # Add our own skip
            s = db_session()
            try:
                skip = Skip(user=self.sock.uid, player=player.id, media=player.last)
                s.add(skip)
                s.commit()
            except IntegrityError:
                log.debug(u"Hissatsu! Double skip!")
                return
            finally:
                s.close()

            log.info(u"User %s requested skipping media %s on player %s", self.sock.uid, player.last, player.id)

            # Broadcast skip count
            skips = s.query(Skip).filter_by(player=player.id, media=player.last).count()
            if skips >= self.get_req_skip_count():
                log.info(u"All skip votes gathered; skipping %d", player.last)
                PlayerDeviceHandler(self.sock, 'playerdev', 'status_change').send_source(player)
            else:
                self.broadcast('player', {
                    'count': skips,
                }, query='current_skip_count', req_auth=True, avoid_self=False, client_type='user')

            # That's that.
            return

        if self.query == 'get_media_skip_count':
            player_id = packet_msg.get('player_id')

            # Make sure we have a valid player
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            # Get current skip count for requested player
            skips = s.query(Skip).filter_by(player=player.id, media=player.last).count()
            self.send_message({'count': skips}, query='current_skip_count')
            return

        if self.query == 'req_skip_count':
            self.send_req_skip_count()
            return

        if self.query == 'pause' and self.is_admin():
            player_id = packet_msg.get('player_id')
            if player_id:
                log.info(u"ADMIN: Force status = 2 on player %d", player_id)
                self._send_message('playerdev', {'status': 2}, query='set_status', target_uid=player_id)
            return

        if self.query == 'play' and self.is_admin():
            player_id = packet_msg.get('player_id')
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            if player.status > 0:
                log.info(u"ADMIN: Force status = 1 on player %d", player_id)
                self._send_message('playerdev', {'status': 1}, query='set_status', target_uid=player_id)
            else:
                PlayerDeviceHandler(self.sock, 'playerdev', 'status_change').send_source(player)
            return

        if self.query == 'force_skip' and self.is_admin():
            player_id = packet_msg.get('player_id')
            s = db_session()
            try:
                player = s.query(Player).filter_by(id=player_id).one()
            except NoResultFound:
                return
            finally:
                s.close()

            log.info(u"ADMIN: Force skipping on player %d", player_id)
            PlayerDeviceHandler(self.sock, 'playerdev', 'status_change').send_source(player)
            return

        # Maintenance mode, not stop (even if it is named so)
        if self.query == 'stop' and self.is_admin():
            player_id = packet_msg.get('player_id')
            if player_id:
                log.info(u"ADMIN: Force status = 4 on player %d", player_id)
                self._send_message('playerdev', {'status': 4}, query='set_status', target_uid=player_id)
            return
Ejemplo n.º 27
0
    def handle(self, packet_msg):
        if not self.is_user_auth():
            return

        password = packet_msg.get('password')
        password2 = packet_msg.get('password2')
        email = packet_msg.get('email', '')
        nickname = packet_msg.get('nickname')

        if len(nickname) < 5 or len(nickname) > 32:
            self.send_error('Nickname should be between 5 and 32 characters long', 400)
            return

        if email and len(email) > 0:
            if len(email) < 3 or len(email) > 128:
                self.send_error('Email should be between 3 and 128 characters long', 400)
                return

        if (password and len(password) > 0) or (password2 and len(password2) > 0):
            if (password and len(password) < 8) or (password2 and len(password2) < 8):
                self.send_error('Password should be at least 8 characters long', 400)
                return

            if password != password2:
                self.send_error('Passwords don\'t match!', 400)
                return

        # Make sure the nickname is not yet reserved
        s = db_session()
        try:
            s.query(User).filter(User.nickname == nickname).filter(User.id != self.sock.uid).one()
            self.send_error('Nickname is already reserved', 405)
            return
        except NoResultFound:
            pass
        finally:
            s.close()

        # Get user
        try:
            user = s.query(User).filter_by(id=self.sock.uid).one()
            username = user.username

            user.nickname = nickname
            user.email = email
            if password:
                user.password = pbkdf2_sha256.encrypt(password)

            s.add(user)
            s.commit()

            self.send_message(message={
                'user': user.serialize()
            })
        except NoResultFound:
            log.warn(u"User %d not found.", self.sock.uid)
            return
        finally:
            s.close()

        # Send simple notification
        log.info(u"Updated profile for user %s.", username)
Ejemplo n.º 28
0
    def handle(self):
        """ Handle incoming messages from the websocket interface """
        try:
            for method_frame, properties, body in self.channel.consume(
                    self.QUEUE_DOWNLOAD):
                data = json.loads(body)

                # Get DB entry for this source
                s = db_session()
                try:
                    source = s.query(Source).filter_by(
                        id=data['source_id']).one()
                except NoResultFound:
                    s.close()
                    log.warn(u"Could not find source!")
                    self.channel.basic_ack(method_frame.delivery_tag)
                    continue

                # Update status
                s.add(source)
                source.status = MEDIASTATUS['fetching_metadata']
                s.commit()
                self.send_msg(
                    'status', {
                        'status': MEDIASTATUS['fetching_metadata'],
                        'source_id': source.id
                    })

                # Check how we need to handle this
                if source.youtube_hash:
                    if data['no_limit']:
                        req_format = 'bestvideo[height <=? 720][fps <=? 30]+bestaudio[abr<=128]/best'
                    else:
                        req_format = 'bestvideo[height <=? 720][fps <=? 30][filesize<{}]+bestaudio[filesize<{}]/best'\
                            .format(settings.LIMIT_VIDEO_SIZE, settings.LIMIT_AUDIO_SIZE)

                    ydl_opts = {
                        'logger': log,
                        'cachedir': settings.TMP_DIR,
                        'format': req_format,
                        'outtmpl': '%(id)s.%(ext)s'
                    }

                    # Download information
                    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                        info = ydl.extract_info(
                            'http://www.youtube.com/watch?v=' +
                            source.youtube_hash,
                            download=False)
                        file_name = ydl.prepare_filename(info)

                    # Form a correct path to the file
                    file_path = os.path.join(settings.CACHE_DIR, file_name)
                    ydl_opts['outtmpl'] = file_path

                    # If we are in debug mode, also dump the file information as json
                    # if settings.DEBUG:
                    #     with open(os.path.join(settings.TMP_DIR, file_name)+'.json', 'wb') as f:
                    #         f.write(json.dumps(info))

                    # Update status
                    source.status = MEDIASTATUS['downloading']
                    source.length_seconds = info['duration']
                    source.file_ext = os.path.splitext(file_name)[1][1:]
                    source.file_name = file_name
                    source.mime_type = mimetypes.guess_type('file://' +
                                                            file_path)[0]

                    # Save video and audio information
                    if 'requested_formats' in info:
                        v, a = info['requested_formats']
                        source.video_bitrate = int(v['tbr'])
                        source.video_codec = v['vcodec']
                        source.video_w = v['width']
                        source.video_h = v['height']
                        source.audio_bitrate = int(a['abr'])
                        source.audio_codec = a['acodec']
                    else:
                        source.video_codec = info['vcodec']
                        source.video_w = info['width']
                        source.video_h = info['height']
                        source.audio_codec = info['acodec']

                    # Dump to DB
                    s.add(source)
                    s.commit()
                    self.send_msg('single', source.serialize())

                    # Start downloading
                    log.info(u"Downloading %s to %s", source.youtube_hash,
                             file_path)
                    try:
                        with youtube_dl.YoutubeDL(ydl_opts) as ydl:
                            ydl.download([
                                'http://www.youtube.com/watch?v=' +
                                source.youtube_hash
                            ])
                    except Exception, e:
                        source.status = MEDIASTATUS['error']
                        source.message = "DL Error"
                        s.add(source)
                        s.commit()
                        self.channel.basic_ack(method_frame.delivery_tag)
                        s.close()
                        log.info(u"Error while attempting to download: %s",
                                 str(e))
                        continue
                else:
                    log.warn(u"Cannot yet download other urls!")

                # Save everything and dequeue this entry
                log.info(u"Download finished.")

                # Attempt to figure out youtube-dl mess
                m_test = os.path.splitext(file_path)
                new_file = u'{}{}'.format(m_test[0], '.mkv')
                if os.path.isfile(new_file):
                    source.file_ext = 'mkv'
                    source.file_name = os.path.basename(new_file)
                    source.mime_type = mimetypes.guess_type('file://' +
                                                            new_file)[0]

                source.status = MEDIASTATUS['finished']
                source.message = 'Video downloaded successfully.'
                s.add(source)
                s.commit()
                self.send_msg(
                    'status', {
                        'status': MEDIASTATUS['finished'],
                        'source_id': source.id,
                        'message': source.message
                    })

                # Finish up
                s.close()
                self.channel.basic_ack(method_frame.delivery_tag)
                log.info(u"Tag %s marked done.", method_frame.delivery_tag)

        except KeyboardInterrupt:
            return