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 simple Telegram bot, written in Python, that you can use to shill (i.e. send messages) your token, or whatever, to channels.

Telegram Shill Bot Ever wanted a Shill Bot but wankers keep scamming for one OR wanted to charge you an arm and a leg? This is a simple bot written in

53 Nov 25, 2022
Tools to help record data from Qiskit jobs

archiver4qiskit Tools to help record data from Qiskit jobs. Install with pip install git+https://github.com/NCCR-SPIN/archiver4qiskit.git Import the

0 Dec 10, 2021
Changes your desktop wallpaper based on the weather.

WallPaperChanger 🖼️ Description ⛈️ This Python script changes your desktop wallpaper based on the weather. Cloning 🌀 $ git clone https://github.com/

Clarence Yang 74 Nov 29, 2022
Save data from Instagram takeout to a SQLite database

instagram-to-sqlite Save data from a Instagram takeout to a SQLite database. Mise En Place git clone https://github.com/gavindsouza/instagram-to-sqlit

gavin 8 Dec 13, 2022
This repository contains free labs for setting up an entire workflow and DevOps environment from a real-world perspective in AWS

DevOps-The-Hard-Way-AWS This tutorial contains a full, real-world solution for setting up an environment that is using DevOps technologies and practic

Mike Levan 1.6k Jan 05, 2023
A badge generator service to count visitors of your markdown file.

Github Visitors Badge A badge generator service to count visitors of your markdown file. Hello every one! In this post, I will tell you the story of m

Kɪꜱᴀʀᴀ Pᴇꜱᴀɴᴊɪᴛʜ Pᴇʀᴇʀᴀ 〄 1 Feb 06, 2022
Unofficial API wrapper for seedr.cc

Seedr API Unofficial API wrapper for seedr.cc Inspired by theabbie's seedr-api Powered by @harp_tech (Telegram) How to use You can install lib via git

Anjana Madu 49 Oct 24, 2022
Python module and command line script client for http://urbandictionary.com

py-urbandict py-urbandict is a client for urbandictionary.com. Project page on github: https://github.com/novel/py-urbandict PyPI: https://pypi.org/pr

Roman Bogorodskiy 32 Oct 01, 2022
A simple tool which automate commands of discord economy bots

A simple tool which automate commands of discord economy bots. Fully configurable using an intuitive configuration made in YAML

SkydenFly 5 Sep 18, 2022
Use PyTgCalls easier than before.

PyTgCalls wrapper Making it easier for you to use pytgcalls. Features No need to care about audio convertion. Play directly from URLs, YouTube and loc

Calls Music 12 Jul 21, 2022
A Matrix-Instagram DM puppeting bridge

mautrix-instagram A Matrix-Instagram DM puppeting bridge. Documentation All setup and usage instructions are located on docs.mau.fi. Some quick links:

89 Dec 14, 2022
Previewer for VapourSynth scripts.

Standalone previewer for VapourSynth scripts Fork of Endilll's vapoursynth-preview (not maintained anymore) This program is meant to be paired with a

Irrational Encoding Wizardry 26 Dec 16, 2022
File-sharing-Bot: Telegram Bot to store Posts and Documents and it can Access by Special Links.

Bromélia HSS bromelia-hss is the second official implementation of a Diameter-based protocol application by using the Python micro framework Bromélia.

1 Dec 17, 2021
Hermes Bytecode Reverse Engineering Tool (Assemble/Disassemble Hermes Bytecode)

hbctool A command-line interface for disassembling and assembling the Hermes Bytecode. Since the React Native team created their own JavaScript engine

Pongsakorn Sommalai 216 Jan 03, 2023
My beancount practice as a template

my-beancount-template 个人 Beancount 方案的模板仓库 相关博客 复式记账指北(一):What and Why? 复式记账指北(二):做账方法论 复式记账指北(三):如何打造不半途而废的记账方案 配置 详细配置请参考博客三。必须修改的配置有: Bot功能:data/be

KAAAsS 29 Nov 29, 2022
Using Streamlit to build a simple UI on top of the OpenSea API

OpenSea API Explorer Using Streamlit to build a simple UI on top of the OpenSea API. 🤝 Contributing Contributions, issues and feature requests are we

Gavin Capriola 1 Jan 04, 2022
Python SDK for 42DI

42di Python SDK Install pip install git+https://github.com/42di/python-sdk import import di #42di import pandas_datareader as pdr Init SDK project =

42DI 2 Nov 03, 2021
A Python Script to automate searching of available vaccination centers in the city and hence booking

Cowin Vaccine Availability Notifier Cowin Vaccine Availability Notifier takes your City or PIN code as an input and automatically notifies you via ema

Jayesh Padhiar 7 Sep 05, 2021
Um script simples para consultar dados, com API's simples.

Info sobre o Script Esta é uma das mais simples ferramentas para consultar dados. Daqui um tempo eu farei um UPGRADE no painel, irei adicionar um banc

Crowley 6 Apr 11, 2022
um simples script para localizar IP

um simples script para localizar IP pkg install git (apt-get install git) pkg install python (apt-get install python) git clone https://github.com/byd

bydeathlxncer 4 Nov 29, 2021