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'

    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
A python library for anti-captcha.com

AntiCaptcha A python library for anti-captcha.com Documentation for the API Requirements git Install git clone https://github.com/ShayBox/AntiCaptcha.

Shayne Hartford 3 Dec 16, 2022
A simple script & container to pull COVID data from covidlive.com.au and post a summary to a slack channel

CovidLive AU Summary Slackbot This bot is a very simple slackbot that pulls data, summarises and posts up to date AU COVID stats to a provided slack c

James 3 Dec 18, 2021
You have 3 files: create mass groups, add mass members, rename all groups (only educational use!)

EDUCATIONAL ONLY! HOW TO INSTALL Edit config.json with your discord account token and the imagepath (if its in the same location as the all_together.p

46 Dec 27, 2022
A Python wrapper around the Twitter API.

Python Twitter A Python wrapper around the Twitter API. By the Python-Twitter Developers Introduction This library provides a pure Python interface fo

Mike Taylor 3.4k Jan 01, 2023
A wordwolf bot with python

ワードウルフBot requirements.txtから依存ライブラリをインストールしてください discordのトークン/Google spread sheetのキー/Sheetの名前を.envに書き込んでください DISCORD_TOKEN SHEET_KEY SHEET_NAME また、.sh

Kato 2 Dec 11, 2022
Huan Xu 1.6k Jan 04, 2023
Most Powerful Chatbot On Telegram Bot

About Hello, I am Lycia [リュキア], An Intelligent ChatBot. If You Are Feeling Lonely, You can Always Come to me and Chat With Me! How To Host The easiest

RedAura 8 May 26, 2021
A client that allows a user, specifiy their discord token, to send images remotely to discord

ImageBot_for_Discord A client that allows a user, specifiy their discord token, to send images remotely to discord. Can select images using a file dia

0 Aug 24, 2022
Information about the weather in a city written using Python

Information about the weather in a city Enter the desired city Climate information of the target city This program is written using Python programming

Amir Hussein Sharifnezhad 4 Nov 17, 2021
Crypto trading bot that detects surges in the bitcoin price and executes trades.

The bot will be trading Bitcoin automatically if the price has increased by more than 3% in the last 10 minutes. We will have a stop loss of 5% and t

164 Oct 20, 2022
SkyzoMusicBot - Bot Music Telegram By Skyzo

SKYZO MUSIC BOT Telegram Music Bot And Stream Feature New Version Ready to use m

Skyzo 19 Apr 08, 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.

Latest Open Source Code for Playing Music in Telegram Video Chat. Made with Pyrogram and Pytgcalls 💖

MusicPlayer_TG Latest Open Source Code for Playing Music in Telegram Video Chat. Made with Pyrogram and Pytgcalls 💖 Requirements 📝 FFmpeg NodeJS nod

Abhijith Sudhakaran 2 Feb 04, 2022
Access Undenied parses AWS AccessDenied CloudTrail events, explains the reasons for them, and offers actionable remediation steps. Open-sourced by Ermetic.

Access Undenied on AWS Access Undenied parses AWS AccessDenied CloudTrail events, explains the reasons for them, and offers actionable fixes. Access U

Ermetic 204 Jan 02, 2023
An incomplete add-on extension to Pyrogram, to create telegram bots a bit more easily

PyStark A star ⭐ from you means a lot An incomplete add-on extension to Pyrogram

Stark Bots 36 Dec 23, 2022
Flask extension that provides integration with Azure Storage

Flask-Azure-Storage A Flask extension that provides integration with Azure Storage Table of Contents Flask-Azure-Storage Install Usage Examples Create

Alejo Arias 17 Nov 14, 2021
A simple notebook to stream torrent files directly to Google Drive using Google Colab.

Colab-Torrent-to-Drive Originally by FKLC, this is a simple notebook to stream torrent files directly to Google Drive using Google Colab. You can eith

1 Jan 11, 2022
Telegram bot for Whisper Message.

Whisper Bot @WhisperStarkBot A star ⭐ from you means a lot to us! Telegram bot for Whisper Message. Usage Deploy to Heroku Tap on above button and fil

Stark Bots 33 Nov 24, 2022
Получение интересной информации о любой пиццерии Додо

dodopizza-abuse Получение инфорации о выбранной пиццерии Додо Установка и запуск на Linux Устанавливаем git и python: apt-get update && apt-get -y ins

Хозя 24 Nov 02, 2022