code time
BIN
resources/fanart.jpg
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
resources/icon.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
resources/icon_clear_cache.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
resources/icon_music_albums.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
resources/icon_music_artists.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
resources/icon_music_explore.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
resources/icon_music_library.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
resources/icon_music_playlists.png
Normal file
|
After Width: | Height: | Size: 964 B |
BIN
resources/icon_music_search.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
resources/icon_music_songs.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
resources/icon_music_top_artists.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
resources/icon_music_top_tracks.png
Normal file
|
After Width: | Height: | Size: 301 B |
179
resources/language/resource.language.de_de/strings.po
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2015-11-04 18:30+0100\n"
|
||||
"Last-Translator: tobhor\n"
|
||||
"Language-Team: German\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: de\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr "Nutzername"
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr "Passwort"
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr "Neuerscheinungen"
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr "Zu meiner Musik hinzufügen"
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr "Aus meiner Musik entfernen"
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr "Folgen"
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr "Nicht mehr folgen"
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr "Beliebteste Lieder des Künstlers"
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr "Ähnliche Künstler"
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr "Meine Musik"
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr "Entdecken"
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr "Empfohlene Wiedergabelisten"
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr "Neuerscheinungen"
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Aus Playlist entfernen"
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr "Alle Alben des Künstlers"
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr "Meistgespielte Künstler"
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr "Meistgespielte Lieder"
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr "Künstler folgen"
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr "Künstler nicht mehr folgen"
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr "Eintrag aktualisieren"
|
||||
|
||||
msgctxt "#11028"
|
||||
msgid "Login details"
|
||||
msgstr "Anmeldedetails"
|
||||
|
||||
msgctxt "#11030"
|
||||
msgid "Append artist name to song title"
|
||||
msgstr "Künstlername an Songtitel anhängen"
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr "Standardansicht für Wiedergabeliste"
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr "Standardansicht für Künstlerliste"
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr "Standardansicht für Albenliste"
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr "Standardansicht für Songliste"
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr "Aktueller Benutzer"
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr "Keine Anmeldedaten vorhanden oder Anmeldung fehlgeschlagen. \n Bitte gebe deine Anmeldedaten im folgenden Einstellungsdialog ein."
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr "Audio"
|
||||
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr "Ansichten"
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr "My recently played playlist"
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr "Gap between tracks when playing a playlist (secs)"
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr "Clear the plugin cache"
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr "Followed artists"
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr ""
|
||||
175
resources/language/resource.language.en_gb/strings.po
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2015-11-04 18:30+0100\n"
|
||||
"Last-Translator: logi85\n"
|
||||
"Language-Team: English\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11028"
|
||||
msgid "Login details"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11030"
|
||||
msgid "Append artist name to song title"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr ""
|
||||
175
resources/language/resource.language.es_ar/strings.po
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2015-11-04 18:30+0100\n"
|
||||
"Last-Translator: trihy\n"
|
||||
"Language-Team: English\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_ar\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr "Nombre de Usuario"
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr "Contraseña"
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr "Nuevos Lanzamientos"
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr "Guardar en Mi Música"
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr "Remover de Mi Música"
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr "Seguir"
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr "Dejar de Seguir"
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr "Canciones Top del Artista"
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr "Artistas Relacionados"
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr "Mi Música"
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr "Explorar"
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr "Playlists Destacadas"
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr "Nuevos Lanzamientos"
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Remover del Playlist"
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr "Todos los Albumes del Artista"
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr "Vista por Defecto para Categorías"
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr "Artistas más Reproducidos "
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr "Canciones más Reproducidas"
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr "Seguir Artista"
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr "Dejar de Seguir Artista"
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr "Refrescar Listado"
|
||||
|
||||
msgctxt "#11028"
|
||||
msgid "Login details"
|
||||
msgstr "Detalles de Login"
|
||||
|
||||
msgctxt "#11030"
|
||||
msgid "Append artist name to song title"
|
||||
msgstr "Adjuntar Nombre del Artista a Título de Canción"
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr "Vista por Defecto para Playlists"
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr "Vista por Defecto para Lista de Artista"
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr "Vista por Defecto para Lista de Album"
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr "Vista por Defecto para Lista de Canción"
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr "Usuario Actual"
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr "Audio"
|
||||
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr "Vistas"
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr "Mi Playlist reproducida Recientemente"
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr "Espacio entre canciones cuando se reproduce una playlist (Segundos)"
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr "Limpiar cache del plugin"
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr "Artistas Seguidos"
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr "Cache de base de datos del plugin exitosamente limpiada"
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr "Usar Normalizacion de Spotify cuando reproduzca canciones"
|
||||
175
resources/language/resource.language.es_es/strings.po
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2015-11-04 18:30+0100\n"
|
||||
"Last-Translator: trihy\n"
|
||||
"Language-Team: English\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr "Nombre de Usuario"
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr "Contraseña"
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr "Nuevos Lanzamientos"
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr "Guardar en Mi Música"
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr "Remover de Mi Música"
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr "Seguir"
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr "Dejar de Seguir"
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr "Canciones Top del Artista"
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr "Artistas Relacionados"
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr "Mi Música"
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr "Explorar"
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr "Playlists Destacadas"
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr "Nuevos Lanzamientos"
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Remover del Playlist"
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr "Todos los Albumes del Artista"
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr "Vista por Defecto para Categorías"
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr "Artistas más Reproducidos "
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr "Canciones más Reproducidas"
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr "Seguir Artista"
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr "Dejar de Seguir Artista"
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr "Refrescar Listado"
|
||||
|
||||
msgctxt "#11028"
|
||||
msgid "Login details"
|
||||
msgstr "Detalles de Login"
|
||||
|
||||
msgctxt "#11030"
|
||||
msgid "Append artist name to song title"
|
||||
msgstr "Adjuntar Nombre del Artista a Título de Canción"
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr "Vista por Defecto para Playlists"
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr "Vista por Defecto para Lista de Artista"
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr "Vista por Defecto para Lista de Album"
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr "Vista por Defecto para Lista de Canción"
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr "Usuario Actual"
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr "Audio"
|
||||
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr "Vistas"
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr "Mi Playlist reproducida Recientemente"
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr "Espacio entre canciones cuando se reproduce una playlist (Segundos)"
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr "Limpiar cache del plugin"
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr "Artistas Seguidos"
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr "Cache de base de datos del plugin exitosamente limpiada"
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr "Usar Normalizacion de Spotify cuando reproduzca canciones"
|
||||
175
resources/language/resource.language.es_mx/strings.po
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2015-11-04 18:30+0100\n"
|
||||
"Last-Translator: trihy\n"
|
||||
"Language-Team: English\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_mx\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr "Nombre de Usuario"
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr "Contraseña"
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr "Nuevos Lanzamientos"
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr "Guardar en Mi Música"
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr "Remover de Mi Música"
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr "Seguir"
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr "Dejar de Seguir"
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr "Canciones Top del Artista"
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr "Artistas Relacionados"
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr "Mi Música"
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr "Explorar"
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr "Playlists Destacadas"
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr "Nuevos Lanzamientos"
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Remover del Playlist"
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr "Todos los Albumes del Artista"
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr "Vista por Defecto para Categorías"
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr "Artistas más Reproducidos "
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr "Canciones más Reproducidas"
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr "Seguir Artista"
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr "Dejar de Seguir Artista"
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr "Refrescar Listado"
|
||||
|
||||
msgctxt "#11028"
|
||||
msgid "Login details"
|
||||
msgstr "Detalles de Login"
|
||||
|
||||
msgctxt "#11030"
|
||||
msgid "Append artist name to song title"
|
||||
msgstr "Adjuntar Nombre del Artista a Título de Canción"
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr "Vista por Defecto para Playlists"
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr "Vista por Defecto para Lista de Artista"
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr "Vista por Defecto para Lista de Album"
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr "Vista por Defecto para Lista de Canción"
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr "Usuario Actual"
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr "Audio"
|
||||
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr "Vistas"
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr "Mi Playlist reproducida Recientemente"
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr "Espacio entre canciones cuando se reproduce una playlist (Segundos)"
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr "Limpiar cache del plugin"
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr "Artistas Seguidos"
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr "Cache de base de datos del plugin exitosamente limpiada"
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr "Usar Normalizacion de Spotify cuando reproduzca canciones"
|
||||
179
resources/language/resource.language.fr_fr/strings.po
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2015-11-04 18:30+0100\n"
|
||||
"Last-Translator: xsellier\n"
|
||||
"Language-Team: French\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: en\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr "Nom d'utilisateur"
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr "Mot de passe"
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr "Nouveautés"
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr "Ajouter a Ma Musique"
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr "Enlever de Ma Musique"
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr "Suivre"
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr "Arrêter de suivre"
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr "Les meilleures chansons de l'artiste"
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr "Artistes similaires"
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr "Ma Musique"
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr "Explorer"
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr "Listes de lectures mises en avant"
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr "Nouveautés"
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Enlever de la liste de lecture"
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr "Tous les albums de cet artiste"
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr "Les artistes les plus écoutés"
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr "Les musiques les plus jouées"
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr "Suivre l'artiste"
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr "Arrêter de suivre l'artiste"
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr "Rafraîchir la liste"
|
||||
|
||||
msgctxt "#11028"
|
||||
msgid "Login details"
|
||||
msgstr "Détails de l'authentification"
|
||||
|
||||
msgctxt "#11030"
|
||||
msgid "Append artist name to song title"
|
||||
msgstr "Mettre l nom de l'artiste à la suite du titre de la chanson"
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr "Liste de lecture comme vue par défaut"
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr "Liste d'artistes comme vue par défaut"
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr "Liste d'albums comme vue par défaut"
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr "Liste de chansons comme vue par défaut"
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr "My recently played playlist"
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr "Gap between tracks when playing a playlist (secs)"
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr "Clear the plugin cache"
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr "Followed artists"
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr ""
|
||||
182
resources/language/resource.language.he_he/strings.po
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2017-09-28 14:10+0300\n"
|
||||
"Last-Translator: A. Dambledore\n"
|
||||
"Language-Team: Eng2Heb\n"
|
||||
"Language: he_IL\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 2.0.4\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr "שם משתמש"
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr "ססמה"
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr "שיחרורים חדשים"
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr "לשמור אל המוזיקה שלי"
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr "הסר מהמוזיקה שלי"
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr "עקוב"
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr "ביטול מעקב"
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr "השירים הכי טובים של האמן"
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr "אמנים קשורים"
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr "המוזיקה שלי"
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr "חקור"
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr "רשימות ניגון מומלצות"
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr "שיחרורים חדשים"
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr "הסר מרשימת ניגון"
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr "כל האלבומים עבור אמן"
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr "האמנים הכי מושמעים"
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr "השירים הכי מושמעים"
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr "עקוב אחר האמן"
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr "בטל עקיבה אחר האמן"
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr "רענן את הרישום"
|
||||
|
||||
msgctxt "#11028"
|
||||
msgid "Login details"
|
||||
msgstr "פרטי התחברות"
|
||||
|
||||
msgctxt "#11030"
|
||||
msgid "Append artist name to song title"
|
||||
msgstr "הוסף שם אמן לכותרת השיר"
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr "תצוגת ברירת המחדל עבור רשימות ניגון"
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr "תצוגת ברירת המחדל עבור רשימת האמנים"
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr "תצוגת ברירת המחדל עבור רשימת אלבומים"
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr "תצוגת ברירת המחדל עבור רשימת השירים"
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr "משתמש נוכחי"
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr ""
|
||||
"לא הוגדרו אישורי כניסה או שהחיבור נכשל.\n"
|
||||
"הזן את הפרטים שלך בתיבת הדו-שיח הגדרות."
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr "אודיו"
|
||||
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr "צפיות"
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr "My recently played playlist"
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr "Gap between tracks when playing a playlist (secs)"
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr "Clear the plugin cache"
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr "Followed artists"
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr ""
|
||||
BIN
resources/language/resource.language.nl_nl/strings.mo
Normal file
179
resources/language/resource.language.nl_nl/strings.po
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
# Kodi Media Center language file
|
||||
# Addon Name: Spotify
|
||||
# Addon id: plugin.audio.spotify
|
||||
# Addon Provider: marcelveldt
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Kodi-Addons\n"
|
||||
"Report-Msgid-Bugs-To: alanwww1@xbmc.org\n"
|
||||
"POT-Creation-Date: 2015-11-04 18:30+0100\n"
|
||||
"PO-Revision-Date: 2019-07-18 15:34+0200\n"
|
||||
"Last-Translator: logi85\n"
|
||||
"Language-Team: Dutch\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: nl\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 2.2.3\n"
|
||||
|
||||
msgctxt "#11001"
|
||||
msgid "Username"
|
||||
msgstr "Gebruikersnaam"
|
||||
|
||||
msgctxt "#11002"
|
||||
msgid "Password"
|
||||
msgstr "Wachtwoord"
|
||||
|
||||
msgctxt "#11005"
|
||||
msgid "New releases"
|
||||
msgstr "Nieuwe releases"
|
||||
|
||||
msgctxt "#11007"
|
||||
msgid "Save to My Music"
|
||||
msgstr "Opslaan naar Mijn Muziek"
|
||||
|
||||
msgctxt "#11008"
|
||||
msgid "Remove from My Music"
|
||||
msgstr "Verwijder uit Mijn Muziek"
|
||||
|
||||
msgctxt "#11009"
|
||||
msgid "Follow"
|
||||
msgstr "Volgen"
|
||||
|
||||
msgctxt "#11010"
|
||||
msgid "Unfollow"
|
||||
msgstr "Niet meer volgen"
|
||||
|
||||
msgctxt "#11011"
|
||||
msgid "Artist top tracks"
|
||||
msgstr "Artiest top-nummers"
|
||||
|
||||
msgctxt "#11012"
|
||||
msgid "Related artists"
|
||||
msgstr "Gerelateerde artiesten"
|
||||
|
||||
msgctxt "#11013"
|
||||
msgid "My Music"
|
||||
msgstr "Mijn Muziek"
|
||||
|
||||
msgctxt "#11014"
|
||||
msgid "Explore"
|
||||
msgstr "Verkennen"
|
||||
|
||||
msgctxt "#11015"
|
||||
msgid "Featured playlists"
|
||||
msgstr "Aanbevolen afspeellijsten"
|
||||
|
||||
msgctxt "#11016"
|
||||
msgid "New releases"
|
||||
msgstr "Nieuwe releases"
|
||||
|
||||
msgctxt "#11017"
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Verwijder uit afspeellijst"
|
||||
|
||||
msgctxt "#11018"
|
||||
msgid "All albums for artist"
|
||||
msgstr "Alle albums van artiest"
|
||||
|
||||
msgctxt "#11020"
|
||||
msgid "Default view for categories"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11023"
|
||||
msgid "Most played artists"
|
||||
msgstr "Meest afgespeelde artiesten"
|
||||
|
||||
msgctxt "#11024"
|
||||
msgid "Most played tracks"
|
||||
msgstr "Meest afgespeelde liedjes"
|
||||
|
||||
msgctxt "#11025"
|
||||
msgid "Follow artist"
|
||||
msgstr "Volg artiest"
|
||||
|
||||
msgctxt "#11026"
|
||||
msgid "Unfollow artist"
|
||||
msgstr "Artiest niet volgen"
|
||||
|
||||
msgctxt "#11027"
|
||||
msgid "Refresh listing"
|
||||
msgstr "Lijst vernieuwen"
|
||||
|
||||
msgctxt "#11036"
|
||||
msgid "Enable this device as Spotify Connect target (experimental)"
|
||||
msgstr "Schakel dit apparaat in als Spotify Connect doel (experimenteel)"
|
||||
|
||||
msgctxt "#11031"
|
||||
msgid "Default view for playlists"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11032"
|
||||
msgid "Default view for artist list"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11033"
|
||||
msgid "Default view for album list"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11034"
|
||||
msgid "Default view for song list"
|
||||
msgstr ""
|
||||
|
||||
msgctxt "#11047"
|
||||
msgid "Current user"
|
||||
msgstr "Huidige gebruiker"
|
||||
|
||||
msgctxt "#11050"
|
||||
msgid ""
|
||||
"Spotify login failed. Either no credentials have been set or the Spotify username or password is incorrect.\n"
|
||||
"Please check your username and password in the addon settings."
|
||||
msgstr ""
|
||||
"Er zijn geen inloggegevens gevonden of het inloggen faalt.\n"
|
||||
"Voer alsjeblieft je inloggegevens in in de plugin instellingen."
|
||||
|
||||
msgctxt "#11054"
|
||||
msgid "Audio"
|
||||
msgstr "Audio"
|
||||
|
||||
#, fuzzy
|
||||
msgctxt "#11055"
|
||||
msgid "Views"
|
||||
msgstr "Weergave"
|
||||
|
||||
msgctxt "#11069"
|
||||
msgid "My recently played playlist"
|
||||
msgstr "My recently played playlist"
|
||||
|
||||
msgctxt "#11070"
|
||||
msgid "Gap between tracks when playing a playlist (secs)"
|
||||
msgstr "Gap between tracks when playing a playlist (secs)"
|
||||
|
||||
msgctxt "#11071"
|
||||
msgid ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"To give better audio streaming from Spotify, a video http rule was just added to 'userdata/playercorefactory.xml'.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11072"
|
||||
msgid "Clear the plugin cache"
|
||||
msgstr "Clear the plugin cache"
|
||||
|
||||
msgctxt "#11073"
|
||||
msgid "Followed artists"
|
||||
msgstr "Followed artists"
|
||||
|
||||
msgctxt "#11074"
|
||||
msgid ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
msgstr ""
|
||||
"Successfully cleared the plugin cache database.\n"
|
||||
"Please restart Kodi for this to take affect."
|
||||
|
||||
msgctxt "#11075"
|
||||
msgid "Use Spotify normalization when playing tracks"
|
||||
msgstr ""
|
||||
50
resources/lib/__init__.py
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__)))
|
||||
|
||||
# IMPORTANT: The 'cherrypy' module cannot be imported as a submodule from 'httpproxy.py'.
|
||||
# I.e, 'from deps import cherrypy' will not work. Not sure why. So we do the following
|
||||
# path hack to put 'cherrypy' on the module search path:
|
||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__), "deps"))
|
||||
|
||||
|
||||
# import pkgutil
|
||||
|
||||
# def list_submodules(list_name, package_name):
|
||||
# for loader, module_name, is_pkg in pkgutil.walk_packages(
|
||||
# package_name.__path__, package_name.__name__ + "."
|
||||
# ):
|
||||
# list_name.append(module_name)
|
||||
# print(f"module_name 1 = {module_name}, is_pkg = {is_pkg}.")
|
||||
# try:
|
||||
# module_name = __import__(module_name, fromlist="dummylist")
|
||||
# except Exception as ex:
|
||||
# print(ex)
|
||||
# module_name = None
|
||||
# print(f"module_name 2 = {module_name}.")
|
||||
# if is_pkg:
|
||||
# list_submodules(list_name, module_name)
|
||||
#
|
||||
#
|
||||
# if len(sys.argv) != 2:
|
||||
# print("Usage: {} [PACKAGE-NAME]".format(os.path.basename(__file__)))
|
||||
# sys.exit(1)
|
||||
# else:
|
||||
# package_name = sys.argv[1]
|
||||
#
|
||||
# print(f"package_name = '{package_name}'.")
|
||||
# try:
|
||||
# package = __import__(package_name)
|
||||
# except ImportError:
|
||||
# print("Package {} not found...".format(package_name))
|
||||
# sys.exit(1)
|
||||
#
|
||||
# print(f"package.__path__ = '{package.__path__}'.")
|
||||
# print(f"package.__name__ = '{package.__name__}'.")
|
||||
#
|
||||
# all_modules = []
|
||||
# list_submodules(all_modules, package)
|
||||
#
|
||||
# print(f"all_modules = {all_modules}.")
|
||||
# sys.exit(1)
|
||||
61
resources/lib/bottle_manager.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
from wsgiref.simple_server import make_server
|
||||
|
||||
from bottle import app, request, HTTPResponse, Bottle
|
||||
import xbmc
|
||||
|
||||
import re
|
||||
|
||||
from librespot.core import Session
|
||||
from librespot.audio.decoders import AudioQuality, VorbisOnlyAudioQuality
|
||||
from librespot.metadata import TrackId
|
||||
|
||||
from utils import log_msg
|
||||
|
||||
class LibrespotServer(Bottle):
|
||||
def __init__(self, session: Session):
|
||||
super(LibrespotServer, self).__init__()
|
||||
self.session: Session = session
|
||||
self.route('/track/<track_id>', callback=self.stream)
|
||||
|
||||
# TODO: Make Range header work PLEASE I BEG
|
||||
|
||||
def stream(self, track_id):
|
||||
try:
|
||||
playabletrack_id = TrackId.from_uri(f"spotify:track:{track_id}")
|
||||
stream = self.session.content_feeder().load(
|
||||
playabletrack_id, VorbisOnlyAudioQuality(AudioQuality.NORMAL), False,
|
||||
None)
|
||||
start = 0
|
||||
end = stream.input_stream.size
|
||||
payload = stream.input_stream.stream()
|
||||
log_msg(stream.input_stream.size)
|
||||
# reqrange = request.get_header("range")
|
||||
# if reqrange is not None:
|
||||
# range_search = re.search(
|
||||
# "^bytes=(?P<start>[0-9]+?)-(?P<end>[0-9]+?)$",
|
||||
# reqrange)
|
||||
# if range_search is not None:
|
||||
# start = int(range_search.group("start"))
|
||||
# end = (int(range_search.group("end"))
|
||||
# if int(range_search.group("end")) <=
|
||||
# stream.input_stream.size else
|
||||
# stream.input_stream.size)
|
||||
# payload.skip(start)
|
||||
# else:
|
||||
# payload = stream
|
||||
response = HTTPResponse(body=payload)
|
||||
response.add_header('Content-Type', 'audio/ogg')
|
||||
# response.add_header('Accept-Ranges', 'bytes')
|
||||
# response.add_header("Content-Length", str(stream.input_stream.size).encode() if
|
||||
# stream.input_stream.size == end else "{}-{}/{}"
|
||||
# .format(start, end,
|
||||
# stream.input_stream.size).encode())
|
||||
return response
|
||||
except Exception as e:
|
||||
log_msg(e)
|
||||
|
||||
def start_thread(web_port: int) -> None:
|
||||
httpd = make_server('127.0.0.1', web_port, app)
|
||||
monitor = xbmc.Monitor()
|
||||
while not monitor.abortRequested():
|
||||
httpd.handle_request()
|
||||
154
resources/lib/defusedxml/ElementTree.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xml.etree.ElementTree facade
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
import sys
|
||||
import warnings
|
||||
from xml.etree.ElementTree import ParseError
|
||||
from xml.etree.ElementTree import TreeBuilder as _TreeBuilder
|
||||
from xml.etree.ElementTree import parse as _parse
|
||||
from xml.etree.ElementTree import tostring
|
||||
|
||||
from .common import PY3
|
||||
|
||||
if PY3:
|
||||
import importlib
|
||||
else:
|
||||
from xml.etree.ElementTree import XMLParser as _XMLParser
|
||||
from xml.etree.ElementTree import iterparse as _iterparse
|
||||
|
||||
|
||||
from .common import (
|
||||
DTDForbidden,
|
||||
EntitiesForbidden,
|
||||
ExternalReferenceForbidden,
|
||||
_generate_etree_functions,
|
||||
)
|
||||
|
||||
__origin__ = "xml.etree.ElementTree"
|
||||
|
||||
|
||||
def _get_py3_cls():
|
||||
"""Python 3.3 hides the pure Python code but defusedxml requires it.
|
||||
|
||||
The code is based on test.support.import_fresh_module().
|
||||
"""
|
||||
pymodname = "xml.etree.ElementTree"
|
||||
cmodname = "_elementtree"
|
||||
|
||||
pymod = sys.modules.pop(pymodname, None)
|
||||
cmod = sys.modules.pop(cmodname, None)
|
||||
|
||||
sys.modules[cmodname] = None
|
||||
try:
|
||||
pure_pymod = importlib.import_module(pymodname)
|
||||
finally:
|
||||
# restore module
|
||||
sys.modules[pymodname] = pymod
|
||||
if cmod is not None:
|
||||
sys.modules[cmodname] = cmod
|
||||
else:
|
||||
sys.modules.pop(cmodname, None)
|
||||
# restore attribute on original package
|
||||
etree_pkg = sys.modules["xml.etree"]
|
||||
if pymod is not None:
|
||||
etree_pkg.ElementTree = pymod
|
||||
elif hasattr(etree_pkg, "ElementTree"):
|
||||
del etree_pkg.ElementTree
|
||||
|
||||
_XMLParser = pure_pymod.XMLParser
|
||||
_iterparse = pure_pymod.iterparse
|
||||
# patch pure module to use ParseError from C extension
|
||||
pure_pymod.ParseError = ParseError
|
||||
|
||||
return _XMLParser, _iterparse
|
||||
|
||||
|
||||
if PY3:
|
||||
_XMLParser, _iterparse = _get_py3_cls()
|
||||
|
||||
|
||||
_sentinel = object()
|
||||
|
||||
|
||||
class DefusedXMLParser(_XMLParser):
|
||||
def __init__(
|
||||
self,
|
||||
html=_sentinel,
|
||||
target=None,
|
||||
encoding=None,
|
||||
forbid_dtd=False,
|
||||
forbid_entities=True,
|
||||
forbid_external=True,
|
||||
):
|
||||
# Python 2.x old style class
|
||||
_XMLParser.__init__(self, target=target, encoding=encoding)
|
||||
if html is not _sentinel:
|
||||
# the 'html' argument has been deprecated and ignored in all
|
||||
# supported versions of Python. Python 3.8 finally removed it.
|
||||
if html:
|
||||
raise TypeError("'html=True' is no longer supported.")
|
||||
else:
|
||||
warnings.warn(
|
||||
"'html' keyword argument is no longer supported. Pass "
|
||||
"in arguments as keyword arguments.",
|
||||
category=DeprecationWarning,
|
||||
)
|
||||
|
||||
self.forbid_dtd = forbid_dtd
|
||||
self.forbid_entities = forbid_entities
|
||||
self.forbid_external = forbid_external
|
||||
if PY3:
|
||||
parser = self.parser
|
||||
else:
|
||||
parser = self._parser
|
||||
if self.forbid_dtd:
|
||||
parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl
|
||||
if self.forbid_entities:
|
||||
parser.EntityDeclHandler = self.defused_entity_decl
|
||||
parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl
|
||||
if self.forbid_external:
|
||||
parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler
|
||||
|
||||
def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset):
|
||||
raise DTDForbidden(name, sysid, pubid)
|
||||
|
||||
def defused_entity_decl(
|
||||
self, name, is_parameter_entity, value, base, sysid, pubid, notation_name
|
||||
):
|
||||
raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name)
|
||||
|
||||
def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
|
||||
# expat 1.2
|
||||
raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover
|
||||
|
||||
def defused_external_entity_ref_handler(self, context, base, sysid, pubid):
|
||||
raise ExternalReferenceForbidden(context, base, sysid, pubid)
|
||||
|
||||
|
||||
# aliases
|
||||
# XMLParse is a typo, keep it for backwards compatibility
|
||||
XMLTreeBuilder = XMLParse = XMLParser = DefusedXMLParser
|
||||
|
||||
parse, iterparse, fromstring = _generate_etree_functions(
|
||||
DefusedXMLParser, _TreeBuilder, _parse, _iterparse
|
||||
)
|
||||
XML = fromstring
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ParseError",
|
||||
"XML",
|
||||
"XMLParse",
|
||||
"XMLParser",
|
||||
"XMLTreeBuilder",
|
||||
"fromstring",
|
||||
"iterparse",
|
||||
"parse",
|
||||
"tostring",
|
||||
]
|
||||
67
resources/lib/defusedxml/__init__.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defuse XML bomb denial of service vulnerabilities
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from .common import (
|
||||
DefusedXmlException,
|
||||
DTDForbidden,
|
||||
EntitiesForbidden,
|
||||
ExternalReferenceForbidden,
|
||||
NotSupportedError,
|
||||
_apply_defusing,
|
||||
)
|
||||
|
||||
|
||||
def defuse_stdlib():
|
||||
"""Monkey patch and defuse all stdlib packages
|
||||
|
||||
:warning: The monkey patch is an EXPERIMETNAL feature.
|
||||
"""
|
||||
defused = {}
|
||||
|
||||
with warnings.catch_warnings():
|
||||
from . import cElementTree
|
||||
from . import ElementTree
|
||||
from . import minidom
|
||||
from . import pulldom
|
||||
from . import sax
|
||||
from . import expatbuilder
|
||||
from . import expatreader
|
||||
from . import xmlrpc
|
||||
|
||||
xmlrpc.monkey_patch()
|
||||
defused[xmlrpc] = None
|
||||
|
||||
defused_mods = [
|
||||
cElementTree,
|
||||
ElementTree,
|
||||
minidom,
|
||||
pulldom,
|
||||
sax,
|
||||
expatbuilder,
|
||||
expatreader,
|
||||
]
|
||||
|
||||
for defused_mod in defused_mods:
|
||||
stdlib_mod = _apply_defusing(defused_mod)
|
||||
defused[defused_mod] = stdlib_mod
|
||||
|
||||
return defused
|
||||
|
||||
|
||||
__version__ = "0.7.1"
|
||||
|
||||
__all__ = [
|
||||
"DefusedXmlException",
|
||||
"DTDForbidden",
|
||||
"EntitiesForbidden",
|
||||
"ExternalReferenceForbidden",
|
||||
"NotSupportedError",
|
||||
]
|
||||
62
resources/lib/defusedxml/cElementTree.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xml.etree.cElementTree
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from .common import _generate_etree_functions
|
||||
|
||||
from xml.etree.cElementTree import TreeBuilder as _TreeBuilder
|
||||
from xml.etree.cElementTree import parse as _parse
|
||||
from xml.etree.cElementTree import tostring
|
||||
|
||||
# iterparse from ElementTree!
|
||||
from xml.etree.ElementTree import iterparse as _iterparse
|
||||
|
||||
# This module is an alias for ElementTree just like xml.etree.cElementTree
|
||||
from .ElementTree import (
|
||||
XML,
|
||||
XMLParse,
|
||||
XMLParser,
|
||||
XMLTreeBuilder,
|
||||
fromstring,
|
||||
iterparse,
|
||||
parse,
|
||||
tostring,
|
||||
DefusedXMLParser,
|
||||
ParseError,
|
||||
)
|
||||
|
||||
__origin__ = "xml.etree.cElementTree"
|
||||
|
||||
|
||||
warnings.warn(
|
||||
"defusedxml.cElementTree is deprecated, import from defusedxml.ElementTree instead.",
|
||||
category=DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
# XMLParse is a typo, keep it for backwards compatibility
|
||||
XMLTreeBuilder = XMLParse = XMLParser = DefusedXMLParser
|
||||
|
||||
parse, iterparse, fromstring = _generate_etree_functions(
|
||||
DefusedXMLParser, _TreeBuilder, _parse, _iterparse
|
||||
)
|
||||
XML = fromstring
|
||||
|
||||
__all__ = [
|
||||
"ParseError",
|
||||
"XML",
|
||||
"XMLParse",
|
||||
"XMLParser",
|
||||
"XMLTreeBuilder",
|
||||
"fromstring",
|
||||
"iterparse",
|
||||
"parse",
|
||||
"tostring",
|
||||
]
|
||||
129
resources/lib/defusedxml/common.py
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Common constants, exceptions and helpe functions
|
||||
"""
|
||||
import sys
|
||||
import xml.parsers.expat
|
||||
|
||||
PY3 = sys.version_info[0] == 3
|
||||
|
||||
# Fail early when pyexpat is not installed correctly
|
||||
if not hasattr(xml.parsers.expat, "ParserCreate"):
|
||||
raise ImportError("pyexpat") # pragma: no cover
|
||||
|
||||
|
||||
class DefusedXmlException(ValueError):
|
||||
"""Base exception"""
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
|
||||
class DTDForbidden(DefusedXmlException):
|
||||
"""Document type definition is forbidden"""
|
||||
|
||||
def __init__(self, name, sysid, pubid):
|
||||
super(DTDForbidden, self).__init__()
|
||||
self.name = name
|
||||
self.sysid = sysid
|
||||
self.pubid = pubid
|
||||
|
||||
def __str__(self):
|
||||
tpl = "DTDForbidden(name='{}', system_id={!r}, public_id={!r})"
|
||||
return tpl.format(self.name, self.sysid, self.pubid)
|
||||
|
||||
|
||||
class EntitiesForbidden(DefusedXmlException):
|
||||
"""Entity definition is forbidden"""
|
||||
|
||||
def __init__(self, name, value, base, sysid, pubid, notation_name):
|
||||
super(EntitiesForbidden, self).__init__()
|
||||
self.name = name
|
||||
self.value = value
|
||||
self.base = base
|
||||
self.sysid = sysid
|
||||
self.pubid = pubid
|
||||
self.notation_name = notation_name
|
||||
|
||||
def __str__(self):
|
||||
tpl = "EntitiesForbidden(name='{}', system_id={!r}, public_id={!r})"
|
||||
return tpl.format(self.name, self.sysid, self.pubid)
|
||||
|
||||
|
||||
class ExternalReferenceForbidden(DefusedXmlException):
|
||||
"""Resolving an external reference is forbidden"""
|
||||
|
||||
def __init__(self, context, base, sysid, pubid):
|
||||
super(ExternalReferenceForbidden, self).__init__()
|
||||
self.context = context
|
||||
self.base = base
|
||||
self.sysid = sysid
|
||||
self.pubid = pubid
|
||||
|
||||
def __str__(self):
|
||||
tpl = "ExternalReferenceForbidden(system_id='{}', public_id={})"
|
||||
return tpl.format(self.sysid, self.pubid)
|
||||
|
||||
|
||||
class NotSupportedError(DefusedXmlException):
|
||||
"""The operation is not supported"""
|
||||
|
||||
|
||||
def _apply_defusing(defused_mod):
|
||||
assert defused_mod is sys.modules[defused_mod.__name__]
|
||||
stdlib_name = defused_mod.__origin__
|
||||
__import__(stdlib_name, {}, {}, ["*"])
|
||||
stdlib_mod = sys.modules[stdlib_name]
|
||||
stdlib_names = set(dir(stdlib_mod))
|
||||
for name, obj in vars(defused_mod).items():
|
||||
if name.startswith("_") or name not in stdlib_names:
|
||||
continue
|
||||
setattr(stdlib_mod, name, obj)
|
||||
return stdlib_mod
|
||||
|
||||
|
||||
def _generate_etree_functions(DefusedXMLParser, _TreeBuilder, _parse, _iterparse):
|
||||
"""Factory for functions needed by etree, dependent on whether
|
||||
cElementTree or ElementTree is used."""
|
||||
|
||||
def parse(source, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True):
|
||||
if parser is None:
|
||||
parser = DefusedXMLParser(
|
||||
target=_TreeBuilder(),
|
||||
forbid_dtd=forbid_dtd,
|
||||
forbid_entities=forbid_entities,
|
||||
forbid_external=forbid_external,
|
||||
)
|
||||
return _parse(source, parser)
|
||||
|
||||
def iterparse(
|
||||
source,
|
||||
events=None,
|
||||
parser=None,
|
||||
forbid_dtd=False,
|
||||
forbid_entities=True,
|
||||
forbid_external=True,
|
||||
):
|
||||
if parser is None:
|
||||
parser = DefusedXMLParser(
|
||||
target=_TreeBuilder(),
|
||||
forbid_dtd=forbid_dtd,
|
||||
forbid_entities=forbid_entities,
|
||||
forbid_external=forbid_external,
|
||||
)
|
||||
return _iterparse(source, events, parser)
|
||||
|
||||
def fromstring(text, forbid_dtd=False, forbid_entities=True, forbid_external=True):
|
||||
parser = DefusedXMLParser(
|
||||
target=_TreeBuilder(),
|
||||
forbid_dtd=forbid_dtd,
|
||||
forbid_entities=forbid_entities,
|
||||
forbid_external=forbid_external,
|
||||
)
|
||||
parser.feed(text)
|
||||
return parser.close()
|
||||
|
||||
return parse, iterparse, fromstring
|
||||
107
resources/lib/defusedxml/expatbuilder.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xml.dom.expatbuilder
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
from xml.dom.expatbuilder import ExpatBuilder as _ExpatBuilder
|
||||
from xml.dom.expatbuilder import Namespaces as _Namespaces
|
||||
|
||||
from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden
|
||||
|
||||
__origin__ = "xml.dom.expatbuilder"
|
||||
|
||||
|
||||
class DefusedExpatBuilder(_ExpatBuilder):
|
||||
"""Defused document builder"""
|
||||
|
||||
def __init__(
|
||||
self, options=None, forbid_dtd=False, forbid_entities=True, forbid_external=True
|
||||
):
|
||||
_ExpatBuilder.__init__(self, options)
|
||||
self.forbid_dtd = forbid_dtd
|
||||
self.forbid_entities = forbid_entities
|
||||
self.forbid_external = forbid_external
|
||||
|
||||
def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset):
|
||||
raise DTDForbidden(name, sysid, pubid)
|
||||
|
||||
def defused_entity_decl(
|
||||
self, name, is_parameter_entity, value, base, sysid, pubid, notation_name
|
||||
):
|
||||
raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name)
|
||||
|
||||
def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
|
||||
# expat 1.2
|
||||
raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover
|
||||
|
||||
def defused_external_entity_ref_handler(self, context, base, sysid, pubid):
|
||||
raise ExternalReferenceForbidden(context, base, sysid, pubid)
|
||||
|
||||
def install(self, parser):
|
||||
_ExpatBuilder.install(self, parser)
|
||||
|
||||
if self.forbid_dtd:
|
||||
parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl
|
||||
if self.forbid_entities:
|
||||
# if self._options.entities:
|
||||
parser.EntityDeclHandler = self.defused_entity_decl
|
||||
parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl
|
||||
if self.forbid_external:
|
||||
parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler
|
||||
|
||||
|
||||
class DefusedExpatBuilderNS(_Namespaces, DefusedExpatBuilder):
|
||||
"""Defused document builder that supports namespaces."""
|
||||
|
||||
def install(self, parser):
|
||||
DefusedExpatBuilder.install(self, parser)
|
||||
if self._options.namespace_declarations:
|
||||
parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler
|
||||
|
||||
def reset(self):
|
||||
DefusedExpatBuilder.reset(self)
|
||||
self._initNamespaces()
|
||||
|
||||
|
||||
def parse(file, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True):
|
||||
"""Parse a document, returning the resulting Document node.
|
||||
|
||||
'file' may be either a file name or an open file object.
|
||||
"""
|
||||
if namespaces:
|
||||
build_builder = DefusedExpatBuilderNS
|
||||
else:
|
||||
build_builder = DefusedExpatBuilder
|
||||
builder = build_builder(
|
||||
forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external
|
||||
)
|
||||
|
||||
if isinstance(file, str):
|
||||
fp = open(file, "rb")
|
||||
try:
|
||||
result = builder.parseFile(fp)
|
||||
finally:
|
||||
fp.close()
|
||||
else:
|
||||
result = builder.parseFile(file)
|
||||
return result
|
||||
|
||||
|
||||
def parseString(
|
||||
string, namespaces=True, forbid_dtd=False, forbid_entities=True, forbid_external=True
|
||||
):
|
||||
"""Parse a document from a string, returning the resulting
|
||||
Document node.
|
||||
"""
|
||||
if namespaces:
|
||||
build_builder = DefusedExpatBuilderNS
|
||||
else:
|
||||
build_builder = DefusedExpatBuilder
|
||||
builder = build_builder(
|
||||
forbid_dtd=forbid_dtd, forbid_entities=forbid_entities, forbid_external=forbid_external
|
||||
)
|
||||
return builder.parseString(string)
|
||||
61
resources/lib/defusedxml/expatreader.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xml.sax.expatreader
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
from xml.sax.expatreader import ExpatParser as _ExpatParser
|
||||
|
||||
from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden
|
||||
|
||||
__origin__ = "xml.sax.expatreader"
|
||||
|
||||
|
||||
class DefusedExpatParser(_ExpatParser):
|
||||
"""Defused SAX driver for the pyexpat C module."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
namespaceHandling=0,
|
||||
bufsize=2 ** 16 - 20,
|
||||
forbid_dtd=False,
|
||||
forbid_entities=True,
|
||||
forbid_external=True,
|
||||
):
|
||||
_ExpatParser.__init__(self, namespaceHandling, bufsize)
|
||||
self.forbid_dtd = forbid_dtd
|
||||
self.forbid_entities = forbid_entities
|
||||
self.forbid_external = forbid_external
|
||||
|
||||
def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset):
|
||||
raise DTDForbidden(name, sysid, pubid)
|
||||
|
||||
def defused_entity_decl(
|
||||
self, name, is_parameter_entity, value, base, sysid, pubid, notation_name
|
||||
):
|
||||
raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name)
|
||||
|
||||
def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
|
||||
# expat 1.2
|
||||
raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover
|
||||
|
||||
def defused_external_entity_ref_handler(self, context, base, sysid, pubid):
|
||||
raise ExternalReferenceForbidden(context, base, sysid, pubid)
|
||||
|
||||
def reset(self):
|
||||
_ExpatParser.reset(self)
|
||||
parser = self._parser
|
||||
if self.forbid_dtd:
|
||||
parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl
|
||||
if self.forbid_entities:
|
||||
parser.EntityDeclHandler = self.defused_entity_decl
|
||||
parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl
|
||||
if self.forbid_external:
|
||||
parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler
|
||||
|
||||
|
||||
def create_parser(*args, **kwargs):
|
||||
return DefusedExpatParser(*args, **kwargs)
|
||||
153
resources/lib/defusedxml/lxml.py
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""DEPRECATED Example code for lxml.etree protection
|
||||
|
||||
The code has NO protection against decompression bombs.
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
import threading
|
||||
import warnings
|
||||
|
||||
from lxml import etree as _etree
|
||||
|
||||
from .common import DTDForbidden, EntitiesForbidden, NotSupportedError
|
||||
|
||||
LXML3 = _etree.LXML_VERSION[0] >= 3
|
||||
|
||||
__origin__ = "lxml.etree"
|
||||
|
||||
tostring = _etree.tostring
|
||||
|
||||
|
||||
warnings.warn(
|
||||
"defusedxml.lxml is no longer supported and will be removed in a future release.",
|
||||
category=DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
|
||||
class RestrictedElement(_etree.ElementBase):
|
||||
"""A restricted Element class that filters out instances of some classes"""
|
||||
|
||||
__slots__ = ()
|
||||
# blacklist = (etree._Entity, etree._ProcessingInstruction, etree._Comment)
|
||||
blacklist = _etree._Entity
|
||||
|
||||
def _filter(self, iterator):
|
||||
blacklist = self.blacklist
|
||||
for child in iterator:
|
||||
if isinstance(child, blacklist):
|
||||
continue
|
||||
yield child
|
||||
|
||||
def __iter__(self):
|
||||
iterator = super(RestrictedElement, self).__iter__()
|
||||
return self._filter(iterator)
|
||||
|
||||
def iterchildren(self, tag=None, reversed=False):
|
||||
iterator = super(RestrictedElement, self).iterchildren(tag=tag, reversed=reversed)
|
||||
return self._filter(iterator)
|
||||
|
||||
def iter(self, tag=None, *tags):
|
||||
iterator = super(RestrictedElement, self).iter(tag=tag, *tags)
|
||||
return self._filter(iterator)
|
||||
|
||||
def iterdescendants(self, tag=None, *tags):
|
||||
iterator = super(RestrictedElement, self).iterdescendants(tag=tag, *tags)
|
||||
return self._filter(iterator)
|
||||
|
||||
def itersiblings(self, tag=None, preceding=False):
|
||||
iterator = super(RestrictedElement, self).itersiblings(tag=tag, preceding=preceding)
|
||||
return self._filter(iterator)
|
||||
|
||||
def getchildren(self):
|
||||
iterator = super(RestrictedElement, self).__iter__()
|
||||
return list(self._filter(iterator))
|
||||
|
||||
def getiterator(self, tag=None):
|
||||
iterator = super(RestrictedElement, self).getiterator(tag)
|
||||
return self._filter(iterator)
|
||||
|
||||
|
||||
class GlobalParserTLS(threading.local):
|
||||
"""Thread local context for custom parser instances"""
|
||||
|
||||
parser_config = {
|
||||
"resolve_entities": False,
|
||||
# 'remove_comments': True,
|
||||
# 'remove_pis': True,
|
||||
}
|
||||
|
||||
element_class = RestrictedElement
|
||||
|
||||
def createDefaultParser(self):
|
||||
parser = _etree.XMLParser(**self.parser_config)
|
||||
element_class = self.element_class
|
||||
if self.element_class is not None:
|
||||
lookup = _etree.ElementDefaultClassLookup(element=element_class)
|
||||
parser.set_element_class_lookup(lookup)
|
||||
return parser
|
||||
|
||||
def setDefaultParser(self, parser):
|
||||
self._default_parser = parser
|
||||
|
||||
def getDefaultParser(self):
|
||||
parser = getattr(self, "_default_parser", None)
|
||||
if parser is None:
|
||||
parser = self.createDefaultParser()
|
||||
self.setDefaultParser(parser)
|
||||
return parser
|
||||
|
||||
|
||||
_parser_tls = GlobalParserTLS()
|
||||
getDefaultParser = _parser_tls.getDefaultParser
|
||||
|
||||
|
||||
def check_docinfo(elementtree, forbid_dtd=False, forbid_entities=True):
|
||||
"""Check docinfo of an element tree for DTD and entity declarations
|
||||
|
||||
The check for entity declarations needs lxml 3 or newer. lxml 2.x does
|
||||
not support dtd.iterentities().
|
||||
"""
|
||||
docinfo = elementtree.docinfo
|
||||
if docinfo.doctype:
|
||||
if forbid_dtd:
|
||||
raise DTDForbidden(docinfo.doctype, docinfo.system_url, docinfo.public_id)
|
||||
if forbid_entities and not LXML3:
|
||||
# lxml < 3 has no iterentities()
|
||||
raise NotSupportedError("Unable to check for entity declarations " "in lxml 2.x")
|
||||
|
||||
if forbid_entities:
|
||||
for dtd in docinfo.internalDTD, docinfo.externalDTD:
|
||||
if dtd is None:
|
||||
continue
|
||||
for entity in dtd.iterentities():
|
||||
raise EntitiesForbidden(entity.name, entity.content, None, None, None, None)
|
||||
|
||||
|
||||
def parse(source, parser=None, base_url=None, forbid_dtd=False, forbid_entities=True):
|
||||
if parser is None:
|
||||
parser = getDefaultParser()
|
||||
elementtree = _etree.parse(source, parser, base_url=base_url)
|
||||
check_docinfo(elementtree, forbid_dtd, forbid_entities)
|
||||
return elementtree
|
||||
|
||||
|
||||
def fromstring(text, parser=None, base_url=None, forbid_dtd=False, forbid_entities=True):
|
||||
if parser is None:
|
||||
parser = getDefaultParser()
|
||||
rootelement = _etree.fromstring(text, parser, base_url=base_url)
|
||||
elementtree = rootelement.getroottree()
|
||||
check_docinfo(elementtree, forbid_dtd, forbid_entities)
|
||||
return rootelement
|
||||
|
||||
|
||||
XML = fromstring
|
||||
|
||||
|
||||
def iterparse(*args, **kwargs):
|
||||
raise NotSupportedError("defused lxml.etree.iterparse not available")
|
||||
63
resources/lib/defusedxml/minidom.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xml.dom.minidom
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
from xml.dom.minidom import _do_pulldom_parse
|
||||
from . import expatbuilder as _expatbuilder
|
||||
from . import pulldom as _pulldom
|
||||
|
||||
__origin__ = "xml.dom.minidom"
|
||||
|
||||
|
||||
def parse(
|
||||
file, parser=None, bufsize=None, forbid_dtd=False, forbid_entities=True, forbid_external=True
|
||||
):
|
||||
"""Parse a file into a DOM by filename or file object."""
|
||||
if parser is None and not bufsize:
|
||||
return _expatbuilder.parse(
|
||||
file,
|
||||
forbid_dtd=forbid_dtd,
|
||||
forbid_entities=forbid_entities,
|
||||
forbid_external=forbid_external,
|
||||
)
|
||||
else:
|
||||
return _do_pulldom_parse(
|
||||
_pulldom.parse,
|
||||
(file,),
|
||||
{
|
||||
"parser": parser,
|
||||
"bufsize": bufsize,
|
||||
"forbid_dtd": forbid_dtd,
|
||||
"forbid_entities": forbid_entities,
|
||||
"forbid_external": forbid_external,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def parseString(
|
||||
string, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True
|
||||
):
|
||||
"""Parse a file into a DOM from a string."""
|
||||
if parser is None:
|
||||
return _expatbuilder.parseString(
|
||||
string,
|
||||
forbid_dtd=forbid_dtd,
|
||||
forbid_entities=forbid_entities,
|
||||
forbid_external=forbid_external,
|
||||
)
|
||||
else:
|
||||
return _do_pulldom_parse(
|
||||
_pulldom.parseString,
|
||||
(string,),
|
||||
{
|
||||
"parser": parser,
|
||||
"forbid_dtd": forbid_dtd,
|
||||
"forbid_entities": forbid_entities,
|
||||
"forbid_external": forbid_external,
|
||||
},
|
||||
)
|
||||
41
resources/lib/defusedxml/pulldom.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xml.dom.pulldom
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
from xml.dom.pulldom import parse as _parse
|
||||
from xml.dom.pulldom import parseString as _parseString
|
||||
from .sax import make_parser
|
||||
|
||||
__origin__ = "xml.dom.pulldom"
|
||||
|
||||
|
||||
def parse(
|
||||
stream_or_string,
|
||||
parser=None,
|
||||
bufsize=None,
|
||||
forbid_dtd=False,
|
||||
forbid_entities=True,
|
||||
forbid_external=True,
|
||||
):
|
||||
if parser is None:
|
||||
parser = make_parser()
|
||||
parser.forbid_dtd = forbid_dtd
|
||||
parser.forbid_entities = forbid_entities
|
||||
parser.forbid_external = forbid_external
|
||||
return _parse(stream_or_string, parser, bufsize)
|
||||
|
||||
|
||||
def parseString(
|
||||
string, parser=None, forbid_dtd=False, forbid_entities=True, forbid_external=True
|
||||
):
|
||||
if parser is None:
|
||||
parser = make_parser()
|
||||
parser.forbid_dtd = forbid_dtd
|
||||
parser.forbid_entities = forbid_entities
|
||||
parser.forbid_external = forbid_external
|
||||
return _parseString(string, parser)
|
||||
60
resources/lib/defusedxml/sax.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xml.sax
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
from xml.sax import InputSource as _InputSource
|
||||
from xml.sax import ErrorHandler as _ErrorHandler
|
||||
|
||||
from . import expatreader
|
||||
|
||||
__origin__ = "xml.sax"
|
||||
|
||||
|
||||
def parse(
|
||||
source,
|
||||
handler,
|
||||
errorHandler=_ErrorHandler(),
|
||||
forbid_dtd=False,
|
||||
forbid_entities=True,
|
||||
forbid_external=True,
|
||||
):
|
||||
parser = make_parser()
|
||||
parser.setContentHandler(handler)
|
||||
parser.setErrorHandler(errorHandler)
|
||||
parser.forbid_dtd = forbid_dtd
|
||||
parser.forbid_entities = forbid_entities
|
||||
parser.forbid_external = forbid_external
|
||||
parser.parse(source)
|
||||
|
||||
|
||||
def parseString(
|
||||
string,
|
||||
handler,
|
||||
errorHandler=_ErrorHandler(),
|
||||
forbid_dtd=False,
|
||||
forbid_entities=True,
|
||||
forbid_external=True,
|
||||
):
|
||||
from io import BytesIO
|
||||
|
||||
if errorHandler is None:
|
||||
errorHandler = _ErrorHandler()
|
||||
parser = make_parser()
|
||||
parser.setContentHandler(handler)
|
||||
parser.setErrorHandler(errorHandler)
|
||||
parser.forbid_dtd = forbid_dtd
|
||||
parser.forbid_entities = forbid_entities
|
||||
parser.forbid_external = forbid_external
|
||||
|
||||
inpsrc = _InputSource()
|
||||
inpsrc.setByteStream(BytesIO(string))
|
||||
parser.parse(inpsrc)
|
||||
|
||||
|
||||
def make_parser(parser_list=[]):
|
||||
return expatreader.create_parser()
|
||||
153
resources/lib/defusedxml/xmlrpc.py
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
# defusedxml
|
||||
#
|
||||
# Copyright (c) 2013 by Christian Heimes <christian@python.org>
|
||||
# Licensed to PSF under a Contributor Agreement.
|
||||
# See https://www.python.org/psf/license for licensing details.
|
||||
"""Defused xmlrpclib
|
||||
|
||||
Also defuses gzip bomb
|
||||
"""
|
||||
from __future__ import print_function, absolute_import
|
||||
|
||||
import io
|
||||
|
||||
from .common import DTDForbidden, EntitiesForbidden, ExternalReferenceForbidden, PY3
|
||||
|
||||
if PY3:
|
||||
__origin__ = "xmlrpc.client"
|
||||
from xmlrpc.client import ExpatParser
|
||||
from xmlrpc import client as xmlrpc_client
|
||||
from xmlrpc import server as xmlrpc_server
|
||||
from xmlrpc.client import gzip_decode as _orig_gzip_decode
|
||||
from xmlrpc.client import GzipDecodedResponse as _OrigGzipDecodedResponse
|
||||
else:
|
||||
__origin__ = "xmlrpclib"
|
||||
from xmlrpclib import ExpatParser
|
||||
import xmlrpclib as xmlrpc_client
|
||||
|
||||
xmlrpc_server = None
|
||||
from xmlrpclib import gzip_decode as _orig_gzip_decode
|
||||
from xmlrpclib import GzipDecodedResponse as _OrigGzipDecodedResponse
|
||||
|
||||
try:
|
||||
import gzip
|
||||
except ImportError: # pragma: no cover
|
||||
gzip = None
|
||||
|
||||
|
||||
# Limit maximum request size to prevent resource exhaustion DoS
|
||||
# Also used to limit maximum amount of gzip decoded data in order to prevent
|
||||
# decompression bombs
|
||||
# A value of -1 or smaller disables the limit
|
||||
MAX_DATA = 30 * 1024 * 1024 # 30 MB
|
||||
|
||||
|
||||
def defused_gzip_decode(data, limit=None):
|
||||
"""gzip encoded data -> unencoded data
|
||||
|
||||
Decode data using the gzip content encoding as described in RFC 1952
|
||||
"""
|
||||
if not gzip: # pragma: no cover
|
||||
raise NotImplementedError
|
||||
if limit is None:
|
||||
limit = MAX_DATA
|
||||
f = io.BytesIO(data)
|
||||
gzf = gzip.GzipFile(mode="rb", fileobj=f)
|
||||
try:
|
||||
if limit < 0: # no limit
|
||||
decoded = gzf.read()
|
||||
else:
|
||||
decoded = gzf.read(limit + 1)
|
||||
except IOError: # pragma: no cover
|
||||
raise ValueError("invalid data")
|
||||
f.close()
|
||||
gzf.close()
|
||||
if limit >= 0 and len(decoded) > limit:
|
||||
raise ValueError("max gzipped payload length exceeded")
|
||||
return decoded
|
||||
|
||||
|
||||
class DefusedGzipDecodedResponse(gzip.GzipFile if gzip else object):
|
||||
"""a file-like object to decode a response encoded with the gzip
|
||||
method, as described in RFC 1952.
|
||||
"""
|
||||
|
||||
def __init__(self, response, limit=None):
|
||||
# response doesn't support tell() and read(), required by
|
||||
# GzipFile
|
||||
if not gzip: # pragma: no cover
|
||||
raise NotImplementedError
|
||||
self.limit = limit = limit if limit is not None else MAX_DATA
|
||||
if limit < 0: # no limit
|
||||
data = response.read()
|
||||
self.readlength = None
|
||||
else:
|
||||
data = response.read(limit + 1)
|
||||
self.readlength = 0
|
||||
if limit >= 0 and len(data) > limit:
|
||||
raise ValueError("max payload length exceeded")
|
||||
self.stringio = io.BytesIO(data)
|
||||
gzip.GzipFile.__init__(self, mode="rb", fileobj=self.stringio)
|
||||
|
||||
def read(self, n):
|
||||
if self.limit >= 0:
|
||||
left = self.limit - self.readlength
|
||||
n = min(n, left + 1)
|
||||
data = gzip.GzipFile.read(self, n)
|
||||
self.readlength += len(data)
|
||||
if self.readlength > self.limit:
|
||||
raise ValueError("max payload length exceeded")
|
||||
return data
|
||||
else:
|
||||
return gzip.GzipFile.read(self, n)
|
||||
|
||||
def close(self):
|
||||
gzip.GzipFile.close(self)
|
||||
self.stringio.close()
|
||||
|
||||
|
||||
class DefusedExpatParser(ExpatParser):
|
||||
def __init__(self, target, forbid_dtd=False, forbid_entities=True, forbid_external=True):
|
||||
ExpatParser.__init__(self, target)
|
||||
self.forbid_dtd = forbid_dtd
|
||||
self.forbid_entities = forbid_entities
|
||||
self.forbid_external = forbid_external
|
||||
parser = self._parser
|
||||
if self.forbid_dtd:
|
||||
parser.StartDoctypeDeclHandler = self.defused_start_doctype_decl
|
||||
if self.forbid_entities:
|
||||
parser.EntityDeclHandler = self.defused_entity_decl
|
||||
parser.UnparsedEntityDeclHandler = self.defused_unparsed_entity_decl
|
||||
if self.forbid_external:
|
||||
parser.ExternalEntityRefHandler = self.defused_external_entity_ref_handler
|
||||
|
||||
def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset):
|
||||
raise DTDForbidden(name, sysid, pubid)
|
||||
|
||||
def defused_entity_decl(
|
||||
self, name, is_parameter_entity, value, base, sysid, pubid, notation_name
|
||||
):
|
||||
raise EntitiesForbidden(name, value, base, sysid, pubid, notation_name)
|
||||
|
||||
def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):
|
||||
# expat 1.2
|
||||
raise EntitiesForbidden(name, None, base, sysid, pubid, notation_name) # pragma: no cover
|
||||
|
||||
def defused_external_entity_ref_handler(self, context, base, sysid, pubid):
|
||||
raise ExternalReferenceForbidden(context, base, sysid, pubid)
|
||||
|
||||
|
||||
def monkey_patch():
|
||||
xmlrpc_client.FastParser = DefusedExpatParser
|
||||
xmlrpc_client.GzipDecodedResponse = DefusedGzipDecodedResponse
|
||||
xmlrpc_client.gzip_decode = defused_gzip_decode
|
||||
if xmlrpc_server:
|
||||
xmlrpc_server.gzip_decode = defused_gzip_decode
|
||||
|
||||
|
||||
def unmonkey_patch():
|
||||
xmlrpc_client.FastParser = None
|
||||
xmlrpc_client.GzipDecodedResponse = _OrigGzipDecodedResponse
|
||||
xmlrpc_client.gzip_decode = _orig_gzip_decode
|
||||
if xmlrpc_server:
|
||||
xmlrpc_server.gzip_decode = _orig_gzip_decode
|
||||
4
resources/lib/deps/__init__.py
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(1, os.path.join(os.path.dirname(__file__)))
|
||||
4417
resources/lib/deps/bottle.py
Executable file
307
resources/lib/deps/simplecache.py
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''provides a simple stateless caching system for Kodi addons and plugins'''
|
||||
|
||||
import sys
|
||||
import xbmcvfs
|
||||
import xbmcgui
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import datetime
|
||||
import time
|
||||
import sqlite3
|
||||
import json
|
||||
from functools import reduce
|
||||
|
||||
class SimpleCache(object):
|
||||
'''simple stateless caching system for Kodi'''
|
||||
enable_mem_cache = True
|
||||
data_is_json = False
|
||||
global_checksum = None
|
||||
_exit = False
|
||||
_auto_clean_interval = datetime.timedelta(hours=4)
|
||||
_win = None
|
||||
_busy_tasks = []
|
||||
_database = None
|
||||
|
||||
def __init__(self, addon_id):
|
||||
'''Initialize our caching class'''
|
||||
self.addon_id = addon_id
|
||||
self._win = xbmcgui.Window(10000)
|
||||
self._monitor = xbmc.Monitor()
|
||||
self.check_cleanup()
|
||||
self._log_msg("Initialized")
|
||||
|
||||
def close(self):
|
||||
'''tell any tasks to stop immediately (as we can be called multithreaded) and cleanup objects'''
|
||||
self._exit = True
|
||||
# wait for all tasks to complete
|
||||
while self._busy_tasks and not self._monitor.abortRequested():
|
||||
xbmc.sleep(25)
|
||||
del self._win
|
||||
del self._monitor
|
||||
self._log_msg("Closed")
|
||||
|
||||
def __del__(self):
|
||||
'''make sure close is called'''
|
||||
if not self._exit:
|
||||
self.close()
|
||||
|
||||
def get(self, endpoint, checksum="", json_data=False):
|
||||
'''
|
||||
get object from cache and return the results
|
||||
endpoint: the (unique) name of the cache object as reference
|
||||
checkum: optional argument to check if the checksum in the cacheobject matches the checkum provided
|
||||
'''
|
||||
checksum = self._get_checksum(checksum)
|
||||
cur_time = self._get_timestamp(datetime.datetime.now())
|
||||
result = None
|
||||
# 1: try memory cache first
|
||||
if self.enable_mem_cache:
|
||||
result = self._get_mem_cache(endpoint, checksum, cur_time, json_data)
|
||||
|
||||
# 2: fallback to _database cache
|
||||
if result is None:
|
||||
result = self._get_db_cache(endpoint, checksum, cur_time, json_data)
|
||||
|
||||
return result
|
||||
|
||||
def set(self, endpoint, data, checksum="", expiration=datetime.timedelta(days=30), json_data=False):
|
||||
'''
|
||||
set data in cache
|
||||
'''
|
||||
task_name = "set.%s" % endpoint
|
||||
self._busy_tasks.append(task_name)
|
||||
checksum = self._get_checksum(checksum)
|
||||
expires = self._get_timestamp(datetime.datetime.now() + expiration)
|
||||
|
||||
# memory cache: write to window property
|
||||
if self.enable_mem_cache and not self._exit:
|
||||
self._set_mem_cache(endpoint, checksum, expires, data, json_data)
|
||||
|
||||
# db cache
|
||||
if not self._exit:
|
||||
self._set_db_cache(endpoint, checksum, expires, data, json_data)
|
||||
|
||||
# remove this task from list
|
||||
self._busy_tasks.remove(task_name)
|
||||
|
||||
def check_cleanup(self):
|
||||
'''check if cleanup is needed - public method, may be called by calling addon'''
|
||||
cur_time = datetime.datetime.now()
|
||||
lastexecuted = self._win.getProperty("simplecache.clean.lastexecuted")
|
||||
if not lastexecuted:
|
||||
self._win.setProperty("simplecache.clean.lastexecuted", repr(cur_time))
|
||||
elif (eval(lastexecuted) + self._auto_clean_interval) < cur_time:
|
||||
# cleanup needed...
|
||||
self._do_cleanup()
|
||||
|
||||
def _get_mem_cache(self, endpoint, checksum, cur_time, json_data):
|
||||
'''
|
||||
get cache data from memory cache
|
||||
we use window properties because we need to be stateless
|
||||
'''
|
||||
result = None
|
||||
cachedata = self._win.getProperty(endpoint)
|
||||
|
||||
if cachedata:
|
||||
if json_data or self.data_is_json:
|
||||
cachedata = json.loads(cachedata)
|
||||
else:
|
||||
cachedata = eval(cachedata)
|
||||
if cachedata[0] > cur_time:
|
||||
if not checksum or checksum == cachedata[2]:
|
||||
result = cachedata[1]
|
||||
return result
|
||||
|
||||
def _set_mem_cache(self, endpoint, checksum, expires, data, json_data):
|
||||
'''
|
||||
window property cache as alternative for memory cache
|
||||
usefull for (stateless) plugins
|
||||
'''
|
||||
cachedata = (expires, data, checksum)
|
||||
if json_data or self.data_is_json:
|
||||
cachedata_str = json.dumps(cachedata)
|
||||
else:
|
||||
cachedata_str = repr(cachedata)
|
||||
self._win.setProperty(endpoint, cachedata_str)
|
||||
|
||||
|
||||
def _get_db_cache(self, endpoint, checksum, cur_time, json_data):
|
||||
'''get cache data from sqllite _database'''
|
||||
result = None
|
||||
query = "SELECT expires, data, checksum FROM simplecache WHERE id = ?"
|
||||
cache_data = self._execute_sql(query, (endpoint,))
|
||||
if cache_data:
|
||||
cache_data = cache_data.fetchone()
|
||||
if cache_data and cache_data[0] > cur_time:
|
||||
if not checksum or cache_data[2] == checksum:
|
||||
if json_data or self.data_is_json:
|
||||
result = json.loads(cache_data[1])
|
||||
else:
|
||||
result = eval(cache_data[1])
|
||||
# also set result in memory cache for further access
|
||||
if self.enable_mem_cache:
|
||||
self._set_mem_cache(endpoint, checksum, cache_data[0], result, json_data)
|
||||
return result
|
||||
|
||||
def _set_db_cache(self, endpoint, checksum, expires, data, json_data):
|
||||
''' store cache data in _database '''
|
||||
query = "INSERT OR REPLACE INTO simplecache( id, expires, data, checksum) VALUES (?, ?, ?, ?)"
|
||||
if json_data or self.data_is_json:
|
||||
data = json.dumps(data)
|
||||
else:
|
||||
data = repr(data)
|
||||
self._execute_sql(query, (endpoint, expires, data, checksum))
|
||||
|
||||
def _do_cleanup(self):
|
||||
'''perform cleanup task'''
|
||||
if self._exit or self._monitor.abortRequested():
|
||||
return
|
||||
self._busy_tasks.append(__name__)
|
||||
cur_time = datetime.datetime.now()
|
||||
cur_timestamp = self._get_timestamp(cur_time)
|
||||
self._log_msg("Running cleanup...")
|
||||
if self._win.getProperty("simplecachecleanbusy"):
|
||||
return
|
||||
self._win.setProperty("simplecachecleanbusy", "busy")
|
||||
|
||||
query = "SELECT id, expires FROM simplecache"
|
||||
for cache_data in self._execute_sql(query).fetchall():
|
||||
cache_id = cache_data[0]
|
||||
cache_expires = cache_data[1]
|
||||
|
||||
if self._exit or self._monitor.abortRequested():
|
||||
return
|
||||
|
||||
# always cleanup all memory objects on each interval
|
||||
self._win.clearProperty(cache_id)
|
||||
|
||||
# clean up db cache object only if expired
|
||||
if cache_expires < cur_timestamp:
|
||||
query = 'DELETE FROM simplecache WHERE id = ?'
|
||||
self._execute_sql(query, (cache_id,))
|
||||
self._log_msg("delete from db %s" % cache_id)
|
||||
|
||||
# compact db
|
||||
self._execute_sql("VACUUM")
|
||||
|
||||
# remove task from list
|
||||
self._busy_tasks.remove(__name__)
|
||||
self._win.setProperty("simplecache.clean.lastexecuted", repr(cur_time))
|
||||
self._win.clearProperty("simplecachecleanbusy")
|
||||
self._log_msg("Auto cleanup done")
|
||||
|
||||
def _get_database(self):
|
||||
'''get reference to our sqllite _database - performs basic integrity check'''
|
||||
addon = xbmcaddon.Addon(self.addon_id)
|
||||
dbpath = addon.getAddonInfo('profile')
|
||||
dbfile = xbmcvfs.translatePath("%s/simplecache.db" % dbpath)
|
||||
|
||||
if not xbmcvfs.exists(dbpath):
|
||||
xbmcvfs.mkdirs(dbpath)
|
||||
del addon
|
||||
try:
|
||||
connection = sqlite3.connect(dbfile, timeout=30, isolation_level=None)
|
||||
connection.execute('SELECT * FROM simplecache LIMIT 1')
|
||||
return connection
|
||||
except Exception as error:
|
||||
# our _database is corrupt or doesn't exist yet, we simply try to recreate it
|
||||
if xbmcvfs.exists(dbfile):
|
||||
xbmcvfs.delete(dbfile)
|
||||
try:
|
||||
connection = sqlite3.connect(dbfile, timeout=30, isolation_level=None)
|
||||
connection.execute(
|
||||
"""CREATE TABLE IF NOT EXISTS simplecache(
|
||||
id TEXT UNIQUE, expires INTEGER, data TEXT, checksum INTEGER)""")
|
||||
return connection
|
||||
except Exception as error:
|
||||
self._log_msg("Exception while initializing _database: %s" % str(error), xbmc.LOGWARNING)
|
||||
self.close()
|
||||
return None
|
||||
|
||||
def _execute_sql(self, query, data=None):
|
||||
'''little wrapper around execute and executemany to just retry a db command if db is locked'''
|
||||
retries = 0
|
||||
result = None
|
||||
error = None
|
||||
# always use new db object because we need to be sure that data is available for other simplecache instances
|
||||
with self._get_database() as _database:
|
||||
while not retries == 10 and not self._monitor.abortRequested():
|
||||
if self._exit:
|
||||
return None
|
||||
try:
|
||||
if isinstance(data, list):
|
||||
result = _database.executemany(query, data)
|
||||
elif data:
|
||||
result = _database.execute(query, data)
|
||||
else:
|
||||
result = _database.execute(query)
|
||||
return result
|
||||
except sqlite3.OperationalError as error:
|
||||
if "_database is locked" in error:
|
||||
self._log_msg("retrying DB commit...")
|
||||
retries += 1
|
||||
self._monitor.waitForAbort(0.5)
|
||||
else:
|
||||
break
|
||||
except Exception as error:
|
||||
break
|
||||
self._log_msg("_database ERROR ! -- %s" % str(error), xbmc.LOGWARNING)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _log_msg(msg, loglevel=xbmc.LOGDEBUG):
|
||||
'''helper to send a message to the kodi log'''
|
||||
xbmc.log("Skin Helper Simplecache --> %s" % msg, level=loglevel)
|
||||
|
||||
@staticmethod
|
||||
def _get_timestamp(date_time):
|
||||
'''Converts a datetime object to unix timestamp'''
|
||||
return int(time.mktime(date_time.timetuple()))
|
||||
|
||||
def _get_checksum(self, stringinput):
|
||||
'''get int checksum from string'''
|
||||
if not stringinput and not self.global_checksum:
|
||||
return 0
|
||||
if self.global_checksum:
|
||||
stringinput = "%s-%s" %(self.global_checksum, stringinput)
|
||||
else:
|
||||
stringinput = str(stringinput)
|
||||
return reduce(lambda x, y: x + y, map(ord, stringinput))
|
||||
|
||||
|
||||
def use_cache(cache_days=14):
|
||||
'''
|
||||
wrapper around our simple cache to use as decorator
|
||||
Usage: define an instance of SimpleCache with name "cache" (self.cache) in your class
|
||||
Any method that needs caching just add @use_cache as decorator
|
||||
NOTE: use unnamed arguments for calling the method and named arguments for optional settings
|
||||
'''
|
||||
def decorator(func):
|
||||
'''our decorator'''
|
||||
def decorated(*args, **kwargs):
|
||||
'''process the original method and apply caching of the results'''
|
||||
method_class = args[0]
|
||||
method_class_name = method_class.__class__.__name__
|
||||
cache_str = "%s.%s" % (method_class_name, func.__name__)
|
||||
# cache identifier is based on positional args only
|
||||
# named args are considered optional and ignored
|
||||
for item in args[1:]:
|
||||
cache_str += u".%s" % item
|
||||
cache_str = cache_str.lower()
|
||||
cachedata = method_class.cache.get(cache_str)
|
||||
global_cache_ignore = False
|
||||
try:
|
||||
global_cache_ignore = method_class.ignore_cache
|
||||
except Exception:
|
||||
pass
|
||||
if cachedata is not None and not kwargs.get("ignore_cache", False) and not global_cache_ignore:
|
||||
return cachedata
|
||||
else:
|
||||
result = func(*args, **kwargs)
|
||||
method_class.cache.set(cache_str, result, expiration=datetime.timedelta(days=cache_days))
|
||||
return result
|
||||
return decorated
|
||||
return decorator
|
||||
5
resources/lib/deps/spotipy/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from .cache_handler import * # noqa
|
||||
from .client import * # noqa
|
||||
from .exceptions import * # noqa
|
||||
from .oauth2 import * # noqa
|
||||
from .util import * # noqa
|
||||
173
resources/lib/deps/spotipy/cache_handler.py
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
__all__ = [
|
||||
'CacheHandler',
|
||||
'CacheFileHandler',
|
||||
'DjangoSessionCacheHandler',
|
||||
'FlaskSessionCacheHandler',
|
||||
'MemoryCacheHandler']
|
||||
|
||||
import errno
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from spotipy.util import CLIENT_CREDS_ENV_VARS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CacheHandler():
|
||||
"""
|
||||
An abstraction layer for handling the caching and retrieval of
|
||||
authorization tokens.
|
||||
|
||||
Custom extensions of this class must implement get_cached_token
|
||||
and save_token_to_cache methods with the same input and output
|
||||
structure as the CacheHandler class.
|
||||
"""
|
||||
|
||||
def get_cached_token(self):
|
||||
"""
|
||||
Get and return a token_info dictionary object.
|
||||
"""
|
||||
# return token_info
|
||||
raise NotImplementedError()
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
"""
|
||||
Save a token_info dictionary object to the cache and return None.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
return None
|
||||
|
||||
|
||||
class CacheFileHandler(CacheHandler):
|
||||
"""
|
||||
Handles reading and writing cached Spotify authorization tokens
|
||||
as json files on disk.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
cache_path=None,
|
||||
username=None,
|
||||
encoder_cls=None):
|
||||
"""
|
||||
Parameters:
|
||||
* cache_path: May be supplied, will otherwise be generated
|
||||
(takes precedence over `username`)
|
||||
* username: May be supplied or set as environment variable
|
||||
(will set `cache_path` to `.cache-{username}`)
|
||||
* encoder_cls: May be supplied as a means of overwriting the
|
||||
default serializer used for writing tokens to disk
|
||||
"""
|
||||
self.encoder_cls = encoder_cls
|
||||
if cache_path:
|
||||
self.cache_path = cache_path
|
||||
else:
|
||||
cache_path = ".cache"
|
||||
username = (username or os.getenv(CLIENT_CREDS_ENV_VARS["client_username"]))
|
||||
if username:
|
||||
cache_path += "-" + str(username)
|
||||
self.cache_path = cache_path
|
||||
|
||||
def get_cached_token(self):
|
||||
token_info = None
|
||||
|
||||
try:
|
||||
f = open(self.cache_path)
|
||||
token_info_string = f.read()
|
||||
f.close()
|
||||
token_info = json.loads(token_info_string)
|
||||
|
||||
except IOError as error:
|
||||
if error.errno == errno.ENOENT:
|
||||
logger.debug("cache does not exist at: %s", self.cache_path)
|
||||
else:
|
||||
logger.warning("Couldn't read cache at: %s", self.cache_path)
|
||||
|
||||
return token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
try:
|
||||
f = open(self.cache_path, "w")
|
||||
f.write(json.dumps(token_info, cls=self.encoder_cls))
|
||||
f.close()
|
||||
except IOError:
|
||||
logger.warning('Couldn\'t write token to cache at: %s',
|
||||
self.cache_path)
|
||||
|
||||
|
||||
class MemoryCacheHandler(CacheHandler):
|
||||
"""
|
||||
A cache handler that simply stores the token info in memory as an
|
||||
instance attribute of this class. The token info will be lost when this
|
||||
instance is freed.
|
||||
"""
|
||||
|
||||
def __init__(self, token_info=None):
|
||||
"""
|
||||
Parameters:
|
||||
* token_info: The token info to store in memory. Can be None.
|
||||
"""
|
||||
self.token_info = token_info
|
||||
|
||||
def get_cached_token(self):
|
||||
return self.token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
self.token_info = token_info
|
||||
|
||||
|
||||
class DjangoSessionCacheHandler(CacheHandler):
|
||||
"""
|
||||
A cache handler that stores the token info in the session framework
|
||||
provided by Django.
|
||||
|
||||
Read more at https://docs.djangoproject.com/en/3.2/topics/http/sessions/
|
||||
"""
|
||||
|
||||
def __init__(self, request):
|
||||
"""
|
||||
Parameters:
|
||||
* request: HttpRequest object provided by Django for every
|
||||
incoming request
|
||||
"""
|
||||
self.request = request
|
||||
|
||||
def get_cached_token(self):
|
||||
token_info = None
|
||||
try:
|
||||
token_info = self.request.session['token_info']
|
||||
except KeyError:
|
||||
logger.debug("Token not found in the session")
|
||||
|
||||
return token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
try:
|
||||
self.request.session['token_info'] = token_info
|
||||
except Exception as e:
|
||||
logger.warning("Error saving token to cache: " + str(e))
|
||||
|
||||
|
||||
class FlaskSessionCacheHandler(CacheHandler):
|
||||
"""
|
||||
A cache handler that stores the token info in the session framework
|
||||
provided by flask.
|
||||
"""
|
||||
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
def get_cached_token(self):
|
||||
token_info = None
|
||||
try:
|
||||
token_info = self.session["token_info"]
|
||||
except KeyError:
|
||||
logger.debug("Token not found in the session")
|
||||
|
||||
return token_info
|
||||
|
||||
def save_token_to_cache(self, token_info):
|
||||
try:
|
||||
self.session["token_info"] = token_info
|
||||
except Exception as e:
|
||||
logger.warning("Error saving token to cache: " + str(e))
|
||||
2035
resources/lib/deps/spotipy/client.py
Normal file
16
resources/lib/deps/spotipy/exceptions.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
class SpotifyException(Exception):
|
||||
|
||||
def __init__(self, http_status, code, msg, reason=None, headers=None):
|
||||
self.http_status = http_status
|
||||
self.code = code
|
||||
self.msg = msg
|
||||
self.reason = reason
|
||||
# `headers` is used to support `Retry-After` in the event of a
|
||||
# 429 status code.
|
||||
if headers is None:
|
||||
headers = {}
|
||||
self.headers = headers
|
||||
|
||||
def __str__(self):
|
||||
return 'http status: {0}, code:{1} - {2}, reason: {3}'.format(
|
||||
self.http_status, self.code, self.msg, self.reason)
|
||||
1308
resources/lib/deps/spotipy/oauth2.py
Normal file
135
resources/lib/deps/spotipy/util.py
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" Shows a user's playlists (need to be authenticated via oauth) """
|
||||
|
||||
__all__ = ["CLIENT_CREDS_ENV_VARS", "prompt_for_user_token"]
|
||||
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
|
||||
import spotipy
|
||||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
CLIENT_CREDS_ENV_VARS = {
|
||||
"client_id": "SPOTIPY_CLIENT_ID",
|
||||
"client_secret": "SPOTIPY_CLIENT_SECRET",
|
||||
"client_username": "SPOTIPY_CLIENT_USERNAME",
|
||||
"redirect_uri": "SPOTIPY_REDIRECT_URI",
|
||||
}
|
||||
|
||||
|
||||
def prompt_for_user_token(
|
||||
username=None,
|
||||
scope=None,
|
||||
client_id=None,
|
||||
client_secret=None,
|
||||
redirect_uri=None,
|
||||
cache_path=None,
|
||||
oauth_manager=None,
|
||||
show_dialog=False
|
||||
):
|
||||
warnings.warn(
|
||||
"'prompt_for_user_token' is deprecated."
|
||||
"Use the following instead: "
|
||||
" auth_manager=SpotifyOAuth(scope=scope)"
|
||||
" spotipy.Spotify(auth_manager=auth_manager)",
|
||||
DeprecationWarning
|
||||
)
|
||||
""" prompts the user to login if necessary and returns
|
||||
the user token suitable for use with the spotipy.Spotify
|
||||
constructor
|
||||
|
||||
Parameters:
|
||||
|
||||
- username - the Spotify username (optional)
|
||||
- scope - the desired scope of the request (optional)
|
||||
- client_id - the client id of your app (required)
|
||||
- client_secret - the client secret of your app (required)
|
||||
- redirect_uri - the redirect URI of your app (required)
|
||||
- cache_path - path to location to save tokens (optional)
|
||||
- oauth_manager - Oauth manager object (optional)
|
||||
- show_dialog - If true, a login prompt always shows (optional, defaults to False)
|
||||
|
||||
"""
|
||||
if not oauth_manager:
|
||||
if not client_id:
|
||||
client_id = os.getenv("SPOTIPY_CLIENT_ID")
|
||||
|
||||
if not client_secret:
|
||||
client_secret = os.getenv("SPOTIPY_CLIENT_SECRET")
|
||||
|
||||
if not redirect_uri:
|
||||
redirect_uri = os.getenv("SPOTIPY_REDIRECT_URI")
|
||||
|
||||
if not client_id:
|
||||
LOGGER.warning(
|
||||
"""
|
||||
You need to set your Spotify API credentials.
|
||||
You can do this by setting environment variables like so:
|
||||
|
||||
export SPOTIPY_CLIENT_ID='your-spotify-client-id'
|
||||
export SPOTIPY_CLIENT_SECRET='your-spotify-client-secret'
|
||||
export SPOTIPY_REDIRECT_URI='your-app-redirect-url'
|
||||
|
||||
Get your credentials at
|
||||
https://developer.spotify.com/my-applications
|
||||
"""
|
||||
)
|
||||
raise spotipy.SpotifyException(550, -1, "no credentials set")
|
||||
|
||||
sp_oauth = oauth_manager or spotipy.SpotifyOAuth(
|
||||
client_id,
|
||||
client_secret,
|
||||
redirect_uri,
|
||||
scope=scope,
|
||||
cache_path=cache_path,
|
||||
username=username,
|
||||
show_dialog=show_dialog
|
||||
)
|
||||
|
||||
# try to get a valid token for this user, from the cache,
|
||||
# if not in the cache, then create a new (this will send
|
||||
# the user to a web page where they can authorize this app)
|
||||
|
||||
token_info = sp_oauth.validate_token(sp_oauth.cache_handler.get_cached_token())
|
||||
|
||||
if not token_info:
|
||||
code = sp_oauth.get_auth_response()
|
||||
token = sp_oauth.get_access_token(code, as_dict=False)
|
||||
else:
|
||||
return token_info["access_token"]
|
||||
|
||||
# Auth'ed API request
|
||||
if token:
|
||||
return token
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_host_port(netloc):
|
||||
if ":" in netloc:
|
||||
host, port = netloc.split(":", 1)
|
||||
port = int(port)
|
||||
else:
|
||||
host = netloc
|
||||
port = None
|
||||
|
||||
return host, port
|
||||
|
||||
|
||||
def normalize_scope(scope):
|
||||
if scope:
|
||||
if isinstance(scope, str):
|
||||
scopes = scope.split(',')
|
||||
elif isinstance(scope, list) or isinstance(scope, tuple):
|
||||
scopes = scope
|
||||
else:
|
||||
raise Exception(
|
||||
"Unsupported scope value, please either provide a list of scopes, "
|
||||
"or a string of scopes separated by commas"
|
||||
)
|
||||
return " ".join(sorted(scopes))
|
||||
else:
|
||||
return None
|
||||
84
resources/lib/http_video_player_setter.py
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import os
|
||||
from xml.etree import ElementTree
|
||||
|
||||
import xbmcvfs
|
||||
from xbmc import LOGDEBUG
|
||||
|
||||
from utils import ADDON_ID, log_msg
|
||||
|
||||
|
||||
class HttpVideoPlayerSetter:
|
||||
def __init__(self):
|
||||
self.__plugin_name = ADDON_ID
|
||||
self.__player_rules_filename = xbmcvfs.translatePath(
|
||||
f"special://masterprofile/playercorefactory.xml"
|
||||
)
|
||||
|
||||
def set_http_rule(self) -> bool:
|
||||
if not os.path.exists(self.__player_rules_filename):
|
||||
self.__create_new_player_rules()
|
||||
log_msg(f"Created a new file '{self.__player_rules_filename}' with a video http rule.")
|
||||
return True
|
||||
else:
|
||||
if self.__add_http_rule():
|
||||
log_msg(f"Added a video http rule to '{self.__player_rules_filename}'")
|
||||
return True
|
||||
|
||||
log_msg(
|
||||
f"There is already a video http rule in '{self.__player_rules_filename}'."
|
||||
" Nothing to do.",
|
||||
LOGDEBUG,
|
||||
)
|
||||
return False
|
||||
|
||||
def __create_new_player_rules(self) -> None:
|
||||
xml_str = f"""<?xml version='1.0' encoding='utf-8'?>
|
||||
<playercorefactory>
|
||||
<!-- This file created by the '{self.__plugin_name}' addon. -->
|
||||
<rules name="system rules">
|
||||
<rule name="http" protocols="http" player="VideoPlayer" />
|
||||
</rules>
|
||||
</playercorefactory>
|
||||
"""
|
||||
with open(self.__player_rules_filename, "w") as f:
|
||||
f.write(xml_str)
|
||||
|
||||
def __add_http_rule(self) -> bool:
|
||||
class CommentedTreeBuilder(ElementTree.TreeBuilder):
|
||||
def comment(self, data):
|
||||
self.start(ElementTree.Comment().tag, {})
|
||||
self.data(data)
|
||||
self.end(ElementTree.Comment().tag)
|
||||
|
||||
parser = ElementTree.XMLParser(target=CommentedTreeBuilder())
|
||||
tree = ElementTree.parse(self.__player_rules_filename, parser=parser)
|
||||
root = tree.getroot()
|
||||
|
||||
http_rule = root.findall("./rules/rule/[@protocols='http']")
|
||||
if http_rule:
|
||||
return False
|
||||
|
||||
rules = root.find("./rules")
|
||||
|
||||
attributes = {
|
||||
"name": "http",
|
||||
"protocols": "http",
|
||||
"player": "VideoPlayer",
|
||||
}
|
||||
new_rule = ElementTree.Element("rule", attributes)
|
||||
new_rule.tail = "\n\n" + " "
|
||||
rules.insert(0, new_rule)
|
||||
|
||||
comment = ElementTree.Comment(
|
||||
f" This http rule added by the '{self.__plugin_name}' addon. "
|
||||
)
|
||||
comment.tail = "\n" + " "
|
||||
rules.insert(0, comment)
|
||||
|
||||
xml_str = ElementTree.tostring(root, encoding="unicode", xml_declaration=True)
|
||||
|
||||
with open(self.__player_rules_filename, "w") as f:
|
||||
f.write(xml_str)
|
||||
f.write("\n")
|
||||
|
||||
return True
|
||||
34
resources/lib/librespot/__init__.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
from __future__ import annotations
|
||||
from librespot.crypto import DiffieHellman
|
||||
from librespot.proto.Keyexchange_pb2 import BuildInfo, Platform, Product, ProductFlags
|
||||
from librespot.structure import Closeable, Runnable
|
||||
import platform
|
||||
|
||||
|
||||
class Version:
|
||||
version_name = "0.0.9"
|
||||
|
||||
@staticmethod
|
||||
def platform() -> Platform:
|
||||
if platform.system() == "Windows":
|
||||
return Platform.PLATFORM_WIN32_X86
|
||||
if platform.system() == "Darwin":
|
||||
return Platform.PLATFORM_OSX_X86
|
||||
return Platform.PLATFORM_LINUX_X86
|
||||
|
||||
@staticmethod
|
||||
def version_string():
|
||||
return "librespot-python " + Version.version_name
|
||||
|
||||
@staticmethod
|
||||
def system_info_string():
|
||||
return Version.version_string() + \
|
||||
"; Python " + platform.python_version() + \
|
||||
"; " + platform.system()
|
||||
|
||||
@staticmethod
|
||||
def standard_build_info() -> BuildInfo:
|
||||
return BuildInfo(product=Product.PRODUCT_CLIENT,
|
||||
product_flags=[ProductFlags.PRODUCT_FLAG_NONE],
|
||||
platform=Version.platform(),
|
||||
version=117300517)
|
||||
912
resources/lib/librespot/audio/__init__.py
Normal file
|
|
@ -0,0 +1,912 @@
|
|||
from __future__ import annotations
|
||||
from librespot import util
|
||||
from librespot.audio.decrypt import AesAudioDecrypt
|
||||
from librespot.audio.format import SuperAudioFormat
|
||||
from librespot.audio.storage import ChannelManager
|
||||
from librespot.cache import CacheManager
|
||||
from librespot.crypto import Packet
|
||||
from librespot.metadata import EpisodeId, PlayableId, TrackId
|
||||
from librespot.proto import Metadata_pb2 as Metadata, StorageResolve_pb2 as StorageResolve
|
||||
from librespot.structure import AudioDecrypt, AudioQualityPicker, Closeable, FeederException, GeneralAudioStream, GeneralWritableStream, HaltListener, NoopAudioDecrypt, PacketsReceiver
|
||||
import concurrent.futures
|
||||
import io
|
||||
import logging
|
||||
import math
|
||||
import queue
|
||||
import random
|
||||
import struct
|
||||
import threading
|
||||
import time
|
||||
import typing
|
||||
import urllib.parse
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from librespot.core import Session
|
||||
|
||||
|
||||
class AbsChunkedInputStream(io.BytesIO, HaltListener):
|
||||
chunk_exception = None
|
||||
closed = False
|
||||
max_chunk_tries = 128
|
||||
preload_ahead = 3
|
||||
preload_chunk_retries = 2
|
||||
retries: typing.List[int]
|
||||
retry_on_chunk_error: bool
|
||||
wait_lock: threading.Condition = threading.Condition()
|
||||
wait_for_chunk = -1
|
||||
__decoded_length = 0
|
||||
__mark = 0
|
||||
__pos = 0
|
||||
|
||||
def __init__(self, retry_on_chunk_error: bool):
|
||||
super().__init__()
|
||||
self.retries = [0] * self.chunks()
|
||||
self.retry_on_chunk_error = retry_on_chunk_error
|
||||
|
||||
def is_closed(self) -> bool:
|
||||
return self.closed
|
||||
|
||||
def buffer(self) -> typing.List[bytes]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def size(self) -> int:
|
||||
raise NotImplementedError()
|
||||
|
||||
def close(self) -> None:
|
||||
self.closed = True
|
||||
with self.wait_lock:
|
||||
self.wait_lock.notify_all()
|
||||
|
||||
def available(self):
|
||||
return self.size() - self.__pos
|
||||
|
||||
def mark_supported(self) -> bool:
|
||||
return True
|
||||
|
||||
def mark(self, read_ahead_limit: int) -> None:
|
||||
self.__mark = self.__pos
|
||||
|
||||
def reset(self) -> None:
|
||||
self.__pos = self.__mark
|
||||
|
||||
def pos(self) -> int:
|
||||
return self.__pos
|
||||
|
||||
def seek(self, where: int, **kwargs) -> None:
|
||||
if where < 0:
|
||||
raise TypeError()
|
||||
if self.closed:
|
||||
raise IOError("Stream is closed!")
|
||||
self.__pos = where
|
||||
self.check_availability(int(self.__pos / (128 * 1024)), False, False)
|
||||
|
||||
def skip(self, n: int) -> int:
|
||||
if n < 0:
|
||||
raise TypeError()
|
||||
if self.closed:
|
||||
raise IOError("Stream is closed!")
|
||||
k = self.size() - self.__pos
|
||||
if n < k:
|
||||
k = n
|
||||
self.__pos += k
|
||||
chunk = int(self.__pos / (128 * 1024))
|
||||
self.check_availability(chunk, False, False)
|
||||
return k
|
||||
|
||||
def requested_chunks(self) -> typing.List[bool]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def available_chunks(self) -> typing.List[bool]:
|
||||
raise NotImplementedError()
|
||||
|
||||
def chunks(self) -> int:
|
||||
raise NotImplementedError()
|
||||
|
||||
def request_chunk_from_stream(self, index: int) -> None:
|
||||
raise NotImplementedError()
|
||||
|
||||
def should_retry(self, chunk: int) -> bool:
|
||||
if self.retries[chunk] < 1:
|
||||
return True
|
||||
if self.retries[chunk] > self.max_chunk_tries:
|
||||
return False
|
||||
return self.retry_on_chunk_error
|
||||
|
||||
def check_availability(self, chunk: int, wait: bool, halted: bool) -> None:
|
||||
if halted and not wait:
|
||||
raise TypeError()
|
||||
if not self.requested_chunks()[chunk]:
|
||||
self.request_chunk_from_stream(chunk)
|
||||
self.requested_chunks()[chunk] = True
|
||||
for i in range(chunk + 1,
|
||||
min(self.chunks() - 1, chunk + self.preload_ahead) + 1):
|
||||
if (self.requested_chunks()[i]
|
||||
and self.retries[i] < self.preload_chunk_retries):
|
||||
self.request_chunk_from_stream(i)
|
||||
self.requested_chunks()[chunk] = True
|
||||
if wait:
|
||||
if self.available_chunks()[chunk]:
|
||||
return
|
||||
retry = False
|
||||
with self.wait_lock:
|
||||
if not halted:
|
||||
self.stream_read_halted(chunk, int(time.time() * 1000))
|
||||
self.chunk_exception = None
|
||||
self.wait_for_chunk = chunk
|
||||
self.wait_lock.wait_for(lambda: self.available_chunks()[chunk])
|
||||
if self.closed:
|
||||
return
|
||||
if self.chunk_exception is not None:
|
||||
if self.should_retry(chunk):
|
||||
retry = True
|
||||
else:
|
||||
raise AbsChunkedInputStream.ChunkException
|
||||
if not retry:
|
||||
self.stream_read_halted(chunk, int(time.time() * 1000))
|
||||
if retry:
|
||||
time.sleep(math.log10(self.retries[chunk]))
|
||||
self.check_availability(chunk, True, True)
|
||||
|
||||
def read(self, __size: int = 0) -> bytes:
|
||||
if self.closed:
|
||||
raise IOError("Stream is closed!")
|
||||
if __size <= 0:
|
||||
if self.__pos == self.size():
|
||||
return b""
|
||||
buffer = io.BytesIO()
|
||||
total_size = self.size()
|
||||
chunk = int(self.__pos / (128 * 1024))
|
||||
chunk_off = int(self.__pos % (128 * 1024))
|
||||
chunk_total = int(math.ceil(total_size / (128 * 1024)))
|
||||
self.check_availability(chunk, True, False)
|
||||
buffer.write(self.buffer()[chunk][chunk_off:])
|
||||
chunk += 1
|
||||
if chunk != chunk_total:
|
||||
while chunk <= chunk_total - 1:
|
||||
self.check_availability(chunk, True, False)
|
||||
buffer.write(self.buffer()[chunk])
|
||||
chunk += 1
|
||||
buffer.seek(0)
|
||||
self.__pos += buffer.getbuffer().nbytes
|
||||
return buffer.read()
|
||||
buffer = io.BytesIO()
|
||||
chunk = int(self.__pos / (128 * 1024))
|
||||
chunk_off = int(self.__pos % (128 * 1024))
|
||||
chunk_end = int(__size / (128 * 1024))
|
||||
chunk_end_off = int(__size % (128 * 1024))
|
||||
if chunk_end > self.size():
|
||||
chunk_end = int(self.size() / (128 * 1024))
|
||||
chunk_end_off = int(self.size() % (128 * 1024))
|
||||
self.check_availability(chunk, True, False)
|
||||
if chunk_off + __size > len(self.buffer()[chunk]):
|
||||
buffer.write(self.buffer()[chunk][chunk_off:])
|
||||
chunk += 1
|
||||
while chunk <= chunk_end:
|
||||
self.check_availability(chunk, True, False)
|
||||
if chunk == chunk_end:
|
||||
buffer.write(self.buffer()[chunk][:chunk_end_off])
|
||||
else:
|
||||
buffer.write(self.buffer()[chunk])
|
||||
chunk += 1
|
||||
else:
|
||||
buffer.write(self.buffer()[chunk][chunk_off:chunk_off + __size])
|
||||
buffer.seek(0)
|
||||
self.__pos += buffer.getbuffer().nbytes
|
||||
return buffer.read()
|
||||
|
||||
def notify_chunk_available(self, index: int) -> None:
|
||||
self.available_chunks()[index] = True
|
||||
self.__decoded_length += len(self.buffer()[index])
|
||||
with self.wait_lock:
|
||||
if index == self.wait_for_chunk and not self.closed:
|
||||
self.wait_for_chunk = -1
|
||||
self.wait_lock.notify_all()
|
||||
|
||||
def notify_chunk_error(self, index: int, ex):
|
||||
self.available_chunks()[index] = False
|
||||
self.requested_chunks()[index] = False
|
||||
self.retries[index] += 1
|
||||
with self.wait_lock:
|
||||
if index == self.wait_for_chunk and not self.closed:
|
||||
self.chunk_exception = ex
|
||||
self.wait_for_chunk = -1
|
||||
self.wait_lock.notify_all()
|
||||
|
||||
def decoded_length(self):
|
||||
return self.__decoded_length
|
||||
|
||||
class ChunkException(IOError):
|
||||
|
||||
@staticmethod
|
||||
def from_stream_error(stream_error: int):
|
||||
return AbsChunkedInputStream \
|
||||
.ChunkException("Failed due to stream error, code: {}".format(stream_error))
|
||||
|
||||
|
||||
class AudioKeyManager(PacketsReceiver, Closeable):
|
||||
audio_key_request_timeout = 20
|
||||
logger = logging.getLogger("Librespot:AudioKeyManager")
|
||||
__callbacks: typing.Dict[int, Callback] = {}
|
||||
__seq_holder = 0
|
||||
__seq_holder_lock = threading.Condition()
|
||||
__session: Session
|
||||
__zero_short = b"\x00\x00"
|
||||
|
||||
def __init__(self, session: Session):
|
||||
self.__session = session
|
||||
|
||||
def dispatch(self, packet: Packet) -> None:
|
||||
payload = io.BytesIO(packet.payload)
|
||||
seq = struct.unpack(">i", payload.read(4))[0]
|
||||
callback = self.__callbacks.get(seq)
|
||||
if callback is None:
|
||||
self.logger.warning(
|
||||
"Couldn't find callback for seq: {}".format(seq))
|
||||
return
|
||||
if packet.is_cmd(Packet.Type.aes_key):
|
||||
key = payload.read(16)
|
||||
callback.key(key)
|
||||
elif packet.is_cmd(Packet.Type.aes_key_error):
|
||||
code = struct.unpack(">H", payload.read(2))[0]
|
||||
callback.error(code)
|
||||
else:
|
||||
self.logger.warning(
|
||||
"Couldn't handle packet, cmd: {}, length: {}".format(
|
||||
packet.cmd, len(packet.payload)))
|
||||
|
||||
def get_audio_key(self,
|
||||
gid: bytes,
|
||||
file_id: bytes,
|
||||
retry: bool = True) -> bytes:
|
||||
seq: int
|
||||
with self.__seq_holder_lock:
|
||||
seq = self.__seq_holder
|
||||
self.__seq_holder += 1
|
||||
out = io.BytesIO()
|
||||
out.write(file_id)
|
||||
out.write(gid)
|
||||
out.write(struct.pack(">i", seq))
|
||||
out.write(self.__zero_short)
|
||||
out.seek(0)
|
||||
self.__session.send(Packet.Type.request_key, out.read())
|
||||
callback = AudioKeyManager.SyncCallback(self)
|
||||
self.__callbacks[seq] = callback
|
||||
key = callback.wait_response()
|
||||
if key is None:
|
||||
if retry:
|
||||
return self.get_audio_key(gid, file_id, False)
|
||||
raise RuntimeError(
|
||||
"Failed fetching audio key! gid: {}, fileId: {}".format(
|
||||
util.bytes_to_hex(gid), util.bytes_to_hex(file_id)))
|
||||
return key
|
||||
|
||||
class Callback:
|
||||
|
||||
def key(self, key: bytes) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
def error(self, code: int) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
class SyncCallback(Callback):
|
||||
__audio_key_manager: AudioKeyManager
|
||||
__reference = queue.Queue()
|
||||
__reference_lock = threading.Condition()
|
||||
|
||||
def __init__(self, audio_key_manager: AudioKeyManager):
|
||||
self.__audio_key_manager = audio_key_manager
|
||||
|
||||
def key(self, key: bytes) -> None:
|
||||
with self.__reference_lock:
|
||||
self.__reference.put(key)
|
||||
self.__reference_lock.notify_all()
|
||||
|
||||
def error(self, code: int) -> None:
|
||||
self.__audio_key_manager.logger.fatal(
|
||||
"Audio key error, code: {}".format(code))
|
||||
with self.__reference_lock:
|
||||
self.__reference.put(None)
|
||||
self.__reference_lock.notify_all()
|
||||
|
||||
def wait_response(self) -> bytes:
|
||||
with self.__reference_lock:
|
||||
self.__reference_lock.wait(
|
||||
AudioKeyManager.audio_key_request_timeout)
|
||||
return self.__reference.get(block=False)
|
||||
|
||||
|
||||
class CdnFeedHelper:
|
||||
_LOGGER: logging = logging.getLogger(__name__)
|
||||
|
||||
@staticmethod
|
||||
def get_url(resp: StorageResolve.StorageResolveResponse) -> str:
|
||||
selected_url = random.choice(resp.cdnurl)
|
||||
while "audio4-gm-fb" in selected_url or "audio-gm-fb" in selected_url:
|
||||
selected_url = random.choice(resp.cdnurl)
|
||||
return selected_url
|
||||
|
||||
@staticmethod
|
||||
def load_track(
|
||||
session: Session, track: Metadata.Track, file: Metadata.AudioFile,
|
||||
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse,
|
||||
str], preload: bool,
|
||||
halt_listener: HaltListener) -> PlayableContentFeeder.LoadedStream:
|
||||
if type(resp_or_url) is str:
|
||||
url = resp_or_url
|
||||
else:
|
||||
url = CdnFeedHelper.get_url(resp_or_url)
|
||||
start = int(time.time() * 1000)
|
||||
key = session.audio_key().get_audio_key(track.gid, file.file_id)
|
||||
audio_key_time = int(time.time() * 1000) - start
|
||||
|
||||
streamer = session.cdn().stream_file(file, key, url, halt_listener)
|
||||
input_stream = streamer.stream()
|
||||
normalization_data = NormalizationData.read(input_stream)
|
||||
if input_stream.skip(0xA7) != 0xA7:
|
||||
raise IOError("Couldn't skip 0xa7 bytes!")
|
||||
return PlayableContentFeeder.LoadedStream(
|
||||
track,
|
||||
streamer,
|
||||
normalization_data,
|
||||
PlayableContentFeeder.Metrics(file.file_id, preload,
|
||||
-1 if preload else audio_key_time),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def load_episode_external(
|
||||
session: Session, episode: Metadata.Episode,
|
||||
halt_listener: HaltListener) -> PlayableContentFeeder.LoadedStream:
|
||||
resp = session.client().head(episode.external_url)
|
||||
|
||||
if resp.status_code != 200:
|
||||
CdnFeedHelper._LOGGER.warning("Couldn't resolve redirect!")
|
||||
|
||||
url = resp.url
|
||||
CdnFeedHelper._LOGGER.debug("Fetched external url for {}: {}".format(
|
||||
util.bytes_to_hex(episode.gid), url))
|
||||
|
||||
streamer = session.cdn().stream_external_episode(
|
||||
episode, url, halt_listener)
|
||||
return PlayableContentFeeder.LoadedStream(
|
||||
episode,
|
||||
streamer,
|
||||
None,
|
||||
PlayableContentFeeder.Metrics(None, False, -1),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def load_episode(
|
||||
session: Session,
|
||||
episode: Metadata.Episode,
|
||||
file: Metadata.AudioFile,
|
||||
resp_or_url: typing.Union[StorageResolve.StorageResolveResponse, str],
|
||||
preload: bool,
|
||||
halt_listener: HaltListener,
|
||||
) -> PlayableContentFeeder.LoadedStream:
|
||||
if type(resp_or_url) is str:
|
||||
url = resp_or_url
|
||||
else:
|
||||
url = CdnFeedHelper.get_url(resp_or_url)
|
||||
start = int(time.time() * 1000)
|
||||
key = session.audio_key().get_audio_key(episode.gid, file.file_id)
|
||||
audio_key_time = int(time.time() * 1000) - start
|
||||
|
||||
streamer = session.cdn().stream_file(file, key, url, halt_listener)
|
||||
input_stream = streamer.stream()
|
||||
normalization_data = NormalizationData.read(input_stream)
|
||||
if input_stream.skip(0xA7) != 0xA7:
|
||||
raise IOError("Couldn't skip 0xa7 bytes!")
|
||||
return PlayableContentFeeder.LoadedStream(
|
||||
episode,
|
||||
streamer,
|
||||
normalization_data,
|
||||
PlayableContentFeeder.Metrics(file.file_id, preload,
|
||||
-1 if preload else audio_key_time),
|
||||
)
|
||||
|
||||
|
||||
class CdnManager:
|
||||
logger: logging = logging.getLogger("Librespot:CdnManager")
|
||||
__session: Session
|
||||
|
||||
def __init__(self, session: Session):
|
||||
self.__session = session
|
||||
|
||||
def get_head(self, file_id: bytes):
|
||||
response = self.__session.client() \
|
||||
.get(self.__session.get_user_attribute("head-files-url", "https://heads-fa.spotify.com/head/{file_id}")
|
||||
.replace("{file_id}", util.bytes_to_hex(file_id)))
|
||||
if response.status_code != 200:
|
||||
raise IOError("{}".format(response.status_code))
|
||||
body = response.content
|
||||
if body is None:
|
||||
raise IOError("Response body is empty!")
|
||||
return body
|
||||
|
||||
def stream_external_episode(self, episode: Metadata.Episode,
|
||||
external_url: str,
|
||||
halt_listener: HaltListener):
|
||||
return CdnManager.Streamer(
|
||||
self.__session,
|
||||
StreamId(episode=episode),
|
||||
SuperAudioFormat.MP3,
|
||||
CdnManager.CdnUrl(self, None, external_url),
|
||||
self.__session.cache(),
|
||||
NoopAudioDecrypt(),
|
||||
halt_listener,
|
||||
)
|
||||
|
||||
def stream_file(self, file: Metadata.AudioFile, key: bytes, url: str,
|
||||
halt_listener: HaltListener):
|
||||
return CdnManager.Streamer(
|
||||
self.__session,
|
||||
StreamId(file=file),
|
||||
SuperAudioFormat.get(file.format),
|
||||
CdnManager.CdnUrl(self, file.file_id, url),
|
||||
self.__session.cache(),
|
||||
AesAudioDecrypt(key),
|
||||
halt_listener,
|
||||
)
|
||||
|
||||
def get_audio_url(self, file_id: bytes):
|
||||
response = self.__session.api()\
|
||||
.send("GET", "/storage-resolve/files/audio/interactive/{}".format(util.bytes_to_hex(file_id)), None, None)
|
||||
if response.status_code != 200:
|
||||
raise IOError(response.status_code)
|
||||
body = response.content
|
||||
if body is None:
|
||||
raise IOError("Response body is empty!")
|
||||
proto = StorageResolve.StorageResolveResponse()
|
||||
proto.ParseFromString(body)
|
||||
if proto.result == StorageResolve.StorageResolveResponse.Result.CDN:
|
||||
url = random.choice(proto.cdnurl)
|
||||
self.logger.debug("Fetched CDN url for {}: {}".format(
|
||||
util.bytes_to_hex(file_id), url))
|
||||
return url
|
||||
raise CdnManager.CdnException(
|
||||
"Could not retrieve CDN url! result: {}".format(proto.result))
|
||||
|
||||
class CdnException(Exception):
|
||||
pass
|
||||
|
||||
class InternalResponse:
|
||||
buffer: bytes
|
||||
headers: typing.Dict[str, str]
|
||||
|
||||
def __init__(self, buffer: bytes, headers: typing.Dict[str, str]):
|
||||
self.buffer = buffer
|
||||
self.headers = headers
|
||||
|
||||
class CdnUrl:
|
||||
__cdn_manager = None
|
||||
__file_id: bytes
|
||||
__expiration: int
|
||||
url: str
|
||||
|
||||
def __init__(self, cdn_manager, file_id: typing.Union[bytes, None],
|
||||
url: str):
|
||||
self.__cdn_manager: CdnManager = cdn_manager
|
||||
self.__file_id = file_id
|
||||
self.set_url(url)
|
||||
|
||||
def url(self):
|
||||
if self.__expiration == -1:
|
||||
return self.url
|
||||
if self.__expiration <= int(time.time() * 1000) + 5 * 60 * 1000:
|
||||
self.url = self.__cdn_manager.get_audio_url(self.__file_id)
|
||||
return self.url
|
||||
|
||||
def set_url(self, url: str):
|
||||
self.url = url
|
||||
if self.__file_id is not None:
|
||||
token_url = urllib.parse.urlparse(url)
|
||||
token_query = urllib.parse.parse_qs(token_url.query)
|
||||
token_list = token_query.get("__token__")
|
||||
try:
|
||||
token_str = str(token_list[0])
|
||||
except TypeError:
|
||||
token_str = ""
|
||||
expires_list = token_query.get("Expires")
|
||||
try:
|
||||
expires_str = str(expires_list[0])
|
||||
except TypeError:
|
||||
expires_str = ""
|
||||
if token_str != "None" and len(token_str) != 0:
|
||||
expire_at = None
|
||||
split = token_str.split("~")
|
||||
for s in split:
|
||||
try:
|
||||
i = s.index("=")
|
||||
except ValueError:
|
||||
continue
|
||||
if s[:i] == "exp":
|
||||
expire_at = int(s[i + 1:])
|
||||
break
|
||||
if expire_at is None:
|
||||
self.__expiration = -1
|
||||
self.__cdn_manager.logger.warning(
|
||||
"Invalid __token__ in CDN url: {}".format(url))
|
||||
return
|
||||
self.__expiration = expire_at * 1000
|
||||
elif expires_str != "None" and len(expires_str) != 0:
|
||||
expires_at = None
|
||||
expires_str = expires_str.split("~")[0]
|
||||
expires_at = int(expires_str)
|
||||
if expires_at is None:
|
||||
self.__expiration = -1
|
||||
self.__cdn_manager.logger.warning("Invalid Expires param in CDN url: {}".format(url))
|
||||
return
|
||||
self.__expiration = expires_at * 1000
|
||||
else:
|
||||
try:
|
||||
i = token_url.query.index("_")
|
||||
except ValueError:
|
||||
self.__expiration = -1
|
||||
self.__cdn_manager.logger \
|
||||
.warning("Couldn't extract expiration, invalid parameter in CDN url: {}".format(url))
|
||||
return
|
||||
self.__expiration = int(token_url.query[:i]) * 1000
|
||||
|
||||
else:
|
||||
self.__expiration = -1
|
||||
|
||||
class Streamer(GeneralAudioStream, GeneralWritableStream):
|
||||
available: typing.List[bool]
|
||||
buffer: typing.List[bytes]
|
||||
chunks: int
|
||||
executor_service = concurrent.futures.ThreadPoolExecutor()
|
||||
halt_listener: HaltListener
|
||||
requested: typing.List[bool]
|
||||
size: int
|
||||
__audio_format: SuperAudioFormat
|
||||
__audio_decrypt: AudioDecrypt
|
||||
__cdn_url: CdnManager.CdnUrl
|
||||
__internal_stream: InternalStream
|
||||
__session: Session
|
||||
__stream_id: StreamId
|
||||
|
||||
def __init__(self, session: Session, stream_id: StreamId,
|
||||
audio_format: SuperAudioFormat,
|
||||
cdn_url: CdnManager.CdnUrl, cache: CacheManager,
|
||||
audio_decrypt: AudioDecrypt, halt_listener: HaltListener):
|
||||
self.__session = session
|
||||
self.__stream_id = stream_id
|
||||
self.__audio_format = audio_format
|
||||
self.__audio_decrypt = audio_decrypt
|
||||
self.__cdn_url = cdn_url
|
||||
self.halt_listener = halt_listener
|
||||
response = self.request(range_start=0,
|
||||
range_end=ChannelManager.chunk_size - 1)
|
||||
content_range = response.headers.get("Content-Range")
|
||||
if content_range is None:
|
||||
raise IOError("Missing Content-Range header!")
|
||||
split = content_range.split("/")
|
||||
self.size = int(split[1])
|
||||
self.chunks = int(math.ceil(self.size / ChannelManager.chunk_size))
|
||||
first_chunk = response.buffer
|
||||
self.available = [False for _ in range(self.chunks)]
|
||||
self.requested = [False for _ in range(self.chunks)]
|
||||
self.buffer = [b"" for _ in range(self.chunks)]
|
||||
self.__internal_stream = CdnManager.Streamer.InternalStream(
|
||||
self, False)
|
||||
self.requested[0] = True
|
||||
self.write_chunk(first_chunk, 0, False)
|
||||
|
||||
def write_chunk(self, chunk: bytes, chunk_index: int,
|
||||
cached: bool) -> None:
|
||||
if self.__internal_stream.is_closed():
|
||||
return
|
||||
self.__session.logger.debug(
|
||||
"Chunk {}/{} completed, cached: {}, stream: {}".format(
|
||||
chunk_index + 1, self.chunks, cached, self.describe()))
|
||||
self.buffer[chunk_index] = self.__audio_decrypt.decrypt_chunk(
|
||||
chunk_index, chunk)
|
||||
self.__internal_stream.notify_chunk_available(chunk_index)
|
||||
|
||||
def stream(self) -> AbsChunkedInputStream:
|
||||
return self.__internal_stream
|
||||
|
||||
def codec(self) -> SuperAudioFormat:
|
||||
return self.__audio_format
|
||||
|
||||
def describe(self) -> str:
|
||||
if self.__stream_id.is_episode():
|
||||
return "episode_gid: {}".format(
|
||||
self.__stream_id.get_episode_gid())
|
||||
return "file_id: {}".format(self.__stream_id.get_file_id())
|
||||
|
||||
def decrypt_time_ms(self) -> int:
|
||||
return self.__audio_decrypt.decrypt_time_ms()
|
||||
|
||||
def request_chunk(self, index: int) -> None:
|
||||
response = self.request(index)
|
||||
self.write_chunk(response.buffer, index, False)
|
||||
|
||||
def request(self, chunk: int = None, range_start: int = None, range_end: int = None)\
|
||||
-> CdnManager.InternalResponse:
|
||||
if chunk is None and range_start is None and range_end is None:
|
||||
raise TypeError()
|
||||
if chunk is not None:
|
||||
range_start = ChannelManager.chunk_size * chunk
|
||||
range_end = (chunk + 1) * ChannelManager.chunk_size - 1
|
||||
response = self.__session.client().get(
|
||||
self.__cdn_url.url,
|
||||
headers={
|
||||
"Range": "bytes={}-{}".format(range_start, range_end)
|
||||
},
|
||||
)
|
||||
if response.status_code != 206:
|
||||
raise IOError(response.status_code)
|
||||
body = response.content
|
||||
if body is None:
|
||||
raise IOError("Response body is empty!")
|
||||
return CdnManager.InternalResponse(body, dict(response.headers))
|
||||
|
||||
class InternalStream(AbsChunkedInputStream):
|
||||
streamer: CdnManager.Streamer
|
||||
|
||||
def __init__(self, streamer, retry_on_chunk_error: bool):
|
||||
self.streamer: CdnManager.Streamer = streamer
|
||||
super().__init__(retry_on_chunk_error)
|
||||
|
||||
def buffer(self) -> typing.List[bytes]:
|
||||
return self.streamer.buffer
|
||||
|
||||
def size(self) -> int:
|
||||
return self.streamer.size
|
||||
|
||||
def close(self) -> None:
|
||||
super().close()
|
||||
del self.streamer.buffer
|
||||
|
||||
def requested_chunks(self) -> typing.List[bool]:
|
||||
return self.streamer.requested
|
||||
|
||||
def available_chunks(self) -> typing.List[bool]:
|
||||
return self.streamer.available
|
||||
|
||||
def chunks(self) -> int:
|
||||
return self.streamer.chunks
|
||||
|
||||
def request_chunk_from_stream(self, index: int) -> None:
|
||||
self.streamer.executor_service \
|
||||
.submit(lambda: self.streamer.request_chunk(index))
|
||||
|
||||
def stream_read_halted(self, chunk: int, _time: int) -> None:
|
||||
if self.streamer.halt_listener is not None:
|
||||
self.streamer.executor_service\
|
||||
.submit(lambda: self.streamer.halt_listener.stream_read_halted(chunk, _time))
|
||||
|
||||
def stream_read_resumed(self, chunk: int, _time: int) -> None:
|
||||
if self.streamer.halt_listener is not None:
|
||||
self.streamer.executor_service \
|
||||
.submit(lambda: self.streamer.halt_listener.stream_read_resumed(chunk, _time))
|
||||
|
||||
|
||||
class NormalizationData:
|
||||
_LOGGER: logging = logging.getLogger(__name__)
|
||||
track_gain_db: float
|
||||
track_peak: float
|
||||
album_gain_db: float
|
||||
album_peak: float
|
||||
|
||||
def __init__(self, track_gain_db: float, track_peak: float,
|
||||
album_gain_db: float, album_peak: float):
|
||||
self.track_gain_db = track_gain_db
|
||||
self.track_peak = track_peak
|
||||
self.album_gain_db = album_gain_db
|
||||
self.album_peak = album_peak
|
||||
|
||||
self._LOGGER.debug(
|
||||
"Loaded normalization data, track_gain: {}, track_peak: {}, album_gain: {}, album_peak: {}"
|
||||
.format(track_gain_db, track_peak, album_gain_db, album_peak))
|
||||
|
||||
@staticmethod
|
||||
def read(input_stream: AbsChunkedInputStream) -> NormalizationData:
|
||||
input_stream.seek(144)
|
||||
data = input_stream.read(4 * 4)
|
||||
input_stream.seek(0)
|
||||
buffer = io.BytesIO(data)
|
||||
return NormalizationData(
|
||||
struct.unpack("<f", buffer.read(4))[0],
|
||||
struct.unpack("<f", buffer.read(4))[0],
|
||||
struct.unpack("<f", buffer.read(4))[0],
|
||||
struct.unpack("<f", buffer.read(4))[0])
|
||||
|
||||
def get_factor(self, normalisation_pregain) -> float:
|
||||
normalisation_factor = float(
|
||||
math.pow(10, (self.track_gain_db + normalisation_pregain) / 20))
|
||||
if normalisation_factor * self.track_peak > 1:
|
||||
self._LOGGER \
|
||||
.warning("Reducing normalisation factor to prevent clipping. Please add negative pregain to avoid.")
|
||||
normalisation_factor = 1 / self.track_peak
|
||||
return normalisation_factor
|
||||
|
||||
|
||||
class PlayableContentFeeder:
|
||||
logger = logging.getLogger("Librespot:PlayableContentFeeder")
|
||||
storage_resolve_interactive = "/storage-resolve/files/audio/interactive/{}"
|
||||
storage_resolve_interactive_prefetch = "/storage-resolve/files/audio/interactive_prefetch/{}"
|
||||
__session: Session
|
||||
|
||||
def __init__(self, session: Session):
|
||||
self.__session = session
|
||||
|
||||
def load(self, playable_id: PlayableId,
|
||||
audio_quality_picker: AudioQualityPicker, preload: bool,
|
||||
halt_listener: typing.Union[HaltListener, None]):
|
||||
if type(playable_id) is TrackId:
|
||||
return self.load_track(playable_id, audio_quality_picker, preload,
|
||||
halt_listener)
|
||||
if type(playable_id) is EpisodeId:
|
||||
return self.load_episode(playable_id, audio_quality_picker,
|
||||
preload, halt_listener)
|
||||
raise TypeError("Unknown content: {}".format(playable_id))
|
||||
|
||||
def load_stream(self, file: Metadata.AudioFile, track: Metadata.Track,
|
||||
episode: Metadata.Episode, preload: bool,
|
||||
halt_lister: HaltListener):
|
||||
if track is None and episode is None:
|
||||
raise RuntimeError()
|
||||
response = self.resolve_storage_interactive(file.file_id, preload)
|
||||
if response.result == StorageResolve.StorageResolveResponse.Result.CDN:
|
||||
if track is not None:
|
||||
return CdnFeedHelper.load_track(self.__session, track, file,
|
||||
response, preload, halt_lister)
|
||||
return CdnFeedHelper.load_episode(self.__session, episode, file,
|
||||
response, preload, halt_lister)
|
||||
if response.result == StorageResolve.StorageResolveResponse.Result.STORAGE:
|
||||
if track is None:
|
||||
pass
|
||||
elif response.result == StorageResolve.StorageResolveResponse.Result.RESTRICTED:
|
||||
raise RuntimeError("Content is restricted!")
|
||||
elif response.result == StorageResolve.StorageResolveResponse.Response.UNRECOGNIZED:
|
||||
raise RuntimeError("Content is unrecognized!")
|
||||
else:
|
||||
raise RuntimeError("Unknown result: {}".format(response.result))
|
||||
|
||||
def load_episode(self, episode_id: EpisodeId,
|
||||
audio_quality_picker: AudioQualityPicker, preload: bool,
|
||||
halt_listener: HaltListener) -> LoadedStream:
|
||||
episode = self.__session.api().get_metadata_4_episode(episode_id)
|
||||
if episode.external_url:
|
||||
return CdnFeedHelper.load_episode_external(self.__session, episode,
|
||||
halt_listener)
|
||||
file = audio_quality_picker.get_file(episode.audio)
|
||||
if file is None:
|
||||
self.logger.fatal(
|
||||
"Couldn't find any suitable audio file, available: {}".format(
|
||||
episode.audio))
|
||||
return self.load_stream(file, None, episode, preload, halt_listener)
|
||||
|
||||
def load_track(self, track_id_or_track: typing.Union[TrackId,
|
||||
Metadata.Track],
|
||||
audio_quality_picker: AudioQualityPicker, preload: bool,
|
||||
halt_listener: HaltListener):
|
||||
if type(track_id_or_track) is TrackId:
|
||||
original = self.__session.api().get_metadata_4_track(
|
||||
track_id_or_track)
|
||||
track = self.pick_alternative_if_necessary(original)
|
||||
if track is None:
|
||||
raise RuntimeError("Cannot get alternative track")
|
||||
else:
|
||||
track = track_id_or_track
|
||||
file = audio_quality_picker.get_file(track.file)
|
||||
if file is None:
|
||||
self.logger.fatal(
|
||||
"Couldn't find any suitable audio file, available: {}".format(
|
||||
track.file))
|
||||
raise FeederException()
|
||||
return self.load_stream(file, track, None, preload, halt_listener)
|
||||
|
||||
def pick_alternative_if_necessary(
|
||||
self, track: Metadata.Track) -> typing.Union[Metadata.Track, None]:
|
||||
if len(track.file) > 0:
|
||||
return track
|
||||
for alt in track.alternative:
|
||||
if len(alt.file) > 0:
|
||||
return Metadata.Track(
|
||||
gid=track.gid,
|
||||
name=track.name,
|
||||
album=track.album,
|
||||
artist=track.artist,
|
||||
number=track.number,
|
||||
disc_number=track.disc_number,
|
||||
duration=track.duration,
|
||||
popularity=track.popularity,
|
||||
explicit=track.explicit,
|
||||
external_id=track.external_id,
|
||||
restriction=track.restriction,
|
||||
file=alt.file,
|
||||
sale_period=track.sale_period,
|
||||
preview=track.preview,
|
||||
tags=track.tags,
|
||||
earliest_live_timestamp=track.earliest_live_timestamp,
|
||||
has_lyrics=track.has_lyrics,
|
||||
availability=track.availability,
|
||||
licensor=track.licensor)
|
||||
return None
|
||||
|
||||
def resolve_storage_interactive(
|
||||
self, file_id: bytes,
|
||||
preload: bool) -> StorageResolve.StorageResolveResponse:
|
||||
resp = self.__session.api().send(
|
||||
"GET",
|
||||
(self.storage_resolve_interactive_prefetch
|
||||
if preload else self.storage_resolve_interactive).format(
|
||||
util.bytes_to_hex(file_id)),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
if resp.status_code != 200:
|
||||
raise RuntimeError(resp.status_code)
|
||||
body = resp.content
|
||||
if body is None:
|
||||
raise RuntimeError("Response body is empty!")
|
||||
storage_resolve_response = StorageResolve.StorageResolveResponse()
|
||||
storage_resolve_response.ParseFromString(body)
|
||||
return storage_resolve_response
|
||||
|
||||
class LoadedStream:
|
||||
episode: Metadata.Episode
|
||||
track: Metadata.Track
|
||||
input_stream: GeneralAudioStream
|
||||
normalization_data: NormalizationData
|
||||
metrics: PlayableContentFeeder.Metrics
|
||||
|
||||
def __init__(self, track_or_episode: typing.Union[Metadata.Track,
|
||||
Metadata.Episode],
|
||||
input_stream: GeneralAudioStream,
|
||||
normalization_data: typing.Union[NormalizationData, None],
|
||||
metrics: PlayableContentFeeder.Metrics):
|
||||
if type(track_or_episode) is Metadata.Track:
|
||||
self.track = track_or_episode
|
||||
self.episode = None
|
||||
elif type(track_or_episode) is Metadata.Episode:
|
||||
self.track = None
|
||||
self.episode = track_or_episode
|
||||
else:
|
||||
raise TypeError()
|
||||
self.input_stream = input_stream
|
||||
self.normalization_data = normalization_data
|
||||
self.metrics = metrics
|
||||
|
||||
class Metrics:
|
||||
file_id: str
|
||||
preloaded_audio_key: bool
|
||||
audio_key_time: int
|
||||
|
||||
def __init__(self, file_id: typing.Union[bytes, None],
|
||||
preloaded_audio_key: bool, audio_key_time: int):
|
||||
self.file_id = None if file_id is None else util.bytes_to_hex(
|
||||
file_id)
|
||||
self.preloaded_audio_key = preloaded_audio_key
|
||||
self.audio_key_time = audio_key_time
|
||||
if preloaded_audio_key and audio_key_time != -1:
|
||||
raise RuntimeError()
|
||||
|
||||
|
||||
class StreamId:
|
||||
file_id: bytes
|
||||
episode_gid: bytes
|
||||
|
||||
def __init__(self,
|
||||
file: Metadata.AudioFile = None,
|
||||
episode: Metadata.Episode = None):
|
||||
if file is None and episode is None:
|
||||
return
|
||||
self.file_id = None if file is None else file.file_id
|
||||
self.episode_gid = None if episode is None else episode.gid
|
||||
|
||||
def get_file_id(self):
|
||||
if self.file_id is None:
|
||||
raise RuntimeError("Not a file!")
|
||||
return util.bytes_to_hex(self.file_id)
|
||||
|
||||
def is_episode(self):
|
||||
return self.episode_gid is not None
|
||||
|
||||
def get_episode_gid(self):
|
||||
if self.episode_gid is None:
|
||||
raise RuntimeError("Not an episode!")
|
||||
return util.bytes_to_hex(self.episode_gid)
|
||||
81
resources/lib/librespot/audio/decoders.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
from __future__ import annotations
|
||||
from librespot.audio import SuperAudioFormat
|
||||
from librespot.proto import Metadata_pb2 as Metadata
|
||||
from librespot.proto.Metadata_pb2 import AudioFile
|
||||
from librespot.structure import AudioQualityPicker
|
||||
import enum
|
||||
import logging
|
||||
import typing
|
||||
|
||||
|
||||
class AudioQuality(enum.Enum):
|
||||
NORMAL = 0x00
|
||||
HIGH = 0x01
|
||||
VERY_HIGH = 0x02
|
||||
|
||||
@staticmethod
|
||||
def get_quality(audio_format: AudioFile.Format) -> AudioQuality:
|
||||
if audio_format in [
|
||||
AudioFile.MP3_96,
|
||||
AudioFile.OGG_VORBIS_96,
|
||||
AudioFile.AAC_24_NORM,
|
||||
]:
|
||||
return AudioQuality.NORMAL
|
||||
if audio_format in [
|
||||
AudioFile.MP3_160,
|
||||
AudioFile.MP3_160_ENC,
|
||||
AudioFile.OGG_VORBIS_160,
|
||||
AudioFile.AAC_24,
|
||||
]:
|
||||
return AudioQuality.HIGH
|
||||
if audio_format in [
|
||||
AudioFile.MP3_320,
|
||||
AudioFile.MP3_256,
|
||||
AudioFile.OGG_VORBIS_320,
|
||||
AudioFile.AAC_48,
|
||||
]:
|
||||
return AudioQuality.VERY_HIGH
|
||||
raise RuntimeError("Unknown format: {}".format(format))
|
||||
|
||||
def get_matches(self,
|
||||
files: typing.List[AudioFile]) -> typing.List[AudioFile]:
|
||||
file_list = []
|
||||
for file in files:
|
||||
if hasattr(file, "format") and AudioQuality.get_quality(
|
||||
file.format) == self:
|
||||
file_list.append(file)
|
||||
return file_list
|
||||
|
||||
|
||||
class VorbisOnlyAudioQuality(AudioQualityPicker):
|
||||
logger = logging.getLogger("Librespot:Player:VorbisOnlyAudioQuality")
|
||||
preferred: AudioQuality
|
||||
|
||||
def __init__(self, preferred: AudioQuality):
|
||||
self.preferred = preferred
|
||||
|
||||
@staticmethod
|
||||
def get_vorbis_file(files: typing.List[Metadata.AudioFile]):
|
||||
for file in files:
|
||||
if file.HasField("format") and SuperAudioFormat.get(
|
||||
file.format) == SuperAudioFormat.VORBIS:
|
||||
return file
|
||||
return None
|
||||
|
||||
def get_file(self, files: typing.List[Metadata.AudioFile]):
|
||||
matches: typing.List[Metadata.AudioFile] = self.preferred.get_matches(
|
||||
files)
|
||||
vorbis: Metadata.AudioFile = VorbisOnlyAudioQuality.get_vorbis_file(
|
||||
matches)
|
||||
if vorbis is None:
|
||||
vorbis: Metadata.AudioFile = VorbisOnlyAudioQuality.get_vorbis_file(
|
||||
files)
|
||||
if vorbis is not None:
|
||||
self.logger.warning(
|
||||
"Using {} because preferred {} couldn't be found.".format(
|
||||
Metadata.AudioFile.Format.Name(vorbis.format),
|
||||
self.preferred))
|
||||
else:
|
||||
self.logger.fatal(
|
||||
"Couldn't find any Vorbis file, available: {}")
|
||||
return vorbis
|
||||
45
resources/lib/librespot/audio/decrypt.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
from __future__ import annotations
|
||||
from Cryptodome.Cipher import AES
|
||||
from Cryptodome.Util import Counter
|
||||
from librespot.audio.storage import ChannelManager
|
||||
from librespot.structure import AudioDecrypt
|
||||
import io
|
||||
import time
|
||||
|
||||
|
||||
class AesAudioDecrypt(AudioDecrypt):
|
||||
audio_aes_iv = b'r\xe0g\xfb\xdd\xcb\xcfw\xeb\xe8\xbcd?c\r\x93'
|
||||
cipher = None
|
||||
decrypt_count = 0
|
||||
decrypt_total_time = 0
|
||||
iv_int = int.from_bytes(audio_aes_iv, "big")
|
||||
iv_diff = 0x100
|
||||
key: bytes
|
||||
|
||||
def __init__(self, key: bytes):
|
||||
self.key = key
|
||||
|
||||
def decrypt_chunk(self, chunk_index: int, buffer: bytes):
|
||||
new_buffer = io.BytesIO()
|
||||
iv = self.iv_int + int(ChannelManager.chunk_size * chunk_index / 16)
|
||||
start = time.time_ns()
|
||||
for i in range(0, len(buffer), 4096):
|
||||
cipher = AES.new(key=self.key,
|
||||
mode=AES.MODE_CTR,
|
||||
counter=Counter.new(128, initial_value=iv))
|
||||
count = min(4096, len(buffer) - i)
|
||||
decrypted_buffer = cipher.decrypt(buffer[i:i + count])
|
||||
new_buffer.write(decrypted_buffer)
|
||||
if count != len(decrypted_buffer):
|
||||
raise RuntimeError(
|
||||
"Couldn't process all data, actual: {}, expected: {}".
|
||||
format(len(decrypted_buffer), count))
|
||||
iv += self.iv_diff
|
||||
self.decrypt_total_time += time.time_ns() - start
|
||||
self.decrypt_count += 1
|
||||
new_buffer.seek(0)
|
||||
return new_buffer.read()
|
||||
|
||||
def decrypt_time_ms(self):
|
||||
return 0 if self.decrypt_count == 0 else int(
|
||||
(self.decrypt_total_time / self.decrypt_count) / 1000000)
|
||||
32
resources/lib/librespot/audio/format.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
from librespot.proto import Metadata_pb2 as Metadata
|
||||
import enum
|
||||
|
||||
|
||||
class SuperAudioFormat(enum.Enum):
|
||||
MP3 = 0x00
|
||||
VORBIS = 0x01
|
||||
AAC = 0x02
|
||||
|
||||
@staticmethod
|
||||
def get(audio_format: Metadata.AudioFile.Format):
|
||||
if audio_format in [
|
||||
Metadata.AudioFile.Format.OGG_VORBIS_96,
|
||||
Metadata.AudioFile.Format.OGG_VORBIS_160,
|
||||
Metadata.AudioFile.Format.OGG_VORBIS_320,
|
||||
]:
|
||||
return SuperAudioFormat.VORBIS
|
||||
if audio_format in [
|
||||
Metadata.AudioFile.Format.MP3_256,
|
||||
Metadata.AudioFile.Format.MP3_320,
|
||||
Metadata.AudioFile.Format.MP3_160,
|
||||
Metadata.AudioFile.Format.MP3_96,
|
||||
Metadata.AudioFile.Format.MP3_160_ENC,
|
||||
]:
|
||||
return SuperAudioFormat.MP3
|
||||
if audio_format in [
|
||||
Metadata.AudioFile.Format.AAC_24,
|
||||
Metadata.AudioFile.Format.AAC_48,
|
||||
Metadata.AudioFile.Format.AAC_24_NORM,
|
||||
]:
|
||||
return SuperAudioFormat.AAC
|
||||
raise RuntimeError("Unknown audio format: {}".format(audio_format))
|
||||
139
resources/lib/librespot/audio/storage.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
from __future__ import annotations
|
||||
from librespot import util
|
||||
from librespot.crypto import Packet
|
||||
from librespot.proto.Metadata_pb2 import AudioFile
|
||||
from librespot.structure import Closeable, PacketsReceiver
|
||||
import concurrent.futures
|
||||
import io
|
||||
import logging
|
||||
import queue
|
||||
import struct
|
||||
import threading
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from librespot.core import Session
|
||||
|
||||
|
||||
class ChannelManager(Closeable, PacketsReceiver):
|
||||
channels: typing.Dict[int, Channel] = {}
|
||||
chunk_size = 128 * 1024
|
||||
executor_service = concurrent.futures.ThreadPoolExecutor()
|
||||
logger = logging.getLogger("Librespot:ChannelManager")
|
||||
seq_holder = 0
|
||||
seq_holder_lock = threading.Condition()
|
||||
__session: Session = None
|
||||
|
||||
def __init__(self, session: Session):
|
||||
self.__session = session
|
||||
|
||||
def request_chunk(self, file_id: bytes, index: int, file: AudioFile):
|
||||
start = int(index * self.chunk_size / 4)
|
||||
end = int((index + 1) * self.chunk_size / 4)
|
||||
channel = ChannelManager.Channel(self, file, index)
|
||||
self.channels[channel.chunk_id] = channel
|
||||
out = io.BytesIO()
|
||||
out.write(struct.pack(">H", channel.chunk_id))
|
||||
out.write(struct.pack(">i", 0x00000000))
|
||||
out.write(struct.pack(">i", 0x00000000))
|
||||
out.write(struct.pack(">i", 0x00004E20))
|
||||
out.write(struct.pack(">i", 0x00030D40))
|
||||
out.write(file_id)
|
||||
out.write(struct.pack(">i", start))
|
||||
out.write(struct.pack(">i", end))
|
||||
out.seek(0)
|
||||
self.__session.send(Packet.Type.stream_chunk, out.read())
|
||||
|
||||
def dispatch(self, packet: Packet) -> None:
|
||||
payload = io.BytesIO(packet.payload)
|
||||
if packet.is_cmd(Packet.Type.stream_chunk_res):
|
||||
chunk_id = struct.unpack(">H", payload.read(2))[0]
|
||||
channel = self.channels.get(chunk_id)
|
||||
if channel is None:
|
||||
self.logger.warning(
|
||||
"Couldn't find channel, id: {}, received: {}".format(
|
||||
chunk_id, len(packet.payload)))
|
||||
return
|
||||
channel.add_to_queue(payload)
|
||||
elif packet.is_cmd(Packet.Type.channel_error):
|
||||
chunk_id = struct.unpack(">H", payload.read(2))[0]
|
||||
channel = self.channels.get(chunk_id)
|
||||
if channel is None:
|
||||
self.logger.warning(
|
||||
"Dropping channel error, id: {}, code: {}".format(
|
||||
chunk_id,
|
||||
struct.unpack(">H", payload.read(2))[0]))
|
||||
return
|
||||
channel.stream_error(struct.unpack(">H", payload.read(2))[0])
|
||||
else:
|
||||
self.logger.warning(
|
||||
"Couldn't handle packet, cmd: {}, payload: {}".format(
|
||||
packet.cmd, util.bytes_to_hex(packet.payload)))
|
||||
|
||||
def close(self) -> None:
|
||||
self.executor_service.shutdown()
|
||||
|
||||
class Channel:
|
||||
channel_manager: ChannelManager
|
||||
chunk_id: int
|
||||
q = queue.Queue()
|
||||
__buffer: io.BytesIO
|
||||
__chunk_index: int
|
||||
__file: AudioFile
|
||||
__header: bool = True
|
||||
|
||||
def __init__(self, channel_manager: ChannelManager, file: AudioFile,
|
||||
chunk_index: int):
|
||||
self.__buffer = io.BytesIO()
|
||||
self.channel_manager = channel_manager
|
||||
self.__file = file
|
||||
self.__chunk_index = chunk_index
|
||||
with self.channel_manager.seq_holder_lock:
|
||||
self.chunk_id = self.channel_manager.seq_holder
|
||||
self.channel_manager.seq_holder += 1
|
||||
self.channel_manager.executor_service.submit(
|
||||
lambda: ChannelManager.Channel.Handler(self))
|
||||
|
||||
def _handle(self, payload: bytes) -> bool:
|
||||
if len(payload) == 0:
|
||||
if not self.__header:
|
||||
self.__file.write_chunk(payload, self.__chunk_index, False)
|
||||
return True
|
||||
self.channel_manager.logger.debug(
|
||||
"Received empty chunk, skipping.")
|
||||
return False
|
||||
if self.__header:
|
||||
length: int
|
||||
while len(payload.buffer) > 0:
|
||||
length = payload.read_short()
|
||||
if not length > 0:
|
||||
break
|
||||
header_id = payload.read_byte()
|
||||
header_data = payload.read(length - 1)
|
||||
self.__file.write_header(int.from_bytes(header_id, "big"),
|
||||
bytearray(header_data), False)
|
||||
self.__header = False
|
||||
else:
|
||||
self.__buffer.write(payload.read(len(payload.buffer)))
|
||||
return False
|
||||
|
||||
def add_to_queue(self, payload):
|
||||
self.q.put(payload)
|
||||
|
||||
def stream_error(self, code: int) -> None:
|
||||
self.__file.stream_error(self.__chunk_index, code)
|
||||
|
||||
class Handler:
|
||||
__channel: ChannelManager.Channel = None
|
||||
|
||||
def __init__(self, channel: ChannelManager.Channel):
|
||||
self.__channel = channel
|
||||
|
||||
def run(self) -> None:
|
||||
self.__channel.channel_manager.logger.debug(
|
||||
"ChannelManager.Handler is starting")
|
||||
with self.__channel.q.all_tasks_done:
|
||||
self.__channel.channel_manager.channels.pop(
|
||||
self.__channel.chunk_id)
|
||||
self.__channel.channel_manager.logger.debug(
|
||||
"ChannelManager.Handler is shutting down")
|
||||
18
resources/lib/librespot/cache.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from __future__ import annotations
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from librespot.core import Session
|
||||
|
||||
|
||||
class CacheManager:
|
||||
clean_up_threshold = 604800000
|
||||
header_hash = 253
|
||||
header_timestamp = 254
|
||||
parent: str
|
||||
|
||||
def __init__(self, session: Session):
|
||||
"""
|
||||
@Todo Implement function
|
||||
:param session:
|
||||
"""
|
||||
2307
resources/lib/librespot/core.py
Normal file
412
resources/lib/librespot/crypto.py
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
from __future__ import annotations
|
||||
from Cryptodome import Random
|
||||
from librespot import util
|
||||
import io
|
||||
import re
|
||||
import struct
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from librespot.core import Session
|
||||
|
||||
|
||||
class CipherPair:
|
||||
__receive_cipher: Shannon
|
||||
__receive_nonce = 0
|
||||
__send_cipher: Shannon
|
||||
__send_nonce = 0
|
||||
|
||||
def __init__(self, send_key: bytes, receive_key: bytes):
|
||||
self.__send_cipher = Shannon()
|
||||
self.__send_cipher.key(send_key)
|
||||
self.__receive_cipher = Shannon()
|
||||
self.__receive_cipher.key(receive_key)
|
||||
|
||||
def send_encoded(self, connection: Session.ConnectionHolder, cmd: bytes,
|
||||
payload: bytes) -> None:
|
||||
"""
|
||||
Send decrypted data to the socket
|
||||
:param connection:
|
||||
:param cmd:
|
||||
:param payload:
|
||||
:return:
|
||||
"""
|
||||
self.__send_cipher.nonce(self.__send_nonce)
|
||||
self.__send_nonce += 1
|
||||
buffer = io.BytesIO()
|
||||
buffer.write(cmd)
|
||||
buffer.write(struct.pack(">H", len(payload)))
|
||||
buffer.write(payload)
|
||||
buffer.seek(0)
|
||||
contents = self.__send_cipher.encrypt(buffer.read())
|
||||
mac = self.__send_cipher.finish(4)
|
||||
connection.write(contents)
|
||||
connection.write(mac)
|
||||
connection.flush()
|
||||
|
||||
def receive_encoded(self, connection: Session.ConnectionHolder) -> Packet:
|
||||
"""
|
||||
Receive and parse decrypted data from the socket
|
||||
Args:
|
||||
connection: ConnectionHolder
|
||||
Return:
|
||||
The parsed packet will be returned
|
||||
"""
|
||||
try:
|
||||
self.__receive_cipher.nonce(self.__receive_nonce)
|
||||
self.__receive_nonce += 1
|
||||
header_bytes = self.__receive_cipher.decrypt(connection.read(3))
|
||||
cmd = struct.pack(">s", bytes([header_bytes[0]]))
|
||||
payload_length = (header_bytes[1] << 8) | (header_bytes[2] & 0xff)
|
||||
payload_bytes = self.__receive_cipher.decrypt(
|
||||
connection.read(payload_length))
|
||||
mac = connection.read(4)
|
||||
expected_mac = self.__receive_cipher.finish(4)
|
||||
if mac != expected_mac:
|
||||
raise RuntimeError()
|
||||
return Packet(cmd, payload_bytes)
|
||||
except IndexError:
|
||||
raise RuntimeError("Failed to receive packet")
|
||||
|
||||
|
||||
class DiffieHellman:
|
||||
"""
|
||||
DiffieHellman Keyexchange
|
||||
"""
|
||||
__prime = int.from_bytes(
|
||||
b'\xff\xff\xff\xff\xff\xff\xff\xff\xc9\x0f'
|
||||
b'\xda\xa2!h\xc24\xc4\xc6b\x8b\x80\xdc\x1c'
|
||||
b'\xd1)\x02N\x08\x8ag\xcct\x02\x0b\xbe\xa6;'
|
||||
b'\x13\x9b"QJ\x08y\x8e4\x04\xdd\xef\x95\x19'
|
||||
b'\xb3\xcd:C\x1b0+\nm\xf2_\x147O\xe15mmQ\xc2'
|
||||
b'E\xe4\x85\xb5vb^~\xc6\xf4LB\xe9\xa6:6 \xff'
|
||||
b'\xff\xff\xff\xff\xff\xff\xff',
|
||||
byteorder="big")
|
||||
__private_key: int
|
||||
__public_key: int
|
||||
|
||||
def __init__(self):
|
||||
key_data = Random.get_random_bytes(0x5f)
|
||||
self.__private_key = int.from_bytes(key_data, byteorder="big")
|
||||
self.__public_key = pow(2, self.__private_key, self.__prime)
|
||||
|
||||
def compute_shared_key(self, remote_key_bytes: bytes):
|
||||
"""
|
||||
Compute shared_key
|
||||
"""
|
||||
remote_key = int.from_bytes(remote_key_bytes, "big")
|
||||
return pow(remote_key, self.__private_key, self.__prime)
|
||||
|
||||
def private_key(self) -> int:
|
||||
"""
|
||||
Return DiffieHellman's private key
|
||||
Returns:
|
||||
DiffieHellman's private key
|
||||
"""
|
||||
return self.__private_key
|
||||
|
||||
def public_key(self) -> int:
|
||||
"""
|
||||
Return DiffieHellman's public key
|
||||
Returns:
|
||||
DiffieHellman's public key
|
||||
"""
|
||||
return self.__public_key
|
||||
|
||||
def public_key_bytes(self) -> bytes:
|
||||
"""
|
||||
Return DiffieHellman's packed public key
|
||||
Returns:
|
||||
DiffieHellman's packed public key
|
||||
"""
|
||||
return util.int_to_bytes(self.__public_key)
|
||||
|
||||
|
||||
class Packet:
|
||||
cmd: bytes
|
||||
payload: bytes
|
||||
|
||||
def __init__(self, cmd: bytes, payload: bytes):
|
||||
self.cmd = cmd
|
||||
self.payload = payload
|
||||
|
||||
def is_cmd(self, cmd: bytes) -> bool:
|
||||
return cmd == self.cmd
|
||||
|
||||
class Type:
|
||||
secret_block = b"\x02"
|
||||
ping = b"\x04"
|
||||
stream_chunk = b"\x08"
|
||||
stream_chunk_res = b"\x09"
|
||||
channel_error = b"\x0a"
|
||||
channel_abort = b"\x0b"
|
||||
request_key = b"\x0c"
|
||||
aes_key = b"\x0d"
|
||||
aes_key_error = b"\x0e"
|
||||
image = b"\x19"
|
||||
country_code = b"\x1b"
|
||||
pong = b"\x49"
|
||||
pong_ack = b"\x4a"
|
||||
pause = b"\x4b"
|
||||
product_info = b"\x50"
|
||||
legacy_welcome = b"\x69"
|
||||
license_version = b"\x76"
|
||||
login = b"\xab"
|
||||
ap_welcome = b"\xac"
|
||||
auth_failure = b"\xad"
|
||||
mercury_req = b"\xb2"
|
||||
mercury_sub = b"\xb3"
|
||||
mercury_unsub = b"\xb4"
|
||||
mercury_event = b"\xb5"
|
||||
track_ended_time = b"\x82"
|
||||
unknown_data_all_zeros = b"\x1f"
|
||||
preferred_locale = b"\x74"
|
||||
unknown_0x4f = b"\x4f"
|
||||
unknown_0x0f = b"\x0f"
|
||||
unknown_0x10 = b"\x10"
|
||||
|
||||
@staticmethod
|
||||
def parse(val: typing.Union[bytes, None]) -> typing.Union[bytes, None]:
|
||||
for cmd in [
|
||||
Packet.Type.__dict__[attr] for attr in Packet.Type.__dict__
|
||||
if re.search("__.+?__", attr) is None
|
||||
and type(Packet.Type.__dict__[attr]) is bytes
|
||||
]:
|
||||
if cmd == val:
|
||||
return cmd
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def for_method(method: str) -> bytes:
|
||||
if method == "SUB":
|
||||
return Packet.Type.mercury_sub
|
||||
if method == "UNSUB":
|
||||
return Packet.Type.mercury_unsub
|
||||
return Packet.Type.mercury_req
|
||||
|
||||
|
||||
class Shannon:
|
||||
n = 16
|
||||
fold = n
|
||||
initkonst = 0x6996c53a
|
||||
keyp = 13
|
||||
r: list
|
||||
crc: list
|
||||
init_r: list
|
||||
konst: int
|
||||
sbuf: int
|
||||
mbuf: int
|
||||
nbuf: int
|
||||
|
||||
def __init__(self):
|
||||
self.r = [0 for _ in range(self.n)]
|
||||
self.crc = [0 for _ in range(self.n)]
|
||||
self.init_r = [0 for _ in range(self.n)]
|
||||
|
||||
def rotl(self, i: int, distance: int) -> int:
|
||||
return ((i << distance) | (i >> (32 - distance))) & 0xffffffff
|
||||
|
||||
def sbox(self, i: int) -> int:
|
||||
i ^= self.rotl(i, 5) | self.rotl(i, 7)
|
||||
i ^= self.rotl(i, 19) | self.rotl(i, 22)
|
||||
return i
|
||||
|
||||
def sbox2(self, i: int) -> int:
|
||||
i ^= self.rotl(i, 7) | self.rotl(i, 22)
|
||||
i ^= self.rotl(i, 5) | self.rotl(i, 19)
|
||||
return i
|
||||
|
||||
def cycle(self) -> None:
|
||||
t: int
|
||||
t = self.r[12] ^ self.r[13] ^ self.konst
|
||||
t = self.sbox(t) ^ self.rotl(self.r[0], 1)
|
||||
for i in range(1, self.n):
|
||||
self.r[i - 1] = self.r[i]
|
||||
self.r[self.n - 1] = t
|
||||
t = self.sbox2(self.r[2] ^ self.r[15])
|
||||
self.r[0] ^= t
|
||||
self.sbuf = t ^ self.r[8] ^ self.r[12]
|
||||
|
||||
def crc_func(self, i: int) -> None:
|
||||
t: int
|
||||
t = self.crc[0] ^ self.crc[2] ^ self.crc[15] ^ i
|
||||
for j in range(1, self.n):
|
||||
self.crc[j - 1] = self.crc[j]
|
||||
self.crc[self.n - 1] = t
|
||||
|
||||
def mac_func(self, i: int) -> None:
|
||||
self.crc_func(i)
|
||||
self.r[self.keyp] ^= i
|
||||
|
||||
def init_state(self) -> None:
|
||||
self.r[0] = 1
|
||||
self.r[1] = 1
|
||||
for i in range(2, self.n):
|
||||
self.r[i] = self.r[i - 1] + self.r[i - 2]
|
||||
self.konst = self.initkonst
|
||||
|
||||
def save_state(self) -> None:
|
||||
for i in range(self.n):
|
||||
self.init_r[i] = self.r[i]
|
||||
|
||||
def reload_state(self) -> None:
|
||||
for i in range(self.n):
|
||||
self.r[i] = self.init_r[i]
|
||||
|
||||
def gen_konst(self) -> None:
|
||||
self.konst = self.r[0]
|
||||
|
||||
def add_key(self, k: int) -> None:
|
||||
self.r[self.keyp] ^= k
|
||||
|
||||
def diffuse(self) -> None:
|
||||
for _ in range(self.fold):
|
||||
self.cycle()
|
||||
|
||||
def load_key(self, key: bytes) -> None:
|
||||
i: int
|
||||
j: int
|
||||
t: int
|
||||
padding_size = int((len(key) + 3) / 4) * 4 - len(key)
|
||||
key = key + (b"\x00" * padding_size) + struct.pack("<I", len(key))
|
||||
for i in range(0, len(key), 4):
|
||||
self.r[self.keyp] = \
|
||||
self.r[self.keyp] ^ \
|
||||
struct.unpack("<I", key[i: i + 4])[0]
|
||||
self.cycle()
|
||||
for i in range(self.n):
|
||||
self.crc[i] = self.r[i]
|
||||
self.diffuse()
|
||||
for i in range(self.n):
|
||||
self.r[i] ^= self.crc[i]
|
||||
|
||||
def key(self, key: bytes) -> None:
|
||||
self.init_state()
|
||||
self.load_key(key)
|
||||
self.gen_konst()
|
||||
self.save_state()
|
||||
self.nbuf = 0
|
||||
|
||||
def nonce(self, nonce: typing.Union[bytes, int]) -> None:
|
||||
if type(nonce) is int:
|
||||
nonce = bytes(struct.pack(">I", nonce))
|
||||
self.reload_state()
|
||||
self.konst = self.initkonst
|
||||
self.load_key(nonce)
|
||||
self.gen_konst()
|
||||
self.nbuf = 0
|
||||
|
||||
def encrypt(self, buffer: bytes, n: int = None) -> bytes:
|
||||
if n is None:
|
||||
return self.encrypt(buffer, len(buffer))
|
||||
buffer = bytearray(buffer)
|
||||
i = 0
|
||||
j: int
|
||||
t: int
|
||||
if self.nbuf != 0:
|
||||
while self.nbuf != 0 and n != 0:
|
||||
self.mbuf ^= (buffer[i] & 0xff) << (32 - self.nbuf)
|
||||
buffer[i] ^= (self.sbuf >> (32 - self.nbuf)) & 0xff
|
||||
i += 1
|
||||
self.nbuf -= 8
|
||||
n -= 1
|
||||
if self.nbuf != 0:
|
||||
return b""
|
||||
self.mac_func(self.mbuf)
|
||||
j = n & ~0x03
|
||||
while i < j:
|
||||
self.cycle()
|
||||
t = ((buffer[i + 3] & 0xFF) << 24) | \
|
||||
((buffer[i + 2] & 0xFF) << 16) | \
|
||||
((buffer[i + 1] & 0xFF) << 8) | \
|
||||
(buffer[i] & 0xFF)
|
||||
self.mac_func(t)
|
||||
t ^= self.sbuf
|
||||
buffer[i + 3] = (t >> 24) & 0xFF
|
||||
buffer[i + 2] = (t >> 16) & 0xFF
|
||||
buffer[i + 1] = (t >> 8) & 0xFF
|
||||
buffer[i] = t & 0xFF
|
||||
i += 4
|
||||
n &= 0x03
|
||||
if n != 0:
|
||||
self.cycle()
|
||||
self.mbuf = 0
|
||||
self.nbuf = 32
|
||||
while self.nbuf != 0 and n != 0:
|
||||
self.mbuf ^= (buffer[i] & 0xff) << (32 - self.nbuf)
|
||||
buffer[i] ^= (self.sbuf >> (32 - self.nbuf)) & 0xff
|
||||
i += 1
|
||||
self.nbuf -= 8
|
||||
n -= 1
|
||||
return bytes(buffer)
|
||||
|
||||
def decrypt(self, buffer: bytes, n: int = None) -> bytes:
|
||||
if n is None:
|
||||
return self.decrypt(buffer, len(buffer))
|
||||
buffer = bytearray(buffer)
|
||||
i = 0
|
||||
j: int
|
||||
t: int
|
||||
if self.nbuf != 0:
|
||||
while self.nbuf != 0 and n != 0:
|
||||
buffer[i] ^= (self.sbuf >> (32 - self.nbuf)) & 0xff
|
||||
self.mbuf ^= (buffer[i] & 0xff) << (32 - self.nbuf)
|
||||
i += 1
|
||||
self.nbuf -= 8
|
||||
n -= 1
|
||||
if self.nbuf != 0:
|
||||
return b""
|
||||
self.mac_func(self.mbuf)
|
||||
j = n & ~0x03
|
||||
while i < j:
|
||||
self.cycle()
|
||||
t = ((buffer[i + 3] & 0xFF) << 24) | \
|
||||
((buffer[i + 2] & 0xFF) << 16) | \
|
||||
((buffer[i + 1] & 0xFF) << 8) | \
|
||||
(buffer[i] & 0xFF)
|
||||
t ^= self.sbuf
|
||||
self.mac_func(t)
|
||||
buffer[i + 3] = (t >> 24) & 0xFF
|
||||
buffer[i + 2] = (t >> 16) & 0xFF
|
||||
buffer[i + 1] = (t >> 8) & 0xFF
|
||||
buffer[i] = t & 0xFF
|
||||
i += 4
|
||||
n &= 0x03
|
||||
if n != 0:
|
||||
self.cycle()
|
||||
self.mbuf = 0
|
||||
self.nbuf = 32
|
||||
while self.nbuf != 0 and n != 0:
|
||||
buffer[i] ^= (self.sbuf >> (32 - self.nbuf)) & 0xff
|
||||
self.mbuf ^= (buffer[i] & 0xff) << (32 - self.nbuf)
|
||||
i += 1
|
||||
self.nbuf -= 8
|
||||
n -= 1
|
||||
return bytes(buffer)
|
||||
|
||||
def finish(self, n: int) -> bytes:
|
||||
buffer = bytearray(4)
|
||||
i = 0
|
||||
j: int
|
||||
if self.nbuf != 0:
|
||||
self.mac_func(self.mbuf)
|
||||
self.cycle()
|
||||
self.add_key(self.initkonst ^ (self.nbuf << 3))
|
||||
self.nbuf = 0
|
||||
for j in range(self.n):
|
||||
self.r[j] ^= self.crc[j]
|
||||
self.diffuse()
|
||||
while n > 0:
|
||||
self.cycle()
|
||||
if n >= 4:
|
||||
buffer[i + 3] = (self.sbuf >> 24) & 0xff
|
||||
buffer[i + 2] = (self.sbuf >> 16) & 0xff
|
||||
buffer[i + 1] = (self.sbuf >> 8) & 0xff
|
||||
buffer[i] = self.sbuf & 0xff
|
||||
n -= 4
|
||||
i += 4
|
||||
else:
|
||||
for j in range(n):
|
||||
buffer[i + j] = (self.sbuf >> (i * 8)) & 0xff
|
||||
break
|
||||
return bytes(buffer)
|
||||
11
resources/lib/librespot/dealer.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
from __future__ import annotations
|
||||
from librespot.core import ApResolver
|
||||
from librespot.metadata import AlbumId, ArtistId, EpisodeId, ShowId, TrackId
|
||||
from librespot.proto import Connect_pb2 as Connect, Metadata_pb2 as Metadata
|
||||
from librespot.structure import Closeable
|
||||
import logging
|
||||
import requests
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from librespot.core import Session
|
||||
394
resources/lib/librespot/mercury.py
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
from __future__ import annotations
|
||||
from librespot import util
|
||||
from librespot.crypto import Packet
|
||||
from librespot.proto import Mercury_pb2 as Mercury, Pubsub_pb2 as Pubsub
|
||||
from librespot.structure import Closeable, PacketsReceiver, SubListener
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import queue
|
||||
import struct
|
||||
import threading
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from librespot.core import Session
|
||||
|
||||
|
||||
class JsonMercuryRequest:
|
||||
request: RawMercuryRequest
|
||||
|
||||
def __init__(self, request: RawMercuryRequest):
|
||||
self.request = request
|
||||
|
||||
|
||||
class MercuryClient(Closeable, PacketsReceiver):
|
||||
logger = logging.getLogger("Librespot:MercuryClient")
|
||||
mercury_request_timeout = 3
|
||||
__callbacks: typing.Dict[int, Callback] = {}
|
||||
__remove_callback_lock = threading.Condition()
|
||||
__partials: typing.Dict[int, typing.List[bytes]] = {}
|
||||
__seq_holder = 0
|
||||
__seq_holder_lock = threading.Condition()
|
||||
__session: Session
|
||||
__subscriptions: typing.List[InternalSubListener] = []
|
||||
__subscriptions_lock = threading.Condition()
|
||||
|
||||
def __init__(self, session: Session):
|
||||
self.__session = session
|
||||
|
||||
def close(self) -> None:
|
||||
"""
|
||||
Close the MercuryClient instance
|
||||
"""
|
||||
if len(self.__subscriptions) != 0:
|
||||
for listener in self.__subscriptions:
|
||||
if listener.is_sub:
|
||||
self.unsubscribe(listener.uri)
|
||||
else:
|
||||
self.not_interested_in(listener.listener)
|
||||
if len(self.__callbacks) != 0:
|
||||
with self.__remove_callback_lock:
|
||||
self.__remove_callback_lock.wait(self.mercury_request_timeout)
|
||||
self.__callbacks.clear()
|
||||
|
||||
def dispatch(self, packet: Packet) -> None:
|
||||
payload = io.BytesIO(packet.payload)
|
||||
seq_length = struct.unpack(">H", payload.read(2))[0]
|
||||
if seq_length == 2:
|
||||
seq = struct.unpack(">H", payload.read(2))[0]
|
||||
elif seq_length == 4:
|
||||
seq = struct.unpack(">i", payload.read(4))[0]
|
||||
elif seq_length == 8:
|
||||
seq = struct.unpack(">q", payload.read(8))[0]
|
||||
else:
|
||||
raise RuntimeError("Unknown seq length: {}".format(seq_length))
|
||||
flags = payload.read(1)
|
||||
parts = struct.unpack(">H", payload.read(2))[0]
|
||||
partial = self.__partials.get(seq)
|
||||
if partial is None or flags == 0:
|
||||
partial = []
|
||||
self.__partials[seq] = partial
|
||||
self.logger.debug(
|
||||
"Handling packet, cmd: 0x{}, seq: {}, flags: {}, parts: {}".format(
|
||||
util.bytes_to_hex(packet.cmd), seq, flags, parts))
|
||||
for _ in range(parts):
|
||||
size = struct.unpack(">H", payload.read(2))[0]
|
||||
buffer = payload.read(size)
|
||||
partial.append(buffer)
|
||||
self.__partials[seq] = partial
|
||||
if flags != b"\x01":
|
||||
return
|
||||
self.__partials.pop(seq)
|
||||
header = Mercury.Header()
|
||||
header.ParseFromString(partial[0])
|
||||
response = MercuryClient.Response(header, partial)
|
||||
if packet.is_cmd(Packet.Type.mercury_event):
|
||||
dispatched = False
|
||||
with self.__subscriptions_lock:
|
||||
for sub in self.__subscriptions:
|
||||
if sub.matches(header.uri):
|
||||
sub.dispatch(response)
|
||||
dispatched = True
|
||||
if not dispatched:
|
||||
self.logger.debug(
|
||||
"Couldn't dispatch Mercury event seq: {}, uri: {}, code: {}, payload: {}"
|
||||
.format(seq, header.uri, header.status_code,
|
||||
response.payload))
|
||||
elif (packet.is_cmd(Packet.Type.mercury_req)
|
||||
or packet.is_cmd(Packet.Type.mercury_sub)
|
||||
or packet.is_cmd(Packet.Type.mercury_sub)):
|
||||
callback = self.__callbacks.get(seq)
|
||||
self.__callbacks.pop(seq)
|
||||
if callback is not None:
|
||||
callback.response(response)
|
||||
else:
|
||||
self.logger.warning(
|
||||
"Skipped Mercury response, seq: {}, uri: {}, code: {}".
|
||||
format(seq, response.uri, response.status_code))
|
||||
with self.__remove_callback_lock:
|
||||
self.__remove_callback_lock.notify_all()
|
||||
else:
|
||||
self.logger.warning(
|
||||
"Couldn't handle packet, seq: {}, uri: {}, code: {}".format(
|
||||
seq, header.uri, header.status_code))
|
||||
|
||||
def interested_in(self, uri: str, listener: SubListener) -> None:
|
||||
self.__subscriptions.append(
|
||||
MercuryClient.InternalSubListener(uri, listener, False))
|
||||
|
||||
def not_interested_in(self, listener: SubListener) -> None:
|
||||
try:
|
||||
for subscription in self.__subscriptions:
|
||||
if subscription.listener is listener:
|
||||
self.__subscriptions.remove(subscription)
|
||||
break
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def send(self, request: RawMercuryRequest, callback) -> int:
|
||||
"""
|
||||
Send the Mercury request
|
||||
Args:
|
||||
request: RawMercuryRequest
|
||||
callback: Callback function
|
||||
Returns:
|
||||
MercuryClient.Response
|
||||
"""
|
||||
buffer = io.BytesIO()
|
||||
seq: int
|
||||
with self.__seq_holder_lock:
|
||||
seq = self.__seq_holder
|
||||
self.__seq_holder += 1
|
||||
self.logger.debug(
|
||||
"Send Mercury request, seq: {}, uri: {}, method: {}".format(
|
||||
seq, request.header.uri, request.header.method))
|
||||
buffer.write(struct.pack(">H", 4))
|
||||
buffer.write(struct.pack(">i", seq))
|
||||
buffer.write(b"\x01")
|
||||
buffer.write(struct.pack(">H", 1 + len(request.payload)))
|
||||
header_bytes = request.header.SerializeToString()
|
||||
buffer.write(struct.pack(">H", len(header_bytes)))
|
||||
buffer.write(header_bytes)
|
||||
for part in request.payload:
|
||||
buffer.write(struct.pack(">H", len(part)))
|
||||
buffer.write(part)
|
||||
buffer.seek(0)
|
||||
cmd = Packet.Type.for_method(request.header.method)
|
||||
self.__session.send(cmd, buffer.read())
|
||||
self.__callbacks[seq] = callback
|
||||
return seq
|
||||
|
||||
def send_sync(self, request: RawMercuryRequest) -> Response:
|
||||
"""
|
||||
Send the Mercury request
|
||||
Args:
|
||||
request: RawMercuryRequest
|
||||
Returns:
|
||||
MercuryClient.Response
|
||||
"""
|
||||
callback = MercuryClient.SyncCallback()
|
||||
seq = self.send(request, callback)
|
||||
try:
|
||||
response = callback.wait_response()
|
||||
if response is None:
|
||||
raise IOError(
|
||||
"Request timeout out, {} passed, yet no response. seq: {}".
|
||||
format(self.mercury_request_timeout, seq))
|
||||
return response
|
||||
except queue.Empty as e:
|
||||
raise IOError(e)
|
||||
|
||||
def send_sync_json(self, request: JsonMercuryRequest) -> typing.Any:
|
||||
response = self.send_sync(request.request)
|
||||
if 200 <= response.status_code < 300:
|
||||
return json.loads(response.payload)
|
||||
raise MercuryClient.MercuryException(response)
|
||||
|
||||
def subscribe(self, uri: str, listener: SubListener) -> None:
|
||||
"""
|
||||
Subscribe URI
|
||||
Args:
|
||||
uri:
|
||||
listener:
|
||||
"""
|
||||
response = self.send_sync(RawMercuryRequest.sub(uri))
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(response)
|
||||
if len(response.payload) > 0:
|
||||
for payload in response.payload:
|
||||
sub = Pubsub.Subscription()
|
||||
sub.ParseFromString(payload)
|
||||
self.__subscriptions.append(
|
||||
MercuryClient.InternalSubListener(sub.uri, listener, True))
|
||||
else:
|
||||
self.__subscriptions.append(
|
||||
MercuryClient.InternalSubListener(uri, listener, True))
|
||||
self.logger.debug("Subscribed successfully to {}!".format(uri))
|
||||
|
||||
def unsubscribe(self, uri) -> None:
|
||||
"""
|
||||
Unsubscribe URI
|
||||
Args:
|
||||
uri:
|
||||
"""
|
||||
response = self.send_sync(RawMercuryRequest.unsub(uri))
|
||||
if response.status_code != 200:
|
||||
raise RuntimeError(response)
|
||||
for subscription in self.__subscriptions:
|
||||
if subscription.matches(uri):
|
||||
self.__subscriptions.remove(subscription)
|
||||
break
|
||||
self.logger.debug("Unsubscribed successfully from {}!".format(uri))
|
||||
|
||||
class Callback:
|
||||
def response(self, response: MercuryClient.Response) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
class InternalSubListener:
|
||||
uri: str
|
||||
listener: SubListener
|
||||
is_sub: bool
|
||||
|
||||
def __init__(self, uri: str, listener: SubListener, is_sub: bool):
|
||||
self.uri = uri
|
||||
self.listener = listener
|
||||
self.is_sub = is_sub
|
||||
|
||||
def matches(self, uri: str) -> bool:
|
||||
"""
|
||||
Compare with the URI given
|
||||
Args:
|
||||
uri: URI to be compared
|
||||
Returns:
|
||||
bool
|
||||
"""
|
||||
return uri.startswith(self.uri)
|
||||
|
||||
def dispatch(self, response: MercuryClient.Response) -> None:
|
||||
"""
|
||||
Dispatch the event response
|
||||
Args:
|
||||
response: Response generated by the event
|
||||
"""
|
||||
self.listener.event(response)
|
||||
|
||||
class MercuryException(Exception):
|
||||
code: int
|
||||
|
||||
def __init__(self, response: MercuryClient.Response):
|
||||
super().__init__("status: {}".format(response.status_code))
|
||||
self.code = response.status_code
|
||||
|
||||
class PubSubException(MercuryException):
|
||||
pass
|
||||
|
||||
class Response:
|
||||
uri: str
|
||||
payload: bytes
|
||||
status_code: int
|
||||
|
||||
def __init__(self, header: Mercury.Header, payload: list[bytes]):
|
||||
self.uri = header.uri
|
||||
self.status_code = header.status_code
|
||||
self.payload = b"".join(payload[1:])
|
||||
|
||||
class SyncCallback(Callback):
|
||||
__reference = queue.Queue()
|
||||
|
||||
def response(self, response: MercuryClient.Response) -> None:
|
||||
"""
|
||||
Set the response
|
||||
:param response:
|
||||
:return:
|
||||
"""
|
||||
self.__reference.put(response)
|
||||
self.__reference.task_done()
|
||||
|
||||
def wait_response(self) -> typing.Any:
|
||||
return self.__reference.get(
|
||||
timeout=MercuryClient.mercury_request_timeout)
|
||||
|
||||
|
||||
class MercuryRequests:
|
||||
keymaster_client_id = "65b708073fc0480ea92a077233ca87bd"
|
||||
|
||||
@staticmethod
|
||||
def get_root_playlists(username: str):
|
||||
"""
|
||||
@TODO implement function
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def request_token(device_id, scope):
|
||||
return JsonMercuryRequest(
|
||||
RawMercuryRequest.get(
|
||||
"hm://keymaster/token/authenticated?scope={}&client_id={}&device_id={}"
|
||||
.format(scope, MercuryRequests.keymaster_client_id,
|
||||
device_id)))
|
||||
|
||||
|
||||
class RawMercuryRequest:
|
||||
header: Mercury.Header
|
||||
payload: typing.List[bytes]
|
||||
|
||||
def __init__(self, header: Mercury.Header, payload: typing.List[bytes]):
|
||||
self.header = header
|
||||
self.payload = payload
|
||||
|
||||
@staticmethod
|
||||
def sub(uri: str):
|
||||
return RawMercuryRequest.new_builder().set_uri(uri).set_method(
|
||||
"SUB").build()
|
||||
|
||||
@staticmethod
|
||||
def unsub(uri: str):
|
||||
return RawMercuryRequest.new_builder().set_uri(uri).set_method(
|
||||
"UNSUB").build()
|
||||
|
||||
@staticmethod
|
||||
def get(uri: str):
|
||||
return RawMercuryRequest.new_builder().set_uri(uri).set_method(
|
||||
"GET").build()
|
||||
|
||||
@staticmethod
|
||||
def send(uri: str, part: bytes):
|
||||
return RawMercuryRequest.new_builder().set_uri(uri) \
|
||||
.add_payload_part(part).set_method("SEND").build()
|
||||
|
||||
@staticmethod
|
||||
def post(uri: str, part: bytes):
|
||||
return RawMercuryRequest.new_builder().set_uri(uri) \
|
||||
.set_method("POST").add_payload_part(part).build()
|
||||
|
||||
@staticmethod
|
||||
def new_builder():
|
||||
return RawMercuryRequest.Builder()
|
||||
|
||||
class Builder:
|
||||
header_dict: dict
|
||||
payload: typing.List[bytes]
|
||||
|
||||
def __init__(self):
|
||||
self.header_dict = {}
|
||||
self.payload = []
|
||||
|
||||
def set_uri(self, uri: str):
|
||||
self.header_dict["uri"] = uri
|
||||
return self
|
||||
|
||||
def set_content_type(self, content_type: str):
|
||||
self.header_dict["content_type"] = content_type
|
||||
return self
|
||||
|
||||
def set_method(self, method: str):
|
||||
self.header_dict["method"] = method
|
||||
return self
|
||||
|
||||
def add_user_field(self,
|
||||
field: Mercury.UserField = None,
|
||||
key: str = None,
|
||||
value: str = None):
|
||||
if field is None and (key is None or value is None):
|
||||
return self
|
||||
try:
|
||||
self.header_dict["user_fields"]
|
||||
except KeyError:
|
||||
self.header_dict["user_fields"] = []
|
||||
if field is not None:
|
||||
self.header_dict["user_fields"].append(field)
|
||||
if key is not None and value is not None:
|
||||
self.header_dict["user_fields"].append(
|
||||
Mercury.UserField(key=key, value=value.encode()))
|
||||
return self
|
||||
|
||||
def add_payload_part(self, part: bytes):
|
||||
self.payload.append(part)
|
||||
return self
|
||||
|
||||
def add_protobuf_payload(self, msg):
|
||||
return self.add_payload_part(msg)
|
||||
|
||||
def build(self):
|
||||
return RawMercuryRequest(Mercury.Header(**self.header_dict),
|
||||
self.payload)
|
||||
283
resources/lib/librespot/metadata.py
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
from __future__ import annotations
|
||||
from librespot import util
|
||||
from librespot.proto.ContextTrack_pb2 import ContextTrack
|
||||
from librespot.util import Base62
|
||||
import re
|
||||
|
||||
|
||||
class SpotifyId:
|
||||
STATIC_FROM_URI = "fromUri"
|
||||
STATIC_FROM_BASE62 = "fromBase62"
|
||||
STATIC_FROM_HEX = "fromHex"
|
||||
|
||||
@staticmethod
|
||||
def from_base62(base62: str):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def from_hex(hex_str: str):
|
||||
raise NotImplementedError
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str):
|
||||
raise NotImplementedError
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
class SpotifyIdParsingException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class PlayableId:
|
||||
base62 = Base62.create_instance_with_inverted_character_set()
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str) -> PlayableId:
|
||||
if not PlayableId.is_supported(uri):
|
||||
return UnsupportedId(uri)
|
||||
if TrackId.pattern.search(uri) is not None:
|
||||
return TrackId.from_uri(uri)
|
||||
if EpisodeId.pattern.search(uri) is not None:
|
||||
return EpisodeId.from_uri(uri)
|
||||
raise TypeError("Unknown uri: {}".format(uri))
|
||||
|
||||
@staticmethod
|
||||
def is_supported(uri: str):
|
||||
return (not uri.startswith("spotify:local:")
|
||||
and not uri == "spotify:delimiter"
|
||||
and not uri == "spotify:meta:delimiter")
|
||||
|
||||
@staticmethod
|
||||
def should_play(track: ContextTrack):
|
||||
return track.metadata_or_default
|
||||
|
||||
def get_gid(self) -> bytes:
|
||||
raise NotImplementedError
|
||||
|
||||
def hex_id(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class PlaylistId(SpotifyId):
|
||||
base62 = Base62.create_instance_with_inverted_character_set()
|
||||
pattern = re.compile(r"spotify:playlist:(.{22})")
|
||||
__id: str
|
||||
|
||||
def __init__(self, _id: str):
|
||||
self.__id = _id
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str) -> PlaylistId:
|
||||
matcher = PlaylistId.pattern.search(uri)
|
||||
if matcher is not None:
|
||||
playlist_id = matcher.group(1)
|
||||
return PlaylistId(playlist_id)
|
||||
raise TypeError("Not a Spotify playlist ID: {}.".format(uri))
|
||||
|
||||
def id(self) -> str:
|
||||
return self.__id
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
return "spotify:playlist:" + self.__id
|
||||
|
||||
|
||||
class UnsupportedId(PlayableId):
|
||||
uri: str
|
||||
|
||||
def __init__(self, uri: str):
|
||||
self.uri = uri
|
||||
|
||||
def get_gid(self) -> bytes:
|
||||
raise TypeError()
|
||||
|
||||
def hex_id(self) -> str:
|
||||
raise TypeError()
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
return self.uri
|
||||
|
||||
|
||||
class AlbumId(SpotifyId):
|
||||
base62 = Base62.create_instance_with_inverted_character_set()
|
||||
pattern = re.compile(r"spotify:album:(.{22})")
|
||||
__hex_id: str
|
||||
|
||||
def __init__(self, hex_id: str):
|
||||
self.__hex_id = hex_id.lower()
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str) -> AlbumId:
|
||||
matcher = AlbumId.pattern.search(uri)
|
||||
if matcher is not None:
|
||||
album_id = matcher.group(1)
|
||||
return AlbumId(util.bytes_to_hex(AlbumId.base62.decode(album_id.encode(), 16)))
|
||||
raise TypeError("Not a Spotify album ID: {}.".format(uri))
|
||||
|
||||
@staticmethod
|
||||
def from_base62(base62: str) -> AlbumId:
|
||||
return AlbumId(util.bytes_to_hex(AlbumId.base62.decode(base62.encode(), 16)))
|
||||
|
||||
@staticmethod
|
||||
def from_hex(hex_str: str) -> AlbumId:
|
||||
return AlbumId(hex_str)
|
||||
|
||||
def to_mercury_uri(self) -> str:
|
||||
return "hm://metadata/4/album/{}".format(self.__hex_id)
|
||||
|
||||
def hex_id(self) -> str:
|
||||
return self.__hex_id
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
return "spotify:album:{}".format(
|
||||
AlbumId.base62.encode(util.hex_to_bytes(self.__hex_id)).decode())
|
||||
|
||||
|
||||
class ArtistId(SpotifyId):
|
||||
base62 = Base62.create_instance_with_inverted_character_set()
|
||||
pattern = re.compile("spotify:artist:(.{22})")
|
||||
__hex_id: str
|
||||
|
||||
def __init__(self, hex_id: str):
|
||||
self.__hex_id = hex_id.lower()
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str) -> ArtistId:
|
||||
matcher = ArtistId.pattern.search(uri)
|
||||
if matcher is not None:
|
||||
artist_id = matcher.group(1)
|
||||
return ArtistId(
|
||||
util.bytes_to_hex(ArtistId.base62.decode(artist_id.encode(), 16)))
|
||||
raise TypeError("Not a Spotify artist ID: {}".format(uri))
|
||||
|
||||
@staticmethod
|
||||
def from_base62(base62: str) -> ArtistId:
|
||||
return ArtistId(util.bytes_to_hex(ArtistId.base62.decode(base62.encode(), 16)))
|
||||
|
||||
@staticmethod
|
||||
def from_hex(hex_str: str) -> ArtistId:
|
||||
return ArtistId(hex_str)
|
||||
|
||||
def to_mercury_uri(self) -> str:
|
||||
return "hm://metadata/4/artist/{}".format(self.__hex_id)
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
return "spotify:artist:{}".format(
|
||||
ArtistId.base62.encode(util.hex_to_bytes(self.__hex_id)).decode())
|
||||
|
||||
def hex_id(self) -> str:
|
||||
return self.__hex_id
|
||||
|
||||
|
||||
class EpisodeId(SpotifyId, PlayableId):
|
||||
pattern = re.compile(r"spotify:episode:(.{22})")
|
||||
__hex_id: str
|
||||
|
||||
def __init__(self, hex_id: str):
|
||||
self.__hex_id = hex_id.lower()
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str) -> EpisodeId:
|
||||
matcher = EpisodeId.pattern.search(uri)
|
||||
if matcher is not None:
|
||||
episode_id = matcher.group(1)
|
||||
return EpisodeId(
|
||||
util.bytes_to_hex(PlayableId.base62.decode(episode_id.encode(), 16)))
|
||||
raise TypeError("Not a Spotify episode ID: {}".format(uri))
|
||||
|
||||
@staticmethod
|
||||
def from_base62(base62: str) -> EpisodeId:
|
||||
return EpisodeId(
|
||||
util.bytes_to_hex(PlayableId.base62.decode(base62.encode(), 16)))
|
||||
|
||||
@staticmethod
|
||||
def from_hex(hex_str: str) -> EpisodeId:
|
||||
return EpisodeId(hex_str)
|
||||
|
||||
def to_mercury_uri(self) -> str:
|
||||
return "hm://metadata/4/episode/{}".format(self.__hex_id)
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
return "Spotify:episode:{}".format(
|
||||
PlayableId.base62.encode(util.hex_to_bytes(self.__hex_id)).decode())
|
||||
|
||||
def hex_id(self) -> str:
|
||||
return self.__hex_id
|
||||
|
||||
def get_gid(self) -> bytes:
|
||||
return util.hex_to_bytes(self.__hex_id)
|
||||
|
||||
|
||||
class ShowId(SpotifyId):
|
||||
base62 = Base62.create_instance_with_inverted_character_set()
|
||||
pattern = re.compile("spotify:show:(.{22})")
|
||||
__hex_id: str
|
||||
|
||||
def __init__(self, hex_id: str):
|
||||
self.__hex_id = hex_id
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str) -> ShowId:
|
||||
matcher = ShowId.pattern.search(uri)
|
||||
if matcher is not None:
|
||||
show_id = matcher.group(1)
|
||||
return ShowId(util.bytes_to_hex(ShowId.base62.decode(show_id.encode(), 16)))
|
||||
raise TypeError("Not a Spotify show ID: {}".format(uri))
|
||||
|
||||
@staticmethod
|
||||
def from_base62(base62: str) -> ShowId:
|
||||
return ShowId(util.bytes_to_hex(ShowId.base62.decode(base62.encode(), 16)))
|
||||
|
||||
@staticmethod
|
||||
def from_hex(hex_str: str) -> ShowId:
|
||||
return ShowId(hex_str)
|
||||
|
||||
def to_mercury_uri(self) -> str:
|
||||
return "hm://metadata/4/show/{}".format(self.__hex_id)
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
return "spotify:show:{}".format(
|
||||
ShowId.base62.encode(util.hex_to_bytes(self.__hex_id)).decode())
|
||||
|
||||
def hex_id(self) -> str:
|
||||
return self.__hex_id
|
||||
|
||||
|
||||
class TrackId(PlayableId, SpotifyId):
|
||||
pattern = re.compile("spotify:track:(.{22})")
|
||||
__hex_id: str
|
||||
|
||||
def __init__(self, hex_id: str):
|
||||
self.__hex_id = hex_id.lower()
|
||||
|
||||
@staticmethod
|
||||
def from_uri(uri: str) -> TrackId:
|
||||
search = TrackId.pattern.search(uri)
|
||||
if search is not None:
|
||||
track_id = search.group(1)
|
||||
return TrackId(
|
||||
util.bytes_to_hex(PlayableId.base62.decode(track_id.encode(), 16)))
|
||||
raise RuntimeError("Not a Spotify track ID: {}".format(uri))
|
||||
|
||||
@staticmethod
|
||||
def from_base62(base62: str) -> TrackId:
|
||||
return TrackId(util.bytes_to_hex(PlayableId.base62.decode(base62.encode(), 16)))
|
||||
|
||||
@staticmethod
|
||||
def from_hex(hex_str: str) -> TrackId:
|
||||
return TrackId(hex_str)
|
||||
|
||||
def to_mercury_uri(self) -> str:
|
||||
return "hm://metadata/4/track/{}".format(self.__hex_id)
|
||||
|
||||
def to_spotify_uri(self) -> str:
|
||||
return "spotify:track:{}".format(TrackId.base62.encode(util.hex_to_bytes(self.__hex_id)).decode())
|
||||
|
||||
def hex_id(self) -> str:
|
||||
return self.__hex_id
|
||||
|
||||
def get_gid(self) -> bytes:
|
||||
return util.hex_to_bytes(self.__hex_id)
|
||||
1984
resources/lib/librespot/proto/Authentication_pb2.py
Normal file
91
resources/lib/librespot/proto/CanvazMeta_pb2.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: canvaz-meta.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="canvaz-meta.proto",
|
||||
package="com.spotify.canvaz",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\022com.spotify.canvazH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b"\n\x11\x63\x61nvaz-meta.proto\x12\x12\x63om.spotify.canvaz*R\n\x04Type\x12\t\n\x05IMAGE\x10\x00\x12\t\n\x05VIDEO\x10\x01\x12\x11\n\rVIDEO_LOOPING\x10\x02\x12\x18\n\x14VIDEO_LOOPING_RANDOM\x10\x03\x12\x07\n\x03GIF\x10\x04\x42\x16\n\x12\x63om.spotify.canvazH\x02\x62\x06proto3",
|
||||
)
|
||||
|
||||
_TYPE = _descriptor.EnumDescriptor(
|
||||
name="Type",
|
||||
full_name="com.spotify.canvaz.Type",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="IMAGE",
|
||||
index=0,
|
||||
number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="VIDEO",
|
||||
index=1,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="VIDEO_LOOPING",
|
||||
index=2,
|
||||
number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="VIDEO_LOOPING_RANDOM",
|
||||
index=3,
|
||||
number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="GIF",
|
||||
index=4,
|
||||
number=4,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=41,
|
||||
serialized_end=123,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_TYPE)
|
||||
|
||||
Type = enum_type_wrapper.EnumTypeWrapper(_TYPE)
|
||||
IMAGE = 0
|
||||
VIDEO = 1
|
||||
VIDEO_LOOPING = 2
|
||||
VIDEO_LOOPING_RANDOM = 3
|
||||
GIF = 4
|
||||
|
||||
DESCRIPTOR.enum_types_by_name["Type"] = _TYPE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
564
resources/lib/librespot/proto/Canvaz_pb2.py
Normal file
|
|
@ -0,0 +1,564 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: canvaz.proto
|
||||
"""Generated protocol buffer code."""
|
||||
import CanvazMeta_pb2 as canvaz__meta__pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="canvaz.proto",
|
||||
package="com.spotify.canvazcache",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\022com.spotify.canvazH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x0c\x63\x61nvaz.proto\x12\x17\x63om.spotify.canvazcache\x1a\x11\x63\x61nvaz-meta.proto"3\n\x06\x41rtist\x12\x0b\n\x03uri\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0e\n\x06\x61vatar\x18\x03 \x01(\t"\xe1\x02\n\x14\x45ntityCanvazResponse\x12\x46\n\x08\x63\x61nvases\x18\x01 \x03(\x0b\x32\x34.com.spotify.canvazcache.EntityCanvazResponse.Canvaz\x12\x16\n\x0ettl_in_seconds\x18\x02 \x01(\x03\x1a\xe8\x01\n\x06\x43\x61nvaz\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x0f\n\x07\x66ile_id\x18\x03 \x01(\t\x12&\n\x04type\x18\x04 \x01(\x0e\x32\x18.com.spotify.canvaz.Type\x12\x12\n\nentity_uri\x18\x05 \x01(\t\x12/\n\x06\x61rtist\x18\x06 \x01(\x0b\x32\x1f.com.spotify.canvazcache.Artist\x12\x10\n\x08\x65xplicit\x18\x07 \x01(\x08\x12\x13\n\x0buploaded_by\x18\x08 \x01(\t\x12\x0c\n\x04\x65tag\x18\t \x01(\t\x12\x12\n\ncanvas_uri\x18\x0b \x01(\t"\x88\x01\n\x13\x45ntityCanvazRequest\x12\x45\n\x08\x65ntities\x18\x01 \x03(\x0b\x32\x33.com.spotify.canvazcache.EntityCanvazRequest.Entity\x1a*\n\x06\x45ntity\x12\x12\n\nentity_uri\x18\x01 \x01(\t\x12\x0c\n\x04\x65tag\x18\x02 \x01(\tB\x16\n\x12\x63om.spotify.canvazH\x02\x62\x06proto3',
|
||||
dependencies=[
|
||||
canvaz__meta__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_ARTIST = _descriptor.Descriptor(
|
||||
name="Artist",
|
||||
full_name="com.spotify.canvazcache.Artist",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="uri",
|
||||
full_name="com.spotify.canvazcache.Artist.uri",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="name",
|
||||
full_name="com.spotify.canvazcache.Artist.name",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="avatar",
|
||||
full_name="com.spotify.canvazcache.Artist.avatar",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=60,
|
||||
serialized_end=111,
|
||||
)
|
||||
|
||||
_ENTITYCANVAZRESPONSE_CANVAZ = _descriptor.Descriptor(
|
||||
name="Canvaz",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazResponse.Canvaz",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="id",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazResponse.Canvaz.id",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="url",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazResponse.Canvaz.url",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="file_id",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.file_id",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="type",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.type",
|
||||
index=3,
|
||||
number=4,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="entity_uri",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.entity_uri",
|
||||
index=4,
|
||||
number=5,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="artist",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.artist",
|
||||
index=5,
|
||||
number=6,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="explicit",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.explicit",
|
||||
index=6,
|
||||
number=7,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="uploaded_by",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.uploaded_by",
|
||||
index=7,
|
||||
number=8,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="etag",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.etag",
|
||||
index=8,
|
||||
number=9,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="canvas_uri",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.Canvaz.canvas_uri",
|
||||
index=9,
|
||||
number=11,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=235,
|
||||
serialized_end=467,
|
||||
)
|
||||
|
||||
_ENTITYCANVAZRESPONSE = _descriptor.Descriptor(
|
||||
name="EntityCanvazResponse",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazResponse",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="canvases",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazResponse.canvases",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="ttl_in_seconds",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazResponse.ttl_in_seconds",
|
||||
index=1,
|
||||
number=2,
|
||||
type=3,
|
||||
cpp_type=2,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[
|
||||
_ENTITYCANVAZRESPONSE_CANVAZ,
|
||||
],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=114,
|
||||
serialized_end=467,
|
||||
)
|
||||
|
||||
_ENTITYCANVAZREQUEST_ENTITY = _descriptor.Descriptor(
|
||||
name="Entity",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazRequest.Entity",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="entity_uri",
|
||||
full_name=
|
||||
"com.spotify.canvazcache.EntityCanvazRequest.Entity.entity_uri",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="etag",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazRequest.Entity.etag",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=564,
|
||||
serialized_end=606,
|
||||
)
|
||||
|
||||
_ENTITYCANVAZREQUEST = _descriptor.Descriptor(
|
||||
name="EntityCanvazRequest",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazRequest",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="entities",
|
||||
full_name="com.spotify.canvazcache.EntityCanvazRequest.entities",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[
|
||||
_ENTITYCANVAZREQUEST_ENTITY,
|
||||
],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=470,
|
||||
serialized_end=606,
|
||||
)
|
||||
|
||||
_ENTITYCANVAZRESPONSE_CANVAZ.fields_by_name[
|
||||
"type"].enum_type = canvaz__meta__pb2._TYPE
|
||||
_ENTITYCANVAZRESPONSE_CANVAZ.fields_by_name["artist"].message_type = _ARTIST
|
||||
_ENTITYCANVAZRESPONSE_CANVAZ.containing_type = _ENTITYCANVAZRESPONSE
|
||||
_ENTITYCANVAZRESPONSE.fields_by_name[
|
||||
"canvases"].message_type = _ENTITYCANVAZRESPONSE_CANVAZ
|
||||
_ENTITYCANVAZREQUEST_ENTITY.containing_type = _ENTITYCANVAZREQUEST
|
||||
_ENTITYCANVAZREQUEST.fields_by_name[
|
||||
"entities"].message_type = _ENTITYCANVAZREQUEST_ENTITY
|
||||
DESCRIPTOR.message_types_by_name["Artist"] = _ARTIST
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
"EntityCanvazResponse"] = _ENTITYCANVAZRESPONSE
|
||||
DESCRIPTOR.message_types_by_name["EntityCanvazRequest"] = _ENTITYCANVAZREQUEST
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Artist = _reflection.GeneratedProtocolMessageType(
|
||||
"Artist",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _ARTIST,
|
||||
"__module__": "canvaz_pb2"
|
||||
# @@protoc_insertion_point(class_scope:com.spotify.canvazcache.Artist)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Artist)
|
||||
|
||||
EntityCanvazResponse = _reflection.GeneratedProtocolMessageType(
|
||||
"EntityCanvazResponse",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"Canvaz":
|
||||
_reflection.GeneratedProtocolMessageType(
|
||||
"Canvaz",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _ENTITYCANVAZRESPONSE_CANVAZ,
|
||||
"__module__": "canvaz_pb2"
|
||||
# @@protoc_insertion_point(class_scope:com.spotify.canvazcache.EntityCanvazResponse.Canvaz)
|
||||
},
|
||||
),
|
||||
"DESCRIPTOR":
|
||||
_ENTITYCANVAZRESPONSE,
|
||||
"__module__":
|
||||
"canvaz_pb2"
|
||||
# @@protoc_insertion_point(class_scope:com.spotify.canvazcache.EntityCanvazResponse)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(EntityCanvazResponse)
|
||||
_sym_db.RegisterMessage(EntityCanvazResponse.Canvaz)
|
||||
|
||||
EntityCanvazRequest = _reflection.GeneratedProtocolMessageType(
|
||||
"EntityCanvazRequest",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"Entity":
|
||||
_reflection.GeneratedProtocolMessageType(
|
||||
"Entity",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _ENTITYCANVAZREQUEST_ENTITY,
|
||||
"__module__": "canvaz_pb2"
|
||||
# @@protoc_insertion_point(class_scope:com.spotify.canvazcache.EntityCanvazRequest.Entity)
|
||||
},
|
||||
),
|
||||
"DESCRIPTOR":
|
||||
_ENTITYCANVAZREQUEST,
|
||||
"__module__":
|
||||
"canvaz_pb2"
|
||||
# @@protoc_insertion_point(class_scope:com.spotify.canvazcache.EntityCanvazRequest)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(EntityCanvazRequest)
|
||||
_sym_db.RegisterMessage(EntityCanvazRequest.Entity)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
63
resources/lib/librespot/proto/ClientToken_pb2.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: client_token.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import builder as _builder
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from librespot.proto import Connectivity_pb2 as connectivity__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12\x63lient_token.proto\x12\x1bspotify.clienttoken.http.v0\x1a\x12\x63onnectivity.proto\"\x84\x02\n\x12\x43lientTokenRequest\x12I\n\x0crequest_type\x18\x01 \x01(\x0e\x32\x33.spotify.clienttoken.http.v0.ClientTokenRequestType\x12\x45\n\x0b\x63lient_data\x18\x02 \x01(\x0b\x32..spotify.clienttoken.http.v0.ClientDataRequestH\x00\x12Q\n\x11\x63hallenge_answers\x18\x03 \x01(\x0b\x32\x34.spotify.clienttoken.http.v0.ChallengeAnswersRequestH\x00\x42\t\n\x07request\"\x99\x01\n\x11\x43lientDataRequest\x12\x16\n\x0e\x63lient_version\x18\x01 \x01(\t\x12\x11\n\tclient_id\x18\x02 \x01(\t\x12Q\n\x15\x63onnectivity_sdk_data\x18\x03 \x01(\x0b\x32\x30.spotify.clienttoken.data.v0.ConnectivitySdkDataH\x00\x42\x06\n\x04\x64\x61ta\"g\n\x17\x43hallengeAnswersRequest\x12\r\n\x05state\x18\x01 \x01(\t\x12=\n\x07\x61nswers\x18\x02 \x03(\x0b\x32,.spotify.clienttoken.http.v0.ChallengeAnswer\"\x81\x02\n\x13\x43lientTokenResponse\x12K\n\rresponse_type\x18\x01 \x01(\x0e\x32\x34.spotify.clienttoken.http.v0.ClientTokenResponseType\x12J\n\rgranted_token\x18\x02 \x01(\x0b\x32\x31.spotify.clienttoken.http.v0.GrantedTokenResponseH\x00\x12\x45\n\nchallenges\x18\x03 \x01(\x0b\x32/.spotify.clienttoken.http.v0.ChallengesResponseH\x00\x42\n\n\x08response\"\x1d\n\x0bTokenDomain\x12\x0e\n\x06\x64omain\x18\x01 \x01(\t\"\x9e\x01\n\x14GrantedTokenResponse\x12\r\n\x05token\x18\x01 \x01(\t\x12\x1d\n\x15\x65xpires_after_seconds\x18\x02 \x01(\x05\x12\x1d\n\x15refresh_after_seconds\x18\x03 \x01(\x05\x12\x39\n\x07\x64omains\x18\x04 \x03(\x0b\x32(.spotify.clienttoken.http.v0.TokenDomain\"_\n\x12\x43hallengesResponse\x12\r\n\x05state\x18\x01 \x01(\t\x12:\n\nchallenges\x18\x02 \x03(\x0b\x32&.spotify.clienttoken.http.v0.Challenge\"&\n\x16\x43lientSecretParameters\x12\x0c\n\x04salt\x18\x01 \x01(\t\"7\n\x14\x45valuateJSParameters\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\x11\n\tlibraries\x18\x02 \x03(\t\"4\n\x12HashCashParameters\x12\x0e\n\x06length\x18\x01 \x01(\x05\x12\x0e\n\x06prefix\x18\x02 \x01(\t\"\xda\x02\n\tChallenge\x12\x38\n\x04type\x18\x01 \x01(\x0e\x32*.spotify.clienttoken.http.v0.ChallengeType\x12W\n\x18\x63lient_secret_parameters\x18\x02 \x01(\x0b\x32\x33.spotify.clienttoken.http.v0.ClientSecretParametersH\x00\x12S\n\x16\x65valuate_js_parameters\x18\x03 \x01(\x0b\x32\x31.spotify.clienttoken.http.v0.EvaluateJSParametersH\x00\x12W\n\x1c\x65valuate_hashcash_parameters\x18\x04 \x01(\x0b\x32/.spotify.clienttoken.http.v0.HashCashParametersH\x00\x42\x0c\n\nparameters\"&\n\x16\x43lientSecretHMACAnswer\x12\x0c\n\x04hmac\x18\x01 \x01(\t\"\"\n\x10\x45valuateJSAnswer\x12\x0e\n\x06result\x18\x01 \x01(\t\" \n\x0eHashCashAnswer\x12\x0e\n\x06suffix\x18\x01 \x01(\t\"\xb4\x02\n\x0f\x43hallengeAnswer\x12\x41\n\rChallengeType\x18\x01 \x01(\x0e\x32*.spotify.clienttoken.http.v0.ChallengeType\x12L\n\rclient_secret\x18\x02 \x01(\x0b\x32\x33.spotify.clienttoken.http.v0.ClientSecretHMACAnswerH\x00\x12\x44\n\x0b\x65valuate_js\x18\x03 \x01(\x0b\x32-.spotify.clienttoken.http.v0.EvaluateJSAnswerH\x00\x12@\n\thash_cash\x18\x04 \x01(\x0b\x32+.spotify.clienttoken.http.v0.HashCashAnswerH\x00\x42\x08\n\x06\x61nswer\"(\n\x15\x43lientTokenBadRequest\x12\x0f\n\x07message\x18\x01 \x01(\t*u\n\x16\x43lientTokenRequestType\x12\x13\n\x0fREQUEST_UNKNOWN\x10\x00\x12\x1f\n\x1bREQUEST_CLIENT_DATA_REQUEST\x10\x01\x12%\n!REQUEST_CHALLENGE_ANSWERS_REQUEST\x10\x02*v\n\x17\x43lientTokenResponseType\x12\x14\n\x10RESPONSE_UNKNOWN\x10\x00\x12#\n\x1fRESPONSE_GRANTED_TOKEN_RESPONSE\x10\x01\x12 \n\x1cRESPONSE_CHALLENGES_RESPONSE\x10\x02*|\n\rChallengeType\x12\x15\n\x11\x43HALLENGE_UNKNOWN\x10\x00\x12 \n\x1c\x43HALLENGE_CLIENT_SECRET_HMAC\x10\x01\x12\x19\n\x15\x43HALLENGE_EVALUATE_JS\x10\x02\x12\x17\n\x13\x43HALLENGE_HASH_CASH\x10\x03\x42#\n\x1f\x63om.spotify.clienttoken.http.v0H\x02\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'client_token_pb2', globals())
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\037com.spotify.clienttoken.http.v0H\002'
|
||||
_CLIENTTOKENREQUESTTYPE._serialized_start=2107
|
||||
_CLIENTTOKENREQUESTTYPE._serialized_end=2224
|
||||
_CLIENTTOKENRESPONSETYPE._serialized_start=2226
|
||||
_CLIENTTOKENRESPONSETYPE._serialized_end=2344
|
||||
_CHALLENGETYPE._serialized_start=2346
|
||||
_CHALLENGETYPE._serialized_end=2470
|
||||
_CLIENTTOKENREQUEST._serialized_start=72
|
||||
_CLIENTTOKENREQUEST._serialized_end=332
|
||||
_CLIENTDATAREQUEST._serialized_start=335
|
||||
_CLIENTDATAREQUEST._serialized_end=488
|
||||
_CHALLENGEANSWERSREQUEST._serialized_start=490
|
||||
_CHALLENGEANSWERSREQUEST._serialized_end=593
|
||||
_CLIENTTOKENRESPONSE._serialized_start=596
|
||||
_CLIENTTOKENRESPONSE._serialized_end=853
|
||||
_TOKENDOMAIN._serialized_start=855
|
||||
_TOKENDOMAIN._serialized_end=884
|
||||
_GRANTEDTOKENRESPONSE._serialized_start=887
|
||||
_GRANTEDTOKENRESPONSE._serialized_end=1045
|
||||
_CHALLENGESRESPONSE._serialized_start=1047
|
||||
_CHALLENGESRESPONSE._serialized_end=1142
|
||||
_CLIENTSECRETPARAMETERS._serialized_start=1144
|
||||
_CLIENTSECRETPARAMETERS._serialized_end=1182
|
||||
_EVALUATEJSPARAMETERS._serialized_start=1184
|
||||
_EVALUATEJSPARAMETERS._serialized_end=1239
|
||||
_HASHCASHPARAMETERS._serialized_start=1241
|
||||
_HASHCASHPARAMETERS._serialized_end=1293
|
||||
_CHALLENGE._serialized_start=1296
|
||||
_CHALLENGE._serialized_end=1642
|
||||
_CLIENTSECRETHMACANSWER._serialized_start=1644
|
||||
_CLIENTSECRETHMACANSWER._serialized_end=1682
|
||||
_EVALUATEJSANSWER._serialized_start=1684
|
||||
_EVALUATEJSANSWER._serialized_end=1718
|
||||
_HASHCASHANSWER._serialized_start=1720
|
||||
_HASHCASHANSWER._serialized_end=1752
|
||||
_CHALLENGEANSWER._serialized_start=1755
|
||||
_CHALLENGEANSWER._serialized_end=2063
|
||||
_CLIENTTOKENBADREQUEST._serialized_start=2065
|
||||
_CLIENTTOKENBADREQUEST._serialized_end=2105
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
2340
resources/lib/librespot/proto/Connect_pb2.py
Normal file
36
resources/lib/librespot/proto/Connectivity_pb2.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: connectivity.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import builder as _builder
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12\x63onnectivity.proto\x12\x1bspotify.clienttoken.data.v0\"{\n\x13\x43onnectivitySdkData\x12Q\n\x16platform_specific_data\x18\x01 \x01(\x0b\x32\x31.spotify.clienttoken.data.v0.PlatformSpecificData\x12\x11\n\tdevice_id\x18\x02 \x01(\t\"\xdf\x01\n\x14PlatformSpecificData\x12\x41\n\x07\x61ndroid\x18\x01 \x01(\x0b\x32..spotify.clienttoken.data.v0.NativeAndroidDataH\x00\x12\x39\n\x03ios\x18\x02 \x01(\x0b\x32*.spotify.clienttoken.data.v0.NativeIOSDataH\x00\x12\x41\n\x07windows\x18\x04 \x01(\x0b\x32..spotify.clienttoken.data.v0.NativeWindowsDataH\x00\x42\x06\n\x04\x64\x61ta\"\xb9\x01\n\x11NativeAndroidData\x12\x19\n\x11major_sdk_version\x18\x01 \x01(\x05\x12\x19\n\x11minor_sdk_version\x18\x02 \x01(\x05\x12\x19\n\x11patch_sdk_version\x18\x03 \x01(\x05\x12\x13\n\x0b\x61pi_version\x18\x04 \x01(\r\x12>\n\x11screen_dimensions\x18\x05 \x01(\x0b\x32#.spotify.clienttoken.data.v0.Screen\"\x9e\x01\n\rNativeIOSData\x12\x1c\n\x14user_interface_idiom\x18\x01 \x01(\x05\x12\x1f\n\x17target_iphone_simulator\x18\x02 \x01(\x08\x12\x12\n\nhw_machine\x18\x03 \x01(\t\x12\x16\n\x0esystem_version\x18\x04 \x01(\t\x12\"\n\x1asimulator_model_identifier\x18\x05 \x01(\t\"\xa0\x01\n\x11NativeWindowsData\x12\x12\n\nsomething1\x18\x01 \x01(\x05\x12\x12\n\nsomething3\x18\x03 \x01(\x05\x12\x12\n\nsomething4\x18\x04 \x01(\x05\x12\x12\n\nsomething6\x18\x06 \x01(\x05\x12\x12\n\nsomething7\x18\x07 \x01(\x05\x12\x12\n\nsomething8\x18\x08 \x01(\x05\x12\x13\n\x0bsomething10\x18\n \x01(\x08\"8\n\x06Screen\x12\r\n\x05width\x18\x01 \x01(\x05\x12\x0e\n\x06height\x18\x02 \x01(\x05\x12\x0f\n\x07\x64\x65nsity\x18\x03 \x01(\x05\x42#\n\x1f\x63om.spotify.clienttoken.data.v0H\x02\x62\x06proto3')
|
||||
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'connectivity_pb2', globals())
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
DESCRIPTOR._serialized_options = b'\n\037com.spotify.clienttoken.data.v0H\002'
|
||||
_CONNECTIVITYSDKDATA._serialized_start=51
|
||||
_CONNECTIVITYSDKDATA._serialized_end=174
|
||||
_PLATFORMSPECIFICDATA._serialized_start=177
|
||||
_PLATFORMSPECIFICDATA._serialized_end=400
|
||||
_NATIVEANDROIDDATA._serialized_start=403
|
||||
_NATIVEANDROIDDATA._serialized_end=588
|
||||
_NATIVEIOSDATA._serialized_start=591
|
||||
_NATIVEIOSDATA._serialized_end=749
|
||||
_NATIVEWINDOWSDATA._serialized_start=752
|
||||
_NATIVEWINDOWSDATA._serialized_end=912
|
||||
_SCREEN._serialized_start=914
|
||||
_SCREEN._serialized_end=970
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
239
resources/lib/librespot/proto/ContextPage_pb2.py
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: context_page.proto
|
||||
"""Generated protocol buffer code."""
|
||||
import ContextTrack_pb2 as context__track__pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="context_page.proto",
|
||||
package="spotify.player.proto",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\023com.spotify.contextH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x12\x63ontext_page.proto\x12\x14spotify.player.proto\x1a\x13\x63ontext_track.proto"\xef\x01\n\x0b\x43ontextPage\x12\x10\n\x08page_url\x18\x01 \x01(\t\x12\x15\n\rnext_page_url\x18\x02 \x01(\t\x12\x41\n\x08metadata\x18\x03 \x03(\x0b\x32/.spotify.player.proto.ContextPage.MetadataEntry\x12\x32\n\x06tracks\x18\x04 \x03(\x0b\x32".spotify.player.proto.ContextTrack\x12\x0f\n\x07loading\x18\x05 \x01(\x08\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x17\n\x13\x63om.spotify.contextH\x02',
|
||||
dependencies=[
|
||||
context__track__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_CONTEXTPAGE_METADATAENTRY = _descriptor.Descriptor(
|
||||
name="MetadataEntry",
|
||||
full_name="spotify.player.proto.ContextPage.MetadataEntry",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="key",
|
||||
full_name="spotify.player.proto.ContextPage.MetadataEntry.key",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="value",
|
||||
full_name="spotify.player.proto.ContextPage.MetadataEntry.value",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=b"8\001",
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=258,
|
||||
serialized_end=305,
|
||||
)
|
||||
|
||||
_CONTEXTPAGE = _descriptor.Descriptor(
|
||||
name="ContextPage",
|
||||
full_name="spotify.player.proto.ContextPage",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="page_url",
|
||||
full_name="spotify.player.proto.ContextPage.page_url",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="next_page_url",
|
||||
full_name="spotify.player.proto.ContextPage.next_page_url",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="metadata",
|
||||
full_name="spotify.player.proto.ContextPage.metadata",
|
||||
index=2,
|
||||
number=3,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="tracks",
|
||||
full_name="spotify.player.proto.ContextPage.tracks",
|
||||
index=3,
|
||||
number=4,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="loading",
|
||||
full_name="spotify.player.proto.ContextPage.loading",
|
||||
index=4,
|
||||
number=5,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[
|
||||
_CONTEXTPAGE_METADATAENTRY,
|
||||
],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=66,
|
||||
serialized_end=305,
|
||||
)
|
||||
|
||||
_CONTEXTPAGE_METADATAENTRY.containing_type = _CONTEXTPAGE
|
||||
_CONTEXTPAGE.fields_by_name[
|
||||
"metadata"].message_type = _CONTEXTPAGE_METADATAENTRY
|
||||
_CONTEXTPAGE.fields_by_name[
|
||||
"tracks"].message_type = context__track__pb2._CONTEXTTRACK
|
||||
DESCRIPTOR.message_types_by_name["ContextPage"] = _CONTEXTPAGE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
ContextPage = _reflection.GeneratedProtocolMessageType(
|
||||
"ContextPage",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"MetadataEntry":
|
||||
_reflection.GeneratedProtocolMessageType(
|
||||
"MetadataEntry",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CONTEXTPAGE_METADATAENTRY,
|
||||
"__module__": "context_page_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.ContextPage.MetadataEntry)
|
||||
},
|
||||
),
|
||||
"DESCRIPTOR":
|
||||
_CONTEXTPAGE,
|
||||
"__module__":
|
||||
"context_page_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.ContextPage)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ContextPage)
|
||||
_sym_db.RegisterMessage(ContextPage.MetadataEntry)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_CONTEXTPAGE_METADATAENTRY._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
215
resources/lib/librespot/proto/ContextPlayerOptions_pb2.py
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: context_player_options.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="context_player_options.proto",
|
||||
package="spotify.player.proto",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\023com.spotify.contextH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x1c\x63ontext_player_options.proto\x12\x14spotify.player.proto"e\n\x14\x43ontextPlayerOptions\x12\x19\n\x11shuffling_context\x18\x01 \x01(\x08\x12\x19\n\x11repeating_context\x18\x02 \x01(\x08\x12\x17\n\x0frepeating_track\x18\x03 \x01(\x08"m\n\x1c\x43ontextPlayerOptionOverrides\x12\x19\n\x11shuffling_context\x18\x01 \x01(\x08\x12\x19\n\x11repeating_context\x18\x02 \x01(\x08\x12\x17\n\x0frepeating_track\x18\x03 \x01(\x08\x42\x17\n\x13\x63om.spotify.contextH\x02',
|
||||
)
|
||||
|
||||
_CONTEXTPLAYEROPTIONS = _descriptor.Descriptor(
|
||||
name="ContextPlayerOptions",
|
||||
full_name="spotify.player.proto.ContextPlayerOptions",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="shuffling_context",
|
||||
full_name=
|
||||
"spotify.player.proto.ContextPlayerOptions.shuffling_context",
|
||||
index=0,
|
||||
number=1,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="repeating_context",
|
||||
full_name=
|
||||
"spotify.player.proto.ContextPlayerOptions.repeating_context",
|
||||
index=1,
|
||||
number=2,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="repeating_track",
|
||||
full_name=
|
||||
"spotify.player.proto.ContextPlayerOptions.repeating_track",
|
||||
index=2,
|
||||
number=3,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=54,
|
||||
serialized_end=155,
|
||||
)
|
||||
|
||||
_CONTEXTPLAYEROPTIONOVERRIDES = _descriptor.Descriptor(
|
||||
name="ContextPlayerOptionOverrides",
|
||||
full_name="spotify.player.proto.ContextPlayerOptionOverrides",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="shuffling_context",
|
||||
full_name=
|
||||
"spotify.player.proto.ContextPlayerOptionOverrides.shuffling_context",
|
||||
index=0,
|
||||
number=1,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="repeating_context",
|
||||
full_name=
|
||||
"spotify.player.proto.ContextPlayerOptionOverrides.repeating_context",
|
||||
index=1,
|
||||
number=2,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="repeating_track",
|
||||
full_name=
|
||||
"spotify.player.proto.ContextPlayerOptionOverrides.repeating_track",
|
||||
index=2,
|
||||
number=3,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=157,
|
||||
serialized_end=266,
|
||||
)
|
||||
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
"ContextPlayerOptions"] = _CONTEXTPLAYEROPTIONS
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
"ContextPlayerOptionOverrides"] = _CONTEXTPLAYEROPTIONOVERRIDES
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
ContextPlayerOptions = _reflection.GeneratedProtocolMessageType(
|
||||
"ContextPlayerOptions",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CONTEXTPLAYEROPTIONS,
|
||||
"__module__": "context_player_options_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.ContextPlayerOptions)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ContextPlayerOptions)
|
||||
|
||||
ContextPlayerOptionOverrides = _reflection.GeneratedProtocolMessageType(
|
||||
"ContextPlayerOptionOverrides",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CONTEXTPLAYEROPTIONOVERRIDES,
|
||||
"__module__": "context_player_options_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.ContextPlayerOptionOverrides)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ContextPlayerOptionOverrides)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
214
resources/lib/librespot/proto/ContextTrack_pb2.py
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: context_track.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="context_track.proto",
|
||||
package="spotify.player.proto",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\023com.spotify.contextH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x13\x63ontext_track.proto\x12\x14spotify.player.proto"\xaa\x01\n\x0c\x43ontextTrack\x12\x0b\n\x03uri\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\t\x12\x0b\n\x03gid\x18\x03 \x01(\x0c\x12\x42\n\x08metadata\x18\x04 \x03(\x0b\x32\x30.spotify.player.proto.ContextTrack.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x17\n\x13\x63om.spotify.contextH\x02',
|
||||
)
|
||||
|
||||
_CONTEXTTRACK_METADATAENTRY = _descriptor.Descriptor(
|
||||
name="MetadataEntry",
|
||||
full_name="spotify.player.proto.ContextTrack.MetadataEntry",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="key",
|
||||
full_name="spotify.player.proto.ContextTrack.MetadataEntry.key",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="value",
|
||||
full_name="spotify.player.proto.ContextTrack.MetadataEntry.value",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=b"8\001",
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=169,
|
||||
serialized_end=216,
|
||||
)
|
||||
|
||||
_CONTEXTTRACK = _descriptor.Descriptor(
|
||||
name="ContextTrack",
|
||||
full_name="spotify.player.proto.ContextTrack",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="uri",
|
||||
full_name="spotify.player.proto.ContextTrack.uri",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="uid",
|
||||
full_name="spotify.player.proto.ContextTrack.uid",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="gid",
|
||||
full_name="spotify.player.proto.ContextTrack.gid",
|
||||
index=2,
|
||||
number=3,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="metadata",
|
||||
full_name="spotify.player.proto.ContextTrack.metadata",
|
||||
index=3,
|
||||
number=4,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[
|
||||
_CONTEXTTRACK_METADATAENTRY,
|
||||
],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=46,
|
||||
serialized_end=216,
|
||||
)
|
||||
|
||||
_CONTEXTTRACK_METADATAENTRY.containing_type = _CONTEXTTRACK
|
||||
_CONTEXTTRACK.fields_by_name[
|
||||
"metadata"].message_type = _CONTEXTTRACK_METADATAENTRY
|
||||
DESCRIPTOR.message_types_by_name["ContextTrack"] = _CONTEXTTRACK
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
ContextTrack = _reflection.GeneratedProtocolMessageType(
|
||||
"ContextTrack",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"MetadataEntry":
|
||||
_reflection.GeneratedProtocolMessageType(
|
||||
"MetadataEntry",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CONTEXTTRACK_METADATAENTRY,
|
||||
"__module__": "context_track_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.ContextTrack.MetadataEntry)
|
||||
},
|
||||
),
|
||||
"DESCRIPTOR":
|
||||
_CONTEXTTRACK,
|
||||
"__module__":
|
||||
"context_track_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.ContextTrack)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ContextTrack)
|
||||
_sym_db.RegisterMessage(ContextTrack.MetadataEntry)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_CONTEXTTRACK_METADATAENTRY._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
260
resources/lib/librespot/proto/Context_pb2.py
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: context.proto
|
||||
"""Generated protocol buffer code."""
|
||||
import ContextPage_pb2 as context__page__pb2
|
||||
import Restrictions_pb2 as restrictions__pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="context.proto",
|
||||
package="spotify.player.proto",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\023com.spotify.contextH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\rcontext.proto\x12\x14spotify.player.proto\x1a\x12\x63ontext_page.proto\x1a\x12restrictions.proto"\x90\x02\n\x07\x43ontext\x12\x0b\n\x03uri\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\x12=\n\x08metadata\x18\x03 \x03(\x0b\x32+.spotify.player.proto.Context.MetadataEntry\x12\x38\n\x0crestrictions\x18\x04 \x01(\x0b\x32".spotify.player.proto.Restrictions\x12\x30\n\x05pages\x18\x05 \x03(\x0b\x32!.spotify.player.proto.ContextPage\x12\x0f\n\x07loading\x18\x06 \x01(\x08\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x17\n\x13\x63om.spotify.contextH\x02',
|
||||
dependencies=[
|
||||
context__page__pb2.DESCRIPTOR,
|
||||
restrictions__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_CONTEXT_METADATAENTRY = _descriptor.Descriptor(
|
||||
name="MetadataEntry",
|
||||
full_name="spotify.player.proto.Context.MetadataEntry",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="key",
|
||||
full_name="spotify.player.proto.Context.MetadataEntry.key",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="value",
|
||||
full_name="spotify.player.proto.Context.MetadataEntry.value",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=b"8\001",
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=305,
|
||||
serialized_end=352,
|
||||
)
|
||||
|
||||
_CONTEXT = _descriptor.Descriptor(
|
||||
name="Context",
|
||||
full_name="spotify.player.proto.Context",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="uri",
|
||||
full_name="spotify.player.proto.Context.uri",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="url",
|
||||
full_name="spotify.player.proto.Context.url",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="metadata",
|
||||
full_name="spotify.player.proto.Context.metadata",
|
||||
index=2,
|
||||
number=3,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="restrictions",
|
||||
full_name="spotify.player.proto.Context.restrictions",
|
||||
index=3,
|
||||
number=4,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="pages",
|
||||
full_name="spotify.player.proto.Context.pages",
|
||||
index=4,
|
||||
number=5,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="loading",
|
||||
full_name="spotify.player.proto.Context.loading",
|
||||
index=5,
|
||||
number=6,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[
|
||||
_CONTEXT_METADATAENTRY,
|
||||
],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=80,
|
||||
serialized_end=352,
|
||||
)
|
||||
|
||||
_CONTEXT_METADATAENTRY.containing_type = _CONTEXT
|
||||
_CONTEXT.fields_by_name["metadata"].message_type = _CONTEXT_METADATAENTRY
|
||||
_CONTEXT.fields_by_name[
|
||||
"restrictions"].message_type = restrictions__pb2._RESTRICTIONS
|
||||
_CONTEXT.fields_by_name["pages"].message_type = context__page__pb2._CONTEXTPAGE
|
||||
DESCRIPTOR.message_types_by_name["Context"] = _CONTEXT
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Context = _reflection.GeneratedProtocolMessageType(
|
||||
"Context",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"MetadataEntry":
|
||||
_reflection.GeneratedProtocolMessageType(
|
||||
"MetadataEntry",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CONTEXT_METADATAENTRY,
|
||||
"__module__": "context_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.Context.MetadataEntry)
|
||||
},
|
||||
),
|
||||
"DESCRIPTOR":
|
||||
_CONTEXT,
|
||||
"__module__":
|
||||
"context_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.Context)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Context)
|
||||
_sym_db.RegisterMessage(Context.MetadataEntry)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_CONTEXT_METADATAENTRY._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
147
resources/lib/librespot/proto/ExplicitContentPubsub_pb2.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: explicit_content_pubsub.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='explicit_content_pubsub.proto',
|
||||
package='spotify.explicit_content.proto',
|
||||
syntax='proto2',
|
||||
serialized_options=b'\n\024com.spotify.explicitH\002',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x1d\x65xplicit_content_pubsub.proto\x12\x1espotify.explicit_content.proto\"*\n\x0cKeyValuePair\x12\x0b\n\x03key\x18\x01 \x02(\t\x12\r\n\x05value\x18\x02 \x02(\t\"S\n\x14UserAttributesUpdate\x12;\n\x05pairs\x18\x01 \x03(\x0b\x32,.spotify.explicit_content.proto.KeyValuePairB\x18\n\x14\x63om.spotify.explicitH\x02'
|
||||
)
|
||||
|
||||
_KEYVALUEPAIR = _descriptor.Descriptor(
|
||||
name='KeyValuePair',
|
||||
full_name='spotify.explicit_content.proto.KeyValuePair',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='key',
|
||||
full_name='spotify.explicit_content.proto.KeyValuePair.key',
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=2,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value',
|
||||
full_name='spotify.explicit_content.proto.KeyValuePair.value',
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=2,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=65,
|
||||
serialized_end=107,
|
||||
)
|
||||
|
||||
_USERATTRIBUTESUPDATE = _descriptor.Descriptor(
|
||||
name='UserAttributesUpdate',
|
||||
full_name='spotify.explicit_content.proto.UserAttributesUpdate',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='pairs',
|
||||
full_name=
|
||||
'spotify.explicit_content.proto.UserAttributesUpdate.pairs',
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=109,
|
||||
serialized_end=192,
|
||||
)
|
||||
|
||||
_USERATTRIBUTESUPDATE.fields_by_name['pairs'].message_type = _KEYVALUEPAIR
|
||||
DESCRIPTOR.message_types_by_name['KeyValuePair'] = _KEYVALUEPAIR
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
'UserAttributesUpdate'] = _USERATTRIBUTESUPDATE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
KeyValuePair = _reflection.GeneratedProtocolMessageType(
|
||||
'KeyValuePair',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _KEYVALUEPAIR,
|
||||
'__module__': 'explicit_content_pubsub_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.explicit_content.proto.KeyValuePair)
|
||||
})
|
||||
_sym_db.RegisterMessage(KeyValuePair)
|
||||
|
||||
UserAttributesUpdate = _reflection.GeneratedProtocolMessageType(
|
||||
'UserAttributesUpdate',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _USERATTRIBUTESUPDATE,
|
||||
'__module__': 'explicit_content_pubsub_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.explicit_content.proto.UserAttributesUpdate)
|
||||
})
|
||||
_sym_db.RegisterMessage(UserAttributesUpdate)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
2497
resources/lib/librespot/proto/Keyexchange_pb2.py
Normal file
625
resources/lib/librespot/proto/Mercury_pb2.py
Normal file
|
|
@ -0,0 +1,625 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: mercury.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='mercury.proto',
|
||||
package='spotify',
|
||||
syntax='proto2',
|
||||
serialized_options=b'\n\013com.spotify',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\rmercury.proto\x12\x07spotify\"B\n\x16MercuryMultiGetRequest\x12(\n\x07request\x18\x01 \x03(\x0b\x32\x17.spotify.MercuryRequest\"<\n\x14MercuryMultiGetReply\x12$\n\x05reply\x18\x01 \x03(\x0b\x32\x15.spotify.MercuryReply\"O\n\x0eMercuryRequest\x12\x0b\n\x03uri\x18\x01 \x01(\t\x12\x14\n\x0c\x63ontent_type\x18\x02 \x01(\t\x12\x0c\n\x04\x62ody\x18\x03 \x01(\x0c\x12\x0c\n\x04\x65tag\x18\x04 \x01(\x0c\"\xf5\x01\n\x0cMercuryReply\x12\x13\n\x0bstatus_code\x18\x01 \x01(\x11\x12\x16\n\x0estatus_message\x18\x02 \x01(\t\x12\x37\n\x0c\x63\x61\x63he_policy\x18\x03 \x01(\x0e\x32!.spotify.MercuryReply.CachePolicy\x12\x0b\n\x03ttl\x18\x04 \x01(\x11\x12\x0c\n\x04\x65tag\x18\x05 \x01(\x0c\x12\x14\n\x0c\x63ontent_type\x18\x06 \x01(\t\x12\x0c\n\x04\x62ody\x18\x07 \x01(\x0c\"@\n\x0b\x43\x61\x63hePolicy\x12\x0c\n\x08\x43\x41\x43HE_NO\x10\x01\x12\x11\n\rCACHE_PRIVATE\x10\x02\x12\x10\n\x0c\x43\x41\x43HE_PUBLIC\x10\x03\"y\n\x06Header\x12\x0b\n\x03uri\x18\x01 \x01(\t\x12\x14\n\x0c\x63ontent_type\x18\x02 \x01(\t\x12\x0e\n\x06method\x18\x03 \x01(\t\x12\x13\n\x0bstatus_code\x18\x04 \x01(\x11\x12\'\n\x0buser_fields\x18\x06 \x03(\x0b\x32\x12.spotify.UserField\"\'\n\tUserField\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x0c\x42\r\n\x0b\x63om.spotify'
|
||||
)
|
||||
|
||||
_MERCURYREPLY_CACHEPOLICY = _descriptor.EnumDescriptor(
|
||||
name='CachePolicy',
|
||||
full_name='spotify.MercuryReply.CachePolicy',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CACHE_NO',
|
||||
index=0,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CACHE_PRIVATE',
|
||||
index=1,
|
||||
number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CACHE_PUBLIC',
|
||||
index=2,
|
||||
number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=419,
|
||||
serialized_end=483,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_MERCURYREPLY_CACHEPOLICY)
|
||||
|
||||
_MERCURYMULTIGETREQUEST = _descriptor.Descriptor(
|
||||
name='MercuryMultiGetRequest',
|
||||
full_name='spotify.MercuryMultiGetRequest',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='request',
|
||||
full_name='spotify.MercuryMultiGetRequest.request',
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=26,
|
||||
serialized_end=92,
|
||||
)
|
||||
|
||||
_MERCURYMULTIGETREPLY = _descriptor.Descriptor(
|
||||
name='MercuryMultiGetReply',
|
||||
full_name='spotify.MercuryMultiGetReply',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='reply',
|
||||
full_name='spotify.MercuryMultiGetReply.reply',
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=94,
|
||||
serialized_end=154,
|
||||
)
|
||||
|
||||
_MERCURYREQUEST = _descriptor.Descriptor(
|
||||
name='MercuryRequest',
|
||||
full_name='spotify.MercuryRequest',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='uri',
|
||||
full_name='spotify.MercuryRequest.uri',
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='content_type',
|
||||
full_name='spotify.MercuryRequest.content_type',
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='body',
|
||||
full_name='spotify.MercuryRequest.body',
|
||||
index=2,
|
||||
number=3,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='etag',
|
||||
full_name='spotify.MercuryRequest.etag',
|
||||
index=3,
|
||||
number=4,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=156,
|
||||
serialized_end=235,
|
||||
)
|
||||
|
||||
_MERCURYREPLY = _descriptor.Descriptor(
|
||||
name='MercuryReply',
|
||||
full_name='spotify.MercuryReply',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='status_code',
|
||||
full_name='spotify.MercuryReply.status_code',
|
||||
index=0,
|
||||
number=1,
|
||||
type=17,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='status_message',
|
||||
full_name='spotify.MercuryReply.status_message',
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='cache_policy',
|
||||
full_name='spotify.MercuryReply.cache_policy',
|
||||
index=2,
|
||||
number=3,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=1,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ttl',
|
||||
full_name='spotify.MercuryReply.ttl',
|
||||
index=3,
|
||||
number=4,
|
||||
type=17,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='etag',
|
||||
full_name='spotify.MercuryReply.etag',
|
||||
index=4,
|
||||
number=5,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='content_type',
|
||||
full_name='spotify.MercuryReply.content_type',
|
||||
index=5,
|
||||
number=6,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='body',
|
||||
full_name='spotify.MercuryReply.body',
|
||||
index=6,
|
||||
number=7,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_MERCURYREPLY_CACHEPOLICY,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=238,
|
||||
serialized_end=483,
|
||||
)
|
||||
|
||||
_HEADER = _descriptor.Descriptor(
|
||||
name='Header',
|
||||
full_name='spotify.Header',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='uri',
|
||||
full_name='spotify.Header.uri',
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='content_type',
|
||||
full_name='spotify.Header.content_type',
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='method',
|
||||
full_name='spotify.Header.method',
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='status_code',
|
||||
full_name='spotify.Header.status_code',
|
||||
index=3,
|
||||
number=4,
|
||||
type=17,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='user_fields',
|
||||
full_name='spotify.Header.user_fields',
|
||||
index=4,
|
||||
number=6,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=485,
|
||||
serialized_end=606,
|
||||
)
|
||||
|
||||
_USERFIELD = _descriptor.Descriptor(
|
||||
name='UserField',
|
||||
full_name='spotify.UserField',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='key',
|
||||
full_name='spotify.UserField.key',
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='value',
|
||||
full_name='spotify.UserField.value',
|
||||
index=1,
|
||||
number=2,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=608,
|
||||
serialized_end=647,
|
||||
)
|
||||
|
||||
_MERCURYMULTIGETREQUEST.fields_by_name[
|
||||
'request'].message_type = _MERCURYREQUEST
|
||||
_MERCURYMULTIGETREPLY.fields_by_name['reply'].message_type = _MERCURYREPLY
|
||||
_MERCURYREPLY.fields_by_name[
|
||||
'cache_policy'].enum_type = _MERCURYREPLY_CACHEPOLICY
|
||||
_MERCURYREPLY_CACHEPOLICY.containing_type = _MERCURYREPLY
|
||||
_HEADER.fields_by_name['user_fields'].message_type = _USERFIELD
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
'MercuryMultiGetRequest'] = _MERCURYMULTIGETREQUEST
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
'MercuryMultiGetReply'] = _MERCURYMULTIGETREPLY
|
||||
DESCRIPTOR.message_types_by_name['MercuryRequest'] = _MERCURYREQUEST
|
||||
DESCRIPTOR.message_types_by_name['MercuryReply'] = _MERCURYREPLY
|
||||
DESCRIPTOR.message_types_by_name['Header'] = _HEADER
|
||||
DESCRIPTOR.message_types_by_name['UserField'] = _USERFIELD
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
MercuryMultiGetRequest = _reflection.GeneratedProtocolMessageType(
|
||||
'MercuryMultiGetRequest',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _MERCURYMULTIGETREQUEST,
|
||||
'__module__': 'mercury_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.MercuryMultiGetRequest)
|
||||
})
|
||||
_sym_db.RegisterMessage(MercuryMultiGetRequest)
|
||||
|
||||
MercuryMultiGetReply = _reflection.GeneratedProtocolMessageType(
|
||||
'MercuryMultiGetReply',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _MERCURYMULTIGETREPLY,
|
||||
'__module__': 'mercury_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.MercuryMultiGetReply)
|
||||
})
|
||||
_sym_db.RegisterMessage(MercuryMultiGetReply)
|
||||
|
||||
MercuryRequest = _reflection.GeneratedProtocolMessageType(
|
||||
'MercuryRequest',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _MERCURYREQUEST,
|
||||
'__module__': 'mercury_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.MercuryRequest)
|
||||
})
|
||||
_sym_db.RegisterMessage(MercuryRequest)
|
||||
|
||||
MercuryReply = _reflection.GeneratedProtocolMessageType(
|
||||
'MercuryReply',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _MERCURYREPLY,
|
||||
'__module__': 'mercury_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.MercuryReply)
|
||||
})
|
||||
_sym_db.RegisterMessage(MercuryReply)
|
||||
|
||||
Header = _reflection.GeneratedProtocolMessageType(
|
||||
'Header',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _HEADER,
|
||||
'__module__': 'mercury_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.Header)
|
||||
})
|
||||
_sym_db.RegisterMessage(Header)
|
||||
|
||||
UserField = _reflection.GeneratedProtocolMessageType(
|
||||
'UserField',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _USERFIELD,
|
||||
'__module__': 'mercury_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.UserField)
|
||||
})
|
||||
_sym_db.RegisterMessage(UserField)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
3698
resources/lib/librespot/proto/Metadata_pb2.py
Normal file
193
resources/lib/librespot/proto/PlayOrigin_pb2.py
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: play_origin.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="play_origin.proto",
|
||||
package="spotify.player.proto",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\023com.spotify.contextH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x11play_origin.proto\x12\x14spotify.player.proto"\xbf\x01\n\nPlayOrigin\x12\x1a\n\x12\x66\x65\x61ture_identifier\x18\x01 \x01(\t\x12\x17\n\x0f\x66\x65\x61ture_version\x18\x02 \x01(\t\x12\x10\n\x08view_uri\x18\x03 \x01(\t\x12\x19\n\x11\x65xternal_referrer\x18\x04 \x01(\t\x12\x1b\n\x13referrer_identifier\x18\x05 \x01(\t\x12\x19\n\x11\x64\x65vice_identifier\x18\x06 \x01(\t\x12\x17\n\x0f\x66\x65\x61ture_classes\x18\x07 \x03(\tB\x17\n\x13\x63om.spotify.contextH\x02',
|
||||
)
|
||||
|
||||
_PLAYORIGIN = _descriptor.Descriptor(
|
||||
name="PlayOrigin",
|
||||
full_name="spotify.player.proto.PlayOrigin",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="feature_identifier",
|
||||
full_name="spotify.player.proto.PlayOrigin.feature_identifier",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="feature_version",
|
||||
full_name="spotify.player.proto.PlayOrigin.feature_version",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="view_uri",
|
||||
full_name="spotify.player.proto.PlayOrigin.view_uri",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="external_referrer",
|
||||
full_name="spotify.player.proto.PlayOrigin.external_referrer",
|
||||
index=3,
|
||||
number=4,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="referrer_identifier",
|
||||
full_name="spotify.player.proto.PlayOrigin.referrer_identifier",
|
||||
index=4,
|
||||
number=5,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="device_identifier",
|
||||
full_name="spotify.player.proto.PlayOrigin.device_identifier",
|
||||
index=5,
|
||||
number=6,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="feature_classes",
|
||||
full_name="spotify.player.proto.PlayOrigin.feature_classes",
|
||||
index=6,
|
||||
number=7,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=44,
|
||||
serialized_end=235,
|
||||
)
|
||||
|
||||
DESCRIPTOR.message_types_by_name["PlayOrigin"] = _PLAYORIGIN
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
PlayOrigin = _reflection.GeneratedProtocolMessageType(
|
||||
"PlayOrigin",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _PLAYORIGIN,
|
||||
"__module__": "play_origin_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.PlayOrigin)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(PlayOrigin)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
162
resources/lib/librespot/proto/Playback_pb2.py
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: playback.proto
|
||||
"""Generated protocol buffer code."""
|
||||
import ContextTrack_pb2 as context__track__pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="playback.proto",
|
||||
package="spotify.player.proto.transfer",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\024com.spotify.transferH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x0eplayback.proto\x12\x1dspotify.player.proto.transfer\x1a\x13\x63ontext_track.proto"\xa5\x01\n\x08Playback\x12\x11\n\ttimestamp\x18\x01 \x01(\x03\x12 \n\x18position_as_of_timestamp\x18\x02 \x01(\x05\x12\x16\n\x0eplayback_speed\x18\x03 \x01(\x01\x12\x11\n\tis_paused\x18\x04 \x01(\x08\x12\x39\n\rcurrent_track\x18\x05 \x01(\x0b\x32".spotify.player.proto.ContextTrackB\x18\n\x14\x63om.spotify.transferH\x02',
|
||||
dependencies=[
|
||||
context__track__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_PLAYBACK = _descriptor.Descriptor(
|
||||
name="Playback",
|
||||
full_name="spotify.player.proto.transfer.Playback",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="timestamp",
|
||||
full_name="spotify.player.proto.transfer.Playback.timestamp",
|
||||
index=0,
|
||||
number=1,
|
||||
type=3,
|
||||
cpp_type=2,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="position_as_of_timestamp",
|
||||
full_name=
|
||||
"spotify.player.proto.transfer.Playback.position_as_of_timestamp",
|
||||
index=1,
|
||||
number=2,
|
||||
type=5,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="playback_speed",
|
||||
full_name="spotify.player.proto.transfer.Playback.playback_speed",
|
||||
index=2,
|
||||
number=3,
|
||||
type=1,
|
||||
cpp_type=5,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=float(0),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="is_paused",
|
||||
full_name="spotify.player.proto.transfer.Playback.is_paused",
|
||||
index=3,
|
||||
number=4,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="current_track",
|
||||
full_name="spotify.player.proto.transfer.Playback.current_track",
|
||||
index=4,
|
||||
number=5,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=71,
|
||||
serialized_end=236,
|
||||
)
|
||||
|
||||
_PLAYBACK.fields_by_name[
|
||||
"current_track"].message_type = context__track__pb2._CONTEXTTRACK
|
||||
DESCRIPTOR.message_types_by_name["Playback"] = _PLAYBACK
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Playback = _reflection.GeneratedProtocolMessageType(
|
||||
"Playback",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _PLAYBACK,
|
||||
"__module__": "playback_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.transfer.Playback)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Playback)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
1851
resources/lib/librespot/proto/Player_pb2.py
Normal file
3221
resources/lib/librespot/proto/Playlist4External_pb2.py
Normal file
460
resources/lib/librespot/proto/PlaylistAnnotate3_pb2.py
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: playlist_annotate3.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="playlist_annotate3.proto",
|
||||
package="spotify_playlist_annotate3.proto",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\036com.spotify.playlist_annotate3H\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x18playlist_annotate3.proto\x12 spotify_playlist_annotate3.proto"a\n\x0fTakedownRequest\x12N\n\x12\x61\x62use_report_state\x18\x01 \x01(\x0e\x32\x32.spotify_playlist_annotate3.proto.AbuseReportState"9\n\x0f\x41nnotateRequest\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\t\x12\x11\n\timage_uri\x18\x02 \x01(\t"5\n\x11TranscodedPicture\x12\x13\n\x0btarget_name\x18\x01 \x01(\t\x12\x0b\n\x03uri\x18\x02 \x01(\t"\xf4\x02\n\x12PlaylistAnnotation\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\t\x12\x0f\n\x07picture\x18\x02 \x01(\t\x12i\n\x1a\x64\x65precated_render_features\x18\x03 \x01(\x0e\x32\x30.spotify_playlist_annotate3.proto.RenderFeatures:\x0fNORMAL_FEATURESB\x02\x18\x01\x12O\n\x12transcoded_picture\x18\x04 \x03(\x0b\x32\x33.spotify_playlist_annotate3.proto.TranscodedPicture\x12(\n\x1ais_abuse_reporting_enabled\x18\x06 \x01(\x08:\x04true\x12R\n\x12\x61\x62use_report_state\x18\x07 \x01(\x0e\x32\x32.spotify_playlist_annotate3.proto.AbuseReportState:\x02OK*<\n\x0eRenderFeatures\x12\x13\n\x0fNORMAL_FEATURES\x10\x01\x12\x15\n\x11\x45XTENDED_FEATURES\x10\x02**\n\x10\x41\x62useReportState\x12\x06\n\x02OK\x10\x00\x12\x0e\n\nTAKEN_DOWN\x10\x01\x42"\n\x1e\x63om.spotify.playlist_annotate3H\x02',
|
||||
)
|
||||
|
||||
_RENDERFEATURES = _descriptor.EnumDescriptor(
|
||||
name="RenderFeatures",
|
||||
full_name="spotify_playlist_annotate3.proto.RenderFeatures",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="NORMAL_FEATURES",
|
||||
index=0,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="EXTENDED_FEATURES",
|
||||
index=1,
|
||||
number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=650,
|
||||
serialized_end=710,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_RENDERFEATURES)
|
||||
|
||||
RenderFeatures = enum_type_wrapper.EnumTypeWrapper(_RENDERFEATURES)
|
||||
_ABUSEREPORTSTATE = _descriptor.EnumDescriptor(
|
||||
name="AbuseReportState",
|
||||
full_name="spotify_playlist_annotate3.proto.AbuseReportState",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="OK",
|
||||
index=0,
|
||||
number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="TAKEN_DOWN",
|
||||
index=1,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=712,
|
||||
serialized_end=754,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_ABUSEREPORTSTATE)
|
||||
|
||||
AbuseReportState = enum_type_wrapper.EnumTypeWrapper(_ABUSEREPORTSTATE)
|
||||
NORMAL_FEATURES = 1
|
||||
EXTENDED_FEATURES = 2
|
||||
OK = 0
|
||||
TAKEN_DOWN = 1
|
||||
|
||||
_TAKEDOWNREQUEST = _descriptor.Descriptor(
|
||||
name="TakedownRequest",
|
||||
full_name="spotify_playlist_annotate3.proto.TakedownRequest",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="abuse_report_state",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.TakedownRequest.abuse_report_state",
|
||||
index=0,
|
||||
number=1,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=62,
|
||||
serialized_end=159,
|
||||
)
|
||||
|
||||
_ANNOTATEREQUEST = _descriptor.Descriptor(
|
||||
name="AnnotateRequest",
|
||||
full_name="spotify_playlist_annotate3.proto.AnnotateRequest",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="description",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.AnnotateRequest.description",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="image_uri",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.AnnotateRequest.image_uri",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=161,
|
||||
serialized_end=218,
|
||||
)
|
||||
|
||||
_TRANSCODEDPICTURE = _descriptor.Descriptor(
|
||||
name="TranscodedPicture",
|
||||
full_name="spotify_playlist_annotate3.proto.TranscodedPicture",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="target_name",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.TranscodedPicture.target_name",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="uri",
|
||||
full_name="spotify_playlist_annotate3.proto.TranscodedPicture.uri",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=220,
|
||||
serialized_end=273,
|
||||
)
|
||||
|
||||
_PLAYLISTANNOTATION = _descriptor.Descriptor(
|
||||
name="PlaylistAnnotation",
|
||||
full_name="spotify_playlist_annotate3.proto.PlaylistAnnotation",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="description",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.PlaylistAnnotation.description",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="picture",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.PlaylistAnnotation.picture",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="deprecated_render_features",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.PlaylistAnnotation.deprecated_render_features",
|
||||
index=2,
|
||||
number=3,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=True,
|
||||
default_value=1,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=b"\030\001",
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="transcoded_picture",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.PlaylistAnnotation.transcoded_picture",
|
||||
index=3,
|
||||
number=4,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="is_abuse_reporting_enabled",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.PlaylistAnnotation.is_abuse_reporting_enabled",
|
||||
index=4,
|
||||
number=6,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=True,
|
||||
default_value=True,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="abuse_report_state",
|
||||
full_name=
|
||||
"spotify_playlist_annotate3.proto.PlaylistAnnotation.abuse_report_state",
|
||||
index=5,
|
||||
number=7,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=True,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=276,
|
||||
serialized_end=648,
|
||||
)
|
||||
|
||||
_TAKEDOWNREQUEST.fields_by_name[
|
||||
"abuse_report_state"].enum_type = _ABUSEREPORTSTATE
|
||||
_PLAYLISTANNOTATION.fields_by_name[
|
||||
"deprecated_render_features"].enum_type = _RENDERFEATURES
|
||||
_PLAYLISTANNOTATION.fields_by_name[
|
||||
"transcoded_picture"].message_type = _TRANSCODEDPICTURE
|
||||
_PLAYLISTANNOTATION.fields_by_name[
|
||||
"abuse_report_state"].enum_type = _ABUSEREPORTSTATE
|
||||
DESCRIPTOR.message_types_by_name["TakedownRequest"] = _TAKEDOWNREQUEST
|
||||
DESCRIPTOR.message_types_by_name["AnnotateRequest"] = _ANNOTATEREQUEST
|
||||
DESCRIPTOR.message_types_by_name["TranscodedPicture"] = _TRANSCODEDPICTURE
|
||||
DESCRIPTOR.message_types_by_name["PlaylistAnnotation"] = _PLAYLISTANNOTATION
|
||||
DESCRIPTOR.enum_types_by_name["RenderFeatures"] = _RENDERFEATURES
|
||||
DESCRIPTOR.enum_types_by_name["AbuseReportState"] = _ABUSEREPORTSTATE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
TakedownRequest = _reflection.GeneratedProtocolMessageType(
|
||||
"TakedownRequest",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _TAKEDOWNREQUEST,
|
||||
"__module__": "playlist_annotate3_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify_playlist_annotate3.proto.TakedownRequest)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(TakedownRequest)
|
||||
|
||||
AnnotateRequest = _reflection.GeneratedProtocolMessageType(
|
||||
"AnnotateRequest",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _ANNOTATEREQUEST,
|
||||
"__module__": "playlist_annotate3_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify_playlist_annotate3.proto.AnnotateRequest)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(AnnotateRequest)
|
||||
|
||||
TranscodedPicture = _reflection.GeneratedProtocolMessageType(
|
||||
"TranscodedPicture",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _TRANSCODEDPICTURE,
|
||||
"__module__": "playlist_annotate3_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify_playlist_annotate3.proto.TranscodedPicture)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(TranscodedPicture)
|
||||
|
||||
PlaylistAnnotation = _reflection.GeneratedProtocolMessageType(
|
||||
"PlaylistAnnotation",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _PLAYLISTANNOTATION,
|
||||
"__module__": "playlist_annotate3_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify_playlist_annotate3.proto.PlaylistAnnotation)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(PlaylistAnnotation)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
_PLAYLISTANNOTATION.fields_by_name[
|
||||
"deprecated_render_features"]._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
112
resources/lib/librespot/proto/Pubsub_pb2.py
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: pubsub.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='pubsub.proto',
|
||||
package='spotify',
|
||||
syntax='proto2',
|
||||
serialized_options=b'\n\013com.spotify',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x0cpubsub.proto\x12\x07spotify\"@\n\x0cSubscription\x12\x0b\n\x03uri\x18\x01 \x01(\t\x12\x0e\n\x06\x65xpiry\x18\x02 \x01(\x05\x12\x13\n\x0bstatus_code\x18\x03 \x01(\x05\x42\r\n\x0b\x63om.spotify'
|
||||
)
|
||||
|
||||
_SUBSCRIPTION = _descriptor.Descriptor(
|
||||
name='Subscription',
|
||||
full_name='spotify.Subscription',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='uri',
|
||||
full_name='spotify.Subscription.uri',
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode('utf-8'),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='expiry',
|
||||
full_name='spotify.Subscription.expiry',
|
||||
index=1,
|
||||
number=2,
|
||||
type=5,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='status_code',
|
||||
full_name='spotify.Subscription.status_code',
|
||||
index=2,
|
||||
number=3,
|
||||
type=5,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto2',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=25,
|
||||
serialized_end=89,
|
||||
)
|
||||
|
||||
DESCRIPTOR.message_types_by_name['Subscription'] = _SUBSCRIPTION
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Subscription = _reflection.GeneratedProtocolMessageType(
|
||||
'Subscription',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _SUBSCRIPTION,
|
||||
'__module__': 'pubsub_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.Subscription)
|
||||
})
|
||||
_sym_db.RegisterMessage(Subscription)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
104
resources/lib/librespot/proto/Queue_pb2.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: queue.proto
|
||||
"""Generated protocol buffer code."""
|
||||
import ContextTrack_pb2 as context__track__pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="queue.proto",
|
||||
package="spotify.player.proto.transfer",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\024com.spotify.transferH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x0bqueue.proto\x12\x1dspotify.player.proto.transfer\x1a\x13\x63ontext_track.proto"U\n\x05Queue\x12\x32\n\x06tracks\x18\x01 \x03(\x0b\x32".spotify.player.proto.ContextTrack\x12\x18\n\x10is_playing_queue\x18\x02 \x01(\x08\x42\x18\n\x14\x63om.spotify.transferH\x02',
|
||||
dependencies=[
|
||||
context__track__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_QUEUE = _descriptor.Descriptor(
|
||||
name="Queue",
|
||||
full_name="spotify.player.proto.transfer.Queue",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="tracks",
|
||||
full_name="spotify.player.proto.transfer.Queue.tracks",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="is_playing_queue",
|
||||
full_name="spotify.player.proto.transfer.Queue.is_playing_queue",
|
||||
index=1,
|
||||
number=2,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=67,
|
||||
serialized_end=152,
|
||||
)
|
||||
|
||||
_QUEUE.fields_by_name[
|
||||
"tracks"].message_type = context__track__pb2._CONTEXTTRACK
|
||||
DESCRIPTOR.message_types_by_name["Queue"] = _QUEUE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Queue = _reflection.GeneratedProtocolMessageType(
|
||||
"Queue",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _QUEUE,
|
||||
"__module__": "queue_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.transfer.Queue)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Queue)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
480
resources/lib/librespot/proto/Restrictions_pb2.py
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: restrictions.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="restrictions.proto",
|
||||
package="spotify.player.proto",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\023com.spotify.contextH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x12restrictions.proto\x12\x14spotify.player.proto"\xbb\x07\n\x0cRestrictions\x12 \n\x18\x64isallow_pausing_reasons\x18\x01 \x03(\t\x12!\n\x19\x64isallow_resuming_reasons\x18\x02 \x03(\t\x12 \n\x18\x64isallow_seeking_reasons\x18\x03 \x03(\t\x12%\n\x1d\x64isallow_peeking_prev_reasons\x18\x04 \x03(\t\x12%\n\x1d\x64isallow_peeking_next_reasons\x18\x05 \x03(\t\x12&\n\x1e\x64isallow_skipping_prev_reasons\x18\x06 \x03(\t\x12&\n\x1e\x64isallow_skipping_next_reasons\x18\x07 \x03(\t\x12\x30\n(disallow_toggling_repeat_context_reasons\x18\x08 \x03(\t\x12.\n&disallow_toggling_repeat_track_reasons\x18\t \x03(\t\x12)\n!disallow_toggling_shuffle_reasons\x18\n \x03(\t\x12"\n\x1a\x64isallow_set_queue_reasons\x18\x0b \x03(\t\x12.\n&disallow_interrupting_playback_reasons\x18\x0c \x03(\t\x12.\n&disallow_transferring_playback_reasons\x18\r \x03(\t\x12\'\n\x1f\x64isallow_remote_control_reasons\x18\x0e \x03(\t\x12\x33\n+disallow_inserting_into_next_tracks_reasons\x18\x0f \x03(\t\x12\x36\n.disallow_inserting_into_context_tracks_reasons\x18\x10 \x03(\t\x12\x32\n*disallow_reordering_in_next_tracks_reasons\x18\x11 \x03(\t\x12\x35\n-disallow_reordering_in_context_tracks_reasons\x18\x12 \x03(\t\x12\x32\n*disallow_removing_from_next_tracks_reasons\x18\x13 \x03(\t\x12\x35\n-disallow_removing_from_context_tracks_reasons\x18\x14 \x03(\t\x12)\n!disallow_updating_context_reasons\x18\x15 \x03(\tB\x17\n\x13\x63om.spotify.contextH\x02',
|
||||
)
|
||||
|
||||
_RESTRICTIONS = _descriptor.Descriptor(
|
||||
name="Restrictions",
|
||||
full_name="spotify.player.proto.Restrictions",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_pausing_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_pausing_reasons",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_resuming_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_resuming_reasons",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_seeking_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_seeking_reasons",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_peeking_prev_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_peeking_prev_reasons",
|
||||
index=3,
|
||||
number=4,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_peeking_next_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_peeking_next_reasons",
|
||||
index=4,
|
||||
number=5,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_skipping_prev_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_skipping_prev_reasons",
|
||||
index=5,
|
||||
number=6,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_skipping_next_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_skipping_next_reasons",
|
||||
index=6,
|
||||
number=7,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_toggling_repeat_context_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_toggling_repeat_context_reasons",
|
||||
index=7,
|
||||
number=8,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_toggling_repeat_track_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_toggling_repeat_track_reasons",
|
||||
index=8,
|
||||
number=9,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_toggling_shuffle_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_toggling_shuffle_reasons",
|
||||
index=9,
|
||||
number=10,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_set_queue_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_set_queue_reasons",
|
||||
index=10,
|
||||
number=11,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_interrupting_playback_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_interrupting_playback_reasons",
|
||||
index=11,
|
||||
number=12,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_transferring_playback_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_transferring_playback_reasons",
|
||||
index=12,
|
||||
number=13,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_remote_control_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_remote_control_reasons",
|
||||
index=13,
|
||||
number=14,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_inserting_into_next_tracks_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_inserting_into_next_tracks_reasons",
|
||||
index=14,
|
||||
number=15,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_inserting_into_context_tracks_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_inserting_into_context_tracks_reasons",
|
||||
index=15,
|
||||
number=16,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_reordering_in_next_tracks_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_reordering_in_next_tracks_reasons",
|
||||
index=16,
|
||||
number=17,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_reordering_in_context_tracks_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_reordering_in_context_tracks_reasons",
|
||||
index=17,
|
||||
number=18,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_removing_from_next_tracks_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_removing_from_next_tracks_reasons",
|
||||
index=18,
|
||||
number=19,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_removing_from_context_tracks_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_removing_from_context_tracks_reasons",
|
||||
index=19,
|
||||
number=20,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="disallow_updating_context_reasons",
|
||||
full_name=
|
||||
"spotify.player.proto.Restrictions.disallow_updating_context_reasons",
|
||||
index=20,
|
||||
number=21,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=45,
|
||||
serialized_end=1000,
|
||||
)
|
||||
|
||||
DESCRIPTOR.message_types_by_name["Restrictions"] = _RESTRICTIONS
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Restrictions = _reflection.GeneratedProtocolMessageType(
|
||||
"Restrictions",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _RESTRICTIONS,
|
||||
"__module__": "restrictions_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.Restrictions)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Restrictions)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
149
resources/lib/librespot/proto/Session_pb2.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: session.proto
|
||||
"""Generated protocol buffer code."""
|
||||
import Context_pb2 as context__pb2
|
||||
import ContextPlayerOptions_pb2 as context__player__options__pb2
|
||||
import PlayOrigin_pb2 as play__origin__pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="session.proto",
|
||||
package="spotify.player.proto.transfer",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\024com.spotify.transferH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\rsession.proto\x12\x1dspotify.player.proto.transfer\x1a\rcontext.proto\x1a\x1c\x63ontext_player_options.proto\x1a\x11play_origin.proto"\xd3\x01\n\x07Session\x12\x35\n\x0bplay_origin\x18\x01 \x01(\x0b\x32 .spotify.player.proto.PlayOrigin\x12.\n\x07\x63ontext\x18\x02 \x01(\x0b\x32\x1d.spotify.player.proto.Context\x12\x13\n\x0b\x63urrent_uid\x18\x03 \x01(\t\x12L\n\x10option_overrides\x18\x04 \x01(\x0b\x32\x32.spotify.player.proto.ContextPlayerOptionOverridesB\x18\n\x14\x63om.spotify.transferH\x02',
|
||||
dependencies=[
|
||||
context__pb2.DESCRIPTOR,
|
||||
context__player__options__pb2.DESCRIPTOR,
|
||||
play__origin__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_SESSION = _descriptor.Descriptor(
|
||||
name="Session",
|
||||
full_name="spotify.player.proto.transfer.Session",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="play_origin",
|
||||
full_name="spotify.player.proto.transfer.Session.play_origin",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="context",
|
||||
full_name="spotify.player.proto.transfer.Session.context",
|
||||
index=1,
|
||||
number=2,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="current_uid",
|
||||
full_name="spotify.player.proto.transfer.Session.current_uid",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="option_overrides",
|
||||
full_name="spotify.player.proto.transfer.Session.option_overrides",
|
||||
index=3,
|
||||
number=4,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=113,
|
||||
serialized_end=324,
|
||||
)
|
||||
|
||||
_SESSION.fields_by_name[
|
||||
"play_origin"].message_type = play__origin__pb2._PLAYORIGIN
|
||||
_SESSION.fields_by_name["context"].message_type = context__pb2._CONTEXT
|
||||
_SESSION.fields_by_name[
|
||||
"option_overrides"].message_type = context__player__options__pb2._CONTEXTPLAYEROPTIONOVERRIDES
|
||||
DESCRIPTOR.message_types_by_name["Session"] = _SESSION
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Session = _reflection.GeneratedProtocolMessageType(
|
||||
"Session",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _SESSION,
|
||||
"__module__": "session_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.transfer.Session)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Session)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
154
resources/lib/librespot/proto/StorageResolve_pb2.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: storage-resolve.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='storage-resolve.proto',
|
||||
package='spotify.download.proto',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.spotify.storageH\002',
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x15storage-resolve.proto\x12\x16spotify.download.proto\"\xaf\x01\n\x16StorageResolveResponse\x12\x45\n\x06result\x18\x01 \x01(\x0e\x32\x35.spotify.download.proto.StorageResolveResponse.Result\x12\x0e\n\x06\x63\x64nurl\x18\x02 \x03(\t\x12\x0e\n\x06\x66ileid\x18\x04 \x01(\x0c\".\n\x06Result\x12\x07\n\x03\x43\x44N\x10\x00\x12\x0b\n\x07STORAGE\x10\x01\x12\x0e\n\nRESTRICTED\x10\x03\x42\x17\n\x13\x63om.spotify.storageH\x02\x62\x06proto3'
|
||||
)
|
||||
|
||||
_STORAGERESOLVERESPONSE_RESULT = _descriptor.EnumDescriptor(
|
||||
name='Result',
|
||||
full_name='spotify.download.proto.StorageResolveResponse.Result',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CDN',
|
||||
index=0,
|
||||
number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='STORAGE',
|
||||
index=1,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='RESTRICTED',
|
||||
index=2,
|
||||
number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=179,
|
||||
serialized_end=225,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_STORAGERESOLVERESPONSE_RESULT)
|
||||
|
||||
_STORAGERESOLVERESPONSE = _descriptor.Descriptor(
|
||||
name='StorageResolveResponse',
|
||||
full_name='spotify.download.proto.StorageResolveResponse',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='result',
|
||||
full_name='spotify.download.proto.StorageResolveResponse.result',
|
||||
index=0,
|
||||
number=1,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='cdnurl',
|
||||
full_name='spotify.download.proto.StorageResolveResponse.cdnurl',
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='fileid',
|
||||
full_name='spotify.download.proto.StorageResolveResponse.fileid',
|
||||
index=2,
|
||||
number=4,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_STORAGERESOLVERESPONSE_RESULT,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=50,
|
||||
serialized_end=225,
|
||||
)
|
||||
|
||||
_STORAGERESOLVERESPONSE.fields_by_name[
|
||||
'result'].enum_type = _STORAGERESOLVERESPONSE_RESULT
|
||||
_STORAGERESOLVERESPONSE_RESULT.containing_type = _STORAGERESOLVERESPONSE
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
'StorageResolveResponse'] = _STORAGERESOLVERESPONSE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
StorageResolveResponse = _reflection.GeneratedProtocolMessageType(
|
||||
'StorageResolveResponse',
|
||||
(_message.Message, ),
|
||||
{
|
||||
'DESCRIPTOR': _STORAGERESOLVERESPONSE,
|
||||
'__module__': 'storage_resolve_pb2'
|
||||
# @@protoc_insertion_point(class_scope:spotify.download.proto.StorageResolveResponse)
|
||||
})
|
||||
_sym_db.RegisterMessage(StorageResolveResponse)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
174
resources/lib/librespot/proto/TransferState_pb2.py
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: transfer_state.proto
|
||||
"""Generated protocol buffer code."""
|
||||
import ContextPlayerOptions_pb2 as context__player__options__pb2
|
||||
import Playback_pb2 as playback__pb2
|
||||
import Queue_pb2 as queue__pb2
|
||||
import Session_pb2 as session__pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="transfer_state.proto",
|
||||
package="spotify.player.proto.transfer",
|
||||
syntax="proto2",
|
||||
serialized_options=b"\n\024com.spotify.transferH\002",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b"\n\x14transfer_state.proto\x12\x1dspotify.player.proto.transfer\x1a\x1c\x63ontext_player_options.proto\x1a\x0eplayback.proto\x1a\rsession.proto\x1a\x0bqueue.proto\"\x99\x02\n\rTransferState\x12;\n\x07options\x18\x01 \x01(\x0b\x32*.spotify.player.proto.ContextPlayerOptions\x12\x39\n\x08playback\x18\x02 \x01(\x0b\x32'.spotify.player.proto.transfer.Playback\x12?\n\x0f\x63urrent_session\x18\x03 \x01(\x0b\x32&.spotify.player.proto.transfer.Session\x12\x33\n\x05queue\x18\x04 \x01(\x0b\x32$.spotify.player.proto.transfer.Queue\x12\x1a\n\x12\x63reation_timestamp\x18\x05 \x01(\x03\x42\x18\n\x14\x63om.spotify.transferH\x02",
|
||||
dependencies=[
|
||||
context__player__options__pb2.DESCRIPTOR,
|
||||
playback__pb2.DESCRIPTOR,
|
||||
session__pb2.DESCRIPTOR,
|
||||
queue__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_TRANSFERSTATE = _descriptor.Descriptor(
|
||||
name="TransferState",
|
||||
full_name="spotify.player.proto.transfer.TransferState",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="options",
|
||||
full_name="spotify.player.proto.transfer.TransferState.options",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="playback",
|
||||
full_name="spotify.player.proto.transfer.TransferState.playback",
|
||||
index=1,
|
||||
number=2,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="current_session",
|
||||
full_name=
|
||||
"spotify.player.proto.transfer.TransferState.current_session",
|
||||
index=2,
|
||||
number=3,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="queue",
|
||||
full_name="spotify.player.proto.transfer.TransferState.queue",
|
||||
index=3,
|
||||
number=4,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="creation_timestamp",
|
||||
full_name=
|
||||
"spotify.player.proto.transfer.TransferState.creation_timestamp",
|
||||
index=4,
|
||||
number=5,
|
||||
type=3,
|
||||
cpp_type=2,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto2",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=130,
|
||||
serialized_end=411,
|
||||
)
|
||||
|
||||
_TRANSFERSTATE.fields_by_name[
|
||||
"options"].message_type = context__player__options__pb2._CONTEXTPLAYEROPTIONS
|
||||
_TRANSFERSTATE.fields_by_name[
|
||||
"playback"].message_type = playback__pb2._PLAYBACK
|
||||
_TRANSFERSTATE.fields_by_name[
|
||||
"current_session"].message_type = session__pb2._SESSION
|
||||
_TRANSFERSTATE.fields_by_name["queue"].message_type = queue__pb2._QUEUE
|
||||
DESCRIPTOR.message_types_by_name["TransferState"] = _TRANSFERSTATE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
TransferState = _reflection.GeneratedProtocolMessageType(
|
||||
"TransferState",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _TRANSFERSTATE,
|
||||
"__module__": "transfer_state_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.player.proto.transfer.TransferState)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(TransferState)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
0
resources/lib/librespot/proto/__init__.py
Normal file
0
resources/lib/librespot/proto/spotify/__init__.py
Normal file
0
resources/lib/librespot/proto/spotify/login5/__init__.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: spotify/login5/v3/client_info.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="spotify/login5/v3/client_info.proto",
|
||||
package="spotify.login5.v3",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\024com.spotify.login5v3",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n#spotify/login5/v3/client_info.proto\x12\x11spotify.login5.v3"2\n\nClientInfo\x12\x11\n\tclient_id\x18\x01 \x01(\t\x12\x11\n\tdevice_id\x18\x02 \x01(\tB\x16\n\x14\x63om.spotify.login5v3b\x06proto3',
|
||||
)
|
||||
|
||||
_CLIENTINFO = _descriptor.Descriptor(
|
||||
name="ClientInfo",
|
||||
full_name="spotify.login5.v3.ClientInfo",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="client_id",
|
||||
full_name="spotify.login5.v3.ClientInfo.client_id",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="device_id",
|
||||
full_name="spotify.login5.v3.ClientInfo.device_id",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=58,
|
||||
serialized_end=108,
|
||||
)
|
||||
|
||||
DESCRIPTOR.message_types_by_name["ClientInfo"] = _CLIENTINFO
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
ClientInfo = _reflection.GeneratedProtocolMessageType(
|
||||
"ClientInfo",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CLIENTINFO,
|
||||
"__module__": "spotify.login5.v3.client_info_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.ClientInfo)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ClientInfo)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
972
resources/lib/librespot/proto/spotify/login5/v3/Login5_pb2.py
Normal file
|
|
@ -0,0 +1,972 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: spotify/login5/v3/login5.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from spotify.login5.v3 import \
|
||||
client_info_pb2 as spotify_dot_login5_dot_v3_dot_client__info__pb2
|
||||
from spotify.login5.v3 import \
|
||||
user_info_pb2 as spotify_dot_login5_dot_v3_dot_user__info__pb2
|
||||
from spotify.login5.v3.challenges import \
|
||||
code_pb2 as spotify_dot_login5_dot_v3_dot_challenges_dot_code__pb2
|
||||
from spotify.login5.v3.challenges import \
|
||||
hashcash_pb2 as spotify_dot_login5_dot_v3_dot_challenges_dot_hashcash__pb2
|
||||
from spotify.login5.v3.credentials import \
|
||||
credentials_pb2 as \
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2
|
||||
from spotify.login5.v3.identifiers import \
|
||||
identifiers_pb2 as \
|
||||
spotify_dot_login5_dot_v3_dot_identifiers_dot_identifiers__pb2
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="spotify/login5/v3/login5.proto",
|
||||
package="spotify.login5.v3",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\024com.spotify.login5v3",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\x1espotify/login5/v3/login5.proto\x12\x11spotify.login5.v3\x1a#spotify/login5/v3/client_info.proto\x1a!spotify/login5/v3/user_info.proto\x1a\'spotify/login5/v3/challenges/code.proto\x1a+spotify/login5/v3/challenges/hashcash.proto\x1a/spotify/login5/v3/credentials/credentials.proto\x1a/spotify/login5/v3/identifiers/identifiers.proto">\n\nChallenges\x12\x30\n\nchallenges\x18\x01 \x03(\x0b\x32\x1c.spotify.login5.v3.Challenge"\x89\x01\n\tChallenge\x12\x41\n\x08hashcash\x18\x01 \x01(\x0b\x32/.spotify.login5.v3.challenges.HashcashChallenge\x12\x39\n\x04\x63ode\x18\x02 \x01(\x0b\x32+.spotify.login5.v3.challenges.CodeChallenge"M\n\x12\x43hallengeSolutions\x12\x37\n\tsolutions\x18\x01 \x03(\x0b\x32$.spotify.login5.v3.ChallengeSolution"\x8f\x01\n\x11\x43hallengeSolution\x12@\n\x08hashcash\x18\x01 \x01(\x0b\x32..spotify.login5.v3.challenges.HashcashSolution\x12\x38\n\x04\x63ode\x18\x02 \x01(\x0b\x32*.spotify.login5.v3.challenges.CodeSolution"\xad\x05\n\x0cLoginRequest\x12\x32\n\x0b\x63lient_info\x18\x01 \x01(\x0b\x32\x1d.spotify.login5.v3.ClientInfo\x12\x15\n\rlogin_context\x18\x02 \x01(\x0c\x12\x42\n\x13\x63hallenge_solutions\x18\x03 \x01(\x0b\x32%.spotify.login5.v3.ChallengeSolutions\x12J\n\x11stored_credential\x18\x64 \x01(\x0b\x32/.spotify.login5.v3.credentials.StoredCredential\x12\x39\n\x08password\x18\x65 \x01(\x0b\x32\'.spotify.login5.v3.credentials.Password\x12Q\n\x15\x66\x61\x63\x65\x62ook_access_token\x18\x66 \x01(\x0b\x32\x32.spotify.login5.v3.credentials.FacebookAccessToken\x12@\n\x0cphone_number\x18g \x01(\x0b\x32*.spotify.login5.v3.identifiers.PhoneNumber\x12\x43\n\x0eone_time_token\x18h \x01(\x0b\x32+.spotify.login5.v3.credentials.OneTimeToken\x12U\n\x17parent_child_credential\x18i \x01(\x0b\x32\x34.spotify.login5.v3.credentials.ParentChildCredential\x12V\n\x18\x61pple_sign_in_credential\x18j \x01(\x0b\x32\x34.spotify.login5.v3.credentials.AppleSignInCredential"m\n\x07LoginOk\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x02 \x01(\t\x12\x19\n\x11stored_credential\x18\x03 \x01(\x0c\x12\x1f\n\x17\x61\x63\x63\x65ss_token_expires_in\x18\x04 \x01(\x05"\xf8\x02\n\rLoginResponse\x12&\n\x02ok\x18\x01 \x01(\x0b\x32\x1a.spotify.login5.v3.LoginOk\x12,\n\x05\x65rror\x18\x02 \x01(\x0e\x32\x1d.spotify.login5.v3.LoginError\x12\x31\n\nchallenges\x18\x03 \x01(\x0b\x32\x1d.spotify.login5.v3.Challenges\x12;\n\x08warnings\x18\x04 \x03(\x0e\x32).spotify.login5.v3.LoginResponse.Warnings\x12\x15\n\rlogin_context\x18\x05 \x01(\x0c\x12\x18\n\x10identifier_token\x18\x06 \x01(\t\x12.\n\tuser_info\x18\x07 \x01(\x0b\x32\x1b.spotify.login5.v3.UserInfo"@\n\x08Warnings\x12\x13\n\x0fUNKNOWN_WARNING\x10\x00\x12\x1f\n\x1b\x44\x45PRECATED_PROTOCOL_VERSION\x10\x01*\xd3\x01\n\nLoginError\x12\x11\n\rUNKNOWN_ERROR\x10\x00\x12\x17\n\x13INVALID_CREDENTIALS\x10\x01\x12\x0f\n\x0b\x42\x41\x44_REQUEST\x10\x02\x12\x1e\n\x1aUNSUPPORTED_LOGIN_PROTOCOL\x10\x03\x12\x0b\n\x07TIMEOUT\x10\x04\x12\x16\n\x12UNKNOWN_IDENTIFIER\x10\x05\x12\x15\n\x11TOO_MANY_ATTEMPTS\x10\x06\x12\x17\n\x13INVALID_PHONENUMBER\x10\x07\x12\x13\n\x0fTRY_AGAIN_LATER\x10\x08\x42\x16\n\x14\x63om.spotify.login5v3b\x06proto3',
|
||||
dependencies=[
|
||||
spotify_dot_login5_dot_v3_dot_client__info__pb2.DESCRIPTOR,
|
||||
spotify_dot_login5_dot_v3_dot_user__info__pb2.DESCRIPTOR,
|
||||
spotify_dot_login5_dot_v3_dot_challenges_dot_code__pb2.DESCRIPTOR,
|
||||
spotify_dot_login5_dot_v3_dot_challenges_dot_hashcash__pb2.DESCRIPTOR,
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2.
|
||||
DESCRIPTOR,
|
||||
spotify_dot_login5_dot_v3_dot_identifiers_dot_identifiers__pb2.
|
||||
DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_LOGINERROR = _descriptor.EnumDescriptor(
|
||||
name="LoginError",
|
||||
full_name="spotify.login5.v3.LoginError",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="UNKNOWN_ERROR",
|
||||
index=0,
|
||||
number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="INVALID_CREDENTIALS",
|
||||
index=1,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="BAD_REQUEST",
|
||||
index=2,
|
||||
number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="UNSUPPORTED_LOGIN_PROTOCOL",
|
||||
index=3,
|
||||
number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="TIMEOUT",
|
||||
index=4,
|
||||
number=4,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="UNKNOWN_IDENTIFIER",
|
||||
index=5,
|
||||
number=5,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="TOO_MANY_ATTEMPTS",
|
||||
index=6,
|
||||
number=6,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="INVALID_PHONENUMBER",
|
||||
index=7,
|
||||
number=7,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="TRY_AGAIN_LATER",
|
||||
index=8,
|
||||
number=8,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1917,
|
||||
serialized_end=2128,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_LOGINERROR)
|
||||
|
||||
LoginError = enum_type_wrapper.EnumTypeWrapper(_LOGINERROR)
|
||||
UNKNOWN_ERROR = 0
|
||||
INVALID_CREDENTIALS = 1
|
||||
BAD_REQUEST = 2
|
||||
UNSUPPORTED_LOGIN_PROTOCOL = 3
|
||||
TIMEOUT = 4
|
||||
UNKNOWN_IDENTIFIER = 5
|
||||
TOO_MANY_ATTEMPTS = 6
|
||||
INVALID_PHONENUMBER = 7
|
||||
TRY_AGAIN_LATER = 8
|
||||
|
||||
_LOGINRESPONSE_WARNINGS = _descriptor.EnumDescriptor(
|
||||
name="Warnings",
|
||||
full_name="spotify.login5.v3.LoginResponse.Warnings",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="UNKNOWN_WARNING",
|
||||
index=0,
|
||||
number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="DEPRECATED_PROTOCOL_VERSION",
|
||||
index=1,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=1850,
|
||||
serialized_end=1914,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_LOGINRESPONSE_WARNINGS)
|
||||
|
||||
_CHALLENGES = _descriptor.Descriptor(
|
||||
name="Challenges",
|
||||
full_name="spotify.login5.v3.Challenges",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="challenges",
|
||||
full_name="spotify.login5.v3.Challenges.challenges",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=309,
|
||||
serialized_end=371,
|
||||
)
|
||||
|
||||
_CHALLENGE = _descriptor.Descriptor(
|
||||
name="Challenge",
|
||||
full_name="spotify.login5.v3.Challenge",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="hashcash",
|
||||
full_name="spotify.login5.v3.Challenge.hashcash",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="code",
|
||||
full_name="spotify.login5.v3.Challenge.code",
|
||||
index=1,
|
||||
number=2,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=374,
|
||||
serialized_end=511,
|
||||
)
|
||||
|
||||
_CHALLENGESOLUTIONS = _descriptor.Descriptor(
|
||||
name="ChallengeSolutions",
|
||||
full_name="spotify.login5.v3.ChallengeSolutions",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="solutions",
|
||||
full_name="spotify.login5.v3.ChallengeSolutions.solutions",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=513,
|
||||
serialized_end=590,
|
||||
)
|
||||
|
||||
_CHALLENGESOLUTION = _descriptor.Descriptor(
|
||||
name="ChallengeSolution",
|
||||
full_name="spotify.login5.v3.ChallengeSolution",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="hashcash",
|
||||
full_name="spotify.login5.v3.ChallengeSolution.hashcash",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="code",
|
||||
full_name="spotify.login5.v3.ChallengeSolution.code",
|
||||
index=1,
|
||||
number=2,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=593,
|
||||
serialized_end=736,
|
||||
)
|
||||
|
||||
_LOGINREQUEST = _descriptor.Descriptor(
|
||||
name="LoginRequest",
|
||||
full_name="spotify.login5.v3.LoginRequest",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="client_info",
|
||||
full_name="spotify.login5.v3.LoginRequest.client_info",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="login_context",
|
||||
full_name="spotify.login5.v3.LoginRequest.login_context",
|
||||
index=1,
|
||||
number=2,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="challenge_solutions",
|
||||
full_name="spotify.login5.v3.LoginRequest.challenge_solutions",
|
||||
index=2,
|
||||
number=3,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="stored_credential",
|
||||
full_name="spotify.login5.v3.LoginRequest.stored_credential",
|
||||
index=3,
|
||||
number=100,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="password",
|
||||
full_name="spotify.login5.v3.LoginRequest.password",
|
||||
index=4,
|
||||
number=101,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="facebook_access_token",
|
||||
full_name="spotify.login5.v3.LoginRequest.facebook_access_token",
|
||||
index=5,
|
||||
number=102,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="phone_number",
|
||||
full_name="spotify.login5.v3.LoginRequest.phone_number",
|
||||
index=6,
|
||||
number=103,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="one_time_token",
|
||||
full_name="spotify.login5.v3.LoginRequest.one_time_token",
|
||||
index=7,
|
||||
number=104,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="parent_child_credential",
|
||||
full_name="spotify.login5.v3.LoginRequest.parent_child_credential",
|
||||
index=8,
|
||||
number=105,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="apple_sign_in_credential",
|
||||
full_name="spotify.login5.v3.LoginRequest.apple_sign_in_credential",
|
||||
index=9,
|
||||
number=106,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=739,
|
||||
serialized_end=1424,
|
||||
)
|
||||
|
||||
_LOGINOK = _descriptor.Descriptor(
|
||||
name="LoginOk",
|
||||
full_name="spotify.login5.v3.LoginOk",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="username",
|
||||
full_name="spotify.login5.v3.LoginOk.username",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="access_token",
|
||||
full_name="spotify.login5.v3.LoginOk.access_token",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="stored_credential",
|
||||
full_name="spotify.login5.v3.LoginOk.stored_credential",
|
||||
index=2,
|
||||
number=3,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="access_token_expires_in",
|
||||
full_name="spotify.login5.v3.LoginOk.access_token_expires_in",
|
||||
index=3,
|
||||
number=4,
|
||||
type=5,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=1426,
|
||||
serialized_end=1535,
|
||||
)
|
||||
|
||||
_LOGINRESPONSE = _descriptor.Descriptor(
|
||||
name="LoginResponse",
|
||||
full_name="spotify.login5.v3.LoginResponse",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="ok",
|
||||
full_name="spotify.login5.v3.LoginResponse.ok",
|
||||
index=0,
|
||||
number=1,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="error",
|
||||
full_name="spotify.login5.v3.LoginResponse.error",
|
||||
index=1,
|
||||
number=2,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="challenges",
|
||||
full_name="spotify.login5.v3.LoginResponse.challenges",
|
||||
index=2,
|
||||
number=3,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="warnings",
|
||||
full_name="spotify.login5.v3.LoginResponse.warnings",
|
||||
index=3,
|
||||
number=4,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=3,
|
||||
has_default_value=False,
|
||||
default_value=[],
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="login_context",
|
||||
full_name="spotify.login5.v3.LoginResponse.login_context",
|
||||
index=4,
|
||||
number=5,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="identifier_token",
|
||||
full_name="spotify.login5.v3.LoginResponse.identifier_token",
|
||||
index=5,
|
||||
number=6,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="user_info",
|
||||
full_name="spotify.login5.v3.LoginResponse.user_info",
|
||||
index=6,
|
||||
number=7,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_LOGINRESPONSE_WARNINGS,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=1538,
|
||||
serialized_end=1914,
|
||||
)
|
||||
|
||||
_CHALLENGES.fields_by_name["challenges"].message_type = _CHALLENGE
|
||||
_CHALLENGE.fields_by_name["hashcash"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_challenges_dot_hashcash__pb2.
|
||||
_HASHCASHCHALLENGE)
|
||||
_CHALLENGE.fields_by_name[
|
||||
"code"].message_type = spotify_dot_login5_dot_v3_dot_challenges_dot_code__pb2._CODECHALLENGE
|
||||
_CHALLENGESOLUTIONS.fields_by_name[
|
||||
"solutions"].message_type = _CHALLENGESOLUTION
|
||||
_CHALLENGESOLUTION.fields_by_name["hashcash"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_challenges_dot_hashcash__pb2.
|
||||
_HASHCASHSOLUTION)
|
||||
_CHALLENGESOLUTION.fields_by_name[
|
||||
"code"].message_type = spotify_dot_login5_dot_v3_dot_challenges_dot_code__pb2._CODESOLUTION
|
||||
_LOGINREQUEST.fields_by_name[
|
||||
"client_info"].message_type = spotify_dot_login5_dot_v3_dot_client__info__pb2._CLIENTINFO
|
||||
_LOGINREQUEST.fields_by_name[
|
||||
"challenge_solutions"].message_type = _CHALLENGESOLUTIONS
|
||||
_LOGINREQUEST.fields_by_name["stored_credential"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2.
|
||||
_STOREDCREDENTIAL)
|
||||
_LOGINREQUEST.fields_by_name["password"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2._PASSWORD)
|
||||
_LOGINREQUEST.fields_by_name["facebook_access_token"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2.
|
||||
_FACEBOOKACCESSTOKEN)
|
||||
_LOGINREQUEST.fields_by_name["phone_number"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_identifiers_dot_identifiers__pb2._PHONENUMBER
|
||||
)
|
||||
_LOGINREQUEST.fields_by_name["one_time_token"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2.
|
||||
_ONETIMETOKEN)
|
||||
_LOGINREQUEST.fields_by_name["parent_child_credential"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2.
|
||||
_PARENTCHILDCREDENTIAL)
|
||||
_LOGINREQUEST.fields_by_name["apple_sign_in_credential"].message_type = (
|
||||
spotify_dot_login5_dot_v3_dot_credentials_dot_credentials__pb2.
|
||||
_APPLESIGNINCREDENTIAL)
|
||||
_LOGINRESPONSE.fields_by_name["ok"].message_type = _LOGINOK
|
||||
_LOGINRESPONSE.fields_by_name["error"].enum_type = _LOGINERROR
|
||||
_LOGINRESPONSE.fields_by_name["challenges"].message_type = _CHALLENGES
|
||||
_LOGINRESPONSE.fields_by_name["warnings"].enum_type = _LOGINRESPONSE_WARNINGS
|
||||
_LOGINRESPONSE.fields_by_name[
|
||||
"user_info"].message_type = spotify_dot_login5_dot_v3_dot_user__info__pb2._USERINFO
|
||||
_LOGINRESPONSE_WARNINGS.containing_type = _LOGINRESPONSE
|
||||
DESCRIPTOR.message_types_by_name["Challenges"] = _CHALLENGES
|
||||
DESCRIPTOR.message_types_by_name["Challenge"] = _CHALLENGE
|
||||
DESCRIPTOR.message_types_by_name["ChallengeSolutions"] = _CHALLENGESOLUTIONS
|
||||
DESCRIPTOR.message_types_by_name["ChallengeSolution"] = _CHALLENGESOLUTION
|
||||
DESCRIPTOR.message_types_by_name["LoginRequest"] = _LOGINREQUEST
|
||||
DESCRIPTOR.message_types_by_name["LoginOk"] = _LOGINOK
|
||||
DESCRIPTOR.message_types_by_name["LoginResponse"] = _LOGINRESPONSE
|
||||
DESCRIPTOR.enum_types_by_name["LoginError"] = _LOGINERROR
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
Challenges = _reflection.GeneratedProtocolMessageType(
|
||||
"Challenges",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CHALLENGES,
|
||||
"__module__": "spotify.login5.v3.login5_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.Challenges)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Challenges)
|
||||
|
||||
Challenge = _reflection.GeneratedProtocolMessageType(
|
||||
"Challenge",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CHALLENGE,
|
||||
"__module__": "spotify.login5.v3.login5_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.Challenge)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Challenge)
|
||||
|
||||
ChallengeSolutions = _reflection.GeneratedProtocolMessageType(
|
||||
"ChallengeSolutions",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CHALLENGESOLUTIONS,
|
||||
"__module__": "spotify.login5.v3.login5_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.ChallengeSolutions)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ChallengeSolutions)
|
||||
|
||||
ChallengeSolution = _reflection.GeneratedProtocolMessageType(
|
||||
"ChallengeSolution",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CHALLENGESOLUTION,
|
||||
"__module__": "spotify.login5.v3.login5_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.ChallengeSolution)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ChallengeSolution)
|
||||
|
||||
LoginRequest = _reflection.GeneratedProtocolMessageType(
|
||||
"LoginRequest",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _LOGINREQUEST,
|
||||
"__module__": "spotify.login5.v3.login5_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.LoginRequest)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(LoginRequest)
|
||||
|
||||
LoginOk = _reflection.GeneratedProtocolMessageType(
|
||||
"LoginOk",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _LOGINOK,
|
||||
"__module__": "spotify.login5.v3.login5_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.LoginOk)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(LoginOk)
|
||||
|
||||
LoginResponse = _reflection.GeneratedProtocolMessageType(
|
||||
"LoginResponse",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _LOGINRESPONSE,
|
||||
"__module__": "spotify.login5.v3.login5_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.LoginResponse)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(LoginResponse)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
263
resources/lib/librespot/proto/spotify/login5/v3/UserInfo_pb2.py
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: spotify/login5/v3/user_info.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="spotify/login5/v3/user_info.proto",
|
||||
package="spotify.login5.v3",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\024com.spotify.login5v3",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n!spotify/login5/v3/user_info.proto\x12\x11spotify.login5.v3"\x97\x02\n\x08UserInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05\x65mail\x18\x02 \x01(\t\x12\x16\n\x0e\x65mail_verified\x18\x03 \x01(\x08\x12\x11\n\tbirthdate\x18\x04 \x01(\t\x12\x32\n\x06gender\x18\x05 \x01(\x0e\x32".spotify.login5.v3.UserInfo.Gender\x12\x14\n\x0cphone_number\x18\x06 \x01(\t\x12\x1d\n\x15phone_number_verified\x18\x07 \x01(\x08\x12 \n\x18\x65mail_already_registered\x18\x08 \x01(\x08"8\n\x06Gender\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04MALE\x10\x01\x12\n\n\x06\x46\x45MALE\x10\x02\x12\x0b\n\x07NEUTRAL\x10\x03\x42\x16\n\x14\x63om.spotify.login5v3b\x06proto3',
|
||||
)
|
||||
|
||||
_USERINFO_GENDER = _descriptor.EnumDescriptor(
|
||||
name="Gender",
|
||||
full_name="spotify.login5.v3.UserInfo.Gender",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="UNKNOWN",
|
||||
index=0,
|
||||
number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="MALE",
|
||||
index=1,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="FEMALE",
|
||||
index=2,
|
||||
number=2,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="NEUTRAL",
|
||||
index=3,
|
||||
number=3,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=280,
|
||||
serialized_end=336,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_USERINFO_GENDER)
|
||||
|
||||
_USERINFO = _descriptor.Descriptor(
|
||||
name="UserInfo",
|
||||
full_name="spotify.login5.v3.UserInfo",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="name",
|
||||
full_name="spotify.login5.v3.UserInfo.name",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="email",
|
||||
full_name="spotify.login5.v3.UserInfo.email",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="email_verified",
|
||||
full_name="spotify.login5.v3.UserInfo.email_verified",
|
||||
index=2,
|
||||
number=3,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="birthdate",
|
||||
full_name="spotify.login5.v3.UserInfo.birthdate",
|
||||
index=3,
|
||||
number=4,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="gender",
|
||||
full_name="spotify.login5.v3.UserInfo.gender",
|
||||
index=4,
|
||||
number=5,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="phone_number",
|
||||
full_name="spotify.login5.v3.UserInfo.phone_number",
|
||||
index=5,
|
||||
number=6,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="phone_number_verified",
|
||||
full_name="spotify.login5.v3.UserInfo.phone_number_verified",
|
||||
index=6,
|
||||
number=7,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="email_already_registered",
|
||||
full_name="spotify.login5.v3.UserInfo.email_already_registered",
|
||||
index=7,
|
||||
number=8,
|
||||
type=8,
|
||||
cpp_type=7,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=False,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_USERINFO_GENDER,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=57,
|
||||
serialized_end=336,
|
||||
)
|
||||
|
||||
_USERINFO.fields_by_name["gender"].enum_type = _USERINFO_GENDER
|
||||
_USERINFO_GENDER.containing_type = _USERINFO
|
||||
DESCRIPTOR.message_types_by_name["UserInfo"] = _USERINFO
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
UserInfo = _reflection.GeneratedProtocolMessageType(
|
||||
"UserInfo",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _USERINFO,
|
||||
"__module__": "spotify.login5.v3.user_info_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.UserInfo)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(UserInfo)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: spotify/login5/v3/challenges/code.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="spotify/login5/v3/challenges/code.proto",
|
||||
package="spotify.login5.v3.challenges",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\024com.spotify.login5v3",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n\'spotify/login5/v3/challenges/code.proto\x12\x1cspotify.login5.v3.challenges"\xbc\x01\n\rCodeChallenge\x12\x42\n\x06method\x18\x01 \x01(\x0e\x32\x32.spotify.login5.v3.challenges.CodeChallenge.Method\x12\x13\n\x0b\x63ode_length\x18\x02 \x01(\x05\x12\x12\n\nexpires_in\x18\x03 \x01(\x05\x12\x1e\n\x16\x63\x61nonical_phone_number\x18\x04 \x01(\t"\x1e\n\x06Method\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x07\n\x03SMS\x10\x01"\x1c\n\x0c\x43odeSolution\x12\x0c\n\x04\x63ode\x18\x01 \x01(\tB\x16\n\x14\x63om.spotify.login5v3b\x06proto3',
|
||||
)
|
||||
|
||||
_CODECHALLENGE_METHOD = _descriptor.EnumDescriptor(
|
||||
name="Method",
|
||||
full_name="spotify.login5.v3.challenges.CodeChallenge.Method",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="UNKNOWN",
|
||||
index=0,
|
||||
number=0,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name="SMS",
|
||||
index=1,
|
||||
number=1,
|
||||
serialized_options=None,
|
||||
type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=232,
|
||||
serialized_end=262,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_CODECHALLENGE_METHOD)
|
||||
|
||||
_CODECHALLENGE = _descriptor.Descriptor(
|
||||
name="CodeChallenge",
|
||||
full_name="spotify.login5.v3.challenges.CodeChallenge",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="method",
|
||||
full_name="spotify.login5.v3.challenges.CodeChallenge.method",
|
||||
index=0,
|
||||
number=1,
|
||||
type=14,
|
||||
cpp_type=8,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="code_length",
|
||||
full_name="spotify.login5.v3.challenges.CodeChallenge.code_length",
|
||||
index=1,
|
||||
number=2,
|
||||
type=5,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="expires_in",
|
||||
full_name="spotify.login5.v3.challenges.CodeChallenge.expires_in",
|
||||
index=2,
|
||||
number=3,
|
||||
type=5,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="canonical_phone_number",
|
||||
full_name=
|
||||
"spotify.login5.v3.challenges.CodeChallenge.canonical_phone_number",
|
||||
index=3,
|
||||
number=4,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_CODECHALLENGE_METHOD,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=74,
|
||||
serialized_end=262,
|
||||
)
|
||||
|
||||
_CODESOLUTION = _descriptor.Descriptor(
|
||||
name="CodeSolution",
|
||||
full_name="spotify.login5.v3.challenges.CodeSolution",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="code",
|
||||
full_name="spotify.login5.v3.challenges.CodeSolution.code",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=264,
|
||||
serialized_end=292,
|
||||
)
|
||||
|
||||
_CODECHALLENGE.fields_by_name["method"].enum_type = _CODECHALLENGE_METHOD
|
||||
_CODECHALLENGE_METHOD.containing_type = _CODECHALLENGE
|
||||
DESCRIPTOR.message_types_by_name["CodeChallenge"] = _CODECHALLENGE
|
||||
DESCRIPTOR.message_types_by_name["CodeSolution"] = _CODESOLUTION
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
CodeChallenge = _reflection.GeneratedProtocolMessageType(
|
||||
"CodeChallenge",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CODECHALLENGE,
|
||||
"__module__": "spotify.login5.v3.challenges.code_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.challenges.CodeChallenge)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(CodeChallenge)
|
||||
|
||||
CodeSolution = _reflection.GeneratedProtocolMessageType(
|
||||
"CodeSolution",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _CODESOLUTION,
|
||||
"__module__": "spotify.login5.v3.challenges.code_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.challenges.CodeSolution)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(CodeSolution)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: spotify/login5/v3/challenges/hashcash.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import \
|
||||
duration_pb2 as google_dot_protobuf_dot_duration__pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="spotify/login5/v3/challenges/hashcash.proto",
|
||||
package="spotify.login5.v3.challenges",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\024com.spotify.login5v3",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n+spotify/login5/v3/challenges/hashcash.proto\x12\x1cspotify.login5.v3.challenges\x1a\x1egoogle/protobuf/duration.proto"3\n\x11HashcashChallenge\x12\x0e\n\x06prefix\x18\x01 \x01(\x0c\x12\x0e\n\x06length\x18\x02 \x01(\x05"O\n\x10HashcashSolution\x12\x0e\n\x06suffix\x18\x01 \x01(\x0c\x12+\n\x08\x64uration\x18\x02 \x01(\x0b\x32\x19.google.protobuf.DurationB\x16\n\x14\x63om.spotify.login5v3b\x06proto3',
|
||||
dependencies=[
|
||||
google_dot_protobuf_dot_duration__pb2.DESCRIPTOR,
|
||||
],
|
||||
)
|
||||
|
||||
_HASHCASHCHALLENGE = _descriptor.Descriptor(
|
||||
name="HashcashChallenge",
|
||||
full_name="spotify.login5.v3.challenges.HashcashChallenge",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="prefix",
|
||||
full_name="spotify.login5.v3.challenges.HashcashChallenge.prefix",
|
||||
index=0,
|
||||
number=1,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="length",
|
||||
full_name="spotify.login5.v3.challenges.HashcashChallenge.length",
|
||||
index=1,
|
||||
number=2,
|
||||
type=5,
|
||||
cpp_type=1,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=0,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=109,
|
||||
serialized_end=160,
|
||||
)
|
||||
|
||||
_HASHCASHSOLUTION = _descriptor.Descriptor(
|
||||
name="HashcashSolution",
|
||||
full_name="spotify.login5.v3.challenges.HashcashSolution",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="suffix",
|
||||
full_name="spotify.login5.v3.challenges.HashcashSolution.suffix",
|
||||
index=0,
|
||||
number=1,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="duration",
|
||||
full_name="spotify.login5.v3.challenges.HashcashSolution.duration",
|
||||
index=1,
|
||||
number=2,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=162,
|
||||
serialized_end=241,
|
||||
)
|
||||
|
||||
_HASHCASHSOLUTION.fields_by_name[
|
||||
"duration"].message_type = google_dot_protobuf_dot_duration__pb2._DURATION
|
||||
DESCRIPTOR.message_types_by_name["HashcashChallenge"] = _HASHCASHCHALLENGE
|
||||
DESCRIPTOR.message_types_by_name["HashcashSolution"] = _HASHCASHSOLUTION
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
HashcashChallenge = _reflection.GeneratedProtocolMessageType(
|
||||
"HashcashChallenge",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _HASHCASHCHALLENGE,
|
||||
"__module__": "spotify.login5.v3.challenges.hashcash_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.challenges.HashcashChallenge)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(HashcashChallenge)
|
||||
|
||||
HashcashSolution = _reflection.GeneratedProtocolMessageType(
|
||||
"HashcashSolution",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _HASHCASHSOLUTION,
|
||||
"__module__": "spotify.login5.v3.challenges.hashcash_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.challenges.HashcashSolution)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(HashcashSolution)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
@ -0,0 +1,483 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: spotify/login5/v3/credentials/credentials.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="spotify/login5/v3/credentials/credentials.proto",
|
||||
package="spotify.login5.v3.credentials",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\024com.spotify.login5v3",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n/spotify/login5/v3/credentials/credentials.proto\x12\x1dspotify.login5.v3.credentials"2\n\x10StoredCredential\x12\x10\n\x08username\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c"9\n\x08Password\x12\n\n\x02id\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x0f\n\x07padding\x18\x03 \x01(\x0c";\n\x13\x46\x61\x63\x65\x62ookAccessToken\x12\x0e\n\x06\x66\x62_uid\x18\x01 \x01(\t\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x02 \x01(\t"\x1d\n\x0cOneTimeToken\x12\r\n\x05token\x18\x01 \x01(\t"|\n\x15ParentChildCredential\x12\x10\n\x08\x63hild_id\x18\x01 \x01(\t\x12Q\n\x18parent_stored_credential\x18\x02 \x01(\x0b\x32/.spotify.login5.v3.credentials.StoredCredential"S\n\x15\x41ppleSignInCredential\x12\x11\n\tauth_code\x18\x01 \x01(\t\x12\x14\n\x0credirect_uri\x18\x02 \x01(\t\x12\x11\n\tbundle_id\x18\x03 \x01(\tB\x16\n\x14\x63om.spotify.login5v3b\x06proto3',
|
||||
)
|
||||
|
||||
_STOREDCREDENTIAL = _descriptor.Descriptor(
|
||||
name="StoredCredential",
|
||||
full_name="spotify.login5.v3.credentials.StoredCredential",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="username",
|
||||
full_name="spotify.login5.v3.credentials.StoredCredential.username",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="data",
|
||||
full_name="spotify.login5.v3.credentials.StoredCredential.data",
|
||||
index=1,
|
||||
number=2,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=82,
|
||||
serialized_end=132,
|
||||
)
|
||||
|
||||
_PASSWORD = _descriptor.Descriptor(
|
||||
name="Password",
|
||||
full_name="spotify.login5.v3.credentials.Password",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="id",
|
||||
full_name="spotify.login5.v3.credentials.Password.id",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="password",
|
||||
full_name="spotify.login5.v3.credentials.Password.password",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="padding",
|
||||
full_name="spotify.login5.v3.credentials.Password.padding",
|
||||
index=2,
|
||||
number=3,
|
||||
type=12,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"",
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=134,
|
||||
serialized_end=191,
|
||||
)
|
||||
|
||||
_FACEBOOKACCESSTOKEN = _descriptor.Descriptor(
|
||||
name="FacebookAccessToken",
|
||||
full_name="spotify.login5.v3.credentials.FacebookAccessToken",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="fb_uid",
|
||||
full_name=
|
||||
"spotify.login5.v3.credentials.FacebookAccessToken.fb_uid",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="access_token",
|
||||
full_name=
|
||||
"spotify.login5.v3.credentials.FacebookAccessToken.access_token",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=193,
|
||||
serialized_end=252,
|
||||
)
|
||||
|
||||
_ONETIMETOKEN = _descriptor.Descriptor(
|
||||
name="OneTimeToken",
|
||||
full_name="spotify.login5.v3.credentials.OneTimeToken",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="token",
|
||||
full_name="spotify.login5.v3.credentials.OneTimeToken.token",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=254,
|
||||
serialized_end=283,
|
||||
)
|
||||
|
||||
_PARENTCHILDCREDENTIAL = _descriptor.Descriptor(
|
||||
name="ParentChildCredential",
|
||||
full_name="spotify.login5.v3.credentials.ParentChildCredential",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="child_id",
|
||||
full_name=
|
||||
"spotify.login5.v3.credentials.ParentChildCredential.child_id",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="parent_stored_credential",
|
||||
full_name=
|
||||
"spotify.login5.v3.credentials.ParentChildCredential.parent_stored_credential",
|
||||
index=1,
|
||||
number=2,
|
||||
type=11,
|
||||
cpp_type=10,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=None,
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=285,
|
||||
serialized_end=409,
|
||||
)
|
||||
|
||||
_APPLESIGNINCREDENTIAL = _descriptor.Descriptor(
|
||||
name="AppleSignInCredential",
|
||||
full_name="spotify.login5.v3.credentials.AppleSignInCredential",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="auth_code",
|
||||
full_name=
|
||||
"spotify.login5.v3.credentials.AppleSignInCredential.auth_code",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="redirect_uri",
|
||||
full_name=
|
||||
"spotify.login5.v3.credentials.AppleSignInCredential.redirect_uri",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="bundle_id",
|
||||
full_name=
|
||||
"spotify.login5.v3.credentials.AppleSignInCredential.bundle_id",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=411,
|
||||
serialized_end=494,
|
||||
)
|
||||
|
||||
_PARENTCHILDCREDENTIAL.fields_by_name[
|
||||
"parent_stored_credential"].message_type = _STOREDCREDENTIAL
|
||||
DESCRIPTOR.message_types_by_name["StoredCredential"] = _STOREDCREDENTIAL
|
||||
DESCRIPTOR.message_types_by_name["Password"] = _PASSWORD
|
||||
DESCRIPTOR.message_types_by_name["FacebookAccessToken"] = _FACEBOOKACCESSTOKEN
|
||||
DESCRIPTOR.message_types_by_name["OneTimeToken"] = _ONETIMETOKEN
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
"ParentChildCredential"] = _PARENTCHILDCREDENTIAL
|
||||
DESCRIPTOR.message_types_by_name[
|
||||
"AppleSignInCredential"] = _APPLESIGNINCREDENTIAL
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
StoredCredential = _reflection.GeneratedProtocolMessageType(
|
||||
"StoredCredential",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _STOREDCREDENTIAL,
|
||||
"__module__": "spotify.login5.v3.credentials.credentials_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.credentials.StoredCredential)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(StoredCredential)
|
||||
|
||||
Password = _reflection.GeneratedProtocolMessageType(
|
||||
"Password",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _PASSWORD,
|
||||
"__module__": "spotify.login5.v3.credentials.credentials_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.credentials.Password)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(Password)
|
||||
|
||||
FacebookAccessToken = _reflection.GeneratedProtocolMessageType(
|
||||
"FacebookAccessToken",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _FACEBOOKACCESSTOKEN,
|
||||
"__module__": "spotify.login5.v3.credentials.credentials_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.credentials.FacebookAccessToken)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(FacebookAccessToken)
|
||||
|
||||
OneTimeToken = _reflection.GeneratedProtocolMessageType(
|
||||
"OneTimeToken",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _ONETIMETOKEN,
|
||||
"__module__": "spotify.login5.v3.credentials.credentials_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.credentials.OneTimeToken)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(OneTimeToken)
|
||||
|
||||
ParentChildCredential = _reflection.GeneratedProtocolMessageType(
|
||||
"ParentChildCredential",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _PARENTCHILDCREDENTIAL,
|
||||
"__module__": "spotify.login5.v3.credentials.credentials_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.credentials.ParentChildCredential)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(ParentChildCredential)
|
||||
|
||||
AppleSignInCredential = _reflection.GeneratedProtocolMessageType(
|
||||
"AppleSignInCredential",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _APPLESIGNINCREDENTIAL,
|
||||
"__module__": "spotify.login5.v3.credentials.credentials_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.credentials.AppleSignInCredential)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(AppleSignInCredential)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: spotify/login5/v3/identifiers/identifiers.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name="spotify/login5/v3/identifiers/identifiers.proto",
|
||||
package="spotify.login5.v3.identifiers",
|
||||
syntax="proto3",
|
||||
serialized_options=b"\n\024com.spotify.login5v3",
|
||||
create_key=_descriptor._internal_create_key,
|
||||
serialized_pb=
|
||||
b'\n/spotify/login5/v3/identifiers/identifiers.proto\x12\x1dspotify.login5.v3.identifiers"U\n\x0bPhoneNumber\x12\x0e\n\x06number\x18\x01 \x01(\t\x12\x18\n\x10iso_country_code\x18\x02 \x01(\t\x12\x1c\n\x14\x63ountry_calling_code\x18\x03 \x01(\tB\x16\n\x14\x63om.spotify.login5v3b\x06proto3',
|
||||
)
|
||||
|
||||
_PHONENUMBER = _descriptor.Descriptor(
|
||||
name="PhoneNumber",
|
||||
full_name="spotify.login5.v3.identifiers.PhoneNumber",
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name="number",
|
||||
full_name="spotify.login5.v3.identifiers.PhoneNumber.number",
|
||||
index=0,
|
||||
number=1,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="iso_country_code",
|
||||
full_name=
|
||||
"spotify.login5.v3.identifiers.PhoneNumber.iso_country_code",
|
||||
index=1,
|
||||
number=2,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
_descriptor.FieldDescriptor(
|
||||
name="country_calling_code",
|
||||
full_name=
|
||||
"spotify.login5.v3.identifiers.PhoneNumber.country_calling_code",
|
||||
index=2,
|
||||
number=3,
|
||||
type=9,
|
||||
cpp_type=9,
|
||||
label=1,
|
||||
has_default_value=False,
|
||||
default_value=b"".decode("utf-8"),
|
||||
message_type=None,
|
||||
enum_type=None,
|
||||
containing_type=None,
|
||||
is_extension=False,
|
||||
extension_scope=None,
|
||||
serialized_options=None,
|
||||
file=DESCRIPTOR,
|
||||
create_key=_descriptor._internal_create_key,
|
||||
),
|
||||
],
|
||||
extensions=[],
|
||||
nested_types=[],
|
||||
enum_types=[],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax="proto3",
|
||||
extension_ranges=[],
|
||||
oneofs=[],
|
||||
serialized_start=82,
|
||||
serialized_end=167,
|
||||
)
|
||||
|
||||
DESCRIPTOR.message_types_by_name["PhoneNumber"] = _PHONENUMBER
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
PhoneNumber = _reflection.GeneratedProtocolMessageType(
|
||||
"PhoneNumber",
|
||||
(_message.Message, ),
|
||||
{
|
||||
"DESCRIPTOR": _PHONENUMBER,
|
||||
"__module__": "spotify.login5.v3.identifiers.identifiers_pb2"
|
||||
# @@protoc_insertion_point(class_scope:spotify.login5.v3.identifiers.PhoneNumber)
|
||||
},
|
||||
)
|
||||
_sym_db.RegisterMessage(PhoneNumber)
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
103
resources/lib/librespot/structure.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
from __future__ import annotations
|
||||
import typing
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from librespot.audio import AbsChunkedInputStream
|
||||
from librespot.audio.format import SuperAudioFormat
|
||||
from librespot.core import DealerClient, Session
|
||||
from librespot.crypto import Packet
|
||||
from librespot.mercury import MercuryClient
|
||||
from librespot.proto import Metadata_pb2 as Metadata
|
||||
|
||||
|
||||
class AudioDecrypt:
|
||||
def decrypt_chunk(self, chunk_index: int, buffer: bytes):
|
||||
raise NotImplementedError
|
||||
|
||||
def decrypt_time_ms(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class AudioQualityPicker:
|
||||
def get_file(self,
|
||||
files: typing.List[Metadata.AudioFile]) -> Metadata.AudioFile:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Closeable:
|
||||
def close(self) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class FeederException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class GeneralAudioStream:
|
||||
def stream(self) -> AbsChunkedInputStream:
|
||||
raise NotImplementedError
|
||||
|
||||
def codec(self) -> SuperAudioFormat:
|
||||
raise NotImplementedError
|
||||
|
||||
def describe(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
def decrypt_time_ms(self) -> int:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class GeneralWritableStream:
|
||||
def write_chunk(self, buffer: bytearray, chunk_index: int, cached: bool):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class HaltListener:
|
||||
def stream_read_halted(self, chunk: int, _time: int) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
def stream_read_resumed(self, chunk: int, _time: int) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class MessageListener:
|
||||
def on_message(self, uri: str, headers: typing.Dict[str, str],
|
||||
payload: bytes):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class NoopAudioDecrypt(AudioDecrypt):
|
||||
def decrypt_chunk(self, chunk_index: int, buffer: bytes):
|
||||
return buffer
|
||||
|
||||
def decrypt_time_ms(self):
|
||||
return 0
|
||||
|
||||
|
||||
class PacketsReceiver:
|
||||
def dispatch(self, packet: Packet):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class RequestListener:
|
||||
def on_request(self, mid: str, pid: int, sender: str,
|
||||
command: typing.Any) -> DealerClient.RequestResult:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Runnable:
|
||||
def run(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class SessionListener:
|
||||
def session_closing(self, session: Session) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
def session_changed(self, session: Session) -> None:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class SubListener:
|
||||
def event(self, resp: MercuryClient.Response) -> None:
|
||||
raise NotImplementedError
|
||||
117
resources/lib/librespot/util.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
from Cryptodome import Random
|
||||
import binascii
|
||||
import math
|
||||
|
||||
|
||||
def bytes_to_hex(buffer: bytes) -> str:
|
||||
"""
|
||||
Convert bytes to hex
|
||||
Args:
|
||||
buffer: Bytes to convert
|
||||
Returns:
|
||||
hex
|
||||
"""
|
||||
return binascii.hexlify(buffer).decode()
|
||||
|
||||
|
||||
def hex_to_bytes(s: str) -> bytes:
|
||||
return binascii.unhexlify(s)
|
||||
|
||||
|
||||
def int_to_bytes(i: int):
|
||||
"""
|
||||
Convert an integer to a byte(s)
|
||||
Args:
|
||||
i: Integer to convert
|
||||
Returns:
|
||||
bytes
|
||||
"""
|
||||
width = i.bit_length()
|
||||
width += 8 - ((width % 8) or 8)
|
||||
fmt = '%%0%dx' % (width // 4)
|
||||
return b"\x00" if i == 0 else binascii.unhexlify(fmt % i)
|
||||
|
||||
|
||||
def random_hex_string(length: int):
|
||||
buffer = Random.get_random_bytes(int(length / 2))
|
||||
return bytes_to_hex(buffer)
|
||||
|
||||
|
||||
class Base62:
|
||||
standard_base = 256
|
||||
target_base = 62
|
||||
alphabet: bytes
|
||||
lookup: bytearray
|
||||
|
||||
def __init__(self, alphabet: bytes):
|
||||
self.alphabet = alphabet
|
||||
self.create_lookup_table()
|
||||
|
||||
@staticmethod
|
||||
def create_instance_with_inverted_character_set():
|
||||
return Base62(Base62.CharacterSets.inverted)
|
||||
|
||||
def encode(self, message: bytes, length: int = -1):
|
||||
indices = self.convert(message, self.standard_base, self.target_base,
|
||||
length)
|
||||
return self.translate(indices, self.alphabet)
|
||||
|
||||
def decode(self, encoded: bytes, length: int = -1):
|
||||
prepared = self.translate(encoded, self.lookup)
|
||||
return self.convert(prepared, self.target_base, self.standard_base,
|
||||
length)
|
||||
|
||||
def translate(self, indices: bytes, dictionary: bytes):
|
||||
translation = bytearray(len(indices))
|
||||
for i in range(len(indices)):
|
||||
translation[i] = dictionary[int.from_bytes(bytes([indices[i]]), "big")]
|
||||
return translation
|
||||
|
||||
def convert(self, message: bytes, source_base: int, target_base: int,
|
||||
length: int):
|
||||
estimated_length = self.estimate_output_length(
|
||||
len(message), source_base, target_base) if length == -1 else length
|
||||
out = b""
|
||||
source = message
|
||||
while len(source) > 0:
|
||||
quotient = b""
|
||||
remainder = 0
|
||||
for b in source:
|
||||
accumulator = int(b & 0xff) + remainder * source_base
|
||||
digit = int(
|
||||
(accumulator - (accumulator % target_base)) / target_base)
|
||||
remainder = int(accumulator % target_base)
|
||||
if len(quotient) > 0 or digit > 0:
|
||||
quotient += bytes([digit])
|
||||
out += bytes([remainder])
|
||||
source = quotient
|
||||
if len(out) < estimated_length:
|
||||
size = len(out)
|
||||
for _ in range(estimated_length - size):
|
||||
out += bytes([0])
|
||||
return self.reverse(out)
|
||||
if len(out) > estimated_length:
|
||||
return self.reverse(out[:estimated_length])
|
||||
return self.reverse(out)
|
||||
|
||||
def estimate_output_length(self, input_length: int, source_base: int,
|
||||
target_base: int):
|
||||
return int(
|
||||
math.ceil((math.log(source_base) / math.log(target_base)) *
|
||||
input_length))
|
||||
|
||||
def reverse(self, arr: bytes):
|
||||
length = len(arr)
|
||||
reversed_arr = bytearray(length)
|
||||
for i in range(length):
|
||||
reversed_arr[length - i - 1] = arr[i]
|
||||
return bytes(reversed_arr)
|
||||
|
||||
def create_lookup_table(self):
|
||||
self.lookup = bytearray(256)
|
||||
for i in range(len(self.alphabet)):
|
||||
self.lookup[self.alphabet[i]] = i & 0xff
|
||||
|
||||
class CharacterSets:
|
||||
gmp = b'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
||||
inverted = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
345
resources/lib/librespot/zeroconf.py
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
from __future__ import annotations
|
||||
from Cryptodome.Cipher import AES
|
||||
from Cryptodome.Hash import HMAC, SHA1
|
||||
from Cryptodome.Util import Counter
|
||||
from librespot import util, Version
|
||||
from librespot.core import Session
|
||||
from librespot.crypto import DiffieHellman
|
||||
from librespot.proto import Connect_pb2 as Connect
|
||||
from librespot.structure import Closeable, Runnable, SessionListener
|
||||
import base64
|
||||
import concurrent.futures
|
||||
import copy
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import socket
|
||||
import threading
|
||||
import typing
|
||||
import urllib.parse
|
||||
import zeroconf
|
||||
|
||||
|
||||
class ZeroconfServer(Closeable):
|
||||
logger = logging.getLogger("Librespot:ZeroconfServer")
|
||||
service = "_spotify-connect._tcp.local."
|
||||
__connecting_username: typing.Union[str, None] = None
|
||||
__connection_lock = threading.Condition()
|
||||
__default_get_info_fields = {
|
||||
"status": 101,
|
||||
"statusString": "OK",
|
||||
"spotifyError": 0,
|
||||
"version": "2.7.1",
|
||||
"libraryVersion": Version.version_name,
|
||||
"accountReq": "PREMIUM",
|
||||
"brandDisplayName": "kokarare1212",
|
||||
"modelDisplayName": "librespot-python",
|
||||
"voiceSupport": "NO",
|
||||
"availability": "",
|
||||
"productID": 0,
|
||||
"tokenType": "default",
|
||||
"groupStatus": "NONE",
|
||||
"resolverVersion": "0",
|
||||
"scope": "streaming,client-authorization-universal",
|
||||
}
|
||||
__default_successful_add_user = {
|
||||
"status": 101,
|
||||
"spotifyError": 0,
|
||||
"statusString": "OK",
|
||||
}
|
||||
__eol = b"\r\n"
|
||||
__max_port = 65536
|
||||
__min_port = 1024
|
||||
__runner: HttpRunner
|
||||
__service_info: zeroconf.ServiceInfo
|
||||
__session: typing.Union[Session, None] = None
|
||||
__session_listeners: typing.List[SessionListener] = []
|
||||
__zeroconf: zeroconf.Zeroconf
|
||||
|
||||
def __init__(self, inner: Inner, listen_port):
|
||||
self.__inner = inner
|
||||
self.__keys = DiffieHellman()
|
||||
if listen_port == -1:
|
||||
listen_port = random.randint(self.__min_port + 1, self.__max_port)
|
||||
self.__runner = ZeroconfServer.HttpRunner(self, listen_port)
|
||||
threading.Thread(target=self.__runner.run,
|
||||
name="zeroconf-http-server").start()
|
||||
self.__zeroconf = zeroconf.Zeroconf()
|
||||
self.__service_info = zeroconf.ServiceInfo(
|
||||
ZeroconfServer.service,
|
||||
inner.device_name + "." + ZeroconfServer.service,
|
||||
listen_port,
|
||||
0,
|
||||
0, {
|
||||
"CPath": "/",
|
||||
"VERSION": "1.0",
|
||||
"STACK": "SP",
|
||||
},
|
||||
self.get_useful_hostname() + ".",
|
||||
addresses=[
|
||||
socket.inet_aton(
|
||||
socket.gethostbyname(self.get_useful_hostname()))
|
||||
])
|
||||
self.__zeroconf.register_service(self.__service_info)
|
||||
threading.Thread(target=self.__zeroconf.start,
|
||||
name="zeroconf-multicast-dns-server").start()
|
||||
|
||||
def add_session_listener(self, listener: ZeroconfServer):
|
||||
self.__session_listeners.append(listener)
|
||||
|
||||
def close(self) -> None:
|
||||
self.__zeroconf.close()
|
||||
self.__runner.close()
|
||||
|
||||
def close_session(self) -> None:
|
||||
if self.__session is None:
|
||||
return
|
||||
for session_listener in self.__session_listeners:
|
||||
session_listener.session_closing(self.__session)
|
||||
self.__session.close()
|
||||
self.__session = None
|
||||
|
||||
def get_useful_hostname(self) -> str:
|
||||
host = socket.gethostname()
|
||||
if host == "localhost":
|
||||
pass
|
||||
else:
|
||||
return host
|
||||
|
||||
def handle_add_user(self, __socket: socket.socket, params: dict[str, str],
|
||||
http_version: str) -> None:
|
||||
username = params.get("userName")
|
||||
if not username:
|
||||
self.logger.error("Missing userName!")
|
||||
return
|
||||
blob_str = params.get("blob")
|
||||
if not blob_str:
|
||||
self.logger.error("Missing blob!")
|
||||
return
|
||||
client_key_str = params.get("clientKey")
|
||||
if not client_key_str:
|
||||
self.logger.error("Missing clientKey!")
|
||||
with self.__connection_lock:
|
||||
if username == self.__connecting_username:
|
||||
self.logger.info(
|
||||
"{} is already trying to connect.".format(username))
|
||||
__socket.send(http_version.encode())
|
||||
__socket.send(b" 403 Forbidden")
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(self.__eol)
|
||||
return
|
||||
shared_key = util.int_to_bytes(
|
||||
self.__keys.compute_shared_key(
|
||||
base64.b64decode(client_key_str.encode())))
|
||||
blob_bytes = base64.b64decode(blob_str)
|
||||
iv = blob_bytes[:16]
|
||||
encrypted = blob_bytes[16:len(blob_bytes) - 20]
|
||||
checksum = blob_bytes[len(blob_bytes) - 20:]
|
||||
sha1 = SHA1.new()
|
||||
sha1.update(shared_key)
|
||||
base_key = sha1.digest()[:16]
|
||||
hmac = HMAC.new(base_key, digestmod=SHA1)
|
||||
hmac.update(b"checksum")
|
||||
checksum_key = hmac.digest()
|
||||
hmac = HMAC.new(base_key, digestmod=SHA1)
|
||||
hmac.update(b"encryption")
|
||||
encryption_key = hmac.digest()
|
||||
hmac = HMAC.new(checksum_key, digestmod=SHA1)
|
||||
hmac.update(encrypted)
|
||||
mac = hmac.digest()
|
||||
if mac != checksum:
|
||||
self.logger.error("Mac and checksum don't match!")
|
||||
__socket.send(http_version.encode())
|
||||
__socket.send(b" 400 Bad Request")
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(self.__eol)
|
||||
return
|
||||
aes = AES.new(encryption_key[:16],
|
||||
AES.MODE_CTR,
|
||||
counter=Counter.new(128,
|
||||
initial_value=int.from_bytes(
|
||||
iv, "big")))
|
||||
decrypted = aes.decrypt(encrypted)
|
||||
self.close_session()
|
||||
with self.__connection_lock:
|
||||
self.__connecting_username = username
|
||||
self.logger.info("Accepted new user from {}. [deviceId: {}]".format(
|
||||
params.get("deviceName"), self.__inner.device_id))
|
||||
response = json.dumps(self.__default_successful_add_user)
|
||||
__socket.send(http_version.encode())
|
||||
__socket.send(b" 200 OK")
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(b"Content-Length: ")
|
||||
__socket.send(str(len(response)).encode())
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(response.encode())
|
||||
self.__session = Session.Builder(self.__inner.conf) \
|
||||
.set_device_id(self.__inner.device_id) \
|
||||
.set_device_name(self.__inner.device_name) \
|
||||
.set_device_type(self.__inner.device_type) \
|
||||
.set_preferred_locale(self.__inner.preferred_locale) \
|
||||
.blob(username, decrypted) \
|
||||
.create()
|
||||
with self.__connection_lock:
|
||||
self.__connecting_username = None
|
||||
for session_listener in self.__session_listeners:
|
||||
session_listener.session_changed(self.__session)
|
||||
|
||||
def handle_get_info(self, __socket: socket.socket,
|
||||
http_version: str) -> None:
|
||||
info = copy.deepcopy(self.__default_get_info_fields)
|
||||
info["deviceID"] = self.__inner.device_id
|
||||
info["remoteName"] = self.__inner.device_name
|
||||
info["publicKey"] = base64.b64encode(
|
||||
self.__keys.public_key_bytes()).decode()
|
||||
info["deviceType"] = Connect.DeviceType.Name(self.__inner.device_type)
|
||||
with self.__connection_lock:
|
||||
info[
|
||||
"activeUser"] = self.__connecting_username if self.__connecting_username is not None else self.__session.username(
|
||||
) if self.has_valid_session() else ""
|
||||
__socket.send(http_version.encode())
|
||||
__socket.send(b" 200 OK")
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(b"Content-Type: application/json")
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(self.__eol)
|
||||
__socket.send(json.dumps(info).encode())
|
||||
|
||||
def has_valid_session(self) -> bool:
|
||||
valid = self.__session and self.__session.is_valid()
|
||||
if not valid:
|
||||
self.__session = None
|
||||
return valid
|
||||
|
||||
def parse_path(self, path: str) -> dict[str, str]:
|
||||
url = "https://host" + path
|
||||
parsed = {}
|
||||
params = urllib.parse.parse_qs(urllib.parse.urlparse(url).query)
|
||||
for key, values in params.items():
|
||||
for value in values:
|
||||
parsed[key] = value
|
||||
return parsed
|
||||
|
||||
def remove_session_listener(self, listener: SessionListener):
|
||||
self.__session_listeners.remove(listener)
|
||||
|
||||
class Builder(Session.Builder):
|
||||
listen_port: int = -1
|
||||
|
||||
def set_listen_port(self, listen_port: int):
|
||||
self.listen_port = listen_port
|
||||
return self
|
||||
|
||||
def create(self) -> ZeroconfServer:
|
||||
return ZeroconfServer(
|
||||
ZeroconfServer.Inner(self.device_type, self.device_name,
|
||||
self.device_id, self.preferred_locale,
|
||||
self.conf), self.listen_port)
|
||||
|
||||
class HttpRunner(Closeable, Runnable):
|
||||
__should_stop = False
|
||||
__socket: socket.socket
|
||||
__worker = concurrent.futures.ThreadPoolExecutor()
|
||||
__zeroconf_server: ZeroconfServer
|
||||
|
||||
def __init__(self, zeroconf_server: ZeroconfServer, port: int):
|
||||
self.__socket = socket.socket()
|
||||
self.__socket.bind((".".join(["0"] * 4), port))
|
||||
self.__socket.listen(5)
|
||||
self.__zeroconf_server = zeroconf_server
|
||||
self.__zeroconf_server.logger.info(
|
||||
"Zeroconf HTTP server started successfully on port {}!".format(
|
||||
port))
|
||||
|
||||
def close(self) -> None:
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
while not self.__should_stop:
|
||||
__socket, address = self.__socket.accept()
|
||||
|
||||
def anonymous():
|
||||
self.__handle(__socket)
|
||||
__socket.close()
|
||||
|
||||
self.__worker.submit(anonymous)
|
||||
|
||||
def __handle(self, __socket: socket.socket) -> None:
|
||||
request = io.BytesIO(__socket.recv(1024 * 1024))
|
||||
request_line = request.readline().strip().split(b" ")
|
||||
if len(request_line) != 3:
|
||||
self.__zeroconf_server.logger.warning(
|
||||
"Unexpected request line: {}".format(request_line))
|
||||
method = request_line[0].decode()
|
||||
path = request_line[1].decode()
|
||||
http_version = request_line[2].decode()
|
||||
headers = {}
|
||||
while True:
|
||||
header = request.readline().strip()
|
||||
if not header:
|
||||
break
|
||||
split = header.split(b":")
|
||||
headers[split[0].decode()] = split[1].strip().decode()
|
||||
if not self.__zeroconf_server.has_valid_session():
|
||||
self.__zeroconf_server.logger.debug(
|
||||
"Handling request: {}, {}, {}, headers: {}".format(
|
||||
method, path, http_version, headers))
|
||||
params = {}
|
||||
if method == "POST":
|
||||
content_type = headers.get("Content-Type")
|
||||
if content_type != "application/x-www-form-urlencoded":
|
||||
self.__zeroconf_server.logger.error(
|
||||
"Bad Content-Type: {}".format(content_type))
|
||||
return
|
||||
content_length_str = headers.get("Content-Length")
|
||||
if content_length_str is None:
|
||||
self.__zeroconf_server.logger.error(
|
||||
"Missing Content-Length header!")
|
||||
return
|
||||
content_length = int(content_length_str)
|
||||
body = request.read(content_length).decode()
|
||||
pairs = body.split("&")
|
||||
for pair in pairs:
|
||||
split = pair.split("=")
|
||||
params[urllib.parse.unquote(
|
||||
split[0])] = urllib.parse.unquote(split[1])
|
||||
else:
|
||||
params = self.__zeroconf_server.parse_path(path)
|
||||
action = params.get("action")
|
||||
if action is None:
|
||||
self.__zeroconf_server.logger.debug(
|
||||
"Request is missing action.")
|
||||
return
|
||||
self.handle_request(__socket, http_version, action, params)
|
||||
|
||||
def handle_request(self, __socket: socket.socket, http_version: str,
|
||||
action: str, params: dict[str, str]) -> None:
|
||||
if action == "addUser":
|
||||
if params is None:
|
||||
raise RuntimeError
|
||||
self.__zeroconf_server.handle_add_user(__socket, params,
|
||||
http_version)
|
||||
elif action == "getInfo":
|
||||
self.__zeroconf_server.handle_get_info(__socket, http_version)
|
||||
else:
|
||||
self.__zeroconf_server.logger.warning(
|
||||
"Unknown action: {}".format(action))
|
||||
|
||||
class Inner:
|
||||
conf: typing.Final[Session.Configuration]
|
||||
device_name: typing.Final[str]
|
||||
device_id: typing.Final[str]
|
||||
device_type: typing.Final[Connect.DeviceType]
|
||||
preferred_locale: typing.Final[str]
|
||||
|
||||
def __init__(self, device_type: Connect.DeviceType, device_name: str,
|
||||
device_id: str, preferred_locale: str,
|
||||
conf: Session.Configuration):
|
||||
self.conf = conf
|
||||
self.device_name = device_name
|
||||
self.device_id = util.random_hex_string(
|
||||
40).lower() if not device_id else device_id
|
||||
self.device_type = device_type
|
||||
self.preferred_locale = preferred_locale
|
||||
66
resources/lib/librespot_auth.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import time
|
||||
from typing import Dict
|
||||
|
||||
from librespot.core import Session
|
||||
from utils import log_msg, log_exception, LOGDEBUG
|
||||
|
||||
CLIENT_ID = "2eb96f9b37494be1824999d58028a305"
|
||||
SPOTTY_SCOPE = [
|
||||
"user-read-playback-state",
|
||||
"user-read-currently-playing",
|
||||
"user-modify-playback-state",
|
||||
"playlist-read-private",
|
||||
"playlist-read-collaborative",
|
||||
"playlist-modify-public",
|
||||
"playlist-modify-private",
|
||||
"user-follow-modify",
|
||||
"user-follow-read",
|
||||
"user-library-read",
|
||||
"user-library-modify",
|
||||
"user-read-private",
|
||||
"user-read-email",
|
||||
"user-read-birthdate",
|
||||
"user-top-read",
|
||||
]
|
||||
|
||||
|
||||
class LibrespotAuth:
|
||||
def __init__(self, session: Session):
|
||||
self.__session = session
|
||||
|
||||
def get_token(self) -> Dict[str, str]:
|
||||
token_info = None
|
||||
|
||||
try:
|
||||
tokenprovider = self.__session.tokens()
|
||||
result = tokenprovider.get_token(
|
||||
"user-read-playback-state",
|
||||
"user-read-currently-playing",
|
||||
"user-modify-playback-state",
|
||||
"playlist-read-private",
|
||||
"playlist-read-collaborative",
|
||||
"playlist-modify-public",
|
||||
"playlist-modify-private",
|
||||
"user-follow-modify",
|
||||
"user-follow-read",
|
||||
"user-library-read",
|
||||
"user-library-modify",
|
||||
"user-read-private",
|
||||
"user-read-email",
|
||||
"user-read-birthdate",
|
||||
"user-top-read",
|
||||
)
|
||||
|
||||
# Transform token info to spotipy compatible format.
|
||||
if result is not None:
|
||||
token_info = {
|
||||
"access_token": result.access_token,
|
||||
"expires_in": result.expires_in,
|
||||
"expires_at": int(time.time()) + result.expires_in,
|
||||
"refresh_token": result.access_token,
|
||||
}
|
||||
log_msg(f"Token: {token_info}", LOGDEBUG)
|
||||
except Exception as exc:
|
||||
log_exception(exc, "Get Spotify token error")
|
||||
|
||||
return token_info
|
||||
151
resources/lib/main_service.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
"""
|
||||
plugin.audio.librespot
|
||||
Spotify player for Kodi
|
||||
main_service.py
|
||||
Background service which launches the http service.
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Dict
|
||||
|
||||
import xbmc
|
||||
import xbmcaddon
|
||||
import xbmcgui
|
||||
from xbmc import LOGDEBUG, LOGWARNING
|
||||
|
||||
from bottle_manager import LibrespotServer
|
||||
import utils
|
||||
from http_video_player_setter import HttpVideoPlayerSetter
|
||||
from save_recently_played import SaveRecentlyPlayed
|
||||
from string_ids import HTTP_VIDEO_RULE_ADDED_STR_ID
|
||||
from utils import PROXY_PORT, log_msg, ADDON_ID
|
||||
|
||||
from librespot_auth import LibrespotAuth
|
||||
|
||||
from librespot.core import Session
|
||||
|
||||
SAVE_TO_RECENTLY_PLAYED_FILE = True
|
||||
|
||||
SPOTIFY_ADDON = xbmcaddon.Addon(id=ADDON_ID)
|
||||
|
||||
|
||||
def abort_app(timeout_in_secs: int) -> bool:
|
||||
return xbmc.Monitor().waitForAbort(timeout_in_secs)
|
||||
|
||||
|
||||
def add_http_video_rule() -> None:
|
||||
video_player_setter = HttpVideoPlayerSetter()
|
||||
|
||||
if not video_player_setter.set_http_rule():
|
||||
return
|
||||
|
||||
msg = SPOTIFY_ADDON.getLocalizedString(HTTP_VIDEO_RULE_ADDED_STR_ID)
|
||||
dialog = xbmcgui.Dialog()
|
||||
header = SPOTIFY_ADDON.getAddonInfo("name")
|
||||
dialog.ok(header, msg)
|
||||
|
||||
def get_username() -> str:
|
||||
addon = xbmcaddon.Addon(id=ADDON_ID)
|
||||
spotify_username = addon.getSetting("username")
|
||||
if not spotify_username:
|
||||
raise Exception("Could not get spotify username.")
|
||||
return spotify_username
|
||||
|
||||
def get_password() -> str:
|
||||
addon = xbmcaddon.Addon(id=ADDON_ID)
|
||||
spotify_password = addon.getSetting("password")
|
||||
if not spotify_password:
|
||||
raise Exception("Could not get spotify password.")
|
||||
return spotify_password
|
||||
|
||||
class MainService:
|
||||
def __init__(self):
|
||||
log_msg(f"Spotify plugin version: {xbmcaddon.Addon(id=ADDON_ID).getAddonInfo('version')}.")
|
||||
|
||||
self.__librespot_session: Session = Session.Builder().user_pass(get_username(), get_password()).create()
|
||||
|
||||
add_http_video_rule()
|
||||
|
||||
self.__librespot_auth: LibrespotAuth = LibrespotAuth(self.__librespot_session)
|
||||
self.__auth_token: Dict[str, str] = dict()
|
||||
|
||||
self.__save_recently_played: SaveRecentlyPlayed = SaveRecentlyPlayed()
|
||||
|
||||
def __save_track_to_recently_played(self, track_id: str) -> None:
|
||||
if SAVE_TO_RECENTLY_PLAYED_FILE:
|
||||
self.__save_recently_played.save_track(track_id)
|
||||
|
||||
def run(self) -> None:
|
||||
log_msg("Starting main service loop.")
|
||||
self.__renew_token()
|
||||
|
||||
librespot_server = LibrespotServer(self.__librespot_session)
|
||||
librespot_server.run(host='127.0.0.1', port=PROXY_PORT)
|
||||
log_msg(f"Started bottle with port {PROXY_PORT}.")
|
||||
|
||||
|
||||
loop_counter = 0
|
||||
loop_wait_in_secs = 6
|
||||
while True:
|
||||
loop_counter += 1
|
||||
if (loop_counter % 10) == 0:
|
||||
log_msg(f"Main loop continuing. Loop counter: {loop_counter}.")
|
||||
|
||||
# Monitor authorization.
|
||||
if (int(self.__auth_token["expires_at"]) - 60) <= (int(time.time())):
|
||||
expire_time = int(self.__auth_token["expires_at"])
|
||||
time_now = int(time.time())
|
||||
log_msg(
|
||||
f"Spotify token expired."
|
||||
f" Expire time: {self.__get_time_str(expire_time)} ({expire_time});"
|
||||
f" time now: {self.__get_time_str(time_now)} ({time_now})."
|
||||
)
|
||||
log_msg("Refreshing auth token now.")
|
||||
self.__renew_token()
|
||||
|
||||
if abort_app(loop_wait_in_secs):
|
||||
break
|
||||
|
||||
librespot_server.close()
|
||||
|
||||
def __renew_token(self) -> None:
|
||||
log_msg("Retrieving auth token....", LOGDEBUG)
|
||||
|
||||
self.__auth_token = self.__get_retry_auth_token()
|
||||
if not self.__auth_token:
|
||||
utils.cache_auth_token("")
|
||||
raise Exception(
|
||||
f"Could not get Spotify auth token for"
|
||||
f" user '{self.__spotty_helper.get_username()}'."
|
||||
)
|
||||
|
||||
log_msg(
|
||||
f"Retrieved Spotify auth token."
|
||||
f" Expires at {self.__get_time_str(int(self.__auth_token['expires_at']))}."
|
||||
)
|
||||
|
||||
# Cache auth token for easy access by the plugin.
|
||||
utils.cache_auth_token(self.__auth_token["access_token"])
|
||||
|
||||
def __get_retry_auth_token(self) -> Dict[str, str]:
|
||||
auth_token = None
|
||||
max_retries = 20
|
||||
count = 0
|
||||
while count < max_retries:
|
||||
auth_token = self.__get_token()
|
||||
if auth_token:
|
||||
break
|
||||
time.sleep(1)
|
||||
count += 1
|
||||
|
||||
if count > 0:
|
||||
log_msg(f"Took {count} retries to get authorization token.", LOGWARNING)
|
||||
|
||||
return auth_token
|
||||
|
||||
def __get_token(self) -> Dict[str, str]:
|
||||
return self.__librespot_auth.get_token()
|
||||
|
||||
@staticmethod
|
||||
def __get_time_str(raw_time: int) -> str:
|
||||
return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(float(raw_time)))
|
||||