Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
pluja | 3eae6f61e3 |
19
README.md
19
README.md
|
@ -1,13 +1,9 @@
|
|||
# Parasitter
|
||||
<p align="center"> <img width="150" src="app/static/img/logo.png"> </img></p>
|
||||
<p align="center"> Twitter and Youtube via RSS with privacy </p>
|
||||
<h3 align="center"> THIS IS A MIRROR FOR THE <a href="https://github.com/pluja/Parasitter/">MAIN REPO</a></h3>
|
||||
<br>
|
||||
|
||||
> Important note: A [new branch](https://git.nixnet.xyz/pluja/Parasitter/src/branch/dev-indep) is being developed as I'm breaking the dependance with Invidious. You can now test it.
|
||||
|
||||
Parasitter allows you to follow your favorite Twitter and YouTube accounts with full privacy. Parasitter uses [Nitter's](https://nitter.net/) and [Invidious](invidio.us) rss feeds in order to gather the latest content from your favourite accounts and builds a *beautiful* feed. We will never connect you to Twitter or YouTube in any way, so your privacy is safe when using Parasitter. Parasitter is written in Python and Flask and uses Semantic-UI as its CSS framework.
|
||||
|
||||
Parasitter doesn't try to compete with Nitter nor Invidious. It serves as a complement, as it beneficiates from them. Parasitter is not a Twitter viewer as Nitter is or a YouTube frontend as Invidious. Instead Parasitter gathers all your accounts in one place so you can stay tuned with their latest content.
|
||||
Parasitter allows you to follow your favorite Twitter and YouTube accounts with full privacy using rss feeds in order to gather the latest content from your favourite accounts and builds a *beautiful* feed so you can read them. Parasitter is written in Python and Flask and uses Semantic-UI as its CSS framework.
|
||||
|
||||
Parasitter is possible thanks to several open-source projects that are listed on the [Powered by](#powered-by) section. Make sure to check out those awesome projects!
|
||||
|
||||
|
@ -28,7 +24,6 @@ Parasitter is possible thanks to several open-source projects that are listed on
|
|||
* Uses RSS feeds (could be expanded to more social networks)
|
||||
* Follow Twitter accounts.
|
||||
* Follow Youtube accounts.
|
||||
* Watch Youtube videos.
|
||||
* Save your favourite Tweets.
|
||||
* Save your favourite Youtube videos [Coming soon!]
|
||||
* Tor-friendly.
|
||||
|
@ -43,18 +38,18 @@ Only the hash of your password is stored on the database. Also no personal infor
|
|||
I always recommend self-hosting, as you will be the only person with access to the data.
|
||||
|
||||
## Privacy
|
||||
Parasitter cares about your privacy, and for this it will never make any connection to Twitter or Youtube. We make use of rss feeds to fetch all the tweets and videos from your followed accounts. If you want to use a specific Nitter or Invidious instance you can replace it at the top of the file `app/routes.py`.
|
||||
Parasitter cares about your privacy, and for this it will never make any connection to Twitter or Youtube. We make use pf rss feeds to fetch all the tweets from your followed accounts. If you want to use a specific Nitter or Invidious instance you can replace it on the file `app/routes.py`.
|
||||
|
||||
It is always recommended to set up a self-hosted instance. It is quite easy and conveninent and will give you full control over your data. The only data that is stored on the Database is:
|
||||
* Hash of the password
|
||||
* Username
|
||||
* Email (Will be deprecated soon!)
|
||||
* Email (we won't send you any mails so you can make up the mail) - This is for future versions.
|
||||
* List of followed users
|
||||
* List of saved posts
|
||||
|
||||
# Self hosting
|
||||
|
||||
### Local
|
||||
> IMPORTANT: Connections to googlevideo will be made to stream the videos (as Invidious did). It is recommended to use a VPS server to preserve your privacy.
|
||||
You don't need a server to run Parasitter. You can run it on your computer locally and own your (little) data. The installation process is done on a GNU/Linux environment, but should be pretty similar on other platforms.
|
||||
|
||||
1. Install `python3`, `pip3`, `python3-venv` (optional) and `git`.
|
||||
|
@ -139,8 +134,8 @@ Another option is to host a Parasitter server so you can access it from anywhere
|
|||
#### TO BE CONTINUED!
|
||||
|
||||
### Powered by:
|
||||
* [Nitter](https://nitter.net)
|
||||
* [Invidious](https://invidio.us)
|
||||
* [RSSBridge](https://github.com/RSS-Bridge/rss-bridge)
|
||||
* [youtube-dl](https://github.com/ytdl-org/youtube-dl)
|
||||
* [Flask](https://flask.palletsprojects.com/)
|
||||
* [SQLAlchemy](https://docs.sqlalchemy.org/en/13/)
|
||||
* [Semantic-UI](https://semantic-ui.com)
|
||||
|
|
|
@ -6,6 +6,7 @@ from requests_futures.sessions import FuturesSession
|
|||
from concurrent.futures import as_completed
|
||||
from werkzeug.urls import url_parse
|
||||
from bs4 import BeautifulSoup
|
||||
from youtube_dl import YoutubeDL
|
||||
from app import app, db
|
||||
import random, string
|
||||
import time, datetime
|
||||
|
@ -17,7 +18,8 @@ import re
|
|||
# Instances - Format must be instance.tld (No '/' and no 'https://')
|
||||
nitterInstance = "https://nitter.net/"
|
||||
nitterInstanceII = "https://nitter.mastodont.cat/"
|
||||
invidiousInstance = "invidious.snopyta.org"
|
||||
invidiousInstance = "invidio.us"
|
||||
proxy = "" #eg. socks5://IP:PORT
|
||||
|
||||
#########################
|
||||
#### Twitter Logic ######
|
||||
|
@ -301,20 +303,24 @@ def ytunfollow(channelId):
|
|||
@app.route('/video/<id>', methods=['POST', 'GET'])
|
||||
@login_required
|
||||
def video(id):
|
||||
data = requests.get('https://{instance}/api/v1/videos/{id}'.format(instance=invidiousInstance, id=id))
|
||||
data = json.loads(data.content)
|
||||
if proxy:
|
||||
ydl_opts = {
|
||||
'proxy':proxy
|
||||
}
|
||||
else:
|
||||
ydl_opts = {}
|
||||
|
||||
ydl = YoutubeDL(ydl_opts)
|
||||
data = ydl.extract_info("{id}".format(id=id), download=False)
|
||||
video = {
|
||||
'title':data['title'],
|
||||
'description':Markup(data['descriptionHtml']),
|
||||
'viewCount':data['viewCount'],
|
||||
'likeCount':data['likeCount'],
|
||||
'dislikeCount':data['dislikeCount'],
|
||||
'authorThumb':data['authorThumbnails'][4]['url'],
|
||||
'author':data['author'],
|
||||
'authorUrl':data['authorUrl'],
|
||||
'instance':invidiousInstance,
|
||||
'id':id
|
||||
'description':Markup(data['description']),
|
||||
'viewCount':data['view_count'],
|
||||
'author':data['uploader'],
|
||||
'authorUrl':data['uploader_url'],
|
||||
'id':id,
|
||||
'url': data['formats'][-1]['url'],
|
||||
'averageRating': str((float(data['average_rating'])/5)*100)
|
||||
}
|
||||
return render_template("video.html", video=video)
|
||||
|
||||
|
@ -500,6 +506,8 @@ def getPosts(account):
|
|||
|
||||
def getInvidiousPosts(ids):
|
||||
videos = []
|
||||
ydl = YoutubeDL()
|
||||
link = ydl.extract_info("https://www.youtube.com/watch?v=XCSfoiD8wUA", download=False)['formats'][-1]['url']
|
||||
with FuturesSession() as session:
|
||||
futures = [session.get('https://{instance}/feed/channel/{id}'.format(instance=invidiousInstance, id=id.channelId)) for id in ids]
|
||||
for future in as_completed(futures):
|
||||
|
@ -511,7 +519,6 @@ def getInvidiousPosts(ids):
|
|||
video.timeStamp = getTimeDiff(vid.published_parsed)
|
||||
video.channelName = vid.author_detail.name
|
||||
video.channelUrl = vid.author_detail.href
|
||||
video.videoUrl = vid.link
|
||||
video.id = vid.link.split("?v=")[1]
|
||||
video.videoTitle = vid.title
|
||||
video.videoThumb = vid.media_thumbnail[0]['url']
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
.para-light-grey{
|
||||
background-color: rgb(250, 82, 82);
|
||||
}
|
||||
|
||||
.para-green{
|
||||
background-color: lightgreen;
|
||||
}
|
||||
|
||||
.twitter{
|
||||
color: rgb(0, 166, 196) !important;
|
||||
}
|
||||
|
||||
.youtube{
|
||||
color: rgb(224, 32, 32) !important;
|
||||
}
|
||||
|
||||
.video-title{
|
||||
font-weight: bold;
|
||||
font-size: 1.15em;
|
||||
}
|
|
@ -9,21 +9,7 @@
|
|||
<title>Parasitter</title>
|
||||
{% endif %}
|
||||
<link rel= "stylesheet" type= "text/css" href= "{{ url_for('static',filename='semantic/semantic.min.css') }}">
|
||||
|
||||
<style>
|
||||
.twitter{
|
||||
color: rgb(0, 166, 196) !important;
|
||||
}
|
||||
|
||||
.youtube{
|
||||
color: rgb(224, 32, 32) !important;
|
||||
}
|
||||
|
||||
.video-title{
|
||||
font-weight: bold;
|
||||
font-size: 1.15em;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type= "text/css" href="{{ url_for('static',filename='styles.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="ui stackable menu">
|
||||
|
|
|
@ -2,38 +2,41 @@
|
|||
|
||||
{% block content %}
|
||||
<div style="margin-top: 2em;" class="ui one column centered grid">
|
||||
<iframe id='ivplayer' width='640' height='360' src='https://{{video.instance}}/embed/{{video.id}}' style='border:none;'>
|
||||
</iframe>
|
||||
|
||||
<video width="720" height="480" controls>
|
||||
<source src="{{video.url}}" type="video/mp4">
|
||||
<track label="English" kind="subtitles" srclang="en" src="captions/vtt/sintel-en.vtt" default>
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 2em;" class="ui one column center aligned grid">
|
||||
<a href="https://{{video.instance}}/watch?v={{video.id}}"><h2 class="ui header">{{video.title}}</h2></a>
|
||||
<h2 class="ui header">{{video.title}}</h2></a>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 2em;" class="ui one column center aligned grid">
|
||||
<a target="_blank" href="https://{{video.instance}}{{video.authorUrl}}" class="ui image label">
|
||||
<img src="{{video.authorThumb}}">
|
||||
{%if video.author.__len__() > 8%}
|
||||
{{video.author[0:8]+'...'}}
|
||||
{%else%}
|
||||
{{video.author}}
|
||||
{%endif%}
|
||||
</a>
|
||||
|
||||
<div class="ui label">
|
||||
<i class="eye icon"></i> {{video.viewCount}}
|
||||
<div style="margin-top: 2em;" class="ui center aligned grid">
|
||||
<div class="two wide column">
|
||||
<a target="_blank" href="{{video.authorUrl}}" class="ui label">
|
||||
{%if video.author.__len__() > 8%}
|
||||
<i class="user icon"></i> {{video.author[0:10]+'...'}}
|
||||
{%else%}
|
||||
<i class="user icon"></i> {{video.author}}
|
||||
{%endif%}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="ui label">
|
||||
<i class="thumbs up green icon"></i> {{video.likeCount}}
|
||||
<div class="two wide column">
|
||||
<div class="ui label">
|
||||
<i class="eye icon"></i>{{video.viewCount}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui label">
|
||||
<i class="thumbs down red icon"></i> {{video.dislikeCount}}
|
||||
<div class="two wide column">
|
||||
<div class="para-light-grey">
|
||||
<div class="para-green" style="height:12px;width:{{video.averageRating.split(".")[0]}}%"></div>
|
||||
</div>
|
||||
<div class="label"> Rating: {{video.averageRating[0:4]}}% <i class="green thumbs up icon"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div style="margin-top: 2em;" class="ui one column center aligned grid">
|
||||
<div style="margin-bottom: 2em;" class="ui comments">
|
||||
<h3 class="ui dividing header">Description</h3>
|
||||
|
|
Loading…
Reference in New Issue