spotify_id.rs 3.3 KB

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