New version 1.2

This commit is contained in:
Wire 2020-07-13 16:36:45 +02:00
parent 26b9e465f1
commit 8891c275cf
8 changed files with 119 additions and 52 deletions

View File

@ -62,7 +62,6 @@ class twitterPost():
validPost = True validPost = True
content = "El gato siguió a la liebre. Esto es un texto de ejemplo." content = "El gato siguió a la liebre. Esto es un texto de ejemplo."
profilePic = "url" profilePic = "url"
twitterAt = "@error"
twitterName = "Error Name" twitterName = "Error Name"
timeStamp = "error" timeStamp = "error"

View File

@ -3,11 +3,16 @@ from flask import render_template, flash, redirect, url_for, request
from app.forms import LoginForm, RegistrationForm, EmptyForm, SearchForm from app.forms import LoginForm, RegistrationForm, EmptyForm, SearchForm
from app.models import User, twitterPost from app.models import User, twitterPost
from werkzeug.urls import url_parse from werkzeug.urls import url_parse
from bs4 import BeautifulSoup
from flask import Markup from flask import Markup
from app import app, db from app import app, db
import time, datetime import time, datetime
import random, string import random, string
import feedparser import feedparser
import requests
nitterInstance = "https://nitter.net/"
nitterInstanceII = "https://nitter.mastodont.cat"
@app.route('/') @app.route('/')
@app.route('/index') @app.route('/index')
@ -17,21 +22,20 @@ def index():
followed = current_user.followed.count() followed = current_user.followed.count()
posts = [] posts = []
avatarPath = "img/avatars/1.png" avatarPath = "img/avatars/1.png"
form = EmptyForm()
for fwd in following: for fwd in following:
avatarPath = "img/avatars/{}.png".format(str(random.randint(1,12))) avatarPath = "img/avatars/{}.png".format(str(random.randint(1,12)))
#Gather profile info. #Gather profile info.
rssFeed = feedparser.parse('https://nitter.net/{}/rss'.format(fwd.username)) rssFeed = feedparser.parse('{instance}{user}/rss'.format(instance=nitterInstance, user=fwd.username))
twitterAt = rssFeed.feed.title.split("/")[1].replace(" ", "")
twitterName = rssFeed.feed.title.split("/")[0]
#Gather posts #Gather posts
if rssFeed.entries != []: if rssFeed.entries != []:
for post in rssFeed.entries: for post in rssFeed.entries:
newPost = twitterPost() newPost = twitterPost()
newPost.profilePic = rssFeed.channel.image.url
newPost.twitterAt = rssFeed.feed.title.split("/")[1].replace(" ", "")
newPost.twitterName = rssFeed.feed.title.split("/")[0]
newPost.username = rssFeed.feed.title.split("/")[0] newPost.username = rssFeed.feed.title.split("/")[0]
newPost.date = getTimeDiff(post.published_parsed) newPost.date = getTimeDiff(post.published_parsed)
newPost.timeStamp = datetime.datetime(*post.published_parsed[:6]) newPost.timeStamp = datetime.datetime(*post.published_parsed[:6])
@ -41,11 +45,16 @@ def index():
if "RT by" in post.title: if "RT by" in post.title:
newPost.isRT = True newPost.isRT = True
newPost.profilePic = ""
else: else:
newPost.isRT = False newPost.isRT = False
try:
newPost.profilePic = rssFeed.channel.image.url
except:
newPost.profilePic = avatarPath
posts.append(newPost) posts.append(newPost)
posts.sort(key=lambda x: x.timeStamp, reverse=True) posts.sort(key=lambda x: x.timeStamp, reverse=True)
return render_template('index.html', title='Home', posts=posts, avatar=avatarPath, followedCount = followed) return render_template('index.html', title='Home', posts=posts, avatar=avatarPath, followedCount=followed, twitterAt=twitterAt, twitterName=twitterName, form=form)
@app.route('/login', methods=['GET', 'POST']) @app.route('/login', methods=['GET', 'POST'])
@ -76,32 +85,37 @@ def logout():
def register(): def register():
if current_user.is_authenticated: if current_user.is_authenticated:
return redirect(url_for('index')) return redirect(url_for('index'))
form = RegistrationForm() form = RegistrationForm()
if form.validate_on_submit(): if form.validate_on_submit():
rssFeed = feedparser.parse('https://nitter.net/{}/rss'.format(form.username.data)) if isTwitterUser(form.username.data):
flash('This is username is taken! Choose a different one.')
if rssFeed.entries == []: else:
user = User(username=form.username.data, email=form.email.data) user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data) user.set_password(form.password.data)
db.session.add(user) db.session.add(user)
db.session.commit() db.session.commit()
flash('Congratulations, you are now a registered user!') flash('Congratulations, you are now a registered user!')
return redirect(url_for('login')) return redirect(url_for('login'))
else:
flash('This is username is taken! Choose a different one.')
return render_template('register.html', title='Register', form=form) return render_template('register.html', title='Register', form=form)
@app.route('/savePost/<url>', methods=['POST'])
@login_required
def savePost(url):
print("SAVEPOST")
print("Saved {}.".format(url.replace('~', '/')))
return redirect(url_for('index'))
@app.route('/follow/<username>', methods=['POST']) @app.route('/follow/<username>', methods=['POST'])
@login_required @login_required
def follow(username): def follow(username):
form = EmptyForm() form = EmptyForm()
if form.validate_on_submit(): if form.validate_on_submit():
user = User.query.filter_by(username=username).first() user = User.query.filter_by(username=username).first()
isTwitter = True isTwitter = isTwitterUser(username)
if user is None and isTwitter: if user is None and isTwitter:
x = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16)) x = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16))
newUser = User(username=username, email="{}@person.is".format(x)) newUser = User(username=username, email="{}@person.is".format(x))
print(x)
db.session.add(newUser) db.session.add(newUser)
db.session.commit() db.session.commit()
flash('You are now following {}!'.format(username)) flash('You are now following {}!'.format(username))
@ -168,13 +182,20 @@ def following():
@login_required @login_required
def search(): def search():
form = SearchForm() form = SearchForm()
parsedResults = []
if form.validate_on_submit(): if form.validate_on_submit():
user = form.username.data user = form.username.data
if isTwitterUser(user): if isTwitterUser(user):
return redirect(url_for('user', username=user)) r = requests.get("{instance}search?f=users&q={usern}".format(instance=nitterInstance, usern=user))
html = BeautifulSoup(str(r.content), features="lxml")
results = html.body.find_all('a', attrs={'class':'tweet-link'})
parsedResults = [s['href'].replace("/", "") for s in results]
return render_template('search.html', form = form, results = parsedResults)
else: else:
flash("User {} does not exist!".format(user)) flash("User {} does not exist!".format(user))
return render_template('search.html', form = form) return render_template('search.html', form = form, results = parsedResults)
else: else:
return render_template('search.html', form = form) return render_template('search.html', form = form)
@ -188,32 +209,30 @@ def notfound():
@login_required @login_required
def user(username): def user(username):
user = User.query.filter_by(username=username).first() user = User.query.filter_by(username=username).first()
isTwitter = True isTwitter = isTwitterUser(username)
rssFeed = feedparser.parse('https://nitter.net/{}/rss'.format(username))
if rssFeed.entries == []: if isTwitter and user is None:
isTwitter = False
if user is None and isTwitter:
x = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16)) x = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(16))
newUser = User(username=username, email="{}@person.is".format(x)) newUser = User(username=username, email="{}@person.is".format(x))
db.session.add(newUser) db.session.add(newUser)
db.session.commit() db.session.commit()
#flash('User {} not found.'.format(username))
elif not isTwitter and user is None: elif not isTwitter and user is None:
return redirect(url_for('notfound')) return redirect(url_for('notfound'))
#Gather profile info. #Gather profile info.
rssFeed = feedparser.parse('https://nitter.net/{}/rss'.format(username)) rssFeed = feedparser.parse('{instance}{user}/rss'.format(instance=nitterInstance,user=username))
try:
profilePicture = rssFeed.channel.image.url
except:
profilePicture = ""
twitterAt = rssFeed.feed.title.split("/")[1].replace(" ", "")
twitterName = rssFeed.feed.title.split("/")[0]
#Gather posts #Gather posts
posts = [] posts = []
for post in rssFeed.entries: for post in rssFeed.entries:
newPost = twitterPost() newPost = twitterPost()
newPost.profilePic = rssFeed.channel.image.url
newPost.twitterAt = rssFeed.feed.title.split("/")[1].replace(" ", "")
newPost.twitterName = rssFeed.feed.title.split("/")[0]
newPost.username = rssFeed.feed.title.split("/")[0] newPost.username = rssFeed.feed.title.split("/")[0]
newPost.date = getTimeDiff(post.published_parsed) newPost.date = getTimeDiff(post.published_parsed)
newPost.timeStamp = datetime.datetime(*post.published_parsed[:6]) newPost.timeStamp = datetime.datetime(*post.published_parsed[:6])
@ -223,35 +242,37 @@ def user(username):
if "RT by" in post.title: if "RT by" in post.title:
newPost.isRT = True newPost.isRT = True
newPost.profilePic = ""
else: else:
newPost.isRT = False newPost.isRT = False
try:
newPost.profilePic = rssFeed.channel.image.url
except:
newPost.profilePic = avatarPath
#validPost = True #validPost = True
posts.append(newPost) posts.append(newPost)
form = EmptyForm() form = EmptyForm()
user = User.query.filter_by(username=username).first() user = User.query.filter_by(username=username).first()
return render_template('user.html', user=user, posts=posts, form=form, profilePic=rssFeed.channel.image.url) return render_template('user.html', user=user, posts=posts, form=form, profilePic=profilePicture, twitterAt=twitterAt, twitterName=twitterName)
def getTimeDiff(t): def getTimeDiff(t):
today = datetime.datetime.now()
tweetTime = datetime.datetime(*t[:6]) tweetTime = datetime.datetime(*t[:6])
diff = today - tweetTime diff = datetime.datetime.now() - tweetTime
timeString = "0m"
if diff.days == 0: if diff.days == 0:
minutes = diff.seconds/60 if diff.seconds > 3599:
if minutes > 60: timeString = "{}h".format(int((diff.seconds/60)/60))
hours = minutes/60
timeString = "{}h".format(hours)
else: else:
timeString = "{}m".format(minutes) timeString = "{}m".format(int(diff.seconds/60))
else: else:
timeString = "{}d".format(diff.days) timeString = "{}d".format(diff.days)
return timeString return timeString
def isTwitterUser(username): def isTwitterUser(username):
rssFeed = feedparser.parse('https://nitter.net/{}/rss'.format(username)) request = requests.get('https://nitter.net/{}'.format(username), timeout=1)
if rssFeed.entries == []: print("User {name} is {boo} twitter.".format(name=username, boo=request.status_code == 404))
if request.status_code == 404:
return False return False
return True return True

BIN
app/static/img/empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -6,14 +6,23 @@
<img class="ui avatar image" src="{{ url_for('static',filename='img/avatars/')}}{{range(1, 12) | random}}.png"> <img class="ui avatar image" src="{{ url_for('static',filename='img/avatars/')}}{{range(1, 12) | random}}.png">
</div> </div>
</div> </div>
<div class="header" id="author"><a href="{{ post.urlToPost }}">{{ post.op }}</a></div> <div class="header" id="author"><a href="{{post.op.replace('@','')}}">{{ post.op }}</a></div>
<div class="meta"> <div class="meta">
<span class="category" id="time"><i class="clock icon"></i> {{post.date}} </span> <span class="category" id="time"><i class="clock icon"></i> {{post.date}} </span>
<span class="category"><i class="retweet icon"></i> {{post.twitterAt}} retwitted</span> <span class="category"><i class="retweet icon"></i> {{twitterAt}} retwitted</span>
</div> </div>
<div class="description"> <div class="description">
<p>{{post.content}}</p> <p>{{post.content}}</p>
</div> </div>
<div class="extra content">
<p>
<form class="ui form" action="{{ url_for('savePost', url=post.urlToPost.replace('/', '~')) }}" method="post">
<button type="submit" class="ui icon button">
<i class="bookmark outline icon"></i>
</button>
</form>
</p>
</div>
</div> </div>
<!--<div class="extra content"> <!--<div class="extra content">
<i class="like icon"></i> 1000 <i class="like icon"></i> 1000

View File

@ -6,13 +6,22 @@
<img class="ui avatar image" src="{{ post.profilePic }}"> <img class="ui avatar image" src="{{ post.profilePic }}">
</div> </div>
</div> </div>
<div class="header" id="author"><a href="{{ post.urlToPost }}">{{ post.op }}</a></div> <div class="header" id="author"><a href="{{post.op.replace('@','')}}">{{ post.op }}</a></div>
<div class="meta"> <div class="meta">
<span class="category" id="time"><i class="clock icon"></i> {{post.date}} </span> <span class="category" id="time"><i class="clock icon"></i> {{post.date}} </span>
</div> </div>
<div class="description"> <div class="description">
<p>{{post.content}}</p> <p>{{post.content}}</p>
</div> </div>
<div class="extra content">
<p>
<form class="ui form" action="{{ url_for('savePost', url=post.urlToPost.replace('/', '~')) }}" method="post">
<button type="submit" class="ui icon button">
<i class="bookmark outline icon"></i>
</button>
</form>
</p>
</div>
</div> </div>
<!--<div class="extra content"> <!--<div class="extra content">
<i class="like icon"></i> 1000 <i class="like icon"></i> 1000

View File

@ -21,6 +21,7 @@
{% else %} {% else %}
<a href="{{ url_for('search') }}" class="item">Search</a> <a href="{{ url_for('search') }}" class="item">Search</a>
<a href="{{ url_for('following') }}" class="item">Following</a> <a href="{{ url_for('following') }}" class="item">Following</a>
<a href="{{ url_for('logout') }}" class="item">Saved</a>
<a href="{{ url_for('logout') }}" class="item">Logout</a> <a href="{{ url_for('logout') }}" class="item">Logout</a>
{% endif %} {% endif %}
</div> </div>

View File

@ -13,6 +13,21 @@
</p> </p>
<p>{{ form.submit() }}</p> <p>{{ form.submit() }}</p>
</form> </form>
{% if results %}
<div style="margin: 0em;" class="ui one column centered grid">
<div class="ui center aligned divided list">
{% for res in results %}
<div class="item">
<img class="ui avatar image" src="{{ url_for('static',filename='img/avatars/')}}{{range(1, 12) | random}}.png">
<div class="content">
<a href="/user/{{res}}">{{res}}</a>
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -4,9 +4,9 @@
<div class="blue ui centered card"> <div class="blue ui centered card">
<div class="content"> <div class="content">
<div class="center aligned author"> <div class="center aligned author">
<img class="ui avatar image" src="{{ profilePic }}"> {{ posts[0].twitterAt }} <img class="ui avatar image" src="{{ profilePic }}"> {{ twitterAt }}
</div> </div>
<div style="margin: .1em" class="center aligned header"><a href="https://nitter.net/{{ posts[0].twitterAt.replace('@','') }}/">{{ posts[0].twitterName }}</a></div> <div style="margin: .1em" class="center aligned header"><a href="https://nitter.net/{{ twitterAt.replace('@','') }}/">{{ twitterName }}</a></div>
<div class="center aligned description"> <div class="center aligned description">
<a> <a>
<i class="users icon"></i> <i class="users icon"></i>
@ -38,12 +38,25 @@
</div> </div>
<div class="ui one column grid" id="card-container"> <div class="ui one column grid" id="card-container">
{% for post in posts %}
{% if post.isRT %} {% if not posts %}
{% include '_post.html' %} <div style="margin-top: 2em;" class="ui one column centered grid">
{% else %} <div style="margin: 1.5em;" class="ui row">
{% include '_post_nort.html' %} <img class="ui medium circular image" src="{{ url_for('static',filename='img/empty.png') }}">
{% endif %} </div>
{% endfor %}
<div style="margin: 1.5em;" class="ui row">
<h2 class="ui header">This feed is empty.</h2>
</div>
</div>
{% else %}
{% for post in posts %}
{% if post.isRT %}
{% include '_post.html' %}
{% else %}
{% include '_post_nort.html' %}
{% endif %}
{% endfor %}
{% endif %}
</div> </div>
{% endblock %} {% endblock %}