An unofficial client library for Google Music.

Overview

gmusicapi: an unofficial API for Google Play Music

gmusicapi allows control of Google Music with Python.

from gmusicapi import Mobileclient

api = Mobileclient()
# after running api.perform_oauth() once:
api.oauth_login('<a previously-registered device id>')
# => True

library = api.get_all_songs()
sweet_track_ids = [track['id'] for track in library
                   if track['artist'] == 'The Cat Empire']

playlist_id = api.create_playlist('Rad muzak')
api.add_songs_to_playlist(playlist_id, sweet_track_ids)

gmusicapi is not supported nor endorsed by Google.

That said, it's actively maintained, and powers a bunch of cool projects:

Getting started

Start with the usage docs, which will guide you through installation and the available apis.

Once you're up and running, you can explore the rest of the docs at http://unofficial-google-music-api.readthedocs.io.

If the documentation doesn't answer your questions, or you just want to get in touch, either drop by #gmusicapi on Freenode or shoot me an email.

Status and updates

build_status

  • January 2020: Python 2 support dropped.
  • November 2018: proper OAuth support for the mobileclient.
  • February 2016: Python 3 support!
  • September 2015: Google switched to a new music uploading endpoint, breaking uploading for outdated versions of gmusicapi.
  • June 2015: Full mobileclient and webclient functionality was restored.
  • May 2015: Limited mobileclient functionality was restored.
  • April 2015: Google deprecated clientlogin, breaking both the webclient and mobileclient.
  • November 2013: I started working fulltime at Venmo, meaning this project is back to night and weekend development.

For fine-grained development updates, follow me on Twitter: @simonmweber.

Issues
  • GetUploadSession error 404: the request was rejected

    GetUploadSession error 404: the request was rejected

    pinned: here's a workaround to test: https://github.com/simon-weber/gmusicapi/issues/380#issuecomment-156743098


    Hello,

    Everytime I try to upload using gmupload.py from gmusicapi-scripts to google music I get :

    GetUploadSession error 404: the request was rejected
    

    for every song.

    Then if I retry I get `ALREADY EXISTS``.

    I can't see those songs in google music.

    gmusicapi 7.0.0 OpenSSL 1.0.1k 8 Jan 2015 Python 2.7.9

    log from gmusicapi.log

    2015-11-11 13:51:46,380 - gmusicapi.Musicmanager1 (shared:201) [DEBUG]: ProvideSample(args=[u'/path/to/my/song/1.mp3. ...', <gmusicapi.protocol.upload_pb2.SignedChallengeInfo object at 0x7fd2d5d059b0>, <gmusicapi.protocol.locker_pb2.Track object at 0x7fd2d5d05a28>, 'XX:XX:XX:XX:XX:XX', ''], kwargs={})
    2015-11-11 13:51:46,625 - gmusicapi.Musicmanager1 (shared:242) [DEBUG]: response_type: SAMPLE_RESPONSE
    sample_response {
      track_sample_response {
        client_track_id: "XXXXXXXXXXXXXXXXXXXXXX"
        response_code: UPLOAD_REQUESTED
        server_track_id: "XXXXXX-XXXXXX-XXXXXX-XXXX"
        expect_match: false
      }
    }
    policy {
      pause_uploads: false
      abort: false
      retry_in_minutes: 5
      bandwidth_cap_kbps: 12000
      pause_downloads: false
      download_bandwidth_cap_kbps: 16000
      send_analytics: false
      enable_gapless: true
      enable_m4p: true
    }
    
    2015-11-11 13:51:46,631 - gmusicapi.Musicmanager1 (shared:201) [DEBUG]: UpdateUploadState(args=['start', 'XX:XX:XX:XX:XX:XX'], kwargs={})
    2015-11-11 13:51:46,674 - gmusicapi.Musicmanager1 (shared:242) [DEBUG]: response_type: SAMPLE_RESPONSE
    sample_response {
    }
    policy {
      pause_uploads: false
      abort: false
      retry_in_minutes: 5
      bandwidth_cap_kbps: 12000
      pause_downloads: false
      download_bandwidth_cap_kbps: 16000
      send_analytics: false
      enable_gapless: true
      enable_m4p: true
    }
    2015-11-11 13:51:46,681 - gmusicapi.Musicmanager1 (shared:201) [DEBUG]: GetUploadSession(args=['XX:XX:XX:XX:XX:XX', 0, <gmusicapi.protocol.locker_pb2.Track object at 0x7fd2d5d05a28>, u'/path/to/my/song. ...', u'XXXXX-XXXXX-XXXXX-XXXXXX', False], kwargs={})
    2015-11-11 13:51:46,884 - gmusicapi.Musicmanager1 (shared:242) [DEBUG]: {u'errorMessage': {u'additionalInfo': {u'uploader_service.GoogleRupioAdditionalInfo': {u'completionInfo': {u'status': u'REJECTED', u'customerSpecificInfo': {u'ResponseCode': 404}}, u'requestRejectedInfo': {u'reasonDescription': u'agent_rejected'}}}, u'reason': u'REQUEST_REJECTED', u'upload_id': u'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'}}
    2015-11-11 13:51:46,884 - gmusicapi.Musicmanager1 (musicmanager:538) [DEBUG]: problem getting upload session: the request was rejected
    code=404 retrying=False
    2015-11-11 13:51:52,888 - gmusicapi.Musicmanager1 (musicmanager:549) [WARNING]: giving up on upload session for '/path/to/my/song/1.mp3': GetUploadSession error 404: the request was rejected
    2015-11-11 13:51:52,893 - gmusicapi.Musicmanager1 (shared:201) [DEBUG]: UpdateUploadState(args=['stopped', 'XX:XX:XX:XX:XX:XX'], kwargs={})
    2015-11-11 13:51:52,937 - gmusicapi.Musicmanager1 (shared:242) [DEBUG]: response_type: SAMPLE_RESPONSE
    sample_response {
    }
    policy {
      pause_uploads: false
      abort: false
      retry_in_minutes: 5
      bandwidth_cap_kbps: 12000
      pause_downloads: false
      download_bandwidth_cap_kbps: 16000
      send_analytics: false
      enable_gapless: true
      enable_m4p: true
    }
    
    bug 
    opened by ibaaj 87
  • Uploading broken: DecodeError, BadStatusLine, session response empty

    Uploading broken: DecodeError, BadStatusLine, session response empty

    Reports that it's uploaded correctly, but it's missed everything in my library.

    Running the tests, I see the following:

    2012-11-21 22:08:45,573 - gmusicapi.UnitTestedApi - WARNING - Received an unexpected response from call loadalltracks. 2012-11-21 22:08:45,821 - gmusicapi.UnitTestedApi - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item .2012-11-21 22:09:55,008 - gmusicapi.UnitTestedApi - WARNING - Received an unexpected response from call loadalltracks. 2012-11-21 22:09:55,250 - gmusicapi.UnitTestedApi - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item 2012-11-21 22:10:56,259 - gmusicapi.UnitTestedApi - WARNING - Received an unexpected response from call loadalltracks. 2012-11-21 22:10:56,488 - gmusicapi.UnitTestedApi - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item

    ....E

    ERROR: test_up_deletion (main.TestWCApiCalls)

    Traceback (most recent call last): File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/integration_test_api.py", line 211, in test_up_deletion self.run_steps("updel_") File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/utils.py", line 234, in run_steps step() File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/integration_test_api.py", line 185, in updel_1_upload result = self.api.upload(some_files) File "", line 2, in upload File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/utils.py", line 136, in wrapper return function(_args, *_kw) File "", line 2, in upload File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/utils.py", line 113, in wrapper return function(_args, *_kw) File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 690, in upload fname_to_id = self._upload_mp3s(map(lambda f: f.name, upload_files)) File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 781, in _upload_mp3s metadataresp = self._mm_pb_call("metadata", metadata_request) File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 887, in _mm_pb_call res.ParseFromString(self.session.post_protobuf(url, req)) File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 1058, in post_protobuf resp = self.android.getresponse() File "/usr/lib/python2.7/httplib.py", line 1030, in getresponse response.begin() File "/usr/lib/python2.7/httplib.py", line 407, in begin version, status, reason = self._read_status() File "/usr/lib/python2.7/httplib.py", line 371, in _read_status raise BadStatusLine(line) BadStatusLine: ''


    Ran 6 tests in 298.702s

    FAILED (errors=1)

    opened by ghost 60
  • 2-step verification (OAuth) not supported in mobileclient or webclient

    2-step verification (OAuth) not supported in mobileclient or webclient

    https://support.google.com/accounts/answer/180744?hl=en

    I plan to investigate what it will take to implement this.

    opened by jakealstad 43
  • OSError(

    OSError("a valid MAC could not be determined.")

    I started getting this error on every login attempt on a Windows 10 machine. Until a couple of days before it didn't complain and when I try this on a VirtualBox runnig Ubuntu it works perfectly. Any idea?

    opened by dvirtz 34
  • Add support for free radio stations

    Add support for free radio stations

    Hi,

    I have added support for free radios on the Kodi addon adding the missing calls in gmusicapi and changing others, please check fork below: https://github.com/simon-weber/gmusicapi/compare/develop...foreverguest:develop

    But this changes the data returned by create_station function, is that ok? Do you suggest another approach?

    opened by foreverguest 29
  • Request: Python3 support?

    Request: Python3 support?

    I use rhythmbox-gmusic to stream Google Play via Rhythmbox while I'm at work. I recently upgraded my Ubuntu laptop to 14.04 Trusty and found that the Rhythmbox version offered in the repos is 3.x, which uses Python 3 under the hood. I'm refraining from upgrading my workstation for the time being.

    I'm just wondering if there are any plans to update this API to support Python3? I realize it's not a simple task, especially considering that mutagen's maintainer seemed very passionate about his disdain for Python3. If it would help at all, in that thread it seems that someone forked mutagen and created mutagenx which works with py3k (also here on GitHub).

    opened by p0lar-bear 28
  • AA streaming broken: http 403 STREAM_ERROR_98

    AA streaming broken: http 403 STREAM_ERROR_98

    As of yesterday, two new params are required for AA streaming: slt and sig. Both need to be present and correct to stream, otherwise you'll get the 403.

    It looks like slt is a psuedo-random salt, which gets hashed with the songid and a secret embedded in the source to result in sig.

    opened by simon-weber 26
  • Mobileclient login stopped working with app passwords

    Mobileclient login stopped working with app passwords

    As of October 4, I'm no longer able to authenticate the Mobileclient interface using an app password on my 2FA-enabled account. It was working on October 3.

    I've tried:

    • Updated to gmusicapi 11.0.3 (Python 2.7)
    • Tried generating a new app password. The old one is still present and does not indicate expiration.
    • Verified that I can authenticate using Mobileclient to a different account that does not use 2FA.

    Is it just me, or is Mobileclient broken for other 2FA users as well?

    opened by dsears 25
  • Application specific password or two-factor auth

    Application specific password or two-factor auth

    This is not a feature request per se. I'd like to know whether it's (or will be) possible to use application specific password like the Google Music Manager does in case user has two-factor auth enabled. The question is more like, whether the API can handle it (currently it throws an exception)?

    opened by odiroot 25
  • Cannot import Mobileclient in python app engine

    Cannot import Mobileclient in python app engine

    I first encountered a protobuf issue, but this fixed it: https://www.simonmweber.com/2013/06/18/python-protobuf-on-app-engine.html

    Now it cannot find pwd. I read that it might have something to do with requests, and I have tried multiple version with no luck.

    File "/Users/*/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle
        handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
      File "/Users/*/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 299, in _LoadHandler
        handler, path, err = LoadObject(self._handler)
      File "/Users/*/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 85, in LoadObject
        obj = __import__(path[0])
      File "/Users/*/git/*/main.py", line 30, in <module>
        from gmusicapi import Mobileclient
      File "libs/gmusicapi/__init__.py", line 9, in <module>
        from gmusicapi.clients import Webclient, Musicmanager, Mobileclient
      File "libs/gmusicapi/clients/__init__.py", line 1, in <module>
        from gmusicapi.clients.webclient import Webclient
      File "libs/gmusicapi/clients/webclient.py", line 6, in <module>
        from gmusicapi.clients.shared import _Base
      File "libs/gmusicapi/clients/shared.py", line 3, in <module>
        from gmusicapi.utils import utils
      File "libs/gmusicapi/utils/utils.py", line 44, in <module>
        log_filepath = os.path.join(my_appdirs.user_log_dir, 'gmusicapi.log')
      File "libs/appdirs.py", line 403, in user_log_dir
        version=self.version)
      File "libs/appdirs.py", line 356, in user_log_dir
        path = user_cache_dir(appname, appauthor, version)
      File "libs/appdirs.py", line 306, in user_cache_dir
        path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache'))
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.py", line 268, in expanduser
        import pwd
      File "/Users/*/google-cloud-sdk/platform/google_appengine/google/appengine/tools/devappserver2/python/sandbox.py", line 898, in load_module
        raise ImportError('No module named %s' % fullname)
    ImportError: No module named pwd
    
    bug 
    opened by clocksmith 23
  • Looks like Google Play Music is going away

    Looks like Google Play Music is going away

    opened by tanimislam 9
  • UnicodeEncodeError with logging when using Mobileclient Search

    UnicodeEncodeError with logging when using Mobileclient Search

    New error popping up:

    --- Logging error ---
    Traceback (most recent call last):
      File "C:\Program Files\Python37\lib\logging\__init__.py", line 985, in emit
        stream.write(msg)
      File "C:\Program Files\Python37\lib\encodings\cp1252.py", line 19, in encode
        return codecs.charmap_encode(input,self.errors,encoding_table)[0]
    UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f49b' in position 32828: character maps to <undefined>
    
    Call Stack:
      File "C:\Program Files\Python37\lib\site-packages\gmusicapi\clients\mobileclient.py", line 1961, in search
        res = self._make_call(mobileclient.Search, query, max_results)
      File "C:\Program Files\Python37\lib\site-packages\gmusicapi\clients\mobileclient.py", line 48, in _make_call
        return super(Mobileclient, self)._make_call(protocol, *args, **kwargs)
      File "C:\Program Files\Python37\lib\site-packages\gmusicapi\clients\shared.py", line 90, in _make_call
        return protocol.perform(self.session, self.validate, *args, **kwargs)
      File "C:\Program Files\Python37\lib\site-packages\gmusicapi\protocol\shared.py", line 247, in perform
        log.debug(cls.filter_response(parsed_response))
    
    

    Happens when calling mobileclient.search("test") and the encoding used for the string doesnt seem to affect it.

    opened by gcfrxbots 1
  • Invalid artist and album ids on search

    Invalid artist and album ids on search

    When receiving the search results from mobileclient, the song_hits are not valid. So the artist and album Ids does not start with A or B as they are supposed to. Not sure if this affects the gmusicapi when working with that ID, if not it should be at least documented.

    (I am using mopidy-gmusic and there an ID without leading A,B or T is handled as an uploaded song).

    opened by susnux 3
  • Replace deprecated validictory with fastest fastjsonschema module

    Replace deprecated validictory with fastest fastjsonschema module

    Hi with this PR I want to propose a replacement for the deprecated validictory module. fastjsonschema module seems to be faster than jsonschema module too. Thanks for this amazing project

    opened by M0Rf30 3
  • Mobileclient remove_entries_from_playlist() always returns the input parameters

    Mobileclient remove_entries_from_playlist() always returns the input parameters

    I've been using this function to remove playlist entries successfully, but I notice that according to the documentation, the function remove_entries_from_playlist():

    Returns a list of entry ids that were removed.

    However, it seems that the function will basically return whatever is specified as the input parameter. As a simple example:

    api.remove_entries_from_playlist(u'hello')
    

    Will return [u'hello]', where I would expect it to return None since no playlist entry ID exists with this value. Is my understanding correct here?

    I'm using version 12.0.0, but from the changelog I believe this also applies for the latest version.

    Cheers!

    opened by spidru 5
  • Searching for youtube video hits and info requires a GPM subscription

    Searching for youtube video hits and info requires a GPM subscription

    This might be an incredibly stupid issue, but it looks like users that don't subscribe to google play music aren't able to search for songs based on video_hits or extract a youtube video.

    Is there any possible workaround for this, or do you absolutely have to sub to GPM?

    opened by gcfrxbots 1
  • Determine tracks added from subscription

    Determine tracks added from subscription

    I currently have a GPM subscription alongside thousands of tracks that I've uploaded and I want to use gmusicapi to tell me what tracks I've uploaded vs what have been added from the subscription.

    I've pulled out a diff of the keys in a track that I uploaded vs a track that I added via subscription.

    Fields in added_track not in uploaded_track trackType explicitType

    trackType has a numeric value of either 4 or 8. explicitType has a numeric value of either 1, 2, or 3.

    Whenever there is trackType, there will be explicitType. However I have come across some tracks that have only explicitType from this pair. For these that only have explicitType, they look to be songs that I purchased from iTunes Music back in the day.

    1. Do you know the significance of these fields (trackType and explicitType)?
    2. Can these be used to accurately determine a track added from a subscription? From my investigation it seems so.
    3. I am thinking of adding a PR to include a function to report on tracks added from a subscription - thoughts?

    I myself am migrating away from GPM so I want to know what tracks to add to my new streaming platform. Others might find this beneficial too - it could be used in a migrating tool from one platform to another.

    opened by jdheyburn 0
  • Feature request: tag successfully uploaded mp3s

    Feature request: tag successfully uploaded mp3s

    Hi, I just installed a docker container which is basically a wrapper for your api. (jaymoulin/google-music-manager) The issue I had was a lot of duplicate tracks getting uploaded which google music seemed to miss. From what I gather, this seems a common problem.

    I was just wondering if it would be an idea to add an option to tag the mp3 files on successful upload or keep a list, so they're skipped on future upload calls? I'd love to get this working, but as it stands, it's unusable for me. Let me know your thoughts. Thanks!

    opened by a575606 4
  • Plan on youtube music

    Plan on youtube music

    As you may have heard google has released a new service called youtube music which has lots of similarity with play music. There are news that google eventually plans to replace play music with youtube music.

    The good thing about youtube music right now is less authorization headache and new information like destinction between singles and albums.

    would be really good this library supported it.

    Just as a recommendation and knowing everyone's opinion.

    opened by sJJdGG 7
  • Webclient.login() not working with 2fa

    Webclient.login() not working with 2fa

    I can' t seem to get Webclient.login() to work. I have a account with 2fa auth. I tried with an app password or my regular password. Mobile client and Music manager work without issue.

    I am using the webclient because it has report_incorrect_match and the other clietns don't have that.

    Is there a workaround in the meantime?

    Thanks.

    opened by GeorgePetri 3
Easy Google Translate: Unofficial Google Translate API

easygoogletranslate Unofficial Google Translate API. This library does not need an api key or something else to use, it's free and simple. You can eit

Ahmet Eren Odacı 5 Jan 11, 2022
veez music bot is a telegram music bot project, allow you to play music on voice chat group telegram.

?? Veez Music Bot Music bot for playing music on telegram voice chat group. Requirements ?? FFmpeg NodeJS nodesource.com Python 3.7+ PyTgCalls ?? Get

levina 117 Jan 13, 2022
veez music is a telegram music bot project, allow you to play music on voice chat group telegram.

?? VEEZ MUSIC BOT Veez Music is a telegram bot project that's allow you to play music on telegram voice chat group. Requirements ?? FFmpeg NodeJS node

levina 23 Aug 29, 2021
ELiza music is a telegram music bot project, allow you to play music on voice chat group telegram.

❤️ ?????????? ?????????? ❤️ Unmaintained. The new repo of @MrsElizaRobot is private. (It is no longer based on this source code. The completely rewrit

Team Eliza 1 Jan 19, 2022
First Party data integration solution built for marketing teams to enable audience and conversion onboarding into Google Marketing products (Google Ads, Campaign Manager, Google Analytics).

Megalista Sample integration code for onboarding offline/CRM data from BigQuery as custom audiences or offline conversions in Google Ads, Google Analy

Google 37 Jan 10, 2022
🐍 The official Python client library for Google's discovery based APIs.

Google API Client This is the Python client library for Google's discovery based APIs. To get started, please see the docs folder. These client librar

Google APIs 5.3k Jan 13, 2022
🐍 The official Python client library for Google's discovery based APIs.

Google API Client This is the Python client library for Google's discovery based APIs. To get started, please see the docs folder. These client librar

Google APIs 5.3k Jan 16, 2022
Python client library for Google Maps API Web Services

Python Client for Google Maps Services Description Use Python? Want to geocode something? Looking for directions? Maybe matrices of directions? This l

Google Maps 3.5k Jan 12, 2022
🔍 Google Search unofficial API for Python with no external dependencies

Python Google Search API Unofficial Google Search API for Python. It uses web scraping in the background and is compatible with both Python 2 and 3. W

Avi Aryan 191 Jul 28, 2021
(unofficial) Googletrans: Free and Unlimited Google translate API for Python. Translates totally free of charge.

Googletrans Googletrans is a free and unlimited python library that implemented Google Translate API. This uses the Google Translate Ajax API to make

Suhun Han 2.8k Jan 20, 2022
rewise is an unofficial wrapper for google search's auto-complete feature

rewise is an unofficial wrapper for google search's auto-complete feature

Somdev Sangwan 67 Dec 30, 2021
Unofficial Python API client for Notion.so

notion-py Unofficial Python 3 client for Notion.so API v3. Object-oriented interface (mapping database tables to Python classes/attributes) Automatic

Jamie Alexandre 3.4k Jan 21, 2022
Unofficial Meteor Client wiki

Welcome to the Unofficial Meteor Client wiki! Meteor FAQs | A rewritten and better FAQ page. Installation Guide | A guide on how to install Meteor Cli

Anti Cope 32 Jan 10, 2022
TeslaPy - A Python implementation based on unofficial documentation of the client side interface to the Tesla Motors Owner API

TeslaPy - A Python implementation based on unofficial documentation of the client side interface to the Tesla Motors Owner API, which provides functiona

Tim Dorssers 116 Jan 13, 2022
JAKYM, Just Another Konsole YouTube-Music. A command line based Youtube music player written in Python with spotify and youtube playlist support

Just Another Konsole YouTube-Music Overview I wanted to create this application so that I could use the command line to play music easily. I often pla

Mayank Jha 63 Jan 1, 2022
A Telegram Music Tag Editor Bot that can remove almost all usernames in the music tags and add own username instead.

Music Tag Editor Bot A Telegram Music Tag Editor Bot that can remove almost all usernames in the music tags and add own username instead. It can also

null 16 Jan 4, 2022
VC-Music , Playing music without bot.

VC-Userbot A Telegram Userbot to play or streaming Audio and Video songs / files in Telegram Voice Chats. It's made with PyTgCalls and Pyrogram Requir

RioProjectX 4 Nov 12, 2021
Music bot for playing music on telegram voice chat group.

Somali X Music ?? Music bot for playing music on telegram voice chat group. Requirements FFmpeg NodeJS nodesource.com Python 3.8+ or Higher PyTgCalls

Abdisamad Omar Mohamed 4 Dec 1, 2021
this is an op music pyrogram music bot.

amanrajputpytgcallmusic this is an op music pyrogram music bot..... this bot user music bot can play music without being admin...... TG-MusicPlayer A

null 2 Dec 27, 2021