Skip to main content

Python client library for feed readers that utilize the Google Reader API

Project description

Google Reader Python API Client

This project is a Python client library for feed readers that utilize the Google Reader API. Although Google Reader was discontinued in 2013, many feed readers continue to rely on this API.

Note that this library is not fully implemented. It has been tested with Miniflux and FreshRSS.

There is no official Google Reader API documentation. This library has been developed by analyzing existing software implementations.

Installation

python3 -m pip install google-reader

Usage Example

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")

>>> client.get_user_info(auth_token)
UserInfo(user_id='1', user_name='admin', user_email='admin@example.org', user_profile_id='1')

>>> client.list_subscriptions(auth_token)
[Subscription(id='feed/6', title='Feed Title', url='https://example.org/feed', html_url='https://example.org/', icon_url='https://reader.example.org/feed/icon/846d0be14a9676baabfb7fbb69a1fbca8bb9dad3', categories=[Category(id='user/1/label/My Test', label='My Test', type='folder')])]

Documentation

Item IDs Format

Item IDs can be returned in short or long form depending on the API method.

  • Long form: The prefix tag:google.com,2005:reader/item/ followed by the ID as an unsigned base 16 number that is 0-padded so that it's always 16 characters wide.
  • Short form: The ID as a signed base 10 number.

Examples:

tag:google.com,2005:reader/item/00000000148b9369	344691561
tag:google.com,2005:reader/item/00000000148b383e	344668222
tag:google.com,2005:reader/item/00000000148b3841	344668225

Stream IDs

Streams can be feeds, tags (labels/folders) or states.

  • Feed: feed/http://example.org/feed or feed/123456
  • Tag: user/-/label/Some Text
  • Read articles: user/-/state/com.google/read
  • Starred articles: user/-/state/com.google/starred
  • Broadcasted articles: user/-/state/com.google/broadcast
  • Annotated articles: user/-/state/com.google/annotated
  • Likes articles: user/-/state/com.google/like
  • Saved web pages: user/-/state/com.google/saved-web-pages

Client Login

Request:

  • URL: /accounts/ClientLogin
  • Method: GET

Querystring parameters:

  • Email: the user's email
  • Passwd: the user's account password

The plain text response contains 3 lines:

SID=...
LSID=...
Auth=<token>

The access token can be retrieved from the third line of the response and should be included in the Authorization header for each request:

Authorization: GoogleLogin auth=<token>

Some endpoints require the POST parameter T to include the access token.

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")

>>> client.login("my_username", "my_password")
AuthToken(TokenType='GoogleLogin', AccessToken='test/8eec3f60a23a5b5464245054f60eb9ced8d5655c')

Token

This endpoint returns a CSRF token required for making modifications. The token must be included as the T parameter in POST requests, along with the Authorization header.

Request:

  • URL: /reader/api/0/token
  • Method: GET
  • Supported formats: Returns the CSRF token in plain text format

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")

>>> client.get_token(auth_token)
'ccd127a64a7150c5fae14e5699b3df6751c083d4ZZZZZZZZZZZZZZZZZ'

User Information

Request:

  • URL: /reader/api/0/user-info
  • Method: GET
  • Supported formats: JSON

Response:

{
  "userId": "1234",
  "userName": "test",
  "userProfileId": "1234",
  "userEmail": "test@example.org",
  "isBloggerUser": true,
  "signupTimeSec": 1163850013,
  "isMultiLoginEnabled": false
}

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")

>>> client.get_user_info(auth_token)
UserInfo(user_id='1234', user_name='test', user_email='test@example.org', user_profile_id='1234')

Subscriptions List

Request:

  • URL: /reader/api/0/subscription/list
  • Method: GET
  • Supported formats: JSON

Response:

{
    "subscriptions": [
        "id": "feed/2",
        "title": "Kanboard Release Notes",
        "url": "https://kanboard.org/releases.xml"
        "htmlUrl": "https://kanboard.org/releases.html",
        "iconUrl": "http://localhost/feed/icon/d8276d41bd515db917b46a38d743932d0d02da51",
        "categories": [
            {
                "id": "user/1/label/All",
                "label": "All",
                "type": "folder"
            }
        ]
    ]
}

Python Example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")

>>> client.list_subscriptions(auth_token)
[Subscription(id='feed/1', title='FreshRSS releases', url='https://github.com/FreshRSS/FreshRSS/releases.atom', html_url='https://github.com/FreshRSS/FreshRSS/', icon_url='http://127.0.0.1:8082/f.php?516d4293', categories=[Tag(id='user/-/label/Uncategorized', label='Uncategorized', type=None)])]

Edit Subscription

Request:

  • URL: /reader/api/0/subscription/edit
  • Method: POST
  • Supported formats: Returns "OK" in plain text
  • CSRF token required: Yes

Creation:

  • ac: the string subscribe
  • s: the stream ID to create (feed/<feed url>)
  • t: the name for this subscription
  • a: the stream ID of a category. If the category doesn’t exist, it will be created (optional)

Edition:

  • ac: the string edit
  • s: the stream ID to edit (feed/<feed url>)
  • r or a: the stream ID of a category. r moves the feed out of the category, a adds the feed to the category
  • t: a new title for the feed

Deletion:

  • ac: the string unsubscribe
  • s: the stream ID to delete (feed/<feed url>)

Python Example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")
>>> csrf_token = client.get_token(auth_token)

>>> client.edit_subscription(auth_token, csrf_token, subscription_id="feed/1", action="edit", add_label_id=google_reader.get_label_id("Test"))
True

>>> c.edit_subscription(auth_token, csrf_token, subscription_id="feed/1", action="edit", title="New Feed Title")
True

Quick Add Subscription

Request:

  • URL: /reader/api/0/subscription/quickadd
  • Method: POST
  • Supported formats: JSON
  • CSRF token required: Yes

Response:

{
  "query": "feed/http://feeds.arstechnica.com/arstechnica/science",
  "numResults": 1,
  "streamId": "feed/http://arstechnica.com/",
  "streamName": "Ars Technica » Scientific Method"
}

Python Example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")
>>> csrf_token = client.get_token(auth_token)

>>> client.quick_add_subscription(auth_token, csrf_token, url="https://lemonde.fr")
QuickAddSubscription(query='https://www.lemonde.fr/rss/une.xml', num_results=1, stream_id='feed/2', stream_name='Le Monde.fr - Actualités et Infos en France et dans le monde'

Get Stream Items IDs

Request:

  • URL: /reader/api/0/stream/items/ids
  • Method: GET
  • Supported formats: JSON

Querystring parameters:

  • s: Stream ID
  • n: Number of items to return
  • r: Order direction. By default, it is newest first. You can pass the value o here to get oldest first.
  • ot: Start time (unix timestamp) from which to start to get items.
  • xt: Exclude Target. For example, set to user/-/state/com.google/read to exclude all read items.
  • it: Include Target. For example, set to user/-/state/com.google/starred to include starred items.
  • c: Continuation (pagination cursor).

Response:

{
    "itemRefs": [
        {"id": "123"},
        {"id": "456"}
    ],
    "continuation": "abcde"
}

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")

>>> client.get_stream_items_ids(auth_token, stream_id="feed/1", limit=2)
StreamIDs(item_refs=[ItemRef(id='1746307865812560'), ItemRef(id='1746307865812559')], continuation='1746307865812559')

Get Stream Items Contents

Request:

  • URL: /reader/api/0/stream/items/contents
  • Methods: GET
  • Supported formats: JSON

Parameter:

  • i: Item ID (can be repeated)

Response:

{
    "alternate": [
        {
            "href": "https://miniflux.app/",
            "type": "text/html"
        }
    ],
    "author": "admin",
    "direction": "ltr",
    "id": "feed/22",
    "items": [
        {
            "alternate": [
                {
                    "href": "https://miniflux.app/releases/2.2.8.html",
                    "type": "text/html"
                }
            ],
            "author": "Myself",
            "canonical": [
                {
                    "href": "https://miniflux.app/releases/2.2.8.html"
                }
            ],
            "categories": [
                "user/1/state/com.google/reading-list",
                "user/1/label/All"
            ],
            "content": {
                "content": "long text",
                "direction": "ltr"
            },
            "crawlTimeMsec": "1746310821141",
            "enclosure": [

                {
                    "type": "application/octet-stream",
                    "url": "https://github.com/miniflux/v2/releases/download/2.2.8/miniflux-linux-amd64"
                },
                {
                    "type": "application/octet-stream",
                    "url": "https://github.com/miniflux/v2/releases/download/2.2.8/miniflux-linux-amd64.sha256"
                }
            ],
            "id": "tag:google.com,2005:reader/item/0000000000000468",
            "origin": {
                "htmlUrl": "https://miniflux.app/",
                "streamId": "feed/22",
                "title": "Miniflux"
            },
            "published": 1745280000,
            "summary": {
                "content": "long text",
                "direction": "ltr"
            },
            "timestampUsec": "1745280000000000",
            "title": "Miniflux 2.2.8",
            "updated": 1746310821
        }
    ],
    "self": [
        {
            "href": "http://localhost/reader/api/0/stream/items/contents"
        }
    ],
    "title": "Miniflux",
    "updated": 1746311274
}

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")

>>> c.get_stream_items_contents(auth_token, item_ids=[google_reader.get_long_item_id(1128)])
StreamContentItems(...)

Edit Tags

Request:

  • URL: /reader/api/0/edit-tag
  • Method: POST
  • Supported formats: Returns "OK" in plain text
  • CSRF token required: Yes

Parameters:

  • i: Item ID (can be repeated)
  • a: tag to add to the items (can be repeated)
  • r: tag to remove from the items (can be repeated)

Possible tags are:

  • user/-/state/com.google/kept-unread
  • user/-/state/com.google/starred
  • user/-/state/com.google/broadcast
  • user/-/state/com.google/read
  • user/-/state/com.google/like
  • user/-/label/tag_name

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")
>>> csrf_token = client.get_token(auth_token)

>>> client.edit_tags(auth_token, csrf_token, item_ids=[google_reader.get_long_item_id(1128)], add_tags=[google_reader.STREAM_STARRED])
True

>>> client.edit_tags(auth_token, csrf_token, item_ids=['1746307865812560'], add_tags=[google_reader.STREAM_STARRED])
True

Delete Tag

Request:

  • URL: /reader/api/0/disable-tag
  • Method: POST
  • Supported formats: Returns "OK" in plain text
  • CSRF token required: Yes

Parameters:

  • s: Stream ID

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")
>>> csrf_token = client.get_token(auth_token)

>>> client.disable_tag(auth_token, csrf_token, tag_id='user/-/label/Test')
True

>>> client.delete_tag(auth_token, csrf_token, tag_id='user/-/label/Test')
True

Rename Tag

Request:

  • URL: /reader/api/0/rename-tag
  • Method: POST
  • Supported formats: Returns "OK" in plain text
  • CSRF token required: Yes

Parameters:

  • s: Tag stream ID
  • dest: New label name, for example: user/-/label/<new label>

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")
>>> csrf_token = client.get_token(auth_token)

>>> client.rename_tag(auth_token, csrf_token, tag_id='user/-/label/All', new_label_name="Something Else")
True

List Tags

Request:

  • URL: /reader/api/0/disable-tag
  • Method: GET
  • Supported formats: JSON

Response:

{
    "tags": [
        {"id": "user/1005921515/state/com.google/starred"},
        {"id": "user/1/label/My Test", "label": "My Test", "type": "folder"}
    ]
}

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")

>>> client.list_tags(auth_token)
[Tag(id='user/-/state/com.google/starred', label=None, type=None), Tag(id='user/-/label/Test', label=None, type='folder'), Tag(id='user/-/label/Uncategorized', label=None, type='folder')]

>>> client.list_tags(auth_token)
[Tag(id='user/1/state/com.google/starred', label=None, type=None), Tag(id='user/1/label/All', label='All', type='folder'), Tag(id='user/1/label/My Test', label='My Test', type='folder')]

Mark all as read

Request:

  • URL: /reader/api/0/mark-all-as-read
  • Method: POST
  • Supported formats: Returns "OK" in plain text
  • CSRF token required: Yes

Parameters:

  • s: Stream ID
  • ts (optional): Unix Timestamp in seconds or microseconds. When provided, only items older than this timestamp are marked as read.

Python example:

>>> import google_reader

>>> client = google_reader.Client("https://reader.example.org/")
>>> auth_token = client.login("my_username", "my_password")
>>> csrf_token = client.get_token(auth_token)

>>> client.mark_all_as_read(auth_token, csrf_token, 'feed/1')
True

Resources

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

google_reader-0.0.3.tar.gz (10.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

google_reader-0.0.3-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

File details

Details for the file google_reader-0.0.3.tar.gz.

File metadata

  • Download URL: google_reader-0.0.3.tar.gz
  • Upload date:
  • Size: 10.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for google_reader-0.0.3.tar.gz
Algorithm Hash digest
SHA256 397d65d772d353f0be3137b05f4a4d0ca5a4d5c0545456769f495e37c0178629
MD5 60ceeb77dbdbaeb18059aa9740dd12f5
BLAKE2b-256 370e72617daa38fa0eaa5ad6e9e6ba25a6dd1186595fbd19e65b70104c799811

See more details on using hashes here.

Provenance

The following attestation bundles were made for google_reader-0.0.3.tar.gz:

Publisher: publish.yml on miniflux/google-reader

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file google_reader-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: google_reader-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 10.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for google_reader-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7747c1b48e72a3b988364211c13e7f5d30655023102ef64e5177f532851a1436
MD5 4b0ca50290c6b7865ae79eaa789927e3
BLAKE2b-256 32ae2750424c1ca9d3be30036ed7091e8288bc9754450719f1000067f7c84117

See more details on using hashes here.

Provenance

The following attestation bundles were made for google_reader-0.0.3-py3-none-any.whl:

Publisher: publish.yml on miniflux/google-reader

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page