A lot of the expensive getters were transformed into cached properties
instead. A lot of things that were properties were transformed into
properties as well.
Client.add_roles and Client.remove_roles would dispatch to the
Client.replace_roles function. However, replace_roles expects Role
objects while the dispatching involved string IDs. So as a result this
needed another layer of dispatch into a _replace_roles function to do
the actual call that all three of them dispatch to.
It probably isn't good to rely on an item that was added to a list to
still be the last item, especially if we could have other async
coroutines modify the list. This may not be an actual issue, but having
the function explicitly return the object that it just added to the list
should guarantee that we don't accidentally pull the wrong item from the
end of the list later.
This bug triggered because we did not call `yield from` to the
coroutine that starts the private message if it isn't found in cache.
Obviously the fix for that is to make the destination resolution a
coroutine and thus it'll be invoked correctly.
Two new options are added to the ffmpeg player. `options` and `pipe`.
If `pipe` is True then we can pass in a file-like object to be the
stdin of ffmpeg. `options` allows you to pass extra things to the
ffmpeg command line.