New version 1.2
This commit is contained in:
parent
26b9e465f1
commit
8891c275cf
@ -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"
|
||||||
|
|
||||||
|
@ -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
BIN
app/static/img/empty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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 %}
|
@ -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 %}
|
Reference in New Issue
Block a user