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
This Telegram bot is created to help monitor individual mood. Lean and mean

Mood bot This bot is created to help monitor your mood. Lean and mean. Deployment Install Docker and Docker Compose Populate .env file cp .env.dist .e

Piotr Markielau 1 Dec 05, 2021
toldium is a modular, fast, reliable and customizable multiplatform bot library for your communities

toldium The easy multiplatform bot toldium is a modular, fast, reliable and customizable multiplatform bot library for your communities, from a commun

Stockdroid Fans 5 Nov 03, 2021
Herramienta para transferir eventos de Sucuri WAF hacia Azure Data Tables.

Transfiere eventos de Sucuri hacia Azure Data Tables Script para transferir eventos del Sucuri Web Application Firewall (WAF) hacia Azure Data Tables,

CSIRT-RD 1 Dec 22, 2021
Automate TikTok follower bot, like bot, share bot, view bot and more using selenium

Zefoy TikTok Automator Automate TikTok follower bot, like bot, share bot, view bot and more using selenium. Click here to report bugs. Usage Download

555 Dec 30, 2022
Lumberjack-bot - A game bot written for Lumberjack game at Telegram platform

This is a game bot written for Lumberjack game at Telegram platform. It is devel

Uğur Uysal 6 Apr 07, 2022
A telegram bot does not allow channels to send messages to the telegram supergroup

Channel Message Handler Getting started Installation $ git clone https://github.com/AbhijithNT/GroupChannelHandler.git Change directory $ cd ChannelMe

Abhijith N T 0 Dec 26, 2021
🖥️ Python - P1 Monitor API Asynchronous Python Client

🖥️ Asynchronous Python client for the P1 Monitor

Klaas Schoute 9 Dec 12, 2022
The most fresh and updateable Telegram userbot. By one of the most active contibutors to GeekTG

Installation Script installation: Simply run this command out of root: . (wget -qO- http://gg.gg/get_hikka) Manual installation: apt update && apt in

Dan Gazizullin 150 Jan 04, 2023
dex.guru python sdk

dexguru-sdk.py dexguru-sdk.py allows you to access dex.guru public methods from your async python scripts. Installation To install latest version, jus

DexGuru 17 Dec 06, 2022
A powerful bot to copy your google drive data to your team drive

⚛️ Clonebot - Heroku version ⚡ CloneBot is a telegram bot that allows you to copy folder/team drive to team drives. One of the main advantage of this

MsGsuite 269 Dec 23, 2022
An Open Source ALL-In-One Telegram RoBot, that can do lot of things.

An Open Source ALL-In-One Telegram RoBot, that can do lot of things.

JOBIN 0 Dec 01, 2021
nuub-bot is a multi-purpose designed and developed in python3

nuub-bot About Nuub-Bot is an open source, fully customizable Discord bot that is constantly growing. You can invite it to your Discord server using t

Baneet Parmar 8 Jun 28, 2022
SEMID - OSINT module with lots of discord functions

SEMID Framework About Semid is a framework with different Discord functions and

Hima 20 Sep 23, 2022
Authenticate your League of legends account on riot client in a few lines of code.

lol-authenticator v1.0.0 Content index Project Setup Dependencies Project Setup Dependencies Python v3.9.6 If you don't have Python installed on your

Cássio Fontoura 5 Aug 28, 2022
Lambda-function - Python codes that allow notification of changes made to some services using the AWS Lambda Function

AWS Lambda Function This repository contains python codes that allow notificatio

Elif Apaydın 3 Feb 11, 2022
Cities bot - A simple example of using aiogram and the wikipedia package

Cities game A simple example of using aiogram and the wikipedia package. The bot

Artem Meller 2 Jan 29, 2022
A bot that downloads all the necessary files from WeLearn and lists your assignments, filter due assignments, etc.

Welearn-bot This is a bot which lets you interact with WeLearn from the command line. It can Download all files/resources from your courses and organi

Parth Bibekar 17 Oct 19, 2022
This is a simple grabber written in Python which helps you to grab products from Willhaben.at

Willhaben Grabber This is a simple grabber written in Python which helps you to grab products from Willhaben.at General info The tool generates a sear

Ramo 0 Feb 16, 2022
Ever wanted a dashboard for making your antispam? This is it.

Ever wanted a dashboard for making your antispam? This is it.

Skelmis 1 Oct 27, 2021
Python Script to download hundreds of images from 'Google Images'. It is a ready-to-run code!

Google Images Download Python Script for 'searching' and 'downloading' hundreds of Google images to the local hard disk! Documentation Documentation H

Hardik Vasa 8.2k Jan 05, 2023