Spodcast is a caching Spotify podcast to RSS proxy

Overview

Spodcast

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. Spodcast consists of the main Spodcast application - a Python 3 command line tool - and a PHP-based RSS feed generator. It uses the librespot-python library to access the Spotift API. To use Spodcast you need a (free) Spotify account. Spodcast only supports the Spotify podcast service, it does not interface with the music streaming service.

How does it work

Spotify hosts podcasts through their proprietary API and does not offer an RSS feed, making it mandatory to use the Spotify (web) app to follow these shows. This makes it impossible to follow Spotify-hosted shows on any device which does not support the Spotify (web) app. Spodcast solves this problem by creating an RSS feed out of data returned through the Spotify podcast API. This feed can be served by any web server which supports PHP. By running Spodcast through a task scheduler (cron on *nix, Task Scheduler on Windows) the feed will be kept up to date without the need for intervention. Have a look at these glorious ASCIIGraphs™ which should answer all unasked questions:

Spodcast regularly queries Spotify for new episodes...

                  --------------
                 |task scheduler|
                  --------------
                        |             ___________
  -------   APIv1   ----V---         /           \
 |Spotify|- - - - >|Spodcast|------>| File system |
  -------           --------         \___________/

You want to listen to an episode using your old, unsupported but still functional phone...

                                           _____         ............
   ___________          ----------        |     | . o O |bla bla bla.|
  /           \        |Web server|  RSS  | YOUR|        ````````````
 | File system |------>|  + PHP   |------>| OLD |
  \___________/         ----------        |PHONE|
                                          |_____|

Thus, by the simple expedient of using a piece of code which produces another piece of code which is used by yet another piece of code to speak to that old, creaky but still functional phone the latter is saved from early forced retirement. You can both feel virtuous for not adding another piece of waste to the pile, provident for not spending funds on a new device which does the same as the old one, smart for escaping the trap of planned obsolescence and whatever other emotion you prefer, including none whatsover.

Installation

Spodcast can be installed from source by running pip install . from within the package root directory:

$ git clone https://github.com/Yetangitu/spodcast.git
$ cd spodcast
$ pip install .

Once installed this way it can be uninstalled using pip uninstall spodcast if so required. If you're planning to use the RSS proxy and web UI you need to make sure the spodcast command is available to the web server user.

Usage

To use Spodcast you need a (free) Spotify account, if you don't have one yet you'll need to take care of that first at https://www.spotify.com/signup/ . If you plan to use the RSS proxy feature you'll also need a web server to serve the RSS feed(s), any server which supports PHP will do here. See Web server requirements for more information on how to configure the server.

Here's spodcast displaying its help message:

$ spodcast -h
usage: spodcast [-h] [-c CONFIG_LOCATION] [-p] [-l LOGIN] [--root-path ROOT_PATH]
                [--skip-existing SKIP_EXISTING] [--retry RETRY]
                [--max-episodes MAX_EPISODES] [--chunk-size CHUNK_SIZE]
                [--download-real-time DOWNLOAD_REAL_TIME] [--language LANGUAGE]
                [--credentials-location CREDENTIALS_LOCATION] [--rss RSS]
                [--log-level LOG_LEVEL]
                [urls ...]

A caching _Spotify_ podcast to RSS proxy.

positional arguments:
  urls                  Download podcast episode(s) from a url. Can take multiple urls.

optional arguments:
  -h, --help            show this help message and exit
  -c CONFIG_LOCATION, --config-location CONFIG_LOCATION
                        Specify the spodcast.json location
  -p, --prepare-feed    Installs RSS feed server code in ROOT_PATH.
  -l LOGIN, --login LOGIN
                        Reads username and password from file passed as argument and stores
                        credentials for later use.
  --root-path ROOT_PATH
                        set root path for podcast cache
  --skip-existing SKIP_EXISTING
                        skip files with the same name and size
  --retry RETRY         retry count for _Spotify_ API access
  --max-episodes MAX_EPISODES
                        number of episodes to download
  --chunk-size CHUNK_SIZE
                        download chunk size
  --download-real-time DOWNLOAD_REAL_TIME
                        simulate streaming client
  --language LANGUAGE   preferred content language
  --credentials-location CREDENTIALS_LOCATION
                        path to credentials file
  --rss RSS             add a (php) RSS feed server and related metadata for feed. To serve
                        the feed, point a web server at the spodcast root path as configured
                        using --root-path.
  --log-level LOG_LEVEL
                        log level (debug/info/warning/error/critical)

Using Spodcast to proxy Spotify podcasts to RSS

The following example shows how to use the spodcast command to prepare the feed root directory and add a Spotify account to be used. It specifies the configuration file to create (-c /mnt/audio/podcast/spodcast.json) and the root path where podcasts will be downloaded to (--root-path /mnt/audio/spodcast). The -p option tells spodcast to prepare the RSS feed server in the root directory which will also be used to store the credential file created by the -l spotify.rc command. That spotify.rc file is a plain text file containing the username and password (separated by a single space character) to use to login to Spotify. It is only needed to create the stored credentials file(s) so it can be deleted once Spotcast is up and running.

spodcast -c /mnt/audio/podcast/spodcast.json --root-path /mnt/audio/spodcast -p -l /home/exampleuser/spotify.rc

Configure the Web server using the path given as root path (in this example that would be /mnt/audio/spodcast) as web root, making sure to exclude files with .json and .info extenstions to avoid leaking your Spotify credentials (even though these are stored in hashed form using hashed file names). Now point a browser at the site you configured for Spodcast and you're ready to add the first show or episode. This is done easily by entering the Spotify show/episode url (e.g. https://open.spotify.com/show/4rOoJ6Egrf8K2IrywzwOMk for The Joe Rogan Experience for the whole show, https://open.spotify.com/episode/2rYwwE7hcpgsDo9vRVHxAI?si=24fb00294b7f40db for a specific episode, notice the show and episode parts of these links) and either hitting Enter or clicking the Add button. Spodcast will now create a directory under the given root path, add the .index.php RSS feed generator script and the index.info show info URL used by that script and the RSS manager script and whatever episode(s) you decided to sync.

Once the initial feed has been created it can be kept up to date by enabling the feed update service found in the Settings menu. Select the update frequency and the start time and click Update, this will create a cron job for the web server which will run the Spodcast manager script to update feeds. While the update frequency is configured for all shows simultaneously this is not the case for the number of episodes to sync and the number to keep in cache, these can be configured individually for each show. The idea here is that some shows may publish more than one episode between update intervals so by fetching the last X episodes on each update nothing will be missed. Episodes which have already been synced will not be synced again so no time or bandwidth is wasted. In the same vein the number of episodes to keep can be configured to make sure your RSS clients have the opportunity to download these before they are rotated out of cache. Once more than X (being the value chosen for keep) episodes have been downloaded the oldest episodes will be deleted to keep the total no more than X.

Point your RSS clients at the Spodcast feed URL for this show and you should see new episodes appear after they were published on Spotify and subsequently picked up on the next update. For the example given in the Web server requirements example that URL would be http://spodcast.example.org/The_Joe_Rogan_Experience.

Here's what the Spodcast feed manager looks like:

Spodcast feed manager

...and on smaller screens it looks like this:

Spodcast feed manager on a small screen

The settings screen is simple and concise:

Spodcast feed manager settings

Each show has its own sync and keep settings. Use the Delete button to, well, delete the show. Use Refresh to retrieve the last [sync] episodes, skipping those which have already been synced.

Show controls

Using the Spodcast CLI command to download a single episode

Spodcast can also be used stand-alone (without the need for a web server) by either just ignoring the feed-related files (.index.php, index.info plus a *.info file for every episode) or by disabling the RSS feed using --rss no on the command line. Instead of using the -l spotify.rc command to add Spotify credentials it is possible to point Spotcast at a single credentials.json file (which will be created if it does not exist yet), spotcastwil ask for the username and password when needed. To get single episode links use the _Spotify_ web app and select _Share->Copy Episode Link_ from the episode menu (three dots in the top-right corner of the episode block). The following example shows (an already configured instance of)spodcast` ready to download a single episode:

spodcast -c ~/.config/spodcast/spodcast.json --credentials-location ~/.config/spodcast/credentials.json --rss no https://open.spotify.com/episode/2rYwwE7hcpgsDo9vRVHxAI?si=24fb00294b7f40db

Like in the previous example Spodcast will create a directory under the root path with the same name as the show from which the episode is downloaded. The episode will be downloaded into this directory under a SHOW_NAME_-__EPISODE_NAME.[ogg|mp3] name. Point a mediaplayer of choice at this file to play the episode. In "manual" mode Spodcast does not do anything by itself, feeds can be kept up to date by running Spotcast with the required settings for --max-episodes (which is the value used for sync in the web UI) and the show URL. Here's how to update the The Joe Rogan Experience show using the spodcast CLI command, syncing the last 3 episodes:

spodcast -c ~/.config/spodcast/spodcast.json --rss no --max-episodes 3 https://open.spotify.com/show/4rOoJ6Egrf8K2IrywzwOMk`

Web server configuration

Spodcast places a hidden .index.php file in the root path and each show directory. The one in the root directory is used to manage feeds while those in the show directories produce RSS feeds based on the information found in all *.info files in that directory. Configure the server to serve those .index.php files as index to make things work as intended. Don't forget to block all web access to files ending in .json and .info to make sure you Spotify credentials (which are stored in hashed form in files named spodcast-cred-MD5_HASH_OF_SPOTIFY_USER_NAME.json in the root path) can not be accessed. For nginx the following should suffice to produce an unencrypted (HTTP) feed under the domain name spodcast.example.org given a feed root directory (as configured using --root-path) of /mnt/audio/spodcast with php-fpm 7.4 listening on unix:/run/php/php7.4-fpm.sock:

server {
        listen 80;
        listen [::]:80;
        server_name spodcast.example.org;

        root /mnt/audio/spodcast;

        index .index.php;

        # these files should not be accessible
        location ~\.(json|info)$ {
                deny all;
                return 404;
        }

        location / {
                try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:/run/php/php7.4-fpm.sock;
        }
}

Examples for other web servers can be found elsewhere, this is basically a default PHP configuration with the only difference being that .index.php is a hidden file.

Comments
  • Cannot get webserver to run properly

    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.

    bug 
    opened by ahuse 20
  • Cannot download episodes anymore (Not found for url exception)

    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:

    • It happens for multiple podcasts I've tried, e.g.: https://open.spotify.com/show/6UUIXmp1V0fK4ZpK7vzAbQ https://open.spotify.com/show/1OLcQdw2PFDPG1jo3s0wbp
    • I intentionally blacked out device id, client id and my username

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

    bug 
    opened by diveflo 18
  • added Dockerfile

    added Dockerfile

    Assumes that you will build the image from the root directory of the repository

    i.e. (using my fork/branch as an example)

    git clone -b dockerfile https://github.com/heywoodlh/Spodcast 
    cd Spodcast &&\
        docker build -t heywoodlh/spodcast -f docker/Dockerfile . 
    

    Then you can run the container like this:

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

    Related, I've also created a Github Action to build a multi-architecture image and push it to Docker Hub: https://github.com/heywoodlh/actions/blob/master/.github/workflows/spodcast-buildx.yml

    If you merge this pull request I will update my Action to point to your repo and continue building images at heywoodlh/spodcast on Docker Hub and I'm happy to keep building them on a weekly basis on my account -- but it'd be awesome if you had an official, cross-architecture image for Spodcast. Feel free to just take my Github Action and implement it here (or I can create a PR for that as well).

    Let me know if that makes sense or if I can be of any help. Thanks for a great project!

    opened by heywoodlh 17
  • Set audio format (.ogg vs. .mp3)

    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?

    opened by ahuse 13
  • Podcast episodes are not completely downloading

    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!

    bug 
    opened by lohningerthomas 12
  • Logs for the Feed update

    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.

    opened by lucashmsilva 11
  • PHP URL Problems

    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?

    bug 
    opened by heywoodlh 6
  • Increase maximum episodes number in feed manager

    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!

    enhancement question 
    opened by diveflo 4
  • duration_ms is not defined

    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'
    
    opened by heywoodlh 2
  • Can't add feeds

    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:

    [email protected]:/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

    opened by lkstnr 1
  • spodcast-the-command clobbers sync/keep info, working on it...

    spodcast-the-command clobbers sync/keep info, working on it...

    FYI, I noticed that spodcast (the Python command) clobbers sync- and keep--related data in the show info file which leads to these values being reset to their defaults when spodcast is invoked. This will be solved in the upcoming release.

    opened by Yetangitu 1
  • StatusCodeEception: 451

    StatusCodeEception: 451

    Hi all, downloading the following podcast https://open.spotify.com/show/6gAIR3HN25mgU1niAZyCm0?si=b2dceeeb02a34a2a results in WARNING:spodcast.podcast:episode 6a1e2afa822c5a34bb1b80bfdd7d0b6d, StatusCodeException: 451

    Example code: spodcast --skip-existing yes --rss-feed no --transcode no --max-episodes 1 https://open.spotify.com/show/6gAIR3HN25mgU1niAZyCm0?si=b2dceeeb02a34a2a

    Downloading individual episodes seems to work. Anyone an idea why? Thanks for your help!

    opened by BumbleCast 1
  • Transcoding not working with docker-compose setup

    Transcoding not working with docker-compose setup

    I can't for the life of me get transcoding to work when using the docker-compose.yml setup. I can see the command is parsed, but no transcoding occurs.

    opened by jamesvincent 0
  • Symbols in password causes errors using docker-compose

    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.

    opened by jamesvincent 0
  • Errors in web interface

    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

    opened by hermy65 2
  • Show with ID starting with 0 does not (completely) work

    Show with ID starting with 0 does not (completely) work

    Hi,

    I have a podcast (https://open.spotify.com/show/09rIWfzXpDbWQf2paN0g6u) where the ID starts with a 0. I can add this via the command line and the web UI (and the download works) but its ID is actually saved without that 0 and any updates therefore don't work.

    Modifying the ID in the index.info and feeds.info files fixes the issue.

    Thanks for your help!

    opened by diveflo 0
Releases(v0.5.2)
  • v0.5.2(Jul 20, 2022)

    This release:

    • fixes #14 (some shows are not downloaded completely)
    • fixes #13 (Cannot download episodes anymore)
    • fixes the problem noted in https://github.com/Yetangitu/Spodcast/issues/13#issuecomment-1171732387 with downloading single episodes
    • uses librespot-python interfaces instead of raw web API access (needed to fix https://github.com/Yetangitu/Spodcast/issues/13)
    • can not yet determine decrypted file size for Spotify-hosted episodes (which used to work) so will only look at the file name to determine whether an episode has already been downloaded. To retry corrupted downloads just remove the partially downloaded file and try again.

    To get spodcast to fetch those episodes it missed while #13 reared its ugly head (i.e. between 2022-06-16 and 2022-06-30) you can temporarily increase --max-episodes (or sync in the web interface, although that only goes up to 5) to whatever number of episodes you expect have been missed - the number depends on the release frequency.

    Source code(tar.gz)
    Source code(zip)
    spodcast-0.5.2.tar.gz(43.19 KB)
  • v0.5.1(Jun 30, 2022)

    This release:

    • fixes #13 (Cannot download episodes anymore)
    • fixes the problem noted in https://github.com/Yetangitu/Spodcast/issues/13#issuecomment-1171732387 with downloading single episodes
    • uses librespot-python interfaces instead of raw web API access (needed to fix https://github.com/Yetangitu/Spodcast/issues/13)
    • can not yet determine decrypted file size for Spotify-hosted episodes (which used to work) so will only look at the file name to determine whether an episode has already been downloaded. To retry corrupted downloads just remove the partially downloaded file and try again.

    To get spodcast to fetch those episodes it missed while #13 reared its ugly head (i.e. between 2022-06-16 and 2022-06-30) you can temporarily increase --max-episodes (or sync in the web interface, although that only goes up to 5) to whatever number of episodes you expect have been missed - the number depends on the release frequency.

    Source code(tar.gz)
    Source code(zip)
    spodcast-0.5.1.tar.gz(43.19 KB)
  • v0.5.0(Jun 30, 2022)

    This release:

    • fixes #13 (Cannot download episodes anymore)
    • uses librespot-python interfaces instead of raw web API access (needed to fix https://github.com/Yetangitu/Spodcast/issues/13)
    • can not yet determine decrypted file size for Spotify-hosted episodes (which used to work) so will only look at the file name to determine whether an episode has already been downloaded. To retry corrupted downloads just remove the partially downloaded file and try again.

    To get spodcast to fetch those episodes it missed while #13 reared its ugly head (i.e. between 2022-06-16 and 2022-06-30) you can temporarily increase --max-episodes (or sync in the web interface, although that only goes up to 5) to whatever number of episodes you expect have been missed - the number depends on the release frequency.

    Source code(tar.gz)
    Source code(zip)
    spodcast-0.5.0.tar.gz(43.19 KB)
  • v0.4.9(May 24, 2022)

    Changes:

    • some shows publish episodes in the wrong order so sort the list before using it (fixes #11)
    • added --transcode yes/no to enable transcoding .ogg into .mp3 for handicapped devices which do not support open codes (iOS, looking at you here)
    • added webcron endpoint to run feed updates in situations where the system scheduler can not be used
    • feed manager is now mostly a single page app with live updates
    • added -v (version) option
    • added versioned updatees for feed and index manager
    • show logos are now hosted locally

    Fixes:

    • direct login now works as intended
    • keep spodcast from clobbering feed manager related data (sync/keep)
    • remove spurious quotes from transcoder configuration endpoint
    • dump amended spodcast config file in case the existing file misses one or more settings
    • fix the case of the missing $SPODCAST_COMMAND in the feed manager

    New install requirements:

    • ffmpeg-python
    • setuptools

    The change to a SPA was necessitated by the introduction of the --transcode yes/no option which (when activated) causes feed updates to take much more time, especially on less powerful hardware. This would cause the feed manager process to timeout before the feeds were updated. This problem is mostly fixed but can still occur in the webcron update process. If this happens the php-fpm and/or web server timeout needs to be increased. This should only happen on slower hardware and/or slow links. See the README for information on how to do this for nginx.

    Source code(tar.gz)
    Source code(zip)
    spodcast-0.4.9.tar.gz(43.35 KB)
  • v0.4.8(Mar 2, 2022)

    Changes:

    • added --transcode yes/no to enable transcoding .ogg into .mp3 for handicapped devices which do not support open codes (iOS, looking at you here)
    • added webcron endpoint to run feed updates in situations where the system scheduler can not be used
    • feed manager is now mostly a single page app with live updates
    • added -v (version) option
    • added versioned updatees for feed and index manager
    • show logos are now hosted locally

    Fixes:

    • direct login now works as intended
    • keep spodcast from clobbering feed manager related data (sync/keep)
    • remove spurious quotes from transcoder configuration endpoint
    • dump amended spodcast config file in case the existing file misses one or more settings
    • fix the case of the missing $SPODCAST_COMMAND in the feed manager

    New install requirements:

    • ffmpeg-python
    • setuptools

    The change to a SPA was necessitated by the introduction of the --transcode yes/no option which (when activated) causes feed updates to take much more time, especially on less powerful hardware. This would cause the feed manager process to timeout before the feeds were updated. This problem is mostly fixed but can still occur in the webcron update process. If this happens the php-fpm and/or web server timeout needs to be increased. This should only happen on slower hardware and/or slow links. See the README for information on how to do this for nginx.

    Source code(tar.gz)
    Source code(zip)
    spodcast-0.4.8.tar.gz(43.13 KB)
  • v0.4.6(Mar 2, 2022)

    Changes:

    • added --transcode yes/no to enable transcoding .ogg into .mp3 for handicapped devices which do not support open codes (iOS, looking at you here)
    • added webcron endpoint to run feed updates in situations where the system scheduler can not be used
    • feed manager is now mostly a single page app with live updates
    • added -v (version) option
    • added versioned updatees for feed and index manager

    Fixes:

    • direct login now works as intended

    New install requirements:

    • ffmpeg-python
    • setuptools

    The change to a SPA was necessitated by the introduction of the --transcode yes/no option which (when activated) causes feed updates to take much more time, especially on less powerful hardware. This would cause the feed manager process to timeout before the feeds were updated. This problem is mostly fixed but can still occur in the webcron update process. If this happens the php-fpm and/or web server timeout needs to be increased. This should only happen on slower hardware and/or slow links. See the README for information on how to do this for nginx.

    Source code(tar.gz)
    Source code(zip)
    spodcast-0.4.6.tar.gz(43.08 KB)
  • v0.4.3(Mar 2, 2022)

    Changes:

    • added --transcode yes/no to enable transcoding .ogg into .mp3 for handicapped devices which do not support open codes (iOS, looking at you here)
    • added webcron endpoint to run feed updates in situations where the system scheduler can not be used
    • feed manager is now mostly a single page app with live updates
    • added -v (version) option
    • added versioned updatees for feed and index manager

    Fixes:

    • direct login now works as intended

    New install requirements:

    • ffmpeg-python
    • setuptools

    The change to a SPA was necessitated by the introduction of the --transcode yes/no option which (when activated) causes feed updates to take much more time, especially on less powerful hardware. This would cause the feed manager process to timeout before the feeds were updated. This problem is mostly fixed but can still occur in the webcron update process. If this happens the php-fpm and/or web server timeout needs to be increased. This should only happen on slower hardware and/or slow links.

    Source code(tar.gz)
    Source code(zip)
    spodcast-0.4.3.tar.gz(42.86 KB)
  • v0.3.7(Feb 23, 2022)

  • v0.3.6(Feb 23, 2022)

  • v0.3.5(Feb 16, 2022)

  • v0.3.3(Feb 15, 2022)

  • v0.3.2(Feb 15, 2022)

  • v0.3.1(Feb 14, 2022)

Owner
Frank de Lange
I mostly use my own code repository but occasionally dump stuff to Github - Internet was meant to be decentralised. Nae lairds, nae kings, we are free men
Frank de Lange
API Basica per a synologys Active Backup For Buissiness

Synology Active Backup for Business API-NPP Informació Per executar el programa

Nil Pujol 0 May 13, 2022
A file-based quote bot written in Python

Let's Write a Python Quote Bot! This repository will get you started with building a quote bot in Python. It's meant to be used along with the Learnin

1 Feb 03, 2022
🦈 Blahaj is a discord bot that shares random images of himself on discord.

🦈 Blahaj Bot Blahaj is a discord bot that shares random images of himself on discord. ⚙️ Developer's Guide To use the bot, follow along the steps Hea

Atul Anand 3 Oct 21, 2022
Official Python client for the MonkeyLearn API. Build and consume machine learning models for language processing from your Python apps.

MonkeyLearn API for Python Official Python client for the MonkeyLearn API. Build and run machine learning models for language processing from your Pyt

MonkeyLearn 157 Nov 22, 2022
"Nesse projeto criei uma automação para abrir as tarefas no Jira em massa pegando de uma determinada fila do Zendesk."

automacao-Zendesk "Nesse projeto criei uma automação para abrir as tarefas no Jira em massa pegando de uma determinada fila do Zendesk." en-us "In thi

tokoyamy 1 Dec 20, 2021
A Discord chat bot for the Tardsquad guild (Discord name for server).

Tardsquad Discord Bot A Discord chat bot for the Tardsquad guild (Discord name for server). Resouces Discord Developer Portal A general tutorial for a

Tardsquad Quality Code Inc. 4 Jul 26, 2022
A powerful application to automatically deploy GitHub Release.

A powerful application to automatically deploy GitHub Release.

Fentaniao 43 Sep 17, 2022
A telegram bot that messages you available vaccine appointments in the Veneto region

Serenissimo, domande frequenti Chi sei? Sono Alberto Granzotto, libero professionista a Berlino. Mi occupo di servizi software, privacy, decentralizza

vrde 31 Sep 30, 2022
派蒙Bot / PaimonBot

派蒙Bot / PaimonBot 基于Mrs4s / go-cqhttp 和 nonebot / nonebot2 的原神QQ群聊机器人 特别鸣谢 MingxuanGame 的人物武器名字自动纠正功能 小灰灰 的人物武器信息api 环境 请务必使用Python3.7以上版本!! 尽量在linux下

晓轩 96 Dec 16, 2022
PyHoroscope - Observational Indian lunisolar calendar, horoscope and matching using the Swiss ephemeris

PyHoroscope Observational Indian lunisolar calendar, horoscope and matching usin

4 Jun 05, 2022
Telegram bot untuk mencari jawaban dibrainly, support inline juga

Brainly-Telebot Bot Untuk Mencari Jawaban Dibrainly Jika ingin clone. Boleh kok Dibuat dengan python menggunakan MTproto Library. Yaitu Pyrogram Bot y

... 7 Mar 17, 2022
自动每天给女友发邮件

github acitons 发邮件 python 脚本 每天 7点半左右给女朋友发送邮件 天气来自: http://www.tianqiapi.com/ 文字图片来源:http://wufazhuce.com/ 风景图:https://qqlykm.cn/api/fengjing 土味情话:htt

gogobody 7 May 12, 2022
This repository contains unofficial code reproducing Agent57

Agent57 This repository contains unofficial code reproducing Agent57, which outp

19 Dec 29, 2022
471 Dec 24, 2022
Share your files on local network just by one click.

Share Your Folder This script helps you to share any folder anywhere on your local network. it's possible to use the script on both: Windows (Click he

Mehran Seifalinia 15 Oct 23, 2022
🚀 An asynchronous python API wrapper meant to replace discord.py - Snappy discord api wrapper written with aiohttp & websockets

Pincer An asynchronous python API wrapper meant to replace discord.py ❗ The package is currently within the planning phase 📌 Links |Join the discord

Pincer 125 Dec 26, 2022
A fully responsive interface to manage all your favorite software on your HTPC.

Python 3 port of Hellowlol's HTPC Manager fork We made this an organization repository to be more independent from single developers. If you want to j

26 Jan 04, 2023
A Bot Telegram Anti Users Channel to automatic ban users who using channel to send message in group.

Tg_Anti_UsersChannel A Bot Telegram Anti Users Channel to automatic ban users who using channel to send message in group. Features: Automatic ban Whit

idzeroid 6 Dec 26, 2021
An API wrapper for discord; maintained and improved from discord.py

Fusion.py Documentation What is Fusion.py you might ask; Fusion.py is a Discord.py fork that has most of the good features from most of the big Discor

Senarc Studios 5 Apr 19, 2022
Python library wrapping and enhancing the Invenio RDM REST API.

Iridium The metal Iridium is used to refine and enhance metal alloys. Similarly, this package provides an enhanced coating around the Invenio RDM APIs

Materials Data Science and Informatics 2 Mar 29, 2022