Beispiel #1
0
    def postprocess_albums(self):
        log.debug(u"Postprocessing albums ...")
        s = session_get()
        found = 0
        for album in s.query(Album).filter_by(deleted=False):
            # Stop if quite is requested
            if not self._run:
                s.rollback()
                return
            # Just jump over PK 1, this is the unknown album
            if album.id == 1:
                continue
            # skip albums that already have an artist
            if album.artist != 1:
                continue

            # See if all tracks in album have matching artist
            test = None
            found_artist = True
            for track in s.query(Track).filter_by(album=album.id):
                if test is None:
                    test = track.artist
                else:
                    if test != track.artist:
                        found_artist = False

            if found_artist:
                # If we got here, all tracks in the album had the same artist.
                # Therefore, set album artist as this.
                found += 1
                album.artist = test

        s.commit()
        s.close()
        log.debug(u"Found artist for %d new albums", found)
Beispiel #2
0
    def on_auth_msg(self, packet_msg):
        sid = packet_msg.get('sid', '')

        s = session_get()
        user = None
        session = None
        try:
            session = s.query(Session).filter_by(key=sid).one()
            user = s.query(User).filter_by(id=session.user).one()
        except NoResultFound:
            pass
        s.close()

        # Session found with token.
        if session and user:
            self.sid = sid
            self.authenticated = True

            log.info(u"Authenticated with '%s'.", self.sid)

            # Send login success message
            self.send_message('auth', {
                'uid': user.id,
                'sid': sid,
                'level': user.level
            })
            return
        self.send_error('auth', "Invalid session", 403)
        log.warning(u"Authentication failed.")
Beispiel #3
0
    def on_auth_msg(self, packet_msg):
        sid = packet_msg.get('sid', '')

        s = session_get()
        user = None
        session = None
        try:
            session = s.query(Session).filter_by(key=sid).one()
            user = s.query(User).filter_by(id=session.user).one()
        except NoResultFound:
            pass
        s.close()

        # Session found with token.
        if session and user:
            self.sid = sid
            self.authenticated = True

            log.info(u"Authenticated with '%s'.", self.sid)

            # Send login success message
            self.send_message('auth', {
                'uid': user.id,
                'sid': sid,
                'level': user.level
            })
            return
        self.send_error('auth', "Invalid session", 403)
        log.warning(u"Authentication failed.")
Beispiel #4
0
    def handle_delete(self, path):
        track = None
        cover = None
        
        # If it does NOT, make sure it is removed from index
        # First, see if track exists with this path. If not, see if it is a cover.
        # If neither, stop here.
        s = session_get()
        try:
            track = s.query(Track).filter_by(file=path, deleted=False).one()
        except NoResultFound:
            try:
                cover = s.query(Cover).filter_by(file=path, deleted=False).one()
            except NoResultFound:
                return
        s.close()

        # If we found a cover, remove it and clear references to it from albums
        if cover:
            self.handle_cover_delete(cover)
            return

        # If we found a track, remove it from any albums. If the albums are now empty, remove them.
        # If artist does not belong to any track, remove it also
        if track:
            self.handle_track_delete(track)
            return
Beispiel #5
0
 def handle_cover_delete(self, cover):
     s = session_get()
     for album in s.query(Album).filter_by(cover=cover.id, deleted=False):
         album.cover = 1
     s.query(Cover).filter_by(id=cover.id, deleted=False).update({'deleted': True, 'updated': utc_now()})
     s.commit()
     s.close()
Beispiel #6
0
    def get(self, session_id, size_flag, cover_id):
        s = session_get()

        # Make sure session is valid
        try:
            s.query(Session).filter_by(key=session_id).one()
        except NoResultFound:
            s.close()
            self.set_status(401)
            self.finish("401")
            log.warning(u"Cover ID %d requested without a valid session.",
                        cover_id)
            return

        # Find the cover we want
        try:
            cover = s.query(Cover).filter_by(id=cover_id).one()
        except NoResultFound:
            s.close()
            self.set_status(404)
            self.finish("404")
            log.warning(u"Cover ID %s does not exist.", cover_id)
            return

        s.close()

        if size_flag == "0":
            cover_file = os.path.join(settings.COVER_CACHE_DIRECTORY,
                                      "{}_small.jpg".format(cover.id))
        elif size_flag == "1":
            cover_file = os.path.join(settings.COVER_CACHE_DIRECTORY,
                                      "{}_medium.jpg".format(cover.id))
        else:
            # Make sure we have a filename
            if not cover.file:
                self.set_status(404)
                self.finish("404")
                log.warning(u"Cover file for ID %d is not set.", cover_id)
                return

            cover_file = cover.file

        # Just pick content type and dump out the file.
        self.set_header("Content-Type",
                        mimetypes.guess_type("file://" + cover_file)[0])
        try:
            with file(cover_file, 'rb') as f:
                ret = yield gen.Task(self.get_data, f)
                self.write(ret)
        except IOError:
            self.set_status(404)
            self.finish("404")
            log.warning(u"Matching file for cover ID %d does not exist.",
                        cover_id)
            return

        self.finish()
Beispiel #7
0
    def postprocess_covers(self):
        log.debug(u"Postprocessing covers ...")
        found = 0
        s = session_get()
        for album in s.query(Album).filter_by(deleted=False):
            # Stop if quit is requested
            if not self._run:
                s.rollback()
                return
            # If album already has a cover, keep going
            if album.cover != 1:
                continue
            # Jump over PK 1, this is the unknown album
            if album.id == 1:
                continue

            # Try to find cover art for this album
            for track in s.query(Track).filter_by(album=album.id):
                mdir = s.query(Directory).get(track.dir)
                cover_art = self._cover_art.get(mdir.directory, None)
                if cover_art:
                    cover = get_or_create(s, Cover, file=cover_art[0], deleted=False)
                    found += 1

                    # Make thumbnails
                    try:
                        img = Image.open(cover_art[0])
                        size = 200, 200
                        out_file = os.path.join(settings.COVER_CACHE_DIRECTORY, '{}_small.jpg'.format(cover.id))
                        img.thumbnail(size, Image.ANTIALIAS)
                        img.save(out_file, "JPEG")
                    except IOError:
                        log.error(u"Unable to create a small thumbnail for cover ID %d", cover.id)

                    try:
                        img = Image.open(cover_art[0])
                        size = 800, 800
                        out_file = os.path.join(settings.COVER_CACHE_DIRECTORY, '{}_medium.jpg'.format(cover.id))
                        img.thumbnail(size, Image.ANTIALIAS)
                        img.save(out_file, "JPEG")
                    except IOError:
                        log.error(u"Unable to create a medium thumbnail for cover ID %d", cover.id)

                    # Set new cover id for album, and update tracks and the album timestamp for sync
                    s.query(Track).filter_by(album=album.id).update({'updated': utc_now()})
                    s.query(Album).filter_by(id=album.id).update({'updated': utc_now(), 'cover': cover.id})

                    # Cover lookup done for this album, continue with next
                    break

        # That's that, commit changes for this album
        s.commit()
        s.close()
        self._cover_art = {}  # Clear cover art cache
        log.debug(u"Found and attached %d new covers.", found)
Beispiel #8
0
 def sync_table(self, name, table, remote_ts, push=False):
     # Send message containing all new data in the table
     s = session_get()
     self.send_message('sync', {
         'query': 'request',
         'table': name,
         'ts': to_isodate(utc_now()),
         'push': push,
         'data': [t.serialize() for t in s.query(table).filter(table.updated > remote_ts)]
     })
     s.close()
Beispiel #9
0
    def get(self, session_id, size_flag, cover_id):
        s = session_get()

        # Make sure session is valid
        try:
            s.query(Session).filter_by(key=session_id).one()
        except NoResultFound:
            s.close()
            self.set_status(401)
            self.finish("401")
            log.warning(u"Cover ID %d requested without a valid session.", cover_id)
            return

        # Find the cover we want
        try:
            cover = s.query(Cover).filter_by(id=cover_id).one()
        except NoResultFound:
            s.close()
            self.set_status(404)
            self.finish("404")
            log.warning(u"Cover ID %s does not exist.", cover_id)
            return

        s.close()

        if size_flag == "0":
            cover_file = os.path.join(settings.COVER_CACHE_DIRECTORY, "{}_small.jpg".format(cover.id))
        elif size_flag == "1":
            cover_file = os.path.join(settings.COVER_CACHE_DIRECTORY, "{}_medium.jpg".format(cover.id))
        else:
            # Make sure we have a filename
            if not cover.file:
                self.set_status(404)
                self.finish("404")
                log.warning(u"Cover file for ID %d is not set.", cover_id)
                return

            cover_file = cover.file

        # Just pick content type and dump out the file.
        self.set_header("Content-Type", mimetypes.guess_type("file://"+cover_file)[0])
        try:
            with file(cover_file, 'rb') as f:
                ret = yield gen.Task(self.get_data, f)
                self.write(ret)
        except IOError:
            self.set_status(404)
            self.finish("404")
            log.warning(u"Matching file for cover ID %d does not exist.", cover_id)
            return

        self.finish()
Beispiel #10
0
    def on_logout_msg(self, packet_msg):
        # Remove session
        s = session_get()
        s.query(Session).filter_by(key=self.sid).delete()
        s.commit()
        s.close()

        # Dump out log
        log.info(u"Logged out '%s'.", self.sid)

        # Deauthenticate & clear session ID
        self.authenticated = False
        self.sid = None
Beispiel #11
0
    def on_logout_msg(self, packet_msg):
        # Remove session
        s = session_get()
        s.query(Session).filter_by(key=self.sid).delete()
        s.commit()
        s.close()

        # Dump out log
        log.info(u"Logged out '%s'.", self.sid)

        # Deauthenticate & clear session ID
        self.authenticated = False
        self.sid = None
Beispiel #12
0
    def preprocess_deleted(self):
        s = session_get()

        log.debug(u"Removing deleted tracks from database ...")
        for track in s.query(Track).filter_by(deleted=False):
            if not os.path.isfile(track.file):
                self.handle_track_delete(track)
        log.debug(u"Removing deleted covers from database ...")
        for cover in s.query(Cover).filter_by(deleted=False):
            if cover.id == 1:
                continue
            if not os.path.isfile(cover.file):
                self.handle_cover_delete(cover)
        s.close()
Beispiel #13
0
 def sync_table(self, name, table, remote_ts, push=False):
     # Send message containing all new data in the table
     s = session_get()
     self.send_message(
         'sync', {
             'query':
             'request',
             'table':
             name,
             'ts':
             to_isodate(utc_now()),
             'push':
             push,
             'data': [
                 t.serialize()
                 for t in s.query(table).filter(table.updated > remote_ts)
             ]
         })
     s.close()
Beispiel #14
0
    def handle_track_delete(self, track):
        s = session_get()
        
        if track.album != 1:
            # If album only has a single (this) track, remove album
            if s.query(Track).filter_by(album=track.album, deleted=False).count() == 0:
                s.query(Album).filter_by(id=track.album, deleted=False).update({'deleted': True, 'updated': utc_now()})
                
        if track.artist != 1:
            # If artist only has a single (this) track, remove artist
            if s.query(Track).filter_by(artist=track.artist, deleted=False).count() == 0:
                s.query(Artist).filter_by(id=track.artist, deleted=False).update({'deleted': True, 'updated': utc_now()})

        # That's that, delete the track.
        s.query(Track).filter_by(id=track.id, deleted=False).update({'deleted': True, 'updated': utc_now()})

        # Save changes
        s.commit()
        s.close()
Beispiel #15
0
    def on_login_msg(self, packet_msg):
        username = packet_msg.get('username', '')
        password = packet_msg.get('password', '')

        s = session_get()
        try:
            user = s.query(User).filter_by(username=username).one()
        except NoResultFound:
            self.send_error('login', 'Incorrect username or password', 401)
            log.warning(u"Invalid username or password in login request.")
            s.close()
            return

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

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

            # Mark connection as authenticated, and save session id
            self.sid = session_id
            self.authenticated = True

            # Dump out log
            log.info(u"Logged in '%s'.", self.sid)

            # TODO: Cleanup old sessions

            # Send login success message
            self.send_message('login', {
                'uid': user.id,
                'sid': session_id,
                'level': user.level
            })
        else:
            self.send_error('login', 'Incorrect username or password', 401)
            log.warning(u"Invalid username or password in login request.")

        s.close()
Beispiel #16
0
    def on_login_msg(self, packet_msg):
        username = packet_msg.get('username', '')
        password = packet_msg.get('password', '')

        s = session_get()
        try:
            user = s.query(User).filter_by(username=username).one()
        except NoResultFound:
            self.send_error('login', 'Incorrect username or password', 401)
            log.warning(u"Invalid username or password in login request.")
            s.close()
            return

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

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

            # Mark connection as authenticated, and save session id
            self.sid = session_id
            self.authenticated = True

            # Dump out log
            log.info(u"Logged in '%s'.", self.sid)

            # TODO: Cleanup old sessions

            # Send login success message
            self.send_message('login', {
                'uid': user.id,
                'sid': session_id,
                'level': user.level
            })
        else:
            self.send_error('login', 'Incorrect username or password', 401)
            log.warning(u"Invalid username or password in login request.")

        s.close()
Beispiel #17
0
    def get(self, session_id, song_id):
        s = session_get()

        # Make sure session is valid
        try:
            s.query(Session).filter_by(key=session_id).one()
        except NoResultFound:
            s.close()
            self.set_status(401)
            self.finish("401")
            log.warning(u"Track ID %d requested without a valid session.", song_id)
            return

        # Find the song we want
        try:
            song = s.query(Track).filter_by(id=song_id).one()
        except NoResultFound:
            s.close()
            self.set_status(404)
            self.finish("404")
            log.warning(u"Nonexistent track ID %d requested.", song_id)
            return

        s.close()

        # See if we got range
        range_bytes = self.request.headers.get('Range')
        range_start = 0
        range_end = None
        if range_bytes:
            range_start, range_end = range_bytes[6:].split("-")
            range_end = None if range_end is "" else int(range_end)
            range_start = int(range_start)

        # Set streaming headers
        self.set_status(206)
        self.set_header("Accept-Ranges", "bytes")

        # Find content length and type
        if song.type in settings.NO_TRANSCODE_FORMATS:
            size = song.bytes_len
            song_file = song.file
            self.set_header("Content-Type", mimetypes.guess_type("file://"+song.file)[0])
        else:
            song_file = os.path.join(
                settings.MUSIC_CACHE_DIRECTORY,
                "{}.{}".format(song.id, settings.TRANSCODE_FORMAT))
            size = song.bytes_tc_len
            self.set_header("Content-Type", "audio/mpeg")

        # Set end range
        if not range_end or range_end >= size:
            range_end = size-1

        # Make sure range_start and range_end are withing size limits
        if range_start >= size:
            self.set_status(416)
            self.finish()
            return

        # Stream out
        try:
            with open(song_file, 'rb') as f:
                # Set range headers
                left = (range_end+1) - range_start
                self.set_header("Content-Length", left)
                self.set_header("Content-Range", "bytes {}-{}/{}".format(range_start, range_end, size))
                self.flush()

                # Forward to starting position and start reading data
                f.seek(range_start)
                while left:
                    r = 16384 if 16384 < left else left
                    data = yield gen.Task(self.get_data, (f, r))
                    self.write(data)
                    left -= r
        except IOError:
            self.set_status(404)
            self.finish("404")
            log.error(u"Requested track ID %d doesn't exist.", song.id)
            return

        # Flush the last bytes before finishing up.
        self.flush()
        try:
            self.finish()
        except HTTPOutputError, o:
            log.error(u"Error while serving track ID %d: %s.", song_id, str(o))
Beispiel #18
0
    def get(self, session_id, song_id):
        s = session_get()

        # Make sure session is valid
        try:
            s.query(Session).filter_by(key=session_id).one()
        except NoResultFound:
            s.close()
            self.set_status(401)
            self.finish("401")
            log.warning(u"Track ID %d requested without a valid session.",
                        song_id)
            return

        # Find the song we want
        try:
            song = s.query(Track).filter_by(id=song_id).one()
        except NoResultFound:
            s.close()
            self.set_status(404)
            self.finish("404")
            log.warning(u"Nonexistent track ID %d requested.", song_id)
            return

        s.close()

        # See if we got range
        range_bytes = self.request.headers.get('Range')
        range_start = 0
        range_end = None
        if range_bytes:
            range_start, range_end = range_bytes[6:].split("-")
            range_end = None if range_end is "" else int(range_end)
            range_start = int(range_start)

        # Set streaming headers
        self.set_status(206)
        self.set_header("Accept-Ranges", "bytes")

        # Find content length and type
        if song.type in settings.NO_TRANSCODE_FORMATS:
            size = song.bytes_len
            song_file = song.file
            self.set_header("Content-Type",
                            mimetypes.guess_type("file://" + song.file)[0])
        else:
            song_file = os.path.join(
                settings.MUSIC_CACHE_DIRECTORY,
                "{}.{}".format(song.id, settings.TRANSCODE_FORMAT))
            size = song.bytes_tc_len
            self.set_header("Content-Type", "audio/mpeg")

        # Set end range
        if not range_end or range_end >= size:
            range_end = size - 1

        # Make sure range_start and range_end are withing size limits
        if range_start >= size:
            self.set_status(416)
            self.finish()
            return

        # Stream out
        try:
            with open(song_file, 'rb') as f:
                # Set range headers
                left = (range_end + 1) - range_start
                self.set_header("Content-Length", left)
                self.set_header(
                    "Content-Range",
                    "bytes {}-{}/{}".format(range_start, range_end, size))
                self.flush()

                # Forward to starting position and start reading data
                f.seek(range_start)
                while left:
                    r = 16384 if 16384 < left else left
                    data = yield gen.Task(self.get_data, (f, r))
                    self.write(data)
                    left -= r
        except IOError:
            self.set_status(404)
            self.finish("404")
            log.error(u"Requested track ID %d doesn't exist.", song.id)
            return

        # Flush the last bytes before finishing up.
        self.flush()
        try:
            self.finish()
        except HTTPOutputError, o:
            log.error(u"Error while serving track ID %d: %s.", song_id, str(o))
Beispiel #19
0
    def on_playlist_msg(self, packet_msg):
        if not self.authenticated:
            return

        query = packet_msg.get('query', '')

        # Creates a new playlist with a given name. Errors out if the name already exists.
        if query == 'add_playlist':
            name = packet_msg.get('name')

            s = session_get()

            if s.query(Playlist).filter_by(name=name,
                                           deleted=False).count() > 0:
                self.send_error('playlist',
                                "Playlist with given name already exists", 500)
                log.warning(u"Playlist with given name already exists.")
            else:
                playlist = Playlist(name=name, updated=utc_now())
                s.add(playlist)
                s.commit()
                self.sync_table('playlist',
                                Playlist,
                                utc_minus_delta(5),
                                push=True)
                log.debug(u"A new playlist created!")

            s.close()
            return

        # Delete playlist and all related items
        if query == 'del_playlist':
            playlist_id = packet_msg.get('id')
            if id > 1:
                s = session_get()
                s.query(PlaylistItem).filter_by(playlist=playlist_id,
                                                deleted=False).update({
                                                    'deleted':
                                                    True,
                                                    'updated':
                                                    utc_now()
                                                })
                s.query(Playlist).filter_by(id=playlist_id).update({
                    'deleted':
                    True,
                    'updated':
                    utc_now()
                })
                s.commit()
                s.close()
                self.sync_table('playlist',
                                Playlist,
                                utc_minus_delta(5),
                                push=True)
                self.sync_table('playlistitem',
                                PlaylistItem,
                                utc_minus_delta(5),
                                push=True)
                self.notify_playlist_changes(playlist_id)
                log.debug(u"Playlist and items deleted!")
                return

        # Copy scratchpad playlist (id 1) to a new playlist
        if query == 'copy_scratchpad':
            to_id = packet_msg.get('id')
            s = session_get()
            s.query(PlaylistItem).filter_by(playlist=to_id,
                                            deleted=False).update({
                                                'deleted':
                                                True,
                                                'updated':
                                                utc_now()
                                            })
            s.commit()

            for item in s.query(PlaylistItem).filter_by(playlist=1,
                                                        deleted=False):
                plitem = PlaylistItem(track=item.track,
                                      playlist=to_id,
                                      number=item.number,
                                      updated=utc_now())
                s.add(plitem)
            s.commit()
            s.close()

            self.sync_table('playlistitem',
                            PlaylistItem,
                            utc_minus_delta(5),
                            push=True)
            self.notify_playlist_changes(to_id)
            log.debug(u"Playlist copied!")
            return

        # Saves tracks to the given playlist. Clears existing tracks.
        if query == 'save_playlist':
            playlist_id = packet_msg.get('id')
            items = packet_msg.get('tracks')

            s = session_get()
            s.query(PlaylistItem).filter_by(playlist=playlist_id,
                                            deleted=False).update({
                                                'deleted':
                                                True,
                                                'updated':
                                                utc_now()
                                            })

            k = 0
            for item in items:
                plitem = PlaylistItem(track=item['id'],
                                      playlist=playlist_id,
                                      number=k,
                                      updated=utc_now())
                s.add(plitem)
                k += 1
            s.commit()
            s.close()

            self.sync_table('playlistitem',
                            PlaylistItem,
                            utc_minus_delta(5),
                            push=True)
            self.notify_playlist_changes(playlist_id)
            log.debug(u"Playlist updated!")
            return
Beispiel #20
0
    def handle_audio(self, path, ext, is_audiobook):
        s = session_get()

        # If track already exists and has not changed, stop here
        # Otherwise either edit or create new track entry
        fsize = os.path.getsize(path)
        try:
            track = s.query(Track).filter_by(file=path).one()
            if fsize == track.bytes_len:
                s.close()
                return
        except NoResultFound:
            track = Track(file=path, album=1, artist=1, type=ext[1:])

        # Attempt to open up the file in Mutagen for tag information
        m = None
        try:
            m = mutagen.File(path)
        except:
            log.warning(u"Could not read header for %s", path)

        # Set correct sizes
        track.bytes_len = fsize
        track.bytes_tc_len = 0

        if m:
            # Find artist
            track_artist = self._get_tag(m, ('TPE1', u'©ART', 'Author', 'Artist', 'ARTIST', 'TXXX:ARTIST'
                                             'TRACK ARTIST', 'TRACKARTIST', 'TrackArtist', 'Track Artist',
                                             'artist'))

            # Find album artist
            album_artist = self._get_tag(m, ('TPE2', u'aART', 'TXXX:ALBUM ARTIST', 'TXXX:ALBUMARTIST', 'ALBUM ARTIST',
                                             'ALBUMARTIST', 'AlbumArtist', 'Album Artist'))

            # Find album title
            album_title = self._get_tag(m, (u'©alb', 'TALB', 'ALBUM', 'album', 'TXXX:ALBUM'))
            
            # Find title
            track_title = self._get_tag(m, (u'©nam', 'TXXX:TITLE', 'TIT2', 'Title', 'TITLE', 'TRACK TITLE',
                                            'TRACKTITLE', 'TrackTitle', 'Track Title'))

            # Find track number
            track_tags = ('TRCK', 'TXXX:TRACK', 'Track', 'trkn', 'TRACK', 'tracknumber', 'TRACKNUMBER')
            track_number = self._get_tag_tuple(m, track_tags)
            if type(track_number) == tuple:
                track.track = int(track_number[0])
            else:
                track_number = self._get_tag(m, track_tags)
                if '/' in track_number:
                    track.track = int(track_number.split('/')[0])
                elif track_number:
                    track.track = int(track_number)

            # Find disc number
            disc_tags = ('TXXX:DISCNUMBER', 'discnumber', 'DISCNUMBER', 'TPOS')
            track_disc = self._get_tag_tuple(m, disc_tags)
            if type(track_disc) == tuple:
                track.disc = int(track_disc[0])
            else:
                track_disc = self._get_tag(m, disc_tags)
                if '/' in track_disc:
                    track.disc = int(track_disc.split('/')[0])
                elif track_disc:
                    track.disc = int(track_disc)

            # Find Genre/Content type
            track.genre = self._get_tag(m, ('TCON', u'@gen', 'gnre', 'Genre', 'genre', 'GENRE', 'TXXX:GENRE'))

            # Find date
            track.date = self._get_tag(m, ('TYER', 'TDAT', 'TDRC', 'TDRL', u'@day', 'date', "DATE", "YEAR", "Date",
                                           "Year", 'TXXX:YEAR'))
            if track.date is None:
                track.date = u""
            
            # Set track title, if found
            if track_title:
                track.title = track_title
            elif track.track and album_title:
                track.title = album_title + u" " + str(track.track)
            elif track.track:
                track.title = "Track " + str(track.track)
            else:
                track.title = os.path.splitext(os.path.basename(path))[0]
            
            # If there is a track artist, add it to its own model
            if track_artist:
                artist = get_or_create(s, Artist, name=track_artist, deleted=False)
                track.artist = artist.id
            elif album_artist:
                artist = get_or_create(s, Artist, name=album_artist, deleted=False)
                track.artist = artist.id

            # If there is no track title or artist, try to parse the filename
            if not track.title or not track.artist:
                filename = os.path.splitext(os.path.basename(path))[0]
                m_artist, m_title = match_track_filename(filename)
                if not track.title and m_title:
                    track.title = m_title
                if not track.artist and m_artist:
                    track.artist = m_artist

            # Looks for album with given information
            if album_title:
                if album_artist:
                    a_artist = get_or_create(s, Artist, name=album_artist, deleted=False)
                else:
                    a_artist = s.query(Artist).get(1)
                
                # Set album
                try:
                    album = s.query(Album).filter_by(title=album_title, artist=a_artist.id, deleted=False).one()
                    track.album = album.id
                except NoResultFound:
                    album = Album(title=album_title, artist=a_artist.id, cover=1, is_audiobook=is_audiobook)
                    s.add(album)
                    s.commit()
                    track.album = album.id

        # Set dir
        bpath = os.path.dirname(path)
        mdir = get_or_create(s, Directory, directory=bpath, deleted=False)
        track.dir = mdir.id
                 
        # Save everything
        s.add(track)
        s.commit()

        # Check if we need to transcode
        if track.type not in settings.NO_TRANSCODE_FORMATS:
            self.transcode(s, track)

        s.close()
Beispiel #21
0
    def on_playlist_msg(self, packet_msg):
        if not self.authenticated:
            return

        query = packet_msg.get('query', '')

        # Creates a new playlist with a given name. Errors out if the name already exists.
        if query == 'add_playlist':
            name = packet_msg.get('name')

            s = session_get()

            if s.query(Playlist).filter_by(name=name, deleted=False).count() > 0:
                self.send_error('playlist', "Playlist with given name already exists", 500)
                log.warning(u"Playlist with given name already exists.")
            else:
                playlist = Playlist(name=name, updated=utc_now())
                s.add(playlist)
                s.commit()
                self.sync_table('playlist', Playlist, utc_minus_delta(5), push=True)
                log.debug(u"A new playlist created!")

            s.close()
            return

        # Delete playlist and all related items
        if query == 'del_playlist':
            playlist_id = packet_msg.get('id')
            if id > 1:
                s = session_get()
                s.query(PlaylistItem).filter_by(playlist=playlist_id, deleted=False).update({
                    'deleted': True,
                    'updated': utc_now()
                })
                s.query(Playlist).filter_by(id=playlist_id).update({
                    'deleted': True,
                    'updated': utc_now()
                })
                s.commit()
                s.close()
                self.sync_table('playlist', Playlist, utc_minus_delta(5), push=True)
                self.sync_table('playlistitem', PlaylistItem, utc_minus_delta(5), push=True)
                self.notify_playlist_changes(playlist_id)
                log.debug(u"Playlist and items deleted!")
                return

        # Copy scratchpad playlist (id 1) to a new playlist
        if query == 'copy_scratchpad':
            to_id = packet_msg.get('id')
            s = session_get()
            s.query(PlaylistItem).filter_by(playlist=to_id, deleted=False).update({
                'deleted': True,
                'updated': utc_now()
            })
            s.commit()

            for item in s.query(PlaylistItem).filter_by(playlist=1, deleted=False):
                plitem = PlaylistItem(track=item.track, playlist=to_id, number=item.number, updated=utc_now())
                s.add(plitem)
            s.commit()
            s.close()

            self.sync_table('playlistitem', PlaylistItem, utc_minus_delta(5), push=True)
            self.notify_playlist_changes(to_id)
            log.debug(u"Playlist copied!")
            return

        # Saves tracks to the given playlist. Clears existing tracks.
        if query == 'save_playlist':
            playlist_id = packet_msg.get('id')
            items = packet_msg.get('tracks')

            s = session_get()
            s.query(PlaylistItem).filter_by(playlist=playlist_id, deleted=False).update({
                'deleted': True,
                'updated': utc_now()
            })

            k = 0
            for item in items:
                plitem = PlaylistItem(track=item['id'], playlist=playlist_id, number=k, updated=utc_now())
                s.add(plitem)
                k += 1
            s.commit()
            s.close()

            self.sync_table('playlistitem', PlaylistItem, utc_minus_delta(5), push=True)
            self.notify_playlist_changes(playlist_id)
            log.debug(u"Playlist updated!")
            return