Add user embeds and API support, closing #65

This commit is contained in:
Dylan 2025-01-28 22:07:46 +00:00
parent 8554a733de
commit 88f5ed6780
5 changed files with 82 additions and 3 deletions

19
templates/user.html Normal file
View File

@ -0,0 +1,19 @@
{% extends 'base.html' %}
{% block head %}
<meta property="og:image" content="{{ pfp }}" />
<meta name="twitter:card" content="tweet" />
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
<meta content="{{ color }}" name="theme-color" />
<meta property="og:site_name" content="{{ appname }}">
<meta name="twitter:title" content="{{ user['name'] }} (@{{ user['screen_name'] }})" />
<meta name="twitter:image" content="{{ user['profile_image_url'] }}" />
<meta name="twitter:creator" content="@{{ user['name'] }}" />
<meta property="og:description" content="{{ desc }}" />
<link rel="alternate" href="{{ host }}/oembed.json?desc={{ urlUser }}&user=Twitter&link={{ link }}&ttype=link&provider={{ appname|urlencode }}" type="application/json+oembed" title="{{ user['name'] }}">
<meta http-equiv="refresh" content="1; url = {{ tweetLink }}" /> {% endblock %} {% block body %} Redirecting you to the tweet in a moment. <a href="{{ link }}">Or click here.</a> {% endblock %}

View File

@ -35,4 +35,10 @@ def test_api_include_rtf_nomedia():
resp = client.get(testMediaTweet.replace("https://twitter.com","https://api.vxtwitter.com")+"?include_rtf=ifnomedia",headers={"User-Agent":"test"})
jData = resp.get_json()
assert resp.status_code==200
assert not any(".rtf" in i for i in jData["mediaURLs"])
assert not any(".rtf" in i for i in jData["mediaURLs"])
def test_api_user():
resp = client.get(testUser.replace("https://twitter.com","https://api.vxtwitter.com")+"?include_rtf=true",headers={"User-Agent":"test"})
jData = resp.get_json()
assert resp.status_code==200
assert jData["screen_name"]=="jack"

View File

@ -40,6 +40,11 @@ def test_embed_FromScratch():
client.get(testMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"})
client.get(testMultiMediaTweet.replace("https://twitter.com",""),headers={"User-Agent":"test"})
def test_embed_User():
cache.clearCache()
resp = client.get(testUser.replace("https://twitter.com",""),headers={"User-Agent":"test"})
assert resp.status_code==200
def test_embed_FromCache():
cache.clearCache()
twitfix.getTweetData(testTextTweet)

View File

@ -16,7 +16,7 @@ import twExtract as twExtract
from cache import addVnfToLinkCache,getVnfFromLinkCache
import vxlogging as log
from utils import getTweetIdFromUrl, pathregex
from vxApi import getApiResponse
from vxApi import getApiResponse, getApiUserResponse
from urllib.parse import urlparse
from PyRTF.Elements import Document
from PyRTF.document.section import Section
@ -138,6 +138,17 @@ def renderArticleTweetEmbed(tweetData,appnameSuffix=""):
color=config['config']['color']
)
def renderUserEmbed(userData,appnameSuffix=""):
return render_template("user.html",
user=userData,
host=config['config']['url'],
desc=userData["description"],
urlEncodedDesc=urllib.parse.quote(userData["description"]),
link=f'https://twitter.com/{userData["screen_name"]}',
appname=config['config']['appname'],
color=config['config']['color']
)
@app.route('/robots.txt')
def robots():
return "User-agent: *\nDisallow: /"
@ -181,6 +192,11 @@ def getTweetData(twitter_url,include_txt="false",include_rtf="false"):
addVnfToLinkCache(twitter_url,tweetData)
return tweetData
def getUserData(twitter_url):
rawUserData = twExtract.extractUser(twitter_url,workaroundTokens=config['config']['workaroundTokens'].split(','))
userData = getApiUserResponse(rawUserData)
return userData
def determineEmbedTweet(tweetData):
# Determine which tweet, i.e main or QRT, to embed the media from.
# if there is no QRT, return the main tweet => default behavior
@ -196,6 +212,7 @@ def determineEmbedTweet(tweetData):
@app.route('/<path:sub_path>') # Default endpoint used by everything
def twitfix(sub_path):
isApiRequest=request.url.startswith("https://api.vx") or request.url.startswith("http://api.vx")
if sub_path in staticFiles:
if 'path' not in staticFiles[sub_path] or staticFiles[sub_path]["path"] == None:
staticFiles[sub_path]["path"] = sub_path
@ -204,9 +221,26 @@ def twitfix(sub_path):
sub_path = "i/" + sub_path
match = pathregex.search(sub_path)
if match is None:
# test for .com/username
if sub_path.count("/") == 0:
username=sub_path
extra=None
else:
# get first subpath
username=sub_path.split("/")[0]
extra = sub_path.split("/")[1]
if extra in [None,"with_replies","media","likes","highlights","superfollows","media"] and username != "" and username != None:
userData = getUserData(f"https://twitter.com/{username}")
if isApiRequest:
if userData is None:
abort(404)
return userData
else:
if userData is None:
return message(msgs.failedToScan)
return renderUserEmbed(userData)
abort(404)
twitter_url = f'https://twitter.com/i/status/{getTweetIdFromUrl(sub_path)}'
isApiRequest=request.url.startswith("https://api.vx") or request.url.startswith("http://api.vx")
include_txt="false"
include_rtf="false"

View File

@ -3,6 +3,21 @@ from datetime import datetime
from configHandler import config
from utils import stripEndTCO
def getApiUserResponse(user):
return {
"id": user["id"],
"screen_name": user["screen_name"],
"name": user["name"],
"profile_image_url": user["profile_image_url_https"],
"description": user["description"],
"location": user["location"],
"followers_count": user["followers_count"],
"following_count": user["friends_count"],
"tweet_count": user["statuses_count"],
"created_at": user["created_at"],
"protected": user["protected"],
}
def getApiResponse(tweet,include_txt=False,include_rtf=False):
tweetL = tweet["legacy"]
if "user_result" in tweet["core"]: