Repository: InstaPy/InstaPy

Issue:
DisplayPurposes API Call (Smart Hashtags) Broken
<!-- Did you know that we have a Discord channel ? Join us: https://discord.gg/FDETsht -->
<!-- Is this a Feature Request ? Please, check out our Wiki first https://github.com/timgrossmann/InstaPy/wiki -->
## Expected Behavior
GET request to https://apidisplaypurposes.com/tag/candles should return a list of smart hashtags 

## Current Behavior
Instapy errors out and crashes. The issue can be reproduced via CURL
```
curl 'https://apidisplaypurposes.com/tag/candles'
```

returns 

```
{
  "info": "Query problem, please contact: contact@influtool.com"
}
```

## Possible Solution (optional)
It appears that the display purposes API has changed. The GET request made by the browser includes various headers that are not included by the InstaPy call.  I was able to get it to work using curl with the following request

```
curl 'https://apidisplaypurposes.com/tag/candles' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15' \
-H 'api-token: 1c68cf4abf746e479b658dc48d811738'
```
The api-token value appears to be dynamically generated as it changes every time the GET request is made by the browser. I was not able to find any documentation on the display purposes API to figure out how the api-token gets generated. 



Discussion:
Same issue has been reported time ago, 
I hope soon to be able to review in more detail what can be done to have this fun service again
How were you able to obtain that specific api-token for the tag 'candles'? I have tried with other api-tokens for other tags and none of them worked for the respective tags.
@KevinRNelson I captured the request from the debug console in the browser and saved it to a curl. I have no idea how its generating the tokens though. 
ok thanks, that is how I have been getting other tokens, but yours is the only one that seems to work.

Yeah but that token only works for "candles" with that specific User-Agent header. Change anything and it stops working. They are hashing the User-Agent header and search query into that token value some how I believe. 
**Solution:**
**pip3 install display-purposes** 

Edit Insta.py:
add on top of the document where other imports are:
**from displaypurposes import displaypurposes**

go to the line 728 where **for tag in tags:** is located and add this between the **for** and the **data = json....**
**user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15'**
**myToken = displaypurposes.generate_api_token(tag, user_agent)**
**head = {'User-Agent':user_agent, 'api-token':myToken}**
**req = requests.get("https://apidisplaypurposes.com/tag/{}".format(tag), headers=head)**

With these changes, the smart hashtags seem to work, although I had another issue in function **like_by_tags** in line 1913 where  **tags = [tag.strip() for tag in tags]** is, saying that tag is an int and does not have the function strip... I do not know why this happened but instead of digging more in I just added this:

**else:
           # deletes white spaces in tags
            tags = [tag.strip() for tag in tags]
            tags = tags or []
            self.quotient_breach = False**

Meaning that if we are using smart hashtags we do not need to delete white spaces in tags

Uploaded a zip with my insta.py


[instapy.zip](https://github.com/timgrossmann/InstaPy/files/5906771/instapy.zip)


 

@ferorga 
Thanks for sharing, this will help to solve the problem with the tags.
Do you mind sharing a branch, or PR to see the code and possible
solutions for the other issue you are facing. 
Let us know what you think.

Resolving patch:
diff --git a/instapy/instapy.py b/instapy/instapy.py
--- a/instapy/instapy.py
+++ b/instapy/instapy.py
@@ -725,7 +725,19 @@ def set_smart_hashtags(
             return
 
         for tag in tags:
-            req = requests.get("https://apidisplaypurposes.com/tag/{}".format(tag))
+            if python_version() > "3.5":
+                # CI Travis alert for Python3.5 and apidisplaypurposes
+                from apidisplaypurposes import displaypurposes
+
+                myToken = displaypurposes.generate_api_token(tag, Settings.user_agent)
+                head = {"User-Agent": Settings.user_agent, "api-token": myToken}
+                req = requests.get(
+                    "https://apidisplaypurposes.com/tag/{}".format(tag), headers=head
+                )
+            else:
+                # Old fashion request, must fail in Python <= 3.5
+                req = requests.get("https://apidisplaypurposes.com/tag/{}".format(tag))
+
             data = json.loads(req.text)
 
             if data["tagExists"] is True:
@@ -1904,11 +1916,11 @@ def like_by_tags(
         elif use_smart_location_hashtags is True and self.smart_location_hashtags != []:
             self.logger.info("Using smart location hashtags")
             tags = self.smart_location_hashtags
-
-        # deletes white spaces in tags
-        tags = [tag.strip() for tag in tags]
-        tags = tags or []
-        self.quotient_breach = False
+        else:
+            # deletes white spaces in tags
+            tags = [tag.strip() for tag in tags]
+            tags = tags or []
+            self.quotient_breach = False
 
         # if session includes like_by_tags, then randomize the tag list
         if use_random_tags is True:


Test patch: