Coder Social home page Coder Social logo

yetangitu / spodcast Goto Github PK

View Code? Open in Web Editor NEW
352.0 8.0 14.0 1.34 MB

Spodcast is a caching Spotify podcast to RSS proxy. Using Spodcast you can follow Spotify-hosted netcasts/podcasts using any player which supports RSS, thus enabling the use of older hardware which is not compatible with the Spotify (web) app.

License: GNU General Public License v3.0

Shell 5.75% Python 93.50% Dockerfile 0.76%
rss-generator spotify-api podcast-fetcher

spodcast's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spodcast's Issues

Can't add feeds

I've set up Spodcast following your tutorial and I think I've set all permissions correctly. www-data can run spodcast.

When adding a url via the web interface, the spinner just disappears after a while and the page stays empty.

I've set "LOG_LEVEL":"DEBUG" and ran the following command as user www-data:

spodcast -c /mnt/audio/spodcast/spodcast.json --max-episodes 1 https://open.spotify.com/show/1OLcQdw2PFDPG1jo3s0wbp

Spodcast seems to find the podcast episode but skips it for some reason. Any help or direction is greatly appreciated!
This is the console output:

www-data@vmd97416:/mnt/audio/spodcast$ spodcast -c /mnt/audio/spodcast/spodcast.json --max-episodes 1 https://open.spotify.com/show/1OLcQdw2PFDPG1jo3s0wbp
DEBUG:spodcast.spodcast:args: Namespace(config_location='/mnt/audio/spodcast/spodcast.json', prepare_feed=False, urls=['https://open.spotify.com/show/1OLcQdw2PFDPG1jo3s0wbp'], login=None, root_path=None, skip_existing=None, retry=None, max_episodes='1', chunk_size=None, download_real_time=None, language=None, credentials_location=None, rss_feed=None, transcode=None, log_level=None, func=<function client at 0x7fce4ac41c10>)
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): apresolve.spotify.com:443
DEBUG:urllib3.connectionpool:https://apresolve.spotify.com:443 "GET /?type=accesspoint HTTP/1.1" 200 None
INFO:Librespot:Session:Created new session! device_id: d6f07bbe25096c88a475cea32cec6fb71ec3376c, ap: ap-gae2.spotify.com:443
INFO:Librespot:Session:Connection successfully!
INFO:Librespot:Session:Session.Receiver started
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): apresolve.spotify.com:443
DEBUG:urllib3.connectionpool:https://apresolve.spotify.com:443 "GET /?type=spclient HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): apresolve.spotify.com:443
INFO:Librespot:Session:Skipping 02
INFO:Librespot:Session:Received license_version: 0
INFO:Librespot:Session:Received country_code: DE
DEBUG:Librespot:Session:Parsed product info: {'type': 'open', 'ab-ad-player-targeting': '1', 'ab-ad-requester': '1', 'ab-android-push-notifications': '1', 'ab-browse-music-tuesday': '1', 'ab-collection-bookmark-model': '1', 'ab-collection-followed-artists-only': '1', 'ab-collection-hide-unavailable-albums': '0', 'ab-collection-offline-mode': '0', 'ab-collection-union': '1', 'ab-desktop-hide-follow': '0', 'ab-desktop-playlist-annotation-edit': '1', 'ab-mobile-discover': '0', 'ab-mobile-running-onlymanualmode': 'only-manual', 'ab-mobile-running-tempo-detection': 'Control', 'ab-mobile-social-feed': '1', 'ab-mobile-startpage': '0', 'ab-moments-experience': '0', 'ab-new-share-flow': '0', 'ab-play-history': '0', 'ab-playlist-extender': '5', 'ab-sugarpills-sanity-check': '0', 'ab-test-group': '779', 'ab-watch-now': '0', 'ab_recently_played_feature_time_filter_threshold': 'com.spotify.gaia=30,driving-mode=120,spotify%3Ainternal%3Astartpage=30', 'ad-catalogues': 'spotify', 'ad-formats-preroll-video': '0', 'ad-formats-video-takeover': '1', 'ad-persist-reward-time': '0', 'ad-session-persistence': '1', 'ad-use-adlogic': 'stream', 'ads': '1', 'allow-override-internal-prefs': '0', 'ap-resolve-pods': '0', 'app-developer': '0', 'arsenal_country': '1', 'audio-preview-url-template': 'https://p.scdn.co/mp3-preview/{id}', 'backend-advised-bitrate': '1', 'browse-overview-enabled': '1', 'buffering-strategy': '0', 'buffering-strategy-parameters': '0.8:0.2:0.0:0.0:0.0:0.0:1.0:10:10:2000:10000:10485760', 'capper-profile': None, 'capping-bar-threshold': '3601', 'catalogue': 'free', 'collection': '1', 'created_by_partner': None, 'enable-annotations': '2', 'enable-annotations-read': '0', 'enable-autostart': '1', 'enable-crossfade': '1', 'enable-gapless': '1', 'expiry': '1', 'explicit-content': '1', 'fb-grant-permission-local-render': '0', 'fb-info-confirmation': 'control', 'financial-product': 'pr:open,tc:0', 'head-file-caching': '1', 'head-files': '1', 'head-files-url': 'https://heads-fa.scdn.co/head/{file_id}', 'high-bitrate': '0', 'image-url': 'https://i.scdn.co/image/{file_id}', 'incognito_mode_timeout': '21600', 'india-experience': '0', 'instant-search': '0', 'instant-search-expand-sidebar': '0', 'is_email_verified': '1', 'key-caching-max-count': '10000', 'key-caching-max-offline-seconds': '1800', 'key-memory-cache-mode': '1:15,300', 'lastfm-session': None, 'libspotify': '0', 'license-acceptance-grace-days': '30', 'license-agreements': None, 'local-files-import': '0', 'metadata-link-lookup-modes': '0', 'mobile': '0', 'mobile-browse': '0', 'mobile-login': '0', 'mobile-payment': '0', 'name': 'Spotify Free', 'network-operator-premium-activation': '1', 'nft-disabled': '1', 'npt-disabled': '2', 'offline': '0', 'on-demand': '1', 'pause-after': '18000', 'payments-locked-state': '0', 'player-license': 'on-demand', 'playlist-annotations-markup': '0', 'playlist-folders': '1', 'preferred-locale': 'en', 'prefetch-keys': '1', 'prefetch-strategy': '0', 'prefetch-window-max': '2', 'profile-image-upload': '1', 'publish-activity': '0', 'publish-playlist': '1', 'radio': '1', 'remote-control': '6', 'send-email': '0', 'shows-collection': '1', 'shows-collection-jam': '1', 'shuffle': '0', 'shuffle-algorithm': '1', 'sidebar-navigation-enabled': '0', 'storage-size-config': '10240,90,500,3', 'streaming': '1', 'streaming-rules': None, 'track-cap': '0', 'ugc-abuse-report': '1', 'ugc-abuse-report-url': 'https://support.spotify.com/abuse/?uri={uri}', 'use-fb-publish-backend': '2', 'use-pl3': '0', 'use-playlist-app': '0', 'use-playlist-uris': '0', 'user-profile-show-invitation-codes': '0', 'video-cdn-sampling': '1', 'video-device-blacklisted': '0', 'video-initial-bitrate': '200000', 'video-keyframe-url': 'http://keyframes-fa.cdn.spotify.com/keyframes/v1/sources/{source_id}/keyframe/heights/{height}/timestamps/{timestamp_ms}.jpg', 'video-manifest-url': 'https://spclient.wg.spotify.com/manifests/v6/{type}/sources/{source_id}/options/supports_drm', 'video-wifi-initial-bitrate': '800000', 'wanted-licenses': None, 'widevine-license-url': 'https://spclient.wg.spotify.com/widevine-license/v1/video/license'}
INFO:Librespot:Session:Skipping 1f
INFO:Librespot:Session:Skipping 69
DEBUG:urllib3.connectionpool:https://apresolve.spotify.com:443 "GET /?type=dealer HTTP/1.1" 200 None
DEBUG:Librespot:TokenProvider:Token expired or not suitable, requesting again. scopes: ['playlist-read'], old_token: None
DEBUG:Librespot:MercuryClient:Send Mercury request, seq: 0, uri: hm://keymaster/token/authenticated?scope=playlist-read&client_id=65b708073fc0480ea92a077233ca87bd&device_id=d6f07bbe25096c88a475cea32cec6fb71ec3376c, method: GET
DEBUG:Librespot:MercuryClient:Handling packet, cmd: 0xb5, seq: 8560867902608113664, flags: b'\x01', parts: 1
DEBUG:Librespot:MercuryClient:Couldn't dispatch Mercury event seq: 8560867902608113664, uri: hm://pusher/v1/connections/ZDZmMDdiYmUyNTA5NmM4OGE0NzVjZWEzMmNlYzZmYjcxZWMzMzc2YytBUCt0Y3A6Ly9nYWUyLWFjY2Vzc3BvaW50LWEtNnZueC5nYWUyLnNwb3RpZnkubmV0OjUwMDkrNTVEMjlGMUI5QjkwOTBCN0YxOTNBMTREMTBDQjYxMTlCMjRDRUNCOThERDIyQTVEN0M4MUEzMkE4MUI5QjJCOA%3D%3D, code: 200, payload: b''
DEBUG:Librespot:Session:Received 0x10: 28c3d872056c29887aa89b2bb07525c155531adf
DEBUG:Librespot:MercuryClient:Handling packet, cmd: 0xb2, seq: 0, flags: b'\x01', parts: 2
DEBUG:Librespot:TokenProvider:Updated token successfully! scopes: ['playlist-read'], new_token: <librespot.core.TokenProvider.StoredToken object at 0x7fce46ea1a00>
INFO:Librespot:Session:Authenticated as 315q64kqplnebfldqygmmqpqelye!
DEBUG:spodcast.app:episode_id_str None. show_id_str 1OLcQdw2PFDPG1jo3s0wbp
DEBUG:spodcast.app:show_id: <librespot.metadata.ShowId object at 0x7fce46e635b0>
INFO:Librespot:Session:Skipping unknown command cmd: 0x75, payload: b'\x00\x00\x00'
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): clienttoken.spotify.com:443
DEBUG:urllib3.connectionpool:https://clienttoken.spotify.com:443 "POST /v1/clienttoken HTTP/1.1" 200 None
DEBUG:Librespot:ApiClient:Updated client token: AABawkvhKpjRCTeXYN8J9Fm7whJBiyYqFevKcp/uBKjE8xEJD56Wh9uH5hjEQw3+p8Qw1wE395/TCXem8+Puv960Ckf8VQ3b/Y1ziwWY6pVBa+3Pqx3/7eHIGcGd6BBhDhKzWuT2bWBdxCbBXWMglyh6BuxeQO84T+B7foTQ3NTUTMLpdmz7GyflIfgRjOIa/HwXQWLIB1HxQ3nreDq5xunuKXj9kUCwy7r5Oc5j5dFPDCeV
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): guc3-spclient.spotify.com:443
DEBUG:urllib3.connectionpool:https://guc3-spclient.spotify.com:443 "GET /metadata/4/show/3bc200e4655841529d8a7a3d2d027e23 HTTP/1.1" 200 15822
DEBUG:spodcast.app:episode_id: e1a3290cae685f4ca143a3afb8fed29e
INFO:spodcast.podcast:Fetching episode information...
DEBUG:urllib3.connectionpool:https://guc3-spclient.spotify.com:443 "GET /metadata/4/episode/e1a3290cae685f4ca143a3afb8fed29e HTTP/1.1" 200 796
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): traffic.megaphone.fm:443
DEBUG:urllib3.connectionpool:https://traffic.megaphone.fm:443 "GET /GLT9899421262.mp3?updated=1661274798 HTTP/1.1" 302 102
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): dcs.megaphone.fm:443
DEBUG:urllib3.connectionpool:https://dcs.megaphone.fm:443 "GET /GLT9899421262.mp3?key=20c38c11dee1691c0afed7c44f8d5525 HTTP/1.1" 200 69670934
INFO:spodcast.podcast:Skipped Fest & Flauschig: #BOOMERCRINGE 34
INFO:spodcast.podcast:Fetching show information...
DEBUG:urllib3.connectionpool:https://guc3-spclient.spotify.com:443 "GET /metadata/4/show/3bc200e4655841529d8a7a3d2d027e23 HTTP/1.1" 200 15822

Podcast episodes are not completely downloading

I noticed that for some podcasts the end of the episodes are missing.

For example I downloaded this show: https://open.spotify.com/show/5JYitG4bOM3sVmAQRdX1Na and for every episode the last minute or so is missing in the downloaded file.

After running the debug output I noticed that Librespot stopped downloading before all chunks were completed:

DEBUG:Librespot:Session:Chunk 156/181 completed, cached: False, stream: file_id: 7c9d5d4e37e4fb6fd91b2460c54afb2059c11daa

DEBUG:urllib3.connectionpool:https://audio4-ak-spotify-com.akamaized.net:443 "GET /audio/7c9d5d4e37e4fb6fd91b2460c54afb2059c11daa?__token__=exp=1657893805~hmac=9f418cd6ab2eaa013c4147924038e9eda979bb052984e084697417f1b16659e9 HTTP/1.1" 206 131072

DEBUG:Librespot:Session:Chunk 157/181 completed, cached: False, stream: file_id: 7c9d5d4e37e4fb6fd91b2460c54afb2059c11daa

DEBUG:urllib3.connectionpool:https://audio4-ak-spotify-com.akamaized.net:443 "GET /audio/7c9d5d4e37e4fb6fd91b2460c54afb2059c11daa?__token__=exp=1657893805~hmac=9f418cd6ab2eaa013c4147924038e9eda979bb052984e084697417f1b16659e9 HTTP/1.1" 206 131072

DEBUG:Librespot:Session:Chunk 158/181 completed, cached: False, stream: file_id: 7c9d5d4e37e4fb6fd91b2460c54afb2059c11daa

INFO:spodcast.podcast:transcoding ogg->mp3

This has to be some issues with certain shows, as either all of the episodes of a show are missing the last minute or they are all fine.

An example for a working podcast would be:
https://open.spotify.com/show/7BTOsF2boKmlYr76BelijW

I have no clue what the issue could be and am open for any suggestion!

Cannot download episodes anymore (Not found for url exception)

Hi,

somehow I cannot download anymore episodes.

The full log:

DEBUG:spodcast.spodcast:args: Namespace(config_location='/mnt/audio/spodcast/spodcast.json', prepare_feed=False, urls=['https://open.spotify.com/show/1OLcQdw2PFDPG1jo3s0wbp'], login=None, root_path='/mnt/audio/spodcast', skip_existing=None, retry=None, max_episodes='5', chunk_size=None, download_real_time=None, language=None, credentials_location=None, rss_feed=None, transcode=None, log_level='debug', func=<function client at 0xb6b07fa0>)
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): apresolve.spotify.com:443
DEBUG:urllib3.connectionpool:https://apresolve.spotify.com:443 "GET /?type=accesspoint HTTP/1.1" 200 None
INFO:Librespot:Session:Created new session! device_id: xxxxxxxxxxxxxxxxxxxxxxx, ap: ap-gew1.spotify.com:4070
INFO:Librespot:Session:Connection successfully!
INFO:Librespot:Session:Session.Receiver started
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): apresolve.spotify.com:443
DEBUG:urllib3.connectionpool:https://apresolve.spotify.com:443 "GET /?type=spclient HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): apresolve.spotify.com:443
INFO:Librespot:Session:Skipping 02
INFO:Librespot:Session:Received license_version: 0
INFO:Librespot:Session:Received country_code: DE
DEBUG:Librespot:Session:Parsed product info: {'type': 'open', 'ab-ad-player-targeting': '1', 'ab-ad-requester': '1', 'ab-android-push-notifications': '1', 'ab-browse-music-tuesday': '1', 'ab-collection-bookmark-model': '1', 'ab-collection-followed-artists-only': '1', 'ab-collection-hide-unavailable-albums': '0', 'ab-collection-offline-mode': '0', 'ab-collection-union': '1', 'ab-desktop-hide-follow': '0', 'ab-desktop-playlist-annotation-edit': '1', 'ab-mobile-discover': '0', 'ab-mobile-running-onlymanualmode': 'only-manual', 'ab-mobile-running-tempo-detection': 'Control', 'ab-mobile-social-feed': '1', 'ab-mobile-startpage': '0', 'ab-moments-experience': '0', 'ab-new-share-flow': '0', 'ab-play-history': '0', 'ab-playlist-extender': '5', 'ab-sugarpills-sanity-check': '2', 'ab-test-group': '767', 'ab-watch-now': '0', 'ab_recently_played_feature_time_filter_threshold': 'com.spotify.gaia=30,driving-mode=120,spotify%3Ainternal%3Astartpage=30', 'ad-catalogues': 'spotify', 'ad-formats-preroll-video': '0', 'ad-formats-video-takeover': '1', 'ad-persist-reward-time': '0', 'ad-session-persistence': '1', 'ad-use-adlogic': 'stream', 'ads': '1', 'allow-override-internal-prefs': '0', 'ap-resolve-pods': '0', 'app-developer': '0', 'arsenal_country': '1', 'audio-preview-url-template': 'https://p.scdn.co/mp3-preview/{id}', 'backend-advised-bitrate': '1', 'browse-overview-enabled': '1', 'buffering-strategy': '0', 'buffering-strategy-parameters': '0.8:0.2:0.0:0.0:0.0:0.0:1.0:10:10:2000:10000:10485760', 'capper-profile': None, 'capping-bar-threshold': '3601', 'catalogue': 'free', 'collection': '1', 'enable-annotations': '2', 'enable-annotations-read': '0', 'enable-autostart': '1', 'enable-crossfade': '1', 'enable-gapless': '1', 'expiry': '1', 'explicit-content': '1', 'fb-grant-permission-local-render': '0', 'fb-info-confirmation': 'control', 'financial-product': 'pr:open,tc:0', 'head-file-caching': '1', 'head-files': '1', 'head-files-url': 'https://heads-fa.scdn.co/head/{file_id}', 'high-bitrate': '0', 'image-url': 'https://i.scdn.co/image/{file_id}', 'incognito_mode_timeout': '21600', 'india-experience': '0', 'instant-search': '0', 'instant-search-expand-sidebar': '0', 'is_email_verified': '0', 'key-caching-max-count': '10000', 'key-caching-max-offline-seconds': '1800', 'key-memory-cache-mode': '1:15,300', 'lastfm-session': None, 'libspotify': '0', 'license-acceptance-grace-days': '30', 'license-agreements': None, 'local-files-import': '0', 'metadata-link-lookup-modes': '0', 'mobile': '0', 'mobile-browse': '0', 'mobile-login': '0', 'mobile-payment': '0', 'name': 'Spotify Free', 'network-operator-premium-activation': '1', 'nft-disabled': '1', 'npt-disabled': '2', 'offline': '0', 'on-demand': '1', 'pause-after': '18000', 'payments-locked-state': '0', 'player-license': 'on-demand', 'playlist-annotations-markup': '0', 'playlist-folders': '1', 'preferred-locale': 'en', 'prefetch-keys': '1', 'prefetch-strategy': '0', 'prefetch-window-max': '2', 'profile-image-upload': '1', 'public-toplist': '0', 'publish-activity': '0', 'publish-playlist': '0', 'radio': '1', 'remote-control': '6', 'send-email': '0', 'shows-collection': '1', 'shows-collection-jam': '1', 'shuffle': '0', 'shuffle-algorithm': '1', 'sidebar-navigation-enabled': '0', 'storage-size-config': '10240,90,500,3', 'streaming': '1', 'streaming-rules': None, 'track-cap': '0', 'ugc-abuse-report': '1', 'ugc-abuse-report-url': 'https://support.spotify.com/abuse/?uri={uri}', 'use-fb-publish-backend': '2', 'use-pl3': '0', 'use-playlist-app': '0', 'use-playlist-uris': '0', 'user-profile-show-invitation-codes': '0', 'video-cdn-sampling': '1', 'video-device-blacklisted': '0', 'video-initial-bitrate': '200000', 'video-keyframe-url': 'http://keyframes-fa.cdn.spotify.com/keyframes/v1/sources/{source_id}/keyframe/heights/{height}/timestamps/{timestamp_ms}.jpg', 'video-manifest-url': 'https://spclient.wg.spotify.com/manifests/v6/{type}/sources/{source_id}/options/supports_drm', 'video-wifi-initial-bitrate': '800000', 'wanted-licenses': None, 'widevine-license-url': 'https://spclient.wg.spotify.com/widevine-license/v1/video/license'}
INFO:Librespot:Session:Skipping 69
INFO:Librespot:Session:Skipping 1f
DEBUG:Librespot:MercuryClient:Handling packet, cmd: 0xb5, seq: 331586318658174976, flags: b'\x01', parts: 1
DEBUG:Librespot:MercuryClient:Couldn't dispatch Mercury event seq: 331586318658174976, uri: hm://pusher/v1/connections/ZjU4MmIxNmNiODE1NWM3YmMxZjgxMDhhMTZmNjRjZjFjODRjMTA5YytBUCt0Y3A6Ly9nZXcxLWFjY2Vzc3BvaW50LWEtZ2Q0OS5nZXcxLnNwb3RpZnkubmV0OjUwMDMrRDEzMDNCNkMwQ0REN0EyOTA3MTg5QzdENjJFOTE4QkNDNjc5RjlBMTJEN0UwNDE3RTZCQjI3NTA1QjcyMDFDNQ%3D%3D, code: 200, payload: b''
DEBUG:Librespot:Session:Received 0x10: 71ecf06a1db7dd2e153baadbd9bdebe8c0626907
INFO:Librespot:Session:Skipping unknown command cmd: 0x75, payload: b'\x00\x00\x00'
DEBUG:urllib3.connectionpool:https://apresolve.spotify.com:443 "GET /?type=dealer HTTP/1.1" 200 None
DEBUG:Librespot:TokenProvider:Token expired or not suitable, requesting again. scopes: ['playlist-read'], old_token: None
DEBUG:Librespot:MercuryClient:Send Mercury request, seq: 0, uri: hm://keymaster/token/authenticated?scope=playlist-read&client_id=xxxxxxxxxxxxxxxx&device_id=xxxxxxxxxxxxxxxx, method: GET
DEBUG:Librespot:MercuryClient:Handling packet, cmd: 0xb2, seq: 0, flags: b'\x01', parts: 2
DEBUG:Librespot:TokenProvider:Updated token successfully! scopes: ['playlist-read'], new_token: <librespot.core.TokenProvider.StoredToken object at 0xb5c38f28>
INFO:Librespot:Session:Authenticated as xxxxx!
DEBUG:spodcast.app:episode_id None. show_id 1OLcQdw2PFDPG1jo3s0wbp
INFO:spodcast.podcast:Fetching episodes...
DEBUG:Librespot:TokenProvider:Token expired or not suitable, requesting again. scopes: ['user-read-email'], old_token: None
DEBUG:Librespot:MercuryClient:Send Mercury request, seq: 1, uri: hm://keymaster/token/authenticated?scope=user-read-email&client_id=xxxxxxxxxxxxxxxx&device_id=xxxxxxxxxxxxxxxx, method: GET
DEBUG:Librespot:MercuryClient:Handling packet, cmd: 0xb2, seq: 1, flags: b'\x01', parts: 2
DEBUG:Librespot:TokenProvider:Updated token successfully! scopes: ['user-read-email'], new_token: <librespot.core.TokenProvider.StoredToken object at 0xb5c388e0>
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=0 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=50 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=100 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=150 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=200 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=250 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=300 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=350 HTTP/1.1" 200 None
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/shows/1OLcQdw2PFDPG1jo3s0wbp/episodes?limit=50&offset=400 HTTP/1.1" 200 None
INFO:spodcast.podcast:Fetching episode information...
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.spotify.com:443
DEBUG:urllib3.connectionpool:https://api.spotify.com:443 "GET /v1/episodes/4cSLQpgJt3mIky4fnjnsPb HTTP/1.1" 200 None
DEBUG:spodcast.podcast:episode info: {'audio_preview_url': 'https://p.scdn.co/mp3-preview/298d41f47db5ba1832183ee0ee563ce30e524650', 'content_type': 'PODCAST_EPISODE', 'description': 'Wie Nacktmulle ihr schreckliches Regiment führen und E-Scooter ellipsenförmige Problemzonen schaffen. Ey Leute! Frech kommt weiter. Einfach mal müde ne Folge aufnehmen und auf dem flambierten Parmesanrad in den Sonnenuntergang reiten. Learn more about your ad choices. Visit podcastchoices.com/adchoices', 'duration_ms': 2978246, 'explicit': False, 'external_urls': {'spotify': 'https://open.spotify.com/episode/4cSLQpgJt3mIky4fnjnsPb'}, 'href': 'https://api.spotify.com/v1/episodes/4cSLQpgJt3mIky4fnjnsPb', 'html_description': '

Wie Nacktmulle ihr schreckliches Regiment führen und E-Scooter ellipsenförmige Problemzonen schaffen. Ey Leute! Frech kommt weiter. Einfach mal müde ne Folge aufnehmen und auf dem flambierten Parmesanrad in den Sonnenuntergang reiten.

Learn more about your ad choices. Visit podcastchoices.com/adchoices

', 'id': '4cSLQpgJt3mIky4fnjnsPb', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6765630000ba8a21e277ef5fc2ffa449254d37', 'width': 640}, {'height': 300, 'url': 'https://i.scdn.co/image/ab67656300005f1f21e277ef5fc2ffa449254d37', 'width': 300}, {'height': 64, 'url': 'https://i.scdn.co/image/ab6765630000f68d21e277ef5fc2ffa449254d37', 'width': 64}], 'is_externally_hosted': False, 'is_paywall_content': False, 'is_playable': True, 'language': 'de', 'languages': ['de'], 'name': 'Einfach müde', 'release_date': '2022-06-18', 'release_date_precision': 'day', 'resume_point': {'fully_played': False, 'resume_position_ms': 0}, 'show': {'available_markets': ['AD', 'AE', 'AG', 'AL', 'AM', 'AO', 'AR', 'AT', 'AU', 'AZ', 'BA', 'BB', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BN', 'BO', 'BR', 'BS', 'BT', 'BW', 'BZ', 'CA', 'CH', 'CI', 'CL', 'CM', 'CO', 'CR', 'CV', 'CW', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'ES', 'FI', 'FJ', 'FM', 'FR', 'GA', 'GB', 'GD', 'GE', 'GH', 'GM', 'GN', 'GQ', 'GR', 'GT', 'GW', 'GY', 'HK', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KH', 'KI', 'KM', 'KN', 'KW', 'LA', 'LB', 'LC', 'LI', 'LR', 'LS', 'LT', 'LU', 'LV', 'MA', 'MC', 'ME', 'MG', 'MH', 'MK', 'ML', 'MN', 'MO', 'MR', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NE', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NZ', 'OM', 'PA', 'PE', 'PG', 'PH', 'PL', 'PS', 'PT', 'PW', 'PY', 'QA', 'RO', 'RS', 'RW', 'SA', 'SB', 'SC', 'SE', 'SG', 'SI', 'SK', 'SL', 'SM', 'SN', 'SR', 'ST', 'SV', 'SZ', 'TD', 'TG', 'TH', 'TL', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'US', 'UY', 'UZ', 'VC', 'VN', 'VU', 'WS', 'XK', 'ZA', 'ZM', 'ZW'], 'copyrights': [], 'description': 'Fest & Flauschig mit Jan Böhmermann und Olli Schulz. Der preisgekrönte, verblüffend fabelhafte, grenzenlos fantastische Podcast für sie, ihn und es.', 'explicit': False, 'external_urls': {'spotify': 'https://open.spotify.com/show/1OLcQdw2PFDPG1jo3s0wbp'}, 'href': 'https://api.spotify.com/v1/shows/1OLcQdw2PFDPG1jo3s0wbp', 'html_description': '

Fest & Flauschig mit Jan Böhmermann und Olli Schulz. Der preisgekrönte, verblüffend fabelhafte, grenzenlos fantastische Podcast für sie, ihn und es.

', 'id': '1OLcQdw2PFDPG1jo3s0wbp', 'images': [{'height': 640, 'url': 'https://i.scdn.co/image/ab6765630000ba8a21e277ef5fc2ffa449254d37', 'width': 640}, {'height': 300, 'url': 'https://i.scdn.co/image/ab67656300005f1f21e277ef5fc2ffa449254d37', 'width': 300}, {'height': 64, 'url': 'https://i.scdn.co/image/ab6765630000f68d21e277ef5fc2ffa449254d37', 'width': 64}], 'is_externally_hosted': False, 'languages': ['de'], 'media_type': 'audio', 'name': 'Fest & Flauschig', 'publisher': 'Jan Böhmermann & Olli Schulz', 'total_episodes': 415, 'type': 'show', 'uri': 'spotify:show:1OLcQdw2PFDPG1jo3s0wbp'}, 'type': 'episode', 'uri': 'spotify:episode:4cSLQpgJt3mIky4fnjnsPb'}
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api-partner.spotify.com:443
DEBUG:urllib3.connectionpool:https://api-partner.spotify.com:443 "GET /pathfinder/v1/query?operationName=getEpisode&variables=%7B%22uri%22:%22spotify:episode:4cSLQpgJt3mIky4fnjnsPb%22%7D&extensions=%7B%22persistedQuery%22:%7B%22version%22:1,%22sha256Hash%22:%22224ba0fd89fcfdfb3a15fa2d82a6112d3f4e2ac88fba5c6713de04d1b72cf482%22%7D%7D HTTP/1.1" 200 None
DEBUG:spodcast.podcast:('{"data":{"episode":{"id":"4cSLQpgJt3mIky4fnjnsPb","uri":"spotify:episode:4cSLQpgJt3mIky4fnjnsPb","name":"Einfach müde","htmlDescription":"

Wie Nacktmulle ihr schreckliches Regiment führen und E-Scooter ellipsenförmige Problemzonen schaffen. Ey Leute! Frech kommt weiter. Einfach mal müde ne Folge aufnehmen und auf dem flambierten Parmesanrad in den Sonnenuntergang reiten.

Learn more about your ad choices. Visit <a href=\"https://podcastchoices.com/adchoices\\" rel=\"nofollow\">podcastchoices.com/adchoices

","description":"Wie Nacktmulle ihr schreckliches Regiment führen und E-Scooter ellipsenförmige Problemzonen schaffen. Ey Leute! Frech kommt weiter. Einfach mal müde ne Folge aufnehmen und auf dem flambierten Parmesanrad in den Sonnenuntergang reiten. Learn more about your ad choices. Visit podcastchoices.com/adchoices","duration":{"totalMilliseconds":2978246},"audio":{"items":[{"url":"https://p.scdn.co/mp3-preview/649ad573183f3e299658d43dcead5fd5e71e2c78","format":"AAC_24","fileId":"649ad573183f3e299658d43dcead5fd5e71e2c78","externallyHosted":false},{"url":"https://p.scdn.co/mp3-preview/531e8201de62066a4f78427f378d134e3e87701b","format":"MP4_128_DUAL","fileId":"531e8201de62066a4f78427f378d134e3e87701b","externallyHosted":false},{"url":"https://p.scdn.co/mp3-preview/e1f819cf9b3c282b00a64e26f12718c64a28fd60","format":"MP4_128","fileId":"e1f819cf9b3c282b00a64e26f12718c64a28fd60","externallyHosted":false},{"url":"https://p.scdn.co/mp3-preview/8f4418c60184e9b0776ae16e4d2766024d103f8d","format":"OGG_VORBIS_96","fileId":"8f4418c60184e9b0776ae16e4d2766024d103f8d","externallyHosted":false}]},"audioPreview":{"url":"https://p.scdn.co/mp3-preview/298d41f47db5ba1832183ee0ee563ce30e524650","format":"MP3_96"},"playability":{"playable":true,"reason":"PLAYABLE"},"playedState":{"playPositionMilliseconds":0,"state":"NOT_STARTED"},"releaseDate":{"isoString":"2022-06-18T21:50:00Z"},"contentRating":{"label":"NONE"},"coverArt":{"sources":[{"url":"https://i.scdn.co/image/ab6765630000f68d21e277ef5fc2ffa449254d37","width":64,"height":64},{"url":"https://i.scdn.co/image/ab67656300005f1f21e277ef5fc2ffa449254d37","width":300,"height":300},{"url":"https://i.scdn.co/image/ab6765630000ba8a21e277ef5fc2ffa449254d37","width":640,"height":640}]},"type":"PODCAST_EPISODE","podcast":{"uri":"spotify:show:1OLcQdw2PFDPG1jo3s0wbp","name":"Fest & Flauschig","coverArt":{"sources":[{"url":"https://i.scdn.co/image/ab6765630000f68d21e277ef5fc2ffa449254d37","width":64,"height":64},{"url":"https://i.scdn.co/image/ab67656300005f1f21e277ef5fc2ffa449254d37","width":300,"height":300},{"url":"https://i.scdn.co/image/ab6765630000ba8a21e277ef5fc2ffa449254d37","width":640,"height":640}]},"trailer":null,"showTypes":["SHOW_TYPE_EXCLUSIVE"]},"sharingInfo":{"shareUrl":"https://open.spotify.com/episode/4cSLQpgJt3mIky4fnjnsPb?si=FUC2Gy4tQFOJ2CUmXOxVyA","shareId":"FUC2Gy4tQFOJ2CUmXOxVyA"},"segments":{"segments":{"totalCount":0}}}},"extensions":{"cacheControl":{"version":1.0,"hints":[]}}}', {'data': {'episode': {'id': '4cSLQpgJt3mIky4fnjnsPb', 'uri': 'spotify:episode:4cSLQpgJt3mIky4fnjnsPb', 'name': 'Einfach müde', 'htmlDescription': '

Wie Nacktmulle ihr schreckliches Regiment führen und E-Scooter ellipsenförmige Problemzonen schaffen. Ey Leute! Frech kommt weiter. Einfach mal müde ne Folge aufnehmen und auf dem flambierten Parmesanrad in den Sonnenuntergang reiten.

Learn more about your ad choices. Visit podcastchoices.com/adchoices

', 'description': 'Wie Nacktmulle ihr schreckliches Regiment führen und E-Scooter ellipsenförmige Problemzonen schaffen. Ey Leute! Frech kommt weiter. Einfach mal müde ne Folge aufnehmen und auf dem flambierten Parmesanrad in den Sonnenuntergang reiten. Learn more about your ad choices. Visit podcastchoices.com/adchoices', 'duration': {'totalMilliseconds': 2978246}, 'audio': {'items': [{'url': 'https://p.scdn.co/mp3-preview/649ad573183f3e299658d43dcead5fd5e71e2c78', 'format': 'AAC_24', 'fileId': '649ad573183f3e299658d43dcead5fd5e71e2c78', 'externallyHosted': False}, {'url': 'https://p.scdn.co/mp3-preview/531e8201de62066a4f78427f378d134e3e87701b', 'format': 'MP4_128_DUAL', 'fileId': '531e8201de62066a4f78427f378d134e3e87701b', 'externallyHosted': False}, {'url': 'https://p.scdn.co/mp3-preview/e1f819cf9b3c282b00a64e26f12718c64a28fd60', 'format': 'MP4_128', 'fileId': 'e1f819cf9b3c282b00a64e26f12718c64a28fd60', 'externallyHosted': False}, {'url': 'https://p.scdn.co/mp3-preview/8f4418c60184e9b0776ae16e4d2766024d103f8d', 'format': 'OGG_VORBIS_96', 'fileId': '8f4418c60184e9b0776ae16e4d2766024d103f8d', 'externallyHosted': False}]}, 'audioPreview': {'url': 'https://p.scdn.co/mp3-preview/298d41f47db5ba1832183ee0ee563ce30e524650', 'format': 'MP3_96'}, 'playability': {'playable': True, 'reason': 'PLAYABLE'}, 'playedState': {'playPositionMilliseconds': 0, 'state': 'NOT_STARTED'}, 'releaseDate': {'isoString': '2022-06-18T21:50:00Z'}, 'contentRating': {'label': 'NONE'}, 'coverArt': {'sources': [{'url': 'https://i.scdn.co/image/ab6765630000f68d21e277ef5fc2ffa449254d37', 'width': 64, 'height': 64}, {'url': 'https://i.scdn.co/image/ab67656300005f1f21e277ef5fc2ffa449254d37', 'width': 300, 'height': 300}, {'url': 'https://i.scdn.co/image/ab6765630000ba8a21e277ef5fc2ffa449254d37', 'width': 640, 'height': 640}]}, 'type': 'PODCAST_EPISODE', 'podcast': {'uri': 'spotify:show:1OLcQdw2PFDPG1jo3s0wbp', 'name': 'Fest & Flauschig', 'coverArt': {'sources': [{'url': 'https://i.scdn.co/image/ab6765630000f68d21e277ef5fc2ffa449254d37', 'width': 64, 'height': 64}, {'url': 'https://i.scdn.co/image/ab67656300005f1f21e277ef5fc2ffa449254d37', 'width': 300, 'height': 300}, {'url': 'https://i.scdn.co/image/ab6765630000ba8a21e277ef5fc2ffa449254d37', 'width': 640, 'height': 640}]}, 'trailer': None, 'showTypes': ['SHOW_TYPE_EXCLUSIVE']}, 'sharingInfo': {'shareUrl': 'https://open.spotify.com/episode/4cSLQpgJt3mIky4fnjnsPb?si=FUC2Gy4tQFOJ2CUmXOxVyA', 'shareId': 'FUC2Gy4tQFOJ2CUmXOxVyA'}, 'segments': {'segments': {'totalCount': 0}}}}, 'extensions': {'cacheControl': {'version': 1.0, 'hints': []}}})
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api-partner.spotify.com:443
DEBUG:urllib3.connectionpool:https://api-partner.spotify.com:443 "GET /pathfinder/v1/query?operationName=getEpisode&variables=%7B%22uri%22:%22spotify:episode:4cSLQpgJt3mIky4fnjnsPb%22%7D&extensions=%7B%22persistedQuery%22:%7B%22version%22:1,%22sha256Hash%22:%22224ba0fd89fcfdfb3a15fa2d82a6112d3f4e2ac88fba5c6713de04d1b72cf482%22%7D%7D HTTP/1.1" 200 None
DEBUG:spodcast.podcast:download_url: https://p.scdn.co/mp3-preview/8f4418c60184e9b0776ae16e4d2766024d103f8d
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): p.scdn.co:443
DEBUG:urllib3.connectionpool:https://p.scdn.co:443 "GET /mp3-preview/8f4418c60184e9b0776ae16e4d2766024d103f8d HTTP/1.1" 404 0
Traceback (most recent call last):
File "/usr/local/bin/spodcast", line 8, in
sys.exit(main())
File "/usr/local/lib/python3.9/dist-packages/spodcast/main.py", line 42, in main
args.func(args)
File "/usr/local/lib/python3.9/dist-packages/spodcast/app.py", line 24, in client
download_episode(episode)
File "/usr/local/lib/python3.9/dist-packages/spodcast/podcast.py", line 172, in download_episode
path, size, mimetype = download_file(download_url, filepath)
File "/usr/local/lib/python3.9/dist-packages/spodcast/podcast.py", line 83, in download_file
r.raise_for_status() # Will only raise for 4xx codes, so...
File "/usr/local/lib/python3.9/dist-packages/requests/models.py", line 960, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: Not Found for url: https://p.scdn.co/mp3-preview/8f4418c60184e9b0776ae16e4d2766024d103f8d

Notes:

Let me know if I can assist somehow:)
Thanks!

Increase maximum episodes number in feed manager

Hi,

would it be possible to allow a higher number than 5 episodes to sync (max episodes) in the feed manager?
I have a podcast that somehow have their episodes in the wrong order so the automatic sync isn't working for this one.

Thanks!

Generate HTML Content Independent of Login

For the docker-compose.yml and corresponding images, it would be nice if the --prepare-feed flag could generate the HTML for the base application (i.e. without any podcasts downloaded yet).

With the current state of the docker-compose.yml file I am about to PR, if a user attempts to visit the application the first time they run the docker-compose.yml they will be met with a 404 error (because Spodcast has not run yet). By setting CRON_SCHEDULE to something like * * * * * a user can workaround that -- but it'd be nice as an end-user to know the application is actually running whether or not any podcasts have been downloaded yet.

Symbols in password causes errors using docker-compose

spodcast-spodcast-cron-1  | crond: USER root pid  34 cmd SPODCAST_ROOT="/data" SPODCAST_HTML="/data/html" SPODCAST_CONFIG_JSON="/data/spodcast.json" SPOTIFY_CREDS_JSON="/data/creds.json" SPOTIFY_RC_PATH="/data/spotify.rc" **SPOTIFY_PASSWORD="pnI7**
spodcast-spodcast-cron-1  | crond: child running /bin/bash
spodcast-spodcast-cron-1  | crond: USER root pid  35 cmd chown -R 101:101 /data/html
spodcast-spodcast-cron-1  | /bin/bash: -c: line 1: unexpected EOF while looking for matching `"'
spodcast-spodcast-cron-1  | /bin/bash: -c: line 2: syntax error: unexpected end of file
spodcast-spodcast-cron-1  | crond: wakeup dt=10

the next char in my password 'pnl7' is a symbol, #! to be precise. This caused issues when running with docker-compose.yml. Having changed my password to a more simple password, all is well using the provided compose.

buzzsprout.com requires useragent

When trying to retrieve a podcast that uses buzzsprout.com, e.g. https://open.spotify.com/episode/0r7ir53f9IEB1w4XTIFddJ we get a 403 error:

INFO:spodcast.podcast:Fetching episode information...

Traceback (most recent call last):
File "/home/pi/spodcast/bin/spodcast", line 8, in
sys.exit(main())
File "/home/pi/spodcast/lib/python3.9/site-packages/spodcast/main.py", line 42, in main
args.func(args)
File "/home/pi/spodcast/lib/python3.9/site-packages/spodcast/app.py", line 24, in client
download_episode(episode_id)
File "/home/pi/spodcast/lib/python3.9/site-packages/spodcast/podcast.py", line 176, in download_episode
path, size, mimetype = download_file(download_url, filepath)
File "/home/pi/spodcast/lib/python3.9/site-packages/spodcast/podcast.py", line 77, in download_file
r.raise_for_status() # Will only raise for 4xx codes, so...
File "/home/pi/spodcast/lib/python3.9/site-packages/requests/models.py", line 1021, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://www.buzzsprout.com/2109129/15240378-charlie-stig-live-q-a-in-person-cbdcs-v-crypto-ai-v-ml-the-future.mp3

It seems as though useragents of "python*" are blocked. requests package will send a 'python-requests' useragent if none is specified, so we can just specify an empty header. We can change the function download_file in podcast.py to include an empty useragent. No 403 and the download completes then:

r = requests.get(url, stream=True, allow_redirects=True, headers={ 'User-Agent': '' })

Errors in web interface

I used the docker-compose file info from this fork: https://github.com/heywoodlh/Spodcast

When i load the webinterface i get the following errors and cannot seem to do anything inside of the webinterface

Warning: uasort() expects parameter 1 to be array, null given in /data/html/.index.php on line 69

Warning: array_keys() expects parameter 1 to be array, null given in /data/html/.index.php on line 505

Warning: Invalid argument supplied for foreach() in /data/html/.index.php on line 505

Warning: Invalid argument supplied for foreach() in /data/html/.index.php on line 581

Spotify Podcast Library now on Apple??

I was using Spodcast as a way to listen to Spotify podcasts in the Apple Podcast app... It seems as though the library is now available, or certainly the shows I listen to...

Is this a new thing? What does this mean for the future of Spodcast?

Can spodcast download podcasts that appear as tracks

I'm able to download podcasts that include /episode/ in the url i.e. https://open.spotify.com/episode/5358drsbZg3Z973JvcdWeN

However, some kids stories / podcasts appear as /tracks/ and don't seem to download i.e. https://open.spotify.com/track/2DLn7ObdemNc73MhPSRdBN

Is this a purposeful limitation to avoid allowing downloading "songs"?

Where is the run.sh file coming from?

When I pull the public image from Docker Hub and I run it, I see there is a run.sh file that actually reads the env variables passed to the docker run command. I'd like to add one more variable to support dynamic folder name, but I can't find any spec or code reference where the run.sh file is generated or copied to the Docker image.

Any pointers?

Thanks!

Possible to grab video?

@Yetangitu firstly, thank you so much for Spodcast! Secondly, I'm not a developer and so I'm unfamiliar with the etiquette of posting here (please delete if this is out of place).

Is it possible to grab the video feed alongside the audio? I appreciate that this is probably outside of the project scope. If it is possible then perhaps someone might fork at some point. I'd love to delete Spotify altogether, but I like having Picture-in-Picture while I work.

legacy-install-failure: pycryptodomex

Encountered this error using the pip installer:
error: legacy-install-failure

× Encountered error while trying to install package.
╰─> pycryptodomex
Any ideas what causes this?

Logs for the Feed update

Is there any logs for the feed update that is set inside the web application? My feeds are not fetching new episodes automatically even after many days the new episode is available in Spotify. When I manually use the "refresh" feature the the episode is fetched. With some logs I'll to check if the schedule is acctually running or any errors are occuring.

Zombie 'Exited' containers

Description:
When I run the following command, an 'exited' container is created. These 'exited' containers soon add up to 100s of zombie containers as I run this command for various podcasts every 24hrs. Any advice would be greatly appreciated.

docker run -v /home/plex/Docker/spodcast_data:/data heywoodlh/spodcast -c /data/spodcast.json --skip-existing yes --rss-feed yes --log-level info --max-episodes 10 'open.spotify.com/show/3UhsI7s4bkH1FcMZI5u9iD'

Capture

Ready-made docker-compose file

Since I already spent a couple of hours trying to get this running without success, I was wondering if it would be possible to provide a simple docker-compose file, that one could plug into Portainer and Spodcast would just work on a provided port. I imagine something like this:

version: '3'
services:
  spodcast:
    image: heywoodlh/spodcast 
    restart: always
    ports:
      - 80:80
    volumes:
      - ./spodcast:/data
    environment:
      SPOTIFY_USERNAME: "username"
      SPOTIFY_PASSWORD: "password"

By using environment variables, the initial setup could be improved so that the user would not be obliged to handle credential files himself but rather let the program do that.
Also at least for me, the whole web-server thing is really complicated with configuration and permission managment. I think, it would tremendously help beginners if something for this would be included in the docker image of Spodcast. After all, the application is of little use without a proper RSS feed server.

Since this might be a little bit more complicated to change, for the moment I would also just be happy to get some guidance how to setup a web-server in docker with the necessary steps for configuration. Thank you! :)

duration_ms is not defined

Traceback (most recent call last):
  File "/usr/local/bin/spodcast", line 8, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/site-packages/spodcast/__main__.py", line 39, in main
    args.func(args)
  File "/usr/local/lib/python3.7/site-packages/spodcast/app.py", line 24, in client
    download_episode(episode)
  File "/usr/local/lib/python3.7/site-packages/spodcast/podcast.py", line 143, in download_episode
    path, size = download_stream(stream, filepath)
  File "/usr/local/lib/python3.7/site-packages/spodcast/podcast.py", line 115, in download_stream
    delta_want = (downloaded / size) * (duration_ms/1000)
NameError: name 'duration_ms' is not defined

This error is not very verbose, how do I work past it?

Here's my command:

spodcast --root-path /tmp/spodcast/html --credentials-location /tmp/spodcast/creds.json --max-episodes 10 -p --chunk-size 1000 --log-level debug --rss urls 'https://open.spotify.com/show/4rOoJ6Egrf8K2IrywzwOMk'

No such file or directory: 'ffmpeg'

Never mind my old post.
I installed spodcast via pip install on a linux machine. everything works well, however the transcoding (to mp3) gives errors:

Traceback (most recent call last):
File "/usr/bin/spodcast", line 33, in
sys.exit(load_entry_point('spodcast==0.5.2', 'console_scripts', 'spodcast')())
File "/usr/lib64/python3.9/site-packages/spodcast/main.py", line 42, in main
args.func(args)
File "/usr/lib64/python3.9/site-packages/spodcast/app.py", line 30, in client
download_episode(episode_id)
File "/usr/lib64/python3.9/site-packages/spodcast/podcast.py", line 172, in download_episode
path, size, mimetype = download_stream(stream, filepath)
File "/usr/lib64/python3.9/site-packages/spodcast/podcast.py", line 144, in download_stream
ffmpeg.run(transcoder, quiet=True)
File "/usr/lib64/python3.9/site-packages/ffmpeg/_run.py", line 313, in run
process = run_async(
File "/usr/lib64/python3.9/site-packages/ffmpeg/_run.py", line 284, in run_async
return subprocess.Popen(
File "/usr/lib64/python3.9/subprocess.py", line 951, in init
self._execute_child(args, executable, preexec_fn, close_fds,
File "/usr/lib64/python3.9/subprocess.py", line 1821, in _execute_child
raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'ffmpeg'

Session.SpotifyAuthenticationException: PremiumAccountRequired

hello,
since today, after weeks of usage, i receive this exception

librespot.core.Session.SpotifyAuthenticationException: PremiumAccountRequired

i tried to login again with

docker run -it -v /tmp/spodcast:/data heywoodlh/spodcast -c /data/spodcast.json --root-path /data/html --log-level info --credentials-location /data/creds.json -p -l /data/spotify.rc

but with no luck.
My account still work from web, to listen to the very same podcast i'm trying to fetch.

It stoped working

It stoped working for me, I'm getting these error messages:

INFO:Librespot:Session:Created new session! device_id: 4111fdfe595800dc705aa0ff4939b59ac595283c, ap: ap-gae2.spotify.com:80
INFO:Librespot:Session:Connection successfully!
INFO:Librespot:Session:Session.Receiver started
INFO:Librespot:Session:Skipping 02
INFO:Librespot:Session:Received license_version: 0
INFO:Librespot:Session:Received country_code: BR
INFO:Librespot:Session:Skipping 1f
INFO:Librespot:Session:Skipping 69
INFO:Librespot:Session:Skipping unknown command cmd: 0x75, payload: b'\x00\x00\x00'
INFO:Librespot:Session:Authenticated as 31d2eplb6lsuy77uikekqfzj5w44!
INFO:Librespot:Session:Created new session! device_id: a59001678e10ffd39b38e2112629011548862466, ap: ap-gue1.spotify.com:443
INFO:Librespot:Session:Connection successfully!
INFO:Librespot:Session:Closing session. device_id: a59001678e10ffd39b38e2112629011548862466
INFO:Librespot:Session:Closed session. device_id: a59001678e10ffd39b38e2112629011548862466
Traceback (most recent call last):
File "/usr/local/bin/spodcast", line 8, in
sys.exit(main())
^^^^^^
File "/usr/local/lib/python3.12/site-packages/spodcast/main.py", line 42, in main
args.func(args)
File "/usr/local/lib/python3.12/site-packages/spodcast/app.py", line 14, in client
Spodcast(args)
File "/usr/local/lib/python3.12/site-packages/spodcast/spodcast.py", line 54, in init
Spodcast.login()
File "/usr/local/lib/python3.12/site-packages/spodcast/spodcast.py", line 78, in login
session = Session.Builder(conf).stored_file().create()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/librespot/core.py", line 1287, in create
session.authenticate(self.login_credentials)
File "/usr/local/lib/python3.12/site-packages/librespot/core.py", line 709, in authenticate
self.__authenticate_partial(credential, False)
File "/usr/local/lib/python3.12/site-packages/librespot/core.py", line 1067, in __authenticate_partial
raise Session.SpotifyAuthenticationException(ap_login_failed)
librespot.core.Session.SpotifyAuthenticationException: BadCredentials

Cannot get webserver to run properly

This tool is awesome, thank you. But i am having a hard setting it up properly.

I got the Web-Interface running, but i cannot add podcasts through it (credentials set, no error message). When i add a podcast through the CLI the podcast shows up on the main page, but the served .index for the podcast is empty.

Can you write a small tutorial how to set up the webserver or point me in the right direction?

I am using a RPi 4 with 64-bit bullseye and nginx, php-fpm.

trying to download a podcast...

Im trying to download like this:
./spodcast --credentials-location /home/panchines/spotify.rc urls https://open.spotify.com/show/6WJJC1RMBJzkH1MhusyZNd

i have my credentials there.
that dont show anything.

what i need to do? I just want to use the cli to download the podcast.
Thanks!

Error when running

I get the following error when running the command Spodcast, I'm using EndeavourOS:

Traceback (most recent call last):
File "/usr/bin/spodcast", line 5, in
from spodcast.main import main
File "/usr/lib/python3.11/site-packages/spodcast/main.py", line 4, in
from spodcast.app import client
File "/usr/lib/python3.11/site-packages/spodcast/app.py", line 7, in
from spodcast.podcast import download_episode, get_episodes
File "/usr/lib/python3.11/site-packages/spodcast/podcast.py", line 19, in
from spodcast.utils import clean_filename, uri_to_url
File "/usr/lib/python3.11/site-packages/spodcast/utils.py", line 7, in
from spodcast.spodcast import Spodcast
File "/usr/lib/python3.11/site-packages/spodcast/spodcast.py", line 16, in
from spodcast.config import Config
File "/usr/lib/python3.11/site-packages/spodcast/config.py", line 12, in
VERSION_STR = pkg_resources.require("Spodcast")[0].version
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/pkg_resources/init.py", line 966, in require
needed = self.resolve(parse_requirements(requirements))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/pkg_resources/init.py", line 827, in resolve
dist = self._resolve_dist(
^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/site-packages/pkg_resources/init.py", line 873, in _resolve_dist
raise VersionConflict(dist, req).with_context(dependent_req)
pkg_resources.ContextualVersionConflict: (zeroconf 0.39.4 (/usr/lib/python3.11/site-packages), Requirement.parse('zeroconf==0.55.0'), {'librespot'})

php version obsolete

The used PHP Version "7.4" is not available on modern systems.
Could you change the ".index.php" so it can work with php8.1?

Cheers

WARNING:Librespot:CdnManager:Couldn't extract expiration, invalid parameter in CDN

Windows 11
Docker Desktop (WSL2)

I'm launching Spodcast using a custom wrapper. This has worked flawlessly for 12+ months I'd say...

Write-Output "Stop any existing/stale containers"
docker ps -q | % { docker stop $_ }
docker container prune -f
Write-Output "Check for new Image updates"
docker pull heywoodlh/spodcast:latest
#docker pull heywoodlh/spodcast-web:latest
#docker pull heywoodlh/spodcast-cron:latest
Write-Output "Run Spodcast and check for latest episodes"
docker run --rm -it -v c:\ProgramData\spodcast:/data heywoodlh/spodcast -c /data/spodcast.json --log-level debug --transcode yes --root-path /data/html --rss-feed yes --max-episodes 8 https://open.spotify.com/show/1Zuurv8AZFWti60lSXiDgz https://open.spotify.com/show/7LuQv400JFzzlJrOuMukRj
#docker container prune -f
Write-Output "Complete"
Write-Output "Killing Docker Desktop Sessions"
Start-Sleep -Seconds 10
#taskkill /F /IM "Docker Desktop.exe"
docker image prune -f
Stop-Transcript

It's hard to put an exact timeframe on it, but my last successful download was ~27th December. Since then, I've been getting issues like this;

INFO:spodcast.podcast:Fetching episode information...
WARNING:Librespot:CdnManager:Couldn't extract expiration, invalid parameter in CDN url: https://audio4-gm-fb.spotifycdn.com/audio/66532ad6c2a84033378fb291901740166002fe70?Expires=1704662349~FullPath~hmac=43xVHO4qgCARU8WSv9y-sz4wk1vonvfaAIMZ865CK94=
Traceback (most recent call last):
  File "/usr/local/bin/spodcast", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/usr/local/lib/python3.12/site-packages/spodcast/__main__.py", line 42, in main
    args.func(args)
  File "/usr/local/lib/python3.12/site-packages/spodcast/app.py", line 30, in client
    download_episode(episode_id)
  File "/usr/local/lib/python3.12/site-packages/spodcast/podcast.py", line 167, in download_episode
    stream = Spodcast.get_content_stream(episode_stream_id, Spodcast.DOWNLOAD_QUALITY)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/spodcast/spodcast.py", line 111, in get_content_stream
    return cls.SESSION.content_feeder().load(content_id, VorbisOnlyAudioQuality(quality), False, None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/librespot/audio/__init__.py", line 725, in load
    return self.load_episode(playable_id, audio_quality_picker,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/librespot/audio/__init__.py", line 763, in load_episode
    return self.load_stream(file, None, episode, preload, halt_listener)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/librespot/audio/__init__.py", line 739, in load_stream
    return CdnFeedHelper.load_episode(self.__session, episode, file,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/librespot/audio/__init__.py", line 391, in load_episode
    streamer = session.cdn().stream_file(file, key, url, halt_listener)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/librespot/audio/__init__.py", line 438, in stream_file
    return CdnManager.Streamer(
           ^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/librespot/audio/__init__.py", line 561, in __init__
    response = self.request(range_start=0,
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/librespot/audio/__init__.py", line 622, in request
    raise IOError(response.status_code)
OSError: 404

I've gone back through the readme and effectively performed clean installs, re-adding credentials etc, to very little avail.

The example in the readme does /occasionally/ work... docker run -it -v c:\ProgramData\spodcast:/data heywoodlh/spodcast -c /data/spodcast.json --log-level info --max-episodes 1 'https://open.spotify.com/show/4rOoJ6Egrf8K2IrywzwOMk'

...so I'm unsure what's causing the more often than not, errors.... issues with the episode/filenames perhaps?

Set audio format (.ogg vs. .mp3)

Some podcasts are downloaded as .mp3 and some as .ogg. I looked at your code and it seems to me, that you are preferring .ogg over .mp3.

In which format are the files stored on Spotify's servers? Either .mp3 or .ogg? Or both formats for some podcasts?
Would it be possible to download the .mp3 for the episodes which are currently downloaded as .ogg?

Include airing date in Episode title

Hi,
first of all, thanks for the amazing script.
Would it be possible to include the airing/release date in the filename?

e.g.
Year-Month-Day - Name of podcast - title of episode

Would help alot to organize files.

edit:
I looked at the code, and it could be done by changing the podcast file

and add in def get_episode_info(episode_id_hex):
date_temp = datetime.strptime(release_date, '%Y-%m-%dT%H:%M:%SZ')
release_date_clean = f'{date_temp.strftime("%Y")}-{date_temp.strftime("%m")}-{date_temp.strftime("%d")}'
return podcast_name, podcast_id, duration_ms, episode_name, description, release_date, uri, external_url, release_date_clean

and in def download_episode(episode_id) -> None:
filename = clean_filename(release_date_clean + ' - ' + podcast_name + ' - ' + episode_name)

(sorry, I am relatively new to github)

HTTP Redirect to Wrong URL when using non-standard port

In setting up the docker-compose.yml file for #15 I noticed that it all works except for the links in my Spodcast web interface.

image

When I click on the link rather than going to http://localhost:8080/The_Joe_Rogan_Experience it goes to http://localhost/The_Joe_Rogan_Experience (notice the missing port 8080) which won't work.

image

I can still manually type in http://localhost:8080/The_Joe_Rogan_Experience and get a feed -- but I'd like for the URL's on the interface to work.

image

I suspect it's the Nginx config I'm using in the Docker image: https://github.com/heywoodlh/Spodcast/blob/55bc1efb29f819a2188b654c5d9ee9c110844cbf/docker/nginx/sites-enabled/spodcast

But any suggestions would be welcome because I haven't been able to figure out what I'm doing wrong.

PHP URL Problems

So I'm running Spodcast on my own server at home -- it is not accessible to the world.

I use FreshRSS for aggregating feeds. For some reason (I'm sure a misconfiguration on my end) the URLs for the media are all messed up when I try the default configuration and subscribing via FreshRSS.

This is what one of the media URLs looks like when I subscribe via FreshRSS (which is a web app running at http://freshrss.local):
http://freshrss.local/i/spodcast.local/The_Joe_Rogan_Experience/The_Joe_Rogan_Experience_-_1782_-_Daniel_Holzman.ogg

What it actually should be is this (notice that the freshrss.local piece is missing):
http://spodcast.local/The_Joe_Rogan_Experience/The_Joe_Rogan_Experience_-_1782_-_Daniel_Holzman.ogg

So for some reason it is prepending the URL of my FreshRSS web app to the media URL when I attempt to subscribe to the RSS feed.

I was able to workaround this by modifying The_Joe_Rogan_Experience's .index.php file and hardcoding the URL I use into the generated media URL:

$hardcoded_url = "http://spodcast.local{$_SERVER['REQUEST_URI']}";
...
...
echo "            <media:content url=\"".$hardcoded_url.$info->filename."\" medium=\"".$info->medium."\" duration=\"".$info->duration."\" type=\"".$info->mimetype."\" />\n";
...
...

I'm not proficient with PHP at all so is there a better way to solve this problem?

Protobuf Error, TypeError: Descriptors cannot not be created directly.

I am getting the following error and am not sure how to fix:

Traceback (most recent call last):
File "/usr/bin/spodcast", line 5, in
from spodcast.main import main
File "/usr/lib/python3.11/site-packages/spodcast/main.py", line 4, in
from spodcast.app import client
File "/usr/lib/python3.11/site-packages/spodcast/app.py", line 4, in
from librespot.audio.decoders import AudioQuality
File "/home/martins/.local/lib/python3.11/site-packages/librespot/init.py", line 3, in
from librespot.proto.Keyexchange_pb2 import BuildInfo, Platform, Product, ProductFlags
File "/home/martins/.local/lib/python3.11/site-packages/librespot/proto/Keyexchange_pb2.py", line 31, in
_descriptor.EnumValueDescriptor(
File "/home/martins/.local/lib/python3.11/site-packages/google/protobuf/descriptor.py", line 796, in new
_message.Message._CheckCalledFromGeneratedFile()
TypeError: Descriptors cannot not be created directly.
If this call came from a _pb2.py file, your generated code is out of date and must be regenerated with protoc >= 3.19.0.
If you cannot immediately regenerate your protos, some other possible workarounds are:

  1. Downgrade the protobuf package to 3.20.x or lower.
  2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will use pure-Python parsing and will be much slower).

More information: https://developers.google.com/protocol-buffers/docs/news/2022-05-06#python-updates

Channel title images are not displayed

For a few weeks now, I have had the problem that title graphics are no longer displayed in my podcast app. This only affects the self-hosted podcasts that I have downloaded with spodcast and is also independent of the app used.

IMG_20240526_052209

I have no idea where this problem is coming from, especially since the corresponding image tags in the RSS feed are set correctly.

<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" >
    <channel>
        <title>Gemischtes Hack</title>
        <link>https://open.spotify.com/show/7BTOsF2boKmlYr76BelijW</link>
        <image>
            <url>http://spodcast.xxxxxxx.info/Gemischtes_Hack//image.jpg</url>
            <title>Gemischtes Hack</title>
            <link>https://open.spotify.com/show/7BTOsF2boKmlYr76BelijW</link>
        </image>
        <description>Felix Lobrecht (Comedian und Autor) und Tommi Schmitt (TV-Moderator und Kolumnist) haben einen Podcast. Jeden Mittwoch exklusiv auf Spotify.</description>
        <atom:link href="http://spodcast.xxxxxxx.info/Gemischtes_Hack/" rel="self" type="application/rss+xml" />
        <item>


[ ...]

The images can also be called up and displayed in the browser via the corresponding url. So it seems that there are no rights problems on the server.

Maybe someone else has this problem and could give me some help.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.