lavalink_rs/python/
player.rsuse std::time::Duration;
use crate::{
model::{
http::UpdatePlayer,
player::{Filters, Player},
track::TrackData,
},
player_context::TrackInQueue,
};
use parking_lot::RwLock;
use pyo3::prelude::*;
#[pymodule]
pub fn player(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<crate::player_context::PlayerContext>()?;
m.add_class::<crate::player_context::TrackInQueue>()?;
m.add_class::<crate::player_context::QueueRef>()?;
Ok(())
}
#[pymethods]
impl crate::player_context::PlayerContext {
#[pyo3(name = "get_queue")]
fn get_queue_py(&self) -> crate::player_context::QueueRef {
self.get_queue()
}
#[pyo3(name = "get_player")]
fn get_player_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let player_inner = player.get_player().await?;
Ok(Python::with_gil(|_py| player_inner))
})
}
#[pyo3(name = "update_player")]
fn update_player_py<'a>(
&self,
py: Python<'a>,
update_player: UpdatePlayer,
no_replace: bool,
) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let player_inner = player.update_player(&update_player, no_replace).await?;
Ok(Python::with_gil(|_py| player_inner))
})
}
#[pyo3(name = "play")]
fn play_py<'a>(
&self,
py: Python<'a>,
track: crate::model::track::TrackData,
) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
player.play(&track).await?;
Ok(Python::with_gil(|py| py.None()))
})
}
#[pyo3(name = "play_now")]
fn play_now_py<'a>(
&self,
py: Python<'a>,
track: crate::model::track::TrackData,
) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
player.play_now(&track).await?;
Ok(Python::with_gil(|py| py.None()))
})
}
#[pyo3(name = "stop_now")]
fn stop_now_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let player_inner = player.stop_now().await?;
Ok(Python::with_gil(|_py| player_inner))
})
}
#[pyo3(name = "set_pause")]
fn set_pause_py<'a>(&self, py: Python<'a>, pause: bool) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let player_inner = player.set_pause(pause).await?;
Ok(Python::with_gil(|_py| player_inner))
})
}
#[pyo3(name = "set_volume")]
fn set_volume_py<'a>(&self, py: Python<'a>, volume: u16) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let player_inner = player.set_volume(volume).await?;
Ok(Python::with_gil(|_py| player_inner))
})
}
#[pyo3(name = "set_filters")]
fn set_filters_py<'a>(&self, py: Python<'a>, filters: Filters) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let player_inner = player.set_filters(filters).await?;
Ok(Python::with_gil(|_py| player_inner))
})
}
#[pyo3(name = "set_position_ms")]
fn set_position_ms_py<'a>(&self, py: Python<'a>, position: u64) -> PyResult<&'a PyAny> {
let player = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let player_inner = player.set_position(Duration::from_millis(position)).await?;
Ok(Python::with_gil(|_py| player_inner))
})
}
#[pyo3(name = "queue")]
fn queue_py<'a>(&self, track: PyTrackInQueue) -> PyResult<()> {
self.queue(track)?;
Ok(())
}
#[pyo3(name = "close")]
fn close_py<'a>(&self) -> PyResult<()> {
self.clone().close()?;
Ok(())
}
#[pyo3(name = "skip")]
fn skip_py<'a>(&self) -> PyResult<()> {
self.skip()?;
Ok(())
}
#[pyo3(name = "finish")]
fn finish_py<'a>(&self, should_continue: bool) -> PyResult<()> {
self.finish(should_continue)?;
Ok(())
}
#[pyo3(name = "update_player_data")]
fn update_player_data_py<'a>(&self, player: Player) -> PyResult<()> {
self.update_player_data(player)?;
Ok(())
}
#[getter]
#[pyo3(name = "data")]
fn get_data_py<'a>(&self, py: Python<'a>) -> PyResult<PyObject> {
let player = self.clone();
let data = player.data::<RwLock<PyObject>>()?.read().clone_ref(py);
Ok(data)
}
#[setter]
#[pyo3(name = "data")]
fn set_data_py(&self, user_data: PyObject) -> PyResult<()> {
let player = self.clone();
*player.data::<RwLock<PyObject>>()?.write() = user_data;
Ok(())
}
}
#[pymethods]
impl crate::player_context::QueueRef {
#[pyo3(name = "get_queue")]
fn get_queue_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> {
let queue = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let q: Vec<_> = queue.get_queue().await?.into();
Ok(Python::with_gil(|_py| q))
})
}
#[pyo3(name = "get_track")]
fn get_track_py<'a>(&self, py: Python<'a>, index: usize) -> PyResult<&'a PyAny> {
let queue = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let q = queue.get_track(index).await?;
Ok(Python::with_gil(|_py| q))
})
}
#[pyo3(name = "get_count")]
fn get_count_py<'a>(&self, py: Python<'a>) -> PyResult<&'a PyAny> {
let queue = self.clone();
pyo3_asyncio::tokio::future_into_py(py, async move {
let q = queue.get_count().await?;
Ok(Python::with_gil(|_py| q))
})
}
#[pyo3(name = "push_to_back")]
fn push_to_back_py(&self, track: PyTrackInQueue) -> PyResult<()> {
Ok(self.push_to_back(TrackInQueue::from(track))?)
}
#[pyo3(name = "push_to_front")]
fn push_to_front_py(&self, track: PyTrackInQueue) -> PyResult<()> {
Ok(self.push_to_front(TrackInQueue::from(track))?)
}
#[pyo3(name = "insert")]
fn insert_py(&self, index: usize, track: PyTrackInQueue) -> PyResult<()> {
Ok(self.insert(index, TrackInQueue::from(track))?)
}
#[pyo3(name = "remove")]
fn remove_py(&self, index: usize) -> PyResult<()> {
Ok(self.remove(index)?)
}
#[pyo3(name = "clear")]
fn clear_py(&self) -> PyResult<()> {
Ok(self.clear()?)
}
#[pyo3(name = "replace")]
fn replace_py(&self, tracks: Vec<PyTrackInQueue>) -> PyResult<()> {
Ok(self.replace(tracks.into_iter().map(TrackInQueue::from).collect())?)
}
#[pyo3(name = "append")]
fn append_py(&self, tracks: Vec<PyTrackInQueue>) -> PyResult<()> {
Ok(self.append(tracks.into_iter().map(TrackInQueue::from).collect())?)
}
#[pyo3(name = "swap")]
fn swap_py(&self, index: usize, track: PyTrackInQueue) -> PyResult<()> {
Ok(self.swap(index, TrackInQueue::from(track))?)
}
}
#[apply(crate::python::with_getter_setter)]
#[pymethods]
impl crate::player_context::TrackInQueue {
getter_setter!(
(track, crate::model::track::TrackData),
(volume, Option<u16>),
(filters, Option<crate::model::player::Filters>),
);
#[getter]
fn get_start_time_ms(&self) -> Option<u128> {
self.start_time.map(|ms| ms.as_millis())
}
#[setter]
fn set_start_time_ms(&mut self, ms: Option<u64>) -> pyo3::PyResult<()> {
self.start_time = ms.map(|ms| Duration::from_millis(ms));
Ok(())
}
#[getter]
fn get_end_time_ms(&self) -> Option<u128> {
self.end_time.map(|ms| ms.as_millis())
}
#[setter]
fn set_end_time_ms(&mut self, ms: Option<u64>) -> pyo3::PyResult<()> {
self.end_time = ms.map(|ms| Duration::from_millis(ms));
Ok(())
}
}
#[derive(FromPyObject)]
pub enum PyTrackInQueue {
#[pyo3(transparent, annotation = "TrackInQueue")]
TrackInQueue(TrackInQueue),
#[pyo3(transparent, annotation = "TrackData")]
TrackData(TrackData),
}
impl From<PyTrackInQueue> for TrackInQueue {
fn from(value: PyTrackInQueue) -> Self {
match value {
PyTrackInQueue::TrackInQueue(x) => x,
PyTrackInQueue::TrackData(x) => x.into(),
}
}
}