use std::collections::HashSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Scope {
UgcImageUpload,
UserReadPlaybackState,
UserModifyPlaybackState,
UserReadCurrentlyPlaying,
Streaming,
PlaylistReadPrivate,
PlaylistReadCollaborative,
PlaylistModifyPrivate,
PlaylistModifyPublic,
UserFollowModify,
UserFollowRead,
UserReadPlaybackPosition,
UserTopRead,
UserReadRecentlyPlayed,
UserLibraryModify,
UserLibraryRead,
UserReadEmail,
UserReadPrivate,
}
pub fn playlist() -> HashSet<Scope> {
vec![
Scope::PlaylistReadPrivate,
Scope::PlaylistReadCollaborative,
Scope::PlaylistModifyPublic,
Scope::PlaylistModifyPrivate,
]
.into_iter()
.collect()
}
pub fn playlist_read() -> HashSet<Scope> {
vec![Scope::PlaylistReadPrivate, Scope::PlaylistReadCollaborative]
.into_iter()
.collect()
}
pub fn playlist_modify() -> HashSet<Scope> {
vec![Scope::PlaylistModifyPublic, Scope::PlaylistModifyPrivate]
.into_iter()
.collect()
}
pub fn user_details() -> HashSet<Scope> {
vec![Scope::UserReadPrivate, Scope::UserReadEmail]
.into_iter()
.collect()
}
pub fn user_library() -> HashSet<Scope> {
vec![Scope::UserLibraryRead, Scope::UserLibraryModify]
.into_iter()
.collect()
}
pub fn user_recents() -> HashSet<Scope> {
vec![Scope::UserTopRead, Scope::UserReadRecentlyPlayed]
.into_iter()
.collect()
}
pub fn user_follow() -> HashSet<Scope> {
vec![Scope::UserFollowRead, Scope::UserFollowModify]
.into_iter()
.collect()
}
pub fn user_playback() -> HashSet<Scope> {
vec![
Scope::UserReadPlaybackPosition,
Scope::UserReadPlaybackState,
Scope::UserReadCurrentlyPlaying,
Scope::UserModifyPlaybackState,
Scope::Streaming,
]
.into_iter()
.collect()
}
pub fn all() -> HashSet<Scope> {
vec![
Scope::UgcImageUpload,
Scope::UserReadPlaybackState,
Scope::UserModifyPlaybackState,
Scope::UserReadCurrentlyPlaying,
Scope::Streaming,
Scope::PlaylistReadPrivate,
Scope::PlaylistReadCollaborative,
Scope::PlaylistModifyPrivate,
Scope::PlaylistModifyPublic,
Scope::UserFollowModify,
Scope::UserFollowRead,
Scope::UserReadPlaybackPosition,
Scope::UserTopRead,
Scope::UserReadRecentlyPlayed,
Scope::UserLibraryModify,
Scope::UserLibraryRead,
Scope::UserReadEmail,
Scope::UserReadPrivate,
]
.into_iter()
.collect()
}
pub fn to_string(set: &HashSet<Scope>) -> String {
set.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join(" ")
}
impl std::fmt::Display for Scope {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::UgcImageUpload => "ugc-image-upload",
Self::UserReadPlaybackState => "user-read-playback-state",
Self::UserModifyPlaybackState => "user-modify-playback-state",
Self::UserReadCurrentlyPlaying => "user-read-currently-playing",
Self::Streaming => "streaming",
Self::PlaylistReadPrivate => "playlist-read-private",
Self::PlaylistReadCollaborative => "playlist-read-collaborative",
Self::PlaylistModifyPrivate => "playlist-modify-private",
Self::PlaylistModifyPublic => "playlist-modify-public",
Self::UserFollowModify => "user-follow-modify",
Self::UserFollowRead => "user-follow-read",
Self::UserReadPlaybackPosition => "user-read-playback-position",
Self::UserTopRead => "user-top-read",
Self::UserReadRecentlyPlayed => "user-read-recently-played",
Self::UserLibraryModify => "user-library-modify",
Self::UserLibraryRead => "user-library-read",
Self::UserReadEmail => "user-read-email",
Self::UserReadPrivate => "user-read-private",
};
write!(f, "{s}")
}
}
impl TryFrom<&str> for Scope {
type Error = ();
fn try_from(value: &str) -> Result<Self, Self::Error> {
let x = match value {
"ugc-image-upload" => Self::UgcImageUpload,
"user-read-playback-state" => Self::UserReadPlaybackState,
"user-modify-playback-state" => Self::UserModifyPlaybackState,
"user-read-currently-playing" => Self::UserReadCurrentlyPlaying,
"streaming" => Self::Streaming,
"playlist-read-private" => Self::PlaylistReadPrivate,
"playlist-read-collaborative" => Self::PlaylistReadCollaborative,
"playlist-modify-private" => Self::PlaylistModifyPrivate,
"playlist-modify-public" => Self::PlaylistModifyPublic,
"user-follow-modify" => Self::UserFollowModify,
"user-follow-read" => Self::UserFollowRead,
"user-read-playback-position" => Self::UserReadPlaybackPosition,
"user-top-read" => Self::UserTopRead,
"user-read-recently-played" => Self::UserReadRecentlyPlayed,
"user-library-modify" => Self::UserLibraryModify,
"user-library-read" => Self::UserLibraryRead,
"user-read-email" => Self::UserReadEmail,
"user-read-private" => Self::UserReadPrivate,
_ => return Err(()),
};
Ok(x)
}
}
impl From<Scope> for HashSet<Scope> {
fn from(val: Scope) -> Self {
vec![val].into_iter().collect()
}
}
impl From<Scope> for Option<HashSet<Scope>> {
fn from(val: Scope) -> Self {
Some(val.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn scope_kebab_case() {
let scope = Scope::UserReadPlaybackState;
assert_eq!("user-read-playback-state", scope.to_string());
}
}