A Python Tumblr API v2 Client

Overview

PyTumblr

Build Status

Installation

Install via pip:

$ pip install pytumblr

Install from source:

$ git clone https://github.com/tumblr/pytumblr.git
$ cd pytumblr
$ python setup.py install

Usage

Create a client

A pytumblr.TumblrRestClient is the object you'll make all of your calls to the Tumblr API through. Creating one is this easy:

client = pytumblr.TumblrRestClient(
    '<consumer_key>',
    '<consumer_secret>',
    '<oauth_token>',
    '<oauth_secret>',
)

client.info() # Grabs the current user information

Two easy ways to get your credentials to are:

  1. The built-in interactive_console.py tool (if you already have a consumer key & secret)
  2. The Tumblr API console at https://api.tumblr.com/console
  3. Get sample login code at https://api.tumblr.com/console/calls/user/info

Supported Methods

User Methods

client.info() # get information about the authenticating user
client.dashboard() # get the dashboard for the authenticating user
client.likes() # get the likes for the authenticating user
client.following() # get the blogs followed by the authenticating user

client.follow('codingjester.tumblr.com') # follow a blog
client.unfollow('codingjester.tumblr.com') # unfollow a blog

client.like(id, reblogkey) # like a post
client.unlike(id, reblogkey) # unlike a post

Blog Methods

client.blog_info(blogName) # get information about a blog
client.posts(blogName, **params) # get posts for a blog
client.avatar(blogName) # get the avatar for a blog
client.blog_likes(blogName) # get the likes on a blog
client.followers(blogName) # get the followers of a blog
client.blog_following(blogName) # get the publicly exposed blogs that [blogName] follows
client.queue(blogName) # get the queue for a given blog
client.submission(blogName) # get the submissions for a given blog

Post Methods

Creating posts

PyTumblr lets you create all of the various types that Tumblr supports. When using these types there are a few defaults that are able to be used with any post type.

The default supported types are described below.

  • state - a string, the state of the post. Supported types are published, draft, queue, private
  • tags - a list, a list of strings that you want tagged on the post. eg: ["testing", "magic", "1"]
  • tweet - a string, the string of the customized tweet you want. eg: "Man I love my mega awesome post!"
  • date - a string, the customized GMT that you want
  • format - a string, the format that your post is in. Support types are html or markdown
  • slug - a string, the slug for the url of the post you want

We'll show examples throughout of these default examples while showcasing all the specific post types.

Creating a photo post

Creating a photo post supports a bunch of different options plus the described default options * caption - a string, the user supplied caption * link - a string, the "click-through" url for the photo * source - a string, the url for the photo you want to use (use this or the data parameter) * data - a list or string, a list of filepaths or a single file path for multipart file upload

#Creates a photo post using a source URL
client.create_photo(blogName, state="published", tags=["testing", "ok"],
                    source="https://68.media.tumblr.com/b965fbb2e501610a29d80ffb6fb3e1ad/tumblr_n55vdeTse11rn1906o1_500.jpg")

#Creates a photo post using a local filepath
client.create_photo(blogName, state="queue", tags=["testing", "ok"],
                    tweet="Woah this is an incredible sweet post [URL]",
                    data="/Users/johnb/path/to/my/image.jpg")

#Creates a photoset post using several local filepaths
client.create_photo(blogName, state="draft", tags=["jb is cool"], format="markdown",
                    data=["/Users/johnb/path/to/my/image.jpg", "/Users/johnb/Pictures/kittens.jpg"],
                    caption="## Mega sweet kittens")
Creating a text post

Creating a text post supports the same options as default and just a two other parameters * title - a string, the optional title for the post. Supports markdown or html * body - a string, the body of the of the post. Supports markdown or html

#Creating a text post
client.create_text(blogName, state="published", slug="testing-text-posts", title="Testing", body="testing1 2 3 4")
Creating a quote post

Creating a quote post supports the same options as default and two other parameter * quote - a string, the full text of the qote. Supports markdown or html * source - a string, the cited source. HTML supported

#Creating a quote post
client.create_quote(blogName, state="queue", quote="I am the Walrus", source="Ringo")
Creating a link post
  • title - a string, the title of post that you want. Supports HTML entities.
  • url - a string, the url that you want to create a link post for.
  • description - a string, the desciption of the link that you have
#Create a link post
client.create_link(blogName, title="I like to search things, you should too.", url="https://duckduckgo.com",
                   description="Search is pretty cool when a duck does it.")
Creating a chat post

Creating a chat post supports the same options as default and two other parameters * title - a string, the title of the chat post * conversation - a string, the text of the conversation/chat, with diablog labels (no html)

#Create a chat post
chat = """John: Testing can be fun!
Renee: Testing is tedious and so are you.
John: Aw.
"""
client.create_chat(blogName, title="Renee just doesn't understand.", conversation=chat, tags=["renee", "testing"])
Creating an audio post

Creating an audio post allows for all default options and a has 3 other parameters. The only thing to keep in mind while dealing with audio posts is to make sure that you use the external_url parameter or data. You cannot use both at the same time. * caption - a string, the caption for your post * external_url - a string, the url of the site that hosts the audio file * data - a string, the filepath of the audio file you want to upload to Tumblr

#Creating an audio file
client.create_audio(blogName, caption="Rock out.", data="/Users/johnb/Music/my/new/sweet/album.mp3")

#lets use soundcloud!
client.create_audio(blogName, caption="Mega rock out.", external_url="https://soundcloud.com/skrillex/sets/recess")
Creating a video post

Creating a video post allows for all default options and has three other options. Like the other post types, it has some restrictions. You cannot use the embed and data parameters at the same time. * caption - a string, the caption for your post * embed - a string, the HTML embed code for the video * data - a string, the path of the file you want to upload

#Creating an upload from YouTube
client.create_video(blogName, caption="Jon Snow. Mega ridiculous sword.",
                    embed="http://www.youtube.com/watch?v=40pUYLacrj4")

#Creating a video post from local file
client.create_video(blogName, caption="testing", data="/Users/johnb/testing/ok/blah.mov")
Editing a post

Updating a post requires you knowing what type a post you're updating. You'll be able to supply to the post any of the options given above for updates.

client.edit_post(blogName, id=post_id, type="text", title="Updated")
client.edit_post(blogName, id=post_id, type="photo", data="/Users/johnb/mega/awesome.jpg")
Reblogging a Post

Reblogging a post just requires knowing the post id and the reblog key, which is supplied in the JSON of any post object.

client.reblog(blogName, id=125356, reblog_key="reblog_key")
Deleting a post

Deleting just requires that you own the post and have the post id

client.delete_post(blogName, 123456) # Deletes your post :(

A note on tags: When passing tags, as params, please pass them as a list (not a comma-separated string):

client.create_text(blogName, tags=['hello', 'world'], ...)
Getting notes for a post

In order to get the notes for a post, you need to have the post id and the blog that it is on.

data = client.notes(blogName, id='123456')

The results include a timestamp you can use to make future calls.

data = client.notes(blogName, id='123456', before_timestamp=data["_links"]["next"]["query_params"]["before_timestamp"])

Tagged Methods

# get posts with a given tag
client.tagged(tag, **params)

Using the interactive console

This client comes with a nice interactive console to run you through the OAuth process, grab your tokens (and store them for future use).

You'll need pyyaml installed to run it, but then it's just:

$ python interactive-console.py

and away you go! Tokens are stored in ~/.tumblr and are also shared by other Tumblr API clients like the Ruby client.

Running tests

The tests (and coverage reports) are run with nose, like this:

python setup.py test

Copyright and license

Copyright 2013 Tumblr, Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations.

Comments
  • oauth issue

    oauth issue

    Hello,

    I received this error when i launched

    python interactive_console.py

    I did give correct "consumer key" and "consumer secret" when prompted

    I am using latest python and installed required modules it requested using python setup.py install Python 2.7.6

    Appreciate your help...

    Traceback (most recent call last): File "interactive_console.py", line 65, in tokens = new_oauth(yaml_path) File "interactive_console.py", line 32, in new_oauth print '\nPlease go here and authorize:\n%s?oauth_token=%s' % (authorize_url, request_token['oauth_token'][0]) KeyError: 'oauth_token'

    opened by srinivasuk 50
  • Unauthorized Error - Get The Number of Followers That A Blog Has

    Unauthorized Error - Get The Number of Followers That A Blog Has

    This is the JSON response, when I use this library to get the followers of a blog.

    {'meta': {'status': 401, 'msg': 'Not Authorized'}, 'response': []}

    This is what I use to call it: #client is declared elsewhere tumblr_followers = json.loads(json.dumps(client.followers('good')))

    print tumblr_followers

    I am able to use the library for getting Blog Posts, I was just wondering how I could get the total number of followers of a blog, since apparently I am not authorized to get this info? Thanks.

    Francois


    After reading some documentation, it turns out you need OAuth, I'm still relatively new to Python, how do I make an OAuth request to Tumblr? I have the OAuth Consumer Key/Secret/API Key/Secret.

    Thanks for the help in advance.

    opened by peoplecallmefrancois 12
  • Python 2/3 support for PyTumblr.

    Python 2/3 support for PyTumblr.

    I have updated the PyTumblr code to be both backwards compatible with Python 2 and forwards compatible with Python 3.

    Some notes about what I've done:

    • Since the oauth2 library isn't Python 3 compatible, I've ripped it out and replaced it with requests-oauthlib, which has cleaned up the multipart posting quite a bit.
    • I've used the future library to be the compatibility layer for both Python 2 and Python 3, hence I've added it as a requirement.
    • I have done some manual testing in both Python 2 and 3 to ensure that the major functionality is still working the way we'd expect, including file uploads.
    • It seems like HTTPretty is giving us back values as Python bytestrings, so I had to update the tests to reflect that. If this is a concern, let me know.
    • There's some issues with running the tests under 3.4 due to how HTTPretty does its mocking of sockets (see this issue for more details), so I've only added 3.3 to be run on Travis. The client itself runs fine under Python 3.4.
    • There's also a few minor PEP8 fixes that I've tossed in as well.

    I'm reading over the CLA right now. I'll try to get it sent in on Tuesday if you're are interested in ever trying to merge this. I'm happy to make updates based on any code review feedback you may have.

    opened by dianakhuang 11
  • ImportError: No module named 'helpers'

    ImportError: No module named 'helpers'

    Is fixed by the Python 3 support pull request

    Which, pending it being merged into master, you can install with

    pip install git+git://github.com/dianakhuang/pytumblr.git@diana/python-3-support
    

    Hopefully this will save someone 5 minutes

    opened by coilysiren 10
  • Add photoset_layout as an option to create_photo

    Add photoset_layout as an option to create_photo

    Even though this is not a documented feature of the Tumblr API, it works well, and this attribute is actually provided by their Posts endpoint (http://www.tumblr.com/docs/en/api/v2#posts)

    Allowing this photoset_layout option as a valid attribute to create an image post would be a nice addition since it gives full control over how photos are laid out in the template.

    opened by taylanpince 8
  • Reblogging with a photo

    Reblogging with a photo

    I've attempted to use pytumblr to reblog a post with an image however I cannot seem to do this properly.

    Noticing the reblog method doesn't accept kwargs caption, link, source, and data I added those to the accepted options in init.py. Then naturally I called reblog like: client.reblog(your_blog_name,id=i,reblog_key=key,type='photo',source=ima)

    however this results in empty reblogs that do not have the photo uploaded. additionally, I have tried manually calling client.request.post() as such: url = "/v2/blog/" + your_blog_name + ".tumblr.com/post/reblog" kwargs = {"type":"photo", "source":ima, "id":i, "reblog_key":key} print client.request.post(url, kwargs)

    with the same result.

    How would I reblog with a photo added?

    opened by PolarisScientia 8
  • client.create_photo

    client.create_photo

    I've just discovered by trial and error that when using client.create_photo method the data parameter (path to photo) must be str (not unicode). However the caption can be unicode. You should specify when you say "string" what type of string too (str or unicode). Thank you.

    opened by Danielez 7
  • Can't use type parameter in posts() function

    Can't use type parameter in posts() function

    The field type is listed as an optional argument for posts() function but the validate_params() function disallows type and raises an exception upon its inclusion, making it impossible to call with the type parameter.

    i.e., this code:

    args = {'type': 'text', 'limit':2} posts = client.posts(urls[0], **args)

    returns this error:

    C:\Users-Removed-\AppData\Local\Enthought\Canopy\User\lib\site-packages\pytumblr-0.0.5-py2.7.egg\pytumblr\helpers.pyc in validate_params(valid_options, params) 25 if disallowed_fields: 26 field_strings = ",".join(disallowed_fields) ---> 27 raise Exception("%s are not allowed fields" % field_strings) 28 29 def validate_blogname(fn):

    Exception: type are not allowed fields

    opened by Chaobunny 7
  • Installation added to readme file

    Installation added to readme file

    As an API v2 user, I encountered with this problem, I needed to install it but since there wasn't clear information about if it is available in pip I tried and saw that it is available, but with adding these tutorial lines it would be easier for the new users. It also includes the downloading and installing it via setup.py version of the installation.

    Need to be added:

    • [ ] Features
    • [ ] Dependencies
    opened by omergulen 6
  • help me

    help me

    hello sorry i'm french i can not run I have an error on the test I have my tumblr key, but I do not understand all

    EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE

    ERROR: test_blogInfo (main.TumblrRestClientTest)

    Traceback (most recent call last): File "/home/pi/pytumblr/pytumblr-master/tests/test_pytumblr.py", line 16, in setUp with open('tests/tumblr_credentials.json', 'r') as f: IOError: [Errno 2] No such file or directory: 'tests/tumblr_credentials.json'

    =========-------------------------------------------------- Ran 33 tests in 0.335s

    FAILED (errors=33)

    opened by mika7700 6
  • 401 unauthorized errors despite correct credentials

    401 unauthorized errors despite correct credentials

    ( Note: could be having the same problem as #34 )

    I've copied all the credentials directly from the API explore console (where all calls complete successfully), and provided them to the Pytumblr client. However, I still receive 401 errors for any requests to the API. I have confirmed my configuration with someone at Tumblr, as well.

    opened by jakemmarsh 6
  • Neue Post Format, post type filters, and content

    Neue Post Format, post type filters, and content

    I'm attempting to get all image posts associated with a list blogs (just personal archive reasons), and I'm running into an issue with the Neue Post Format / NPF. If I'm understanding the documentation correctly, NPF should return what's effectively a JSON layout of the post, and NPF posts can be identified by having is_blocks_post_format as True.

    The post I'm having issues with is post id 186412013514. It's marked as a text type post, NPF, and contains a single image.

    The following is the line to find the post as generated by the API console:

    client.posts('vagelio', type='photo', limit=1, offset=40, reblog_info=True)
    
    And the response...
    {
      "meta": {
        "status": 200,
        "msg": "OK"
      },
      "response": {
        "blog": {
          "ask": true,
          "ask_anon": true,
          "ask_page_title": "Ask me anything",
          "asks_allow_media": true,
          "avatar": [
            {
              "width": 512,
              "height": 512,
              "url": ["https://64.media.tumblr.com/avatar_712957997181_512.png"](https://64.media.tumblr.com/avatar_712957997181_512.png)
            },
            {
              "width": 128,
              "height": 128,
              "url": ["https://64.media.tumblr.com/avatar_712957997181_128.png"](https://64.media.tumblr.com/avatar_712957997181_128.png)
            },
            {
              "width": 96,
              "height": 96,
              "url": ["https://64.media.tumblr.com/avatar_712957997181_96.png"](https://64.media.tumblr.com/avatar_712957997181_96.png)
            },
            {
              "width": 64,
              "height": 64,
              "url": ["https://64.media.tumblr.com/avatar_712957997181_64.png"](https://64.media.tumblr.com/avatar_712957997181_64.png)
            }
          ],
          "can_chat": false,
          "can_subscribe": false,
          "description": "Freelancer illustrator\nContact: [email protected]",
          "is_nsfw": false,
          "name": "vagelio",
          "posts": 154,
          "share_likes": false,
          "subscribed": false,
          "theme": {
            "header_full_width": 938,
            "header_full_height": 1364,
            "header_focus_width": 879,
            "header_focus_height": 495,
            "avatar_shape": "square",
            "background_color": "#DCDED4",
            "body_font": "Helvetica Neue",
            "header_bounds": "177,879,672,0",
            "header_image": ["https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s938x1364/93da9b234204a90b33359be4d6a450f39df2da3f.jpg"](https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s938x1364/93da9b234204a90b33359be4d6a450f39df2da3f.jpg),
            "header_image_focused": ["https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072_c0,12977,93710,49267/9163dcae16537f1de57a42dde0f6e85172e62015.jpg"](https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072_c0,12977,93710,49267/9163dcae16537f1de57a42dde0f6e85172e62015.jpg),
            "header_image_poster": "",
            "header_image_scaled": ["https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072/ebce2594714645366b4aa030b5750c66d2ea76df.jpg"](https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072/ebce2594714645366b4aa030b5750c66d2ea76df.jpg),
            "header_stretch": true,
            "link_color": "#567080",
            "show_avatar": true,
            "show_description": true,
            "show_header_image": true,
            "show_title": true,
            "title_color": "#2E2E2E",
            "title_font": "Sans Serif",
            "title_font_weight": "bold"
          },
          "title": "Vagelio",
          "total_posts": 154,
          "updated": 1669230150,
          "url": ["https://vagelio.tumblr.com/"](https://vagelio.tumblr.com/),
          "uuid": "t:vmv8w8qw3xgtMosxZINm4Q"
        },
        "posts": [
          {
            "type": "text",
            "is_blocks_post_format": true,
            "blog_name": "vagelio",
            "blog": {
              "name": "vagelio",
              "title": "Vagelio",
              "description": "Freelancer illustrator\nContact: [email protected]",
              "url": ["https://vagelio.tumblr.com/"](https://vagelio.tumblr.com/),
              "uuid": "t:vmv8w8qw3xgtMosxZINm4Q",
              "updated": 1669230150,
              "tumblrmart_accessories": {}
            },
            "id": 186412013514,
            "id_string": "186412013514",
            "post_url": ["https://vagelio.tumblr.com/post/186412013514/argam-tiefling-rogue-part-of-a-larger-commission"](https://vagelio.tumblr.com/post/186412013514/argam-tiefling-rogue-part-of-a-larger-commission),
            "slug": "argam-tiefling-rogue-part-of-a-larger-commission",
            "date": "2019-07-20 01:32:58 GMT",
            "timestamp": 1563586378,
            "state": "published",
            "format": "html",
            "reblog_key": "xwQgX7xU",
            "tags": [
              "dungeons and dragons",
              "rpg",
              "illustration",
              "character concept",
              "dnd",
              "commission",
              "fantasy",
              "dnd character",
              "character art",
              "5e",
              "sketch",
              "sketchbook",
              "dnd 5e",
              "tiefling",
              "Rogue",
              "portrait",
              "commisionwork",
              "vagelio kaliva",
              "Vagelio"
            ],
            "short_url": ["https://tmblr.co/Z5xoYx2jd1PVA"](https://tmblr.co/Z5xoYx2jd1PVA),
            "summary": "Argam, tiefling rogue. Part of a larger commission for a kickstarter module.\nFind me on\nTumblr:...",
            "should_open_in_legacy": false,
            "recommended_source": null,
            "recommended_color": null,
            "note_count": 36,
            "title": "",
            "body": "

    Argam, tiefling rogue. Part of a larger commission for a kickstarter module.

    Find me on

    Tumblr: http://vagelio.tumblr.com/

    Facebook: https://www.facebook.com/vageliokali

    Instagram: https://www.instagram.com/vageliokal/

    Deviantart: http://vagelio.deviantart.com/

    ", "reblog": { "comment": "

    Argam, tiefling rogue. Part of a larger commission for a kickstarter module.

    Find me on

    Tumblr: http://vagelio.tumblr.com/

    Facebook: https://www.facebook.com/vageliokali

    Instagram: https://www.instagram.com/vageliokal/

    Deviantart: http://vagelio.deviantart.com/

    ", "tree_html": "" }, "trail": [ { "blog": { "name": "vagelio", "active": true, "theme": { "header_full_width": 938, "header_full_height": 1364, "header_focus_width": 879, "header_focus_height": 495, "avatar_shape": "square", "background_color": "#DCDED4", "body_font": "Helvetica Neue", "header_bounds": "177,879,672,0", "header_image": ["https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s938x1364/93da9b234204a90b33359be4d6a450f39df2da3f.jpg"](https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s938x1364/93da9b234204a90b33359be4d6a450f39df2da3f.jpg), "header_image_focused": ["https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072_c0,12977,93710,49267/9163dcae16537f1de57a42dde0f6e85172e62015.jpg"](https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072_c0,12977,93710,49267/9163dcae16537f1de57a42dde0f6e85172e62015.jpg), "header_image_poster": "", "header_image_scaled": ["https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072/ebce2594714645366b4aa030b5750c66d2ea76df.jpg"](https://64.media.tumblr.com/bc8d9592a2e59aa531c1732d67074363/60aceee2e7f46bf5-9d/s2048x3072/ebce2594714645366b4aa030b5750c66d2ea76df.jpg), "header_stretch": true, "link_color": "#567080", "show_avatar": true, "show_description": true, "show_header_image": true, "show_title": true, "title_color": "#2E2E2E", "title_font": "Sans Serif", "title_font_weight": "bold" }, "share_likes": false, "share_following": false, "can_be_followed": true }, "post": { "id": "186412013514" }, "content_raw": "

    Argam, tiefling rogue. Part of a larger commission for a kickstarter module.

    Find me on

    Tumblr: http://vagelio.tumblr.com/

    Facebook: https://www.facebook.com/vageliokali

    Instagram: https://www.instagram.com/vageliokal/

    Deviantart: http://vagelio.deviantart.com/

    ", "content": "

    \"image\"

    Argam, tiefling rogue. Part of a larger commission for a kickstarter module.

    Find me on

    Tumblr: http://vagelio.tumblr.com/

    Facebook: https://www.facebook.com/vageliokali

    Instagram: https://www.instagram.com/vageliokal/

    Deviantart: http://vagelio.deviantart.com/

    ", "is_current_item": true, "is_root_item": true } ], "can_like": false, "interactability_reblog": "everyone", "can_reblog": false, "can_send_in_message": true, "can_reply": false, "display_avatar": true } ], "total_posts": 149, "_links": { "next": { "href": "/v2/blog/vagelio.tumblr.com/posts/photo?type=photo&limit=1&offset=40&reblog_info=true&tumblelog=vagelio.tumblr.com&page_number=VH-0kfNfc0AU9JcdaiZtcKHeFS0_5P3WZdEnabkhmd0zbGM4dW1hN1JKbXdZelpabWZONlU4Y1lNd0xMdWxZR3JFSGpTNWpmUDdZelRxc2RVRjZOOUNabEMybUlQNiszUkVhZ2QyNURCMTNoMHY0RENmbWRIUitKQVpFdFJ3cDhWL2xLOXJLbkhkWm42YVE3SzJtTHJadzNYWkdZQW8rdThFTmUwSm81OEZ2NzZXMTE1K3pBSmVWbWVOVWc4Z3h2T0JZcDIrRFRiQnREMGg5TUhBQjk5QWtYSDZpbk1ITWt0N3EyQWsyeGt5clR5OFVrYXFSTmhzNG1WNC96cHZRdHlMRTJzM1FpUzhTNjNFK01iTjY1L1Z0RDZMU3M4RnhXRk9BSWRGNkhKM3EvN2g1S2g4R1RoYXdrekJ1KzdKT2ZHd0gwZklWOGQ2bzE3ajYvTHdIOW1PRTFJQ2tOWTdkbFlOUXJmU3JqTm5sY21OV1JnUU5LblltRDgzbjFzS2Z2S1h5eHJhRkZyTmtXNzg1RUNYVVk5bS9wR2lhYnBRN2E4ZEFMczVlUzhOZkFQdXB1K2V3elZWZz09", "method": "GET", "query_params": { "type": "photo", "limit": "1", "offset": "40", "reblog_info": "true", "tumblelog": "vagelio.tumblr.com", "page_number": "VH-0kfNfc0AU9JcdaiZtcKHeFS0_5P3WZdEnabkhmd0zbGM4dW1hN1JKbXdZelpabWZONlU4Y1lNd0xMdWxZR3JFSGpTNWpmUDdZelRxc2RVRjZOOUNabEMybUlQNiszUkVhZ2QyNURCMTNoMHY0RENmbWRIUitKQVpFdFJ3cDhWL2xLOXJLbkhkWm42YVE3SzJtTHJadzNYWkdZQW8rdThFTmUwSm81OEZ2NzZXMTE1K3pBSmVWbWVOVWc4Z3h2T0JZcDIrRFRiQnREMGg5TUhBQjk5QWtYSDZpbk1ITWt0N3EyQWsyeGt5clR5OFVrYXFSTmhzNG1WNC96cHZRdHlMRTJzM1FpUzhTNjNFK01iTjY1L1Z0RDZMU3M4RnhXRk9BSWRGNkhKM3EvN2g1S2g4R1RoYXdrekJ1KzdKT2ZHd0gwZklWOGQ2bzE3ajYvTHdIOW1PRTFJQ2tOWTdkbFlOUXJmU3JqTm5sY21OV1JnUU5LblltRDgzbjFzS2Z2S1h5eHJhRkZyTmtXNzg1RUNYVVk5bS9wR2lhYnBRN2E4ZEFMczVlUzhOZkFQdXB1K2V3elZWZz09" } } } } }

    Firstly, this post probably shouldn't be in the response I'm getting because I'm filtering for only photo type files and it's marked as text.

    Secondly, and more importantly, the content block seems to be raw HTML. I thought it was just a fluke until I opened up another random photos-like post to the same result. Adding filter=... to the function call either leaves it unchanged or cuts all of the non-text content from the post.

    My understanding is that it should look more like this:

    (Low-effort creation based on the NPF API examples.)
    {
        "content": [
            {
                "type": "image",
                "media": [
                    {
                        "type": "image/jpeg",
                        "url": "https://64.media.tumblr.com/ab6859e23877a7d3a47a12cac73f529a/0267aa057059a2a1-a2/s500x750/1758d513b10010d980864d10f7e75d72c40ee21a.jpg",
                        "width": 1280,
                        "height": 1073
                    },
                    {
                        "type": "image/jpeg",
                        "url": "https://64.media.tumblr.com/ab6859e23877a7d3a47a12cac73f529a/0267aa057059a2a1-a2/s500x750/1758d513b10010d980864d10f7e75d72c40ee21a.jpg",
                        "width": 540,
                        "height": 400
                    },
                    {
                        "type": "image/jpeg",
                        "url": "https://64.media.tumblr.com/ab6859e23877a7d3a47a12cac73f529a/0267aa057059a2a1-a2/s500x750/1758d513b10010d980864d10f7e75d72c40ee21a.jpg",
                        "width": 250,
                        "height": 150
                    }
                ],
            },
            {
                "type": "text",
                "text": "The person's social information would be here."
            },
        ],
    }
    

    Am I misunderstanding the API?

    (Oh, also the npf=true flag doesn't seem to work for the client.posts() function.)

    opened by ldv8434 1
  • Upload v0.1.1 to pypi?

    Upload v0.1.1 to pypi?

    I note there was a version bump to v0.1.1 back in March, however the latest version on PyPi is still 0.1.0 - would it be possible to get 0.1.1 released and uploaded?

    opened by snail-coupe 0
  • API returns older posts than requested

    API returns older posts than requested

    Hi, when using the tagged method with the current date's timestamp int(datetime.datetime.now().timestamp()), for certain tags (e.g., fashion), the API returns posts starting from the year 2015 while for others start at the current date (2022-07-20). This is probably more of an issue with the server rather than the API, however, it is still an issue.

    opened by daubaris 0
Releases(0.1.1)
Owner
Tumblr
Tumblr
wyscoutapi is an extremely basic API client for the Wyscout API (v2 & v3) for Python

wyscoutapi wyscoutapi is an extremely basic API client for the Wyscout API (v2 & v3). Usage Install with pip install wyscoutapi. To connect to the Wys

Ben Torvaney 11 Nov 22, 2022
Beyonic API Python official client library simplified examples using Flask, Django and Fast API.

Beyonic API Python official client library simplified examples using Flask, Django and Fast API.

Harun Mbaabu Mwenda 46 Sep 1, 2022
Python API Client for Twitter API v2

?? Python Client For Twitter API v2 ?? Why Twitter Stream ? Twitter-Stream.py a python API client for Twitter API v2 now supports FilteredStream, Samp

Twitivity 31 Nov 19, 2022
Dns-Client-Server - Dns Client Server For Python

Dns-client-server DNS Server: supporting all types of queries and replies. Shoul

Nishant Badgujar 1 Feb 15, 2022
Raphtory-client - The python client for the Raphtory project

Raphtory Client This is the python client for the Raphtory project Install via p

Raphtory 5 Apr 28, 2022
Drcom-pt-client - Drcom Pt version client with refresh timer

drcom-pt-client Drcom Pt version client with refresh timer Dr.com Pt版本客户端 可用于网页认

null 4 Nov 16, 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
🖥️ Python - P1 Monitor API Asynchronous Python Client

??️ Asynchronous Python client for the P1 Monitor

Klaas Schoute 9 Dec 12, 2022
Python API Client for Close

Close API A convenient Python wrapper for the Close API. API docs: http://developer.close.com Support: [email protected] Installation pip install clos

Close 56 Nov 30, 2022
Python client for CoinPayments API

pyCoinPayments - Python API client for CoinPayments Updates This library has now been converted to work with python3 This is an unofficial client for

James 27 Sep 21, 2022
DEPRECATED - Official Python Client for the Discogs API

⚠️ DEPRECATED This repository is no longer maintained. You can still use a REST client like Requests or other third-party Python library to access the

Discogs 483 Dec 31, 2022
The Foursquare API client for Python

foursquare Python client for the foursquare API. Philosophy: Map foursquare's endpoints one-to-one Clean, simple, Pythonic calls Only handle raw data,

Mike Lewis 400 Dec 19, 2022
Python Client for Instagram API

This project is not actively maintained. Proceed at your own risk! python-instagram A Python 2/3 client for the Instagram REST and Search APIs Install

Facebook Archive 2.9k Dec 30, 2022
A Python Client for News API

newsapi-python A Python client for the News API. License Provided under MIT License by Matt Lisivick. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRAN

Matt Lisivick 281 Dec 29, 2022
SmartFile API Client (Python).

A SmartFile Open Source project. Read more about how SmartFile uses and contributes to Open Source software. Summary This library includes two API cli

SmartFile 19 Jan 11, 2022
Python client for the Socrata Open Data API

sodapy sodapy is a python client for the Socrata Open Data API. Installation You can install with pip install sodapy. If you want to install from sour

Cristina 368 Dec 9, 2022
Python client for the Echo Nest API

Pyechonest Tap into The Echo Nest's Musical Brain for the best music search, information, recommendations and remix tools on the web. Pyechonest is an

The Echo Nest 655 Dec 29, 2022
A super awesome Twitter API client for Python.

birdy birdy is a super awesome Twitter API client for Python in just a little under 400 LOC. TL;DR Features Future proof dynamic API with full REST an

Inueni 259 Dec 28, 2022
Cord Python API Client

Cord Python API Client The data programming platform for AI ?? Features Minimal low-level Python client that allows you to interact with Cord's API Su

Cord 52 Nov 25, 2022