Source code for soco.plugins.sharelink

"""ShareLink Plugin."""

import re

from ..plugins import SoCoPlugin
from ..exceptions import SoCoException


[docs]class ShareClass: """Base class for supported services."""
[docs] def canonical_uri(self, uri): """Recognize a share link and return its canonical representation. Args: uri (str): A URI like "https://tidal.com/browse/album/157273956". Returns: str: The canonical URI or None if not recognized. """ raise NotImplementedError
[docs] def service_number(self): """Return the service number. Returns: int: A number identifying the supported music service. """ raise NotImplementedError
[docs] @staticmethod def magic(): """Return magic. Returns: dict: Magic prefix/key/class values for each share type. """ return { "album": { "prefix": "x-rincon-cpcontainer:1004206c", "key": "00040000", "class": "object.container.album.musicAlbum", }, "episode": { "prefix": "", "key": "00032020", "class": "object.item.audioItem.musicTrack", }, "track": { "prefix": "", "key": "00032020", "class": "object.item.audioItem.musicTrack", }, "show": { "prefix": "x-rincon-cpcontainer:1006206c", "key": "1006206c", "class": "object.container.playlistContainer", }, "song": { "prefix": "", "key": "10032020", "class": "object.item.audioItem.musicTrack", }, "playlist": { "prefix": "x-rincon-cpcontainer:1006206c", "key": "1006206c", "class": "object.container.playlistContainer", }, }
[docs] def extract(self, uri): """Extract the share type and encoded URI from a share link. Returns: share_type: The shared type, like "album" or "track". encoded_uri: An escaped URI with a service-specific format. """ raise NotImplementedError
[docs]class SpotifyShare(ShareClass): """Spotify share class."""
[docs] def canonical_uri(self, uri): match = re.search( r"spotify.*[:/](album|episode|playlist|show|track)[:/](\w+)", uri ) if match: return "spotify:" + match.group(1) + ":" + match.group(2) return None
[docs] def service_number(self): return 2311
[docs] def extract(self, uri): spotify_uri = self.canonical_uri(uri) share_type = spotify_uri.split(":")[1] encoded_uri = spotify_uri.replace(":", "%3a") return (share_type, encoded_uri)
[docs]class SpotifyUSShare(SpotifyShare): """Spotify US share class."""
[docs] def service_number(self): return 3079
[docs]class TIDALShare(ShareClass): """TIDAL share class."""
[docs] def canonical_uri(self, uri): match = re.search(r"https://tidal.*[:/](album|track|playlist)[:/]([\w-]+)", uri) if match: return "tidal:" + match.group(1) + ":" + match.group(2) return None
[docs] def service_number(self): return 44551
[docs] def extract(self, uri): tidal_uri = self.canonical_uri(uri) share_type = tidal_uri.split(":")[1] encoded_uri = tidal_uri.replace("tidal:", "").replace(":", "%2f") return (share_type, encoded_uri)
[docs]class DeezerShare(ShareClass): """Deezer share class."""
[docs] def canonical_uri(self, uri): match = re.search( r"https://www.deezer.*[:/](album|track|playlist)[:/]([\w-]+)", uri ) if match: return "deezer:" + match.group(1) + ":" + match.group(2) return None
[docs] def service_number(self): return 519
[docs] def extract(self, uri): deezer_uri = self.canonical_uri(uri) share_type = deezer_uri.split(":")[1] encoded_uri = deezer_uri.replace("deezer:", "").replace(":", "-") return (share_type, encoded_uri)
[docs]class AppleMusicShare(ShareClass): """Apple Music share class."""
[docs] def canonical_uri(self, uri): # https://music.apple.com/dk/album/black-velvet/217502930?i=217503142 match = re.search( r"https://music\.apple\.com/\w+/album/[^/]+/\d+\?i=(\d+)", uri ) if match: return "song:" + match.group(1) # https://music.apple.com/dk/album/amused-to-death/975952384 match = re.search(r"https://music\.apple\.com/\w+/album/[^/]+/(\d+)", uri) if match: return "album:" + match.group(1) # Apple-created playlist # https://music.apple.com/dk/playlist/power-ballads-essentials/pl.92e04ee75ed64804b9df468b5f45a161 # User-created playlist # https://music.apple.com/de/playlist/unnamed-playlist/pl.u-rR2PCrLdLJk match = re.search( r"https://music\.apple\.com/\w+/playlist/[^/]+/(pl\.[-a-zA-Z0-9]+)", uri ) if match: return "playlist:" + match.group(1) return None
[docs] def service_number(self): return 52231
[docs] def extract(self, uri): uri = self.canonical_uri(uri) share_type = uri.split(":")[0] encoded_uri = uri.replace(":", "%3a") return (share_type, encoded_uri)
[docs]class ShareLinkPlugin(SoCoPlugin): """A SoCo plugin for playing music service share links.""" def __init__(self, soco): """Initialize the plugin.""" super().__init__(soco) self.services = [ SpotifyShare(), SpotifyUSShare(), TIDALShare(), DeezerShare(), AppleMusicShare(), ] @property def name(self): return "ShareLink Plugin"