Example #1
0
def swap(range_A, range_B):
    '''Swaps the items contained in one range with the items contained in the
    other range.
    
    Return value: Nothing meaningful.
    '''
    A = split_range(range_A)
    B = split_range(range_B)
    data.lock.acquire()
    try:
        # Normalize the case where negative numbers are used as range indices.
        n = len(data.song_queue)
        if A[0] < 0:   A[0] = n - A[0]
        if A[1] < 0:   A[1] = n - A[1]
        if B[0] < 0:   B[0] = n - B[0]
        if B[1] < 0:   B[1] = n - B[1]
        # Forbid overlapping ranges.
        if is_overlapping(A, B, len(data.song_queue)):
            raise ValueError("Overlapping ranges may not be swapped: %s %s" % (A, B))
        # Make sure range A is closer to the head of the queue than range B.
        if A > B:
            A, B = B, A
        # Split the queue into various slices, delineated by the given ranges.
        prefix  = data.song_queue[:A[0]]
        slice_A = data.song_queue[A[0]:A[1]]
        infix   = data.song_queue[A[1]:B[0]]
        slice_B = data.song_queue[B[0]:B[1]]
        suffix  = data.song_queue[B[1]:]
        # Piece the slices back together, swapping A with B.
        data.song_queue = prefix + slice_B + infix + slice_A + suffix
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #2
0
def swap(range_A, range_B):
    '''Swaps the items contained in one range with the items contained in the
    other range.
    
    Return value: Nothing meaningful.
    '''
    A = split_range(range_A)
    B = split_range(range_B)
    data.lock.acquire()
    try:
        # Normalize the case where negative numbers are used as range indices.
        n = len(data.song_queue)
        if A[0] < 0: A[0] = n - A[0]
        if A[1] < 0: A[1] = n - A[1]
        if B[0] < 0: B[0] = n - B[0]
        if B[1] < 0: B[1] = n - B[1]
        # Forbid overlapping ranges.
        if is_overlapping(A, B, len(data.song_queue)):
            raise ValueError("Overlapping ranges may not be swapped: %s %s" %
                             (A, B))
        # Make sure range A is closer to the head of the queue than range B.
        if A > B:
            A, B = B, A
        # Split the queue into various slices, delineated by the given ranges.
        prefix = data.song_queue[:A[0]]
        slice_A = data.song_queue[A[0]:A[1]]
        infix = data.song_queue[A[1]:B[0]]
        slice_B = data.song_queue[B[0]:B[1]]
        suffix = data.song_queue[B[1]:]
        # Piece the slices back together, swapping A with B.
        data.song_queue = prefix + slice_B + infix + slice_A + suffix
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #3
0
def indexed_list(range=()):
    '''Lists the song queue's contents. If a range is specified, only the
    items that fall within that range are listed.
 
    This differs from list() only in its return value, and is useful when you
    want to know the starting position of your selected range within the song
    queue (which can be different than the starting index of the specified range
    if, for example, the starting index is a negative integer).
 
    Arguments: Either none, or an array of integers that represents a range.
      * If no range is given, the whole list is returned.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: A struct with two elements. This first is "list", an array of
        (base64-encoded) strings, representing the selected range from the song
        queue's contents. The second is "start", an integer index value that
        represents the position of the first item of the returned list in the
        song queue.
    '''
    start, end = split_range(range)
    list = [Binary(i.encode()) for i in data.song_queue[start:end]]
    start_index = start
    if start_index < 0:
        start_index = len(data.song_queue) + start_index
        if start_index < 0:
            start_index = 0
    return {'start': start_index, 'list': list}
Example #4
0
def replace_range(range, items):
    '''Replaces a slice of the contents of the queue with the given items.
 
    This is equivalent to calling cut() and prepend() in succession, except
    that this operation is atomic.
 
    Argument: The first is an array of integers that represents a range.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
      * The second argument is an array of (base64-encoded) strings,
        representing the items to be added.
      * When adding local filenames to the queue, only absolute pathnames
        should be used.  Using relative pathnames would be foolish because
        the server isn't aware of the client's current working directory.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    for i in items:
        if not hasattr(i, 'data'):
            raise TypeError("Objects of type '%s' cannot be inserted." % \
                            i.__class__.__name__)
    data.lock.acquire()
    try:
        data.song_queue[start:end] = [
            _f for _f in [str(i.data.decode()) for i in items] if _f
        ]
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #5
0
def sub(pattern, replace, range=()):
    '''Performs a regular expression substitution on the items in the queue.
    
    Arguments: The first is a (base64-encoded) regular expression that specifies
        the text to be replaced.
      * The second argument is the (base64-encoded) string that will be used to
        replace the first occurrence of the regular expression within each queue
        item. Any backslash escapes in this string will be processed, including
        special character translation (e.g. "\\n" to newline) and backreferences
        to groups within the match.
      * Optionally, an array of integers may be given as a third argument.
        This argument represents a range to which the substitution will be
        limited. This range is interpreted in the same way as the range argument
        in other Moosic methods.
      * If performing a replacement changes an item in the queue into the empty
        string, then it is removed from the queue.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    if hasattr(pattern, 'data'):
        pattern = str(pattern.data)
    if hasattr(replace, 'data'):
        replace = str(replace.data)
    pattern = re.compile(pattern)
    data.lock.acquire()
    try:
        data.song_queue[start:end] = filter(None, [pattern.sub(replace, item, 1)
                                      for item in data.song_queue[start:end]])
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #6
0
def filter_(regexp, range=()):
    '''Removes all items that don't match the given regular expression.
 
    Arguments: A regular expression that specifies which items to keep.
      * Optionally, an array of integers may be given as a second argument.
        This argument represents a range to which the filtering will be
        limited.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    data.lock.acquire()
    try:
        if hasattr(regexp, 'data'):
            regexp = regexp.data.decode()
        data.song_queue[start:end] = grep(regexp, data.song_queue[start:end])
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #7
0
def filter_(regexp, range=()):
    '''Removes all items that don't match the given regular expression.
 
    Arguments: A regular expression that specifies which items to keep.
      * Optionally, an array of integers may be given as a second argument.
        This argument represents a range to which the filtering will be
        limited.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    data.lock.acquire()
    try:
        if hasattr(regexp, 'data'):
            regexp = regexp.data
        data.song_queue[start:end] = grep(regexp, data.song_queue[start:end])
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #8
0
def indexed_list(range=()):
    '''Lists the song queue's contents. If a range is specified, only the
    items that fall within that range are listed.
 
    This differs from list() only in its return value, and is useful when you
    want to know the starting position of your selected range within the song
    queue (which can be different than the starting index of the specified range
    if, for example, the starting index is a negative integer).
 
    Arguments: Either none, or an array of integers that represents a range.
      * If no range is given, the whole list is returned.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: A struct with two elements. This first is "list", an array of
        (base64-encoded) strings, representing the selected range from the song
        queue's contents. The second is "start", an integer index value that
        represents the position of the first item of the returned list in the
        song queue.
    '''
    start, end = split_range(range)
    list = [Binary(i) for i in data.song_queue[start:end]]
    start_index = start
    if start_index < 0:
        start_index = len(data.song_queue) + start_index
        if start_index < 0:
            start_index = 0
    return {'start':start_index, 'list':list}
Example #9
0
def replace_range(range, items):
    '''Replaces a slice of the contents of the queue with the given items.
 
    This is equivalent to calling cut() and prepend() in succession, except
    that this operation is atomic.
 
    Argument: The first is an array of integers that represents a range.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
      * The second argument is an array of (base64-encoded) strings,
        representing the items to be added.
      * When adding local filenames to the queue, only absolute pathnames
        should be used.  Using relative pathnames would be foolish because
        the server isn't aware of the client's current working directory.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    for i in items:
        if not hasattr(i, 'data'):
            raise TypeError("Objects of type '%s' cannot be inserted." % \
                            i.__class__.__name__)
    data.lock.acquire()
    try:
        data.song_queue[start:end] = filter(None, [str(i.data) for i in items])
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #10
0
def list(range=()):
    '''Lists the song queue's contents. If a range is specified, only the
    items that fall within that range are listed.
 
    Arguments: Either none, or an array of integers that represents a range.
      * If no range is given, the whole list is returned.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: An array of (base64-encoded) strings, representing the
        selected range from the song queue's contents.
    '''
    start, end = split_range(range)
    return [Binary(i) for i in data.song_queue[start:end]]
Example #11
0
def list(range=()):
    '''Lists the song queue's contents. If a range is specified, only the
    items that fall within that range are listed.
 
    Arguments: Either none, or an array of integers that represents a range.
      * If no range is given, the whole list is returned.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: An array of (base64-encoded) strings, representing the
        selected range from the song queue's contents.
    '''
    start, end = split_range(range)
    return [Binary(i.encode()) for i in data.song_queue[start:end]]
Example #12
0
def cut(range):
    '''Remove all queued items that fall within the given range.
 
    Arguments: An array of integers that represents a range.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    data.lock.acquire()
    try:
        del data.song_queue[start:end]
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #13
0
def crop(range):
    '''Remove all queued items that do not fall within the given range.
 
    Arguments: An array of integers that represents a range.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    data.lock.acquire()
    try:
        data.song_queue = data.song_queue[start:end]
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #14
0
def move(range, dest):
    '''Moves a range of items to a new position within the queue.
 
    Arguments: The first argument is an array of integers that represents a
        range of items to be moved. 
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
      * The second argument, "destination", specifies the position in the queue
        where the items will be moved.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    # Use an out-of-bound piece of data to mark the old positions of moved
    # items.  Since the playlist normally only contains strings, any non-string
    # value will work as an effective marker.
    mark = None
    data.lock.acquire()
    try:
        # Copy the items to be moved.
        stuff_to_move = data.song_queue[start:end]
        # "Delete" the items from their old position by replacing them with
        # marker values. Regular removal isn't done at this point because we
        # don't want to invalidate the meaning of our destination index.
        data.song_queue[start:end] = [mark] * len(stuff_to_move)
        # Place the collected items at their destination.
        data.song_queue[dest:dest] = stuff_to_move
        # Remove the markers.
        data.song_queue = [
            item for item in data.song_queue if item is not mark
        ]
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #15
0
def move(range, dest):
    '''Moves a range of items to a new position within the queue.
 
    Arguments: The first argument is an array of integers that represents a
        range of items to be moved. 
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
      * The second argument, "destination", specifies the position in the queue
        where the items will be moved.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    # Use an out-of-bound piece of data to mark the old positions of moved
    # items.  Since the playlist normally only contains strings, any non-string
    # value will work as an effective marker.
    mark = None
    data.lock.acquire()
    try:
        # Copy the items to be moved.
        stuff_to_move = data.song_queue[start:end]
        # "Delete" the items from their old position by replacing them with
        # marker values. Regular removal isn't done at this point because we
        # don't want to invalidate the meaning of our destination index.
        data.song_queue[start:end] = [mark]*len(stuff_to_move)
        # Place the collected items at their destination.
        data.song_queue[dest:dest] = stuff_to_move
        # Remove the markers.
        data.song_queue = [item for item in data.song_queue if item is not mark]
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #16
0
def reverse(range=()):
    '''Reverses the order of the items in the queue.
 
    Arguments: Either none, or an array of integers that represents a range.
      * If no range is given, the whole list is affected.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    altered_slice = data.song_queue[start:end]
    altered_slice.reverse()
    data.lock.acquire()
    try:
        data.song_queue[start:end] = altered_slice
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True
Example #17
0
def reverse(range=()):
    '''Reverses the order of the items in the queue.
 
    Arguments: Either none, or an array of integers that represents a range.
      * If no range is given, the whole list is affected.
      * If the range contains a single integer, it will represent all members
        of the queue whose index is greater than or equal to the value of the
        integer.
      * If the range contains two integers, it will represent all members of
        the queue whose index is greater than or equal to the value of the
        first integer and less than the value of the second integer.
      * If the range contains more than two integers, an error will occur.
    Return value: Nothing meaningful.
    '''
    start, end = split_range(range)
    altered_slice = data.song_queue[start:end]
    altered_slice.reverse()
    data.lock.acquire()
    try:
        data.song_queue[start:end] = altered_slice
    finally:
        data.last_queue_update = time.time()
        data.lock.release()
    return True