spotify_id.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. use std;
  2. use std::fmt;
  3. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
  4. pub enum SpotifyAudioType {
  5. Track,
  6. Podcast,
  7. NonPlayable,
  8. }
  9. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
  10. pub struct SpotifyId {
  11. pub id: u128,
  12. pub audio_type: SpotifyAudioType,
  13. }
  14. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
  15. pub struct SpotifyIdError;
  16. const BASE62_DIGITS: &'static [u8] =
  17. b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  18. const BASE16_DIGITS: &'static [u8] = b"0123456789abcdef";
  19. impl SpotifyId {
  20. fn as_track(n: u128) -> SpotifyId {
  21. SpotifyId {
  22. id: n.to_owned(),
  23. audio_type: SpotifyAudioType::Track,
  24. }
  25. }
  26. pub fn from_base16(id: &str) -> Result<SpotifyId, SpotifyIdError> {
  27. let data = id.as_bytes();
  28. let mut n = 0u128;
  29. for c in data {
  30. let d = match BASE16_DIGITS.iter().position(|e| e == c) {
  31. None => return Err(SpotifyIdError),
  32. Some(x) => x as u128,
  33. };
  34. n = n * 16;
  35. n = n + d;
  36. }
  37. Ok(SpotifyId::as_track(n))
  38. }
  39. pub fn from_base62(id: &str) -> Result<SpotifyId, SpotifyIdError> {
  40. let data = id.as_bytes();
  41. let mut n = 0u128;
  42. for c in data {
  43. let d = match BASE62_DIGITS.iter().position(|e| e == c) {
  44. None => return Err(SpotifyIdError),
  45. Some(x) => x as u128,
  46. };
  47. n = n * 62;
  48. n = n + d;
  49. }
  50. Ok(SpotifyId::as_track(n))
  51. }
  52. pub fn from_raw(data: &[u8]) -> Result<SpotifyId, SpotifyIdError> {
  53. if data.len() != 16 {
  54. return Err(SpotifyIdError);
  55. };
  56. let mut arr: [u8; 16] = Default::default();
  57. arr.copy_from_slice(&data[0..16]);
  58. Ok(SpotifyId::as_track(u128::from_be_bytes(arr)))
  59. }
  60. pub fn from_uri(uri: &str) -> Result<SpotifyId, SpotifyIdError> {
  61. let parts = uri.split(":").collect::<Vec<&str>>();
  62. let gid = parts.last().unwrap();
  63. if uri.contains(":episode:") {
  64. let mut spotify_id = SpotifyId::from_base62(gid).unwrap();
  65. let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::Podcast);
  66. Ok(spotify_id)
  67. } else if uri.contains(":track:") {
  68. SpotifyId::from_base62(gid)
  69. } else {
  70. // show/playlist/artist/album/??
  71. let mut spotify_id = SpotifyId::from_base62(gid).unwrap();
  72. let _ = std::mem::replace(&mut spotify_id.audio_type, SpotifyAudioType::NonPlayable);
  73. Ok(spotify_id)
  74. }
  75. }
  76. pub fn to_base16(&self) -> String {
  77. format!("{:032x}", self.id)
  78. }
  79. pub fn to_base62(&self) -> String {
  80. let &SpotifyId { id: mut n, .. } = self;
  81. let mut data = [0u8; 22];
  82. for i in 0..22 {
  83. data[21 - i] = BASE62_DIGITS[(n % 62) as usize];
  84. n /= 62;
  85. }
  86. std::str::from_utf8(&data).unwrap().to_owned()
  87. }
  88. pub fn to_raw(&self) -> [u8; 16] {
  89. self.id.to_be_bytes()
  90. }
  91. }
  92. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
  93. pub struct FileId(pub [u8; 20]);
  94. impl FileId {
  95. pub fn to_base16(&self) -> String {
  96. self.0
  97. .iter()
  98. .map(|b| format!("{:02x}", b))
  99. .collect::<Vec<String>>()
  100. .concat()
  101. }
  102. }
  103. impl fmt::Debug for FileId {
  104. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  105. f.debug_tuple("FileId").field(&self.to_base16()).finish()
  106. }
  107. }
  108. impl fmt::Display for FileId {
  109. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  110. f.write_str(&self.to_base16())
  111. }
  112. }