Add support for viewing Accounts and Video Channels
This commit is contained in:
parent
ea6b5ea173
commit
4470aa5c47
13 changed files with 395 additions and 31 deletions
1
TODO
1
TODO
|
@ -1,5 +1,4 @@
|
||||||
## MISSING
|
## MISSING
|
||||||
- Viewing User Profiles
|
|
||||||
- Viewing Comment Replies
|
- Viewing Comment Replies
|
||||||
- Length Of Video in search_results.html
|
- Length Of Video in search_results.html
|
||||||
## FIX
|
## FIX
|
||||||
|
|
161
main.py
161
main.py
|
@ -47,33 +47,56 @@ class VideoWrapper:
|
||||||
self.no_quality_selected = not self.video
|
self.no_quality_selected = not self.video
|
||||||
|
|
||||||
|
|
||||||
# Format:
|
# Helper Class for using caches
|
||||||
# key: domain
|
class Cache:
|
||||||
# entry: [ instance_name, last_time_updated ]
|
def __init__(self):
|
||||||
cached_instance_names = {}
|
self.dict = {}
|
||||||
|
|
||||||
|
def get(self, arg, func):
|
||||||
|
if arg in self.dict:
|
||||||
|
last_time_updated = (self.dict[arg])[1]
|
||||||
|
time_diff = datetime.now() - last_time_updated
|
||||||
|
|
||||||
|
if time_diff.days > 0:
|
||||||
|
self.dict[arg] = [
|
||||||
|
func(arg),
|
||||||
|
datetime.now()
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.dict[arg] = [
|
||||||
|
func(arg),
|
||||||
|
datetime.now()
|
||||||
|
]
|
||||||
|
|
||||||
|
return (self.dict[arg])[0]
|
||||||
|
|
||||||
|
|
||||||
|
cached_instance_names = Cache()
|
||||||
|
cached_account_infos = Cache()
|
||||||
|
cached_video_channel_infos = Cache()
|
||||||
|
|
||||||
# cache the instance names so we don't have to send a request to the domain every time someone
|
# cache the instance names so we don't have to send a request to the domain every time someone
|
||||||
# loads any site
|
# loads any site
|
||||||
def get_instance_name(domain):
|
def get_instance_name(domain):
|
||||||
if domain in cached_instance_names:
|
return cached_instance_names.get(domain, peertube.get_instance_name)
|
||||||
last_time_updated = (cached_instance_names[domain])[1]
|
|
||||||
time_diff = datetime.now() - last_time_updated
|
|
||||||
|
|
||||||
# only check once every day
|
|
||||||
if time_diff.days != 0:
|
|
||||||
cached_instance_names[domain] = [
|
|
||||||
peertube.get_instance_name(domain),
|
|
||||||
datetime.now()
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
cached_instance_names[domain] = [
|
|
||||||
peertube.get_instance_name(domain),
|
|
||||||
datetime.now()
|
|
||||||
]
|
|
||||||
|
|
||||||
return (cached_instance_names[domain])[0]
|
|
||||||
|
|
||||||
|
|
||||||
|
# simple wrapper that is used inside the cached_account_infos
|
||||||
|
def get_account(info):
|
||||||
|
info = info.split("@")
|
||||||
|
return peertube.account(info[1], info[0])
|
||||||
|
|
||||||
|
def get_account_info(name):
|
||||||
|
return cached_account_infos.get(name, get_account)
|
||||||
|
|
||||||
|
|
||||||
|
# simple wrapper that is used inside the cached_video_channel_infos
|
||||||
|
def get_video_channel(info):
|
||||||
|
info = info.split("@")
|
||||||
|
return peertube.video_channel(info[1], info[0])
|
||||||
|
|
||||||
|
def get_video_channel_info(name):
|
||||||
|
return cached_video_channel_infos.get(name, get_video_channel)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,5 +165,101 @@ async def video(domain, id):
|
||||||
embed=embed,
|
embed=embed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_channel_or_account_name(domain, name):
|
||||||
|
if '@' in name:
|
||||||
|
return name
|
||||||
|
return name + "@" + domain
|
||||||
|
|
||||||
|
# --- Accounts ---
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/accounts/<string:name>")
|
||||||
|
async def accounts(domain, name):
|
||||||
|
return redirect("/" + domain + "/accounts/" + name + "/video-channels")
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/accounts/<string:name>/video-channels")
|
||||||
|
async def account__video_channels(domain, name):
|
||||||
|
return await render_template(
|
||||||
|
"accounts/video_channels.html",
|
||||||
|
domain=domain,
|
||||||
|
commit=commit,
|
||||||
|
instance_name=get_instance_name(domain),
|
||||||
|
|
||||||
|
name = name,
|
||||||
|
account = get_account_info(build_channel_or_account_name(domain, name)),
|
||||||
|
video_channels = peertube.account_video_channels(domain, name)
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/accounts/<string:name>/videos")
|
||||||
|
async def account__videos(domain, name):
|
||||||
|
return await render_template(
|
||||||
|
"accounts/videos.html",
|
||||||
|
domain=domain,
|
||||||
|
commit=commit,
|
||||||
|
instance_name=get_instance_name(domain),
|
||||||
|
|
||||||
|
name = name,
|
||||||
|
account = get_account_info(build_channel_or_account_name(domain, name)),
|
||||||
|
videos = peertube.account_videos(domain, name)
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/accounts/<string:name>/about")
|
||||||
|
async def account__about(domain, name):
|
||||||
|
return await render_template(
|
||||||
|
"accounts/about.html",
|
||||||
|
domain=domain,
|
||||||
|
commit=commit,
|
||||||
|
instance_name=get_instance_name(domain),
|
||||||
|
|
||||||
|
name = name,
|
||||||
|
account = get_account_info(build_channel_or_account_name(domain, name)),
|
||||||
|
about = peertube.account(domain, name)
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Video-Channels ---
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/video-channels/<string:name>")
|
||||||
|
async def video_channels(domain, name):
|
||||||
|
return redirect("/" + domain + "/video-channels/" + name + "/videos")
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/video-channels/<string:name>/videos")
|
||||||
|
async def video_channels__videos(domain, name):
|
||||||
|
return await render_template(
|
||||||
|
"video_channels/videos.html",
|
||||||
|
domain=domain,
|
||||||
|
commit=commit,
|
||||||
|
instance_name=get_instance_name(domain),
|
||||||
|
|
||||||
|
name = name,
|
||||||
|
video_channel = get_video_channel_info(build_channel_or_account_name(domain, name)),
|
||||||
|
videos = peertube.video_channel_videos(domain, name)
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/video-channels/<string:name>/video-playlists")
|
||||||
|
async def video_channels__video_playlists(domain, name):
|
||||||
|
return await render_template(
|
||||||
|
"video_channels/video_playlists.html",
|
||||||
|
domain=domain,
|
||||||
|
commit=commit,
|
||||||
|
instance_name=get_instance_name(domain),
|
||||||
|
|
||||||
|
name = name,
|
||||||
|
video_channel = get_video_channel_info(build_channel_or_account_name(domain, name)),
|
||||||
|
video_playlists = peertube.video_channel_video_playlists(domain, name)
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route("/<string:domain>/video-channels/<string:name>/about")
|
||||||
|
async def video_channels__about(domain, name):
|
||||||
|
return await render_template(
|
||||||
|
"video_channels/about.html",
|
||||||
|
domain=domain,
|
||||||
|
commit=commit,
|
||||||
|
instance_name=get_instance_name(domain),
|
||||||
|
|
||||||
|
name = name,
|
||||||
|
video_channel = get_video_channel_info(build_channel_or_account_name(domain, name)),
|
||||||
|
about = peertube.video_channel(domain, name)
|
||||||
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run()
|
app.run()
|
||||||
|
|
44
peertube.py
44
peertube.py
|
@ -26,16 +26,48 @@ def search(domain, term, start = 0, count = 10):
|
||||||
|
|
||||||
def get_comments(domain, id):
|
def get_comments(domain, id):
|
||||||
url = "https://" + domain + "/api/v1/videos/" + id + "/comment-threads"
|
url = "https://" + domain + "/api/v1/videos/" + id + "/comment-threads"
|
||||||
comments_object = json.loads(requests.get(url).text)
|
return json.loads(requests.get(url).text)
|
||||||
return comments_object
|
|
||||||
|
|
||||||
|
# --- Accounts ---
|
||||||
|
|
||||||
|
def account_video_channels(domain, name):
|
||||||
|
url = "https://" + domain + "/api/v1/accounts/" + name + "/video-channels"
|
||||||
|
return json.loads(requests.get(url).text)
|
||||||
|
|
||||||
|
def account_videos(domain, name):
|
||||||
|
url = "https://" + domain + "/api/v1/accounts/" + name + "/videos"
|
||||||
|
return json.loads(requests.get(url).text)
|
||||||
|
|
||||||
|
def account(domain, name):
|
||||||
|
url = "https://" + domain + "/api/v1/accounts/" + name
|
||||||
|
return json.loads(requests.get(url).text)
|
||||||
|
|
||||||
|
# --- Video Channels ---
|
||||||
|
|
||||||
|
def video_channel_videos(domain, name):
|
||||||
|
url = "https://" + domain + "/api/v1/video-channels/" + name + "/videos"
|
||||||
|
return json.loads(requests.get(url).text)
|
||||||
|
|
||||||
|
def video_channel_video_playlists(domain, name):
|
||||||
|
url = "https://" + domain + "/api/v1/video-channels/" + name + "/video-playlists"
|
||||||
|
return json.loads(requests.get(url).text)
|
||||||
|
|
||||||
|
def video_channel(domain, name):
|
||||||
|
url = "https://" + domain + "/api/v1/video-channels/" + name
|
||||||
|
return json.loads(requests.get(url).text)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
#name = get_instance_name("videos.lukesmith.xyz")
|
#name = get_instance_name("videos.lukesmith.xyz")
|
||||||
#print(name)
|
#print(name)
|
||||||
com = get_comments("videos.lukesmith.xyz", "d1bfb082-b203-43dc-9676-63d28fe65db5")
|
|
||||||
print(json.dumps(com, indent=2))
|
#com = get_comments("videos.lukesmith.xyz", "d1bfb082-b203-43dc-9676-63d28fe65db5")
|
||||||
|
#print(json.dumps(com, indent=2))
|
||||||
|
|
||||||
#vid = video("diode.zone", "c4f0d71b-bd8b-4641-87b0-6d9edd4fa9ce")
|
#vid = video("diode.zone", "c4f0d71b-bd8b-4641-87b0-6d9edd4fa9ce")
|
||||||
#print(json.dumps(vid, indent=2))
|
#print(json.dumps(vid, indent=2))
|
||||||
#_, results = search("diode.zone", "test")
|
|
||||||
#print(json.dumps(results, indent=2))
|
_, results = search("diode.zone", "test")
|
||||||
|
print(json.dumps(results, indent=2))
|
||||||
|
|
||||||
|
#video_channels = account_video_channels("peer.tube", "mouse@peertube.dsmouse.net")
|
||||||
|
#print(json.dumps(video_channels, indent=2))
|
||||||
|
|
9
templates/accounts/about.html
Normal file
9
templates/accounts/about.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "accounts/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block sub_content %}
|
||||||
|
|
||||||
|
Coming Soon!
|
||||||
|
|
||||||
|
{% endblock %}
|
31
templates/accounts/base.html
Normal file
31
templates/accounts/base.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://{{ account.host }}{{ account.avatar.path }}" height="100"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b>{{ account.displayName }}</b> {{ account.name }}
|
||||||
|
<br>
|
||||||
|
{{ account.followersCount }} Followers
|
||||||
|
</td>
|
||||||
|
<tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<a href="/{{ domain }}/accounts/{{ name }}/video-channels">Video Channels</a>
|
||||||
|
<b> | </b>
|
||||||
|
<a href="/{{ domain }}/accounts/{{ name }}/videos">Videos</a>
|
||||||
|
<b> | </b>
|
||||||
|
<a href="/{{ domain }}/accounts/{{ name }}/about">About</a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
{% block sub_content %}{% endblock %}
|
||||||
|
|
||||||
|
{% endblock %}
|
28
templates/accounts/video_channels.html
Normal file
28
templates/accounts/video_channels.html
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{% extends "accounts/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block sub_content %}
|
||||||
|
|
||||||
|
{{ video_channels.total }} Channels
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{% for channel in video_channels.data %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://{{ domain }}{{ channel.avatar.path }}" height="75"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/{{ domain }}/video-channels/{{ channel.name }}@{{ channel.host }}">
|
||||||
|
<b>{{ channel.displayName }}</b>
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
{{ channel.followersCount }} Followers
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
31
templates/accounts/videos.html
Normal file
31
templates/accounts/videos.html
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends "accounts/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block sub_content %}
|
||||||
|
|
||||||
|
{{ videos.total }} Videos
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{% for video in videos.data %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/{{ domain }}/videos/watch/{{ video.uuid }}">
|
||||||
|
<img src="https://{{ domain }}{{ video.thumbnailPath }}" height="150"/>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/{{ domain }}/videos/watch/{{ video.uuid }}">{{ video.name }}</a>
|
||||||
|
<br>
|
||||||
|
{{ video.views }} Views
|
||||||
|
<br>
|
||||||
|
<b>{{ video.channel.displayName }}</b>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -14,11 +14,17 @@
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/{{ domain }}/watch/{{ result.uuid }}">{{ result.name }}</a>
|
<a href="/{{ domain }}/videos/watch/{{ result.uuid }}">{{ result.name }}</a>
|
||||||
<br>
|
<br>
|
||||||
{{ result.views }} Views
|
{{ result.views }} Views
|
||||||
<br>
|
<br>
|
||||||
|
<a href="/{{ domain }}/accounts/{{ result.channel.name }}@{{ result.channel.host }}">
|
||||||
<b>{{ result.channel.displayName }}</b>
|
<b>{{ result.channel.displayName }}</b>
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
<a href="/{{ domain }}/accounts/{{ result.account.name }}@{{ result.account.host }}">
|
||||||
|
{{ result.account.name }}@{{ result.account.host }}
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -5,7 +5,13 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h3>{{ video.name }}</h3>
|
<h3>{{ video.name }}</h3>
|
||||||
By:
|
By:
|
||||||
<b>{{ video.channel.displayName }}</b> ({{ video.channel.name }}@{{ video.channel.host }})
|
<a href="/{{ domain }}/video-channels/{{ video.channel.name }}@{{ video.channel.host }}/videos">
|
||||||
|
<b>{{ video.channel.displayName }}</b>
|
||||||
|
</a>
|
||||||
|
<a href="/{{ domain }}/accounts/{{ video.channel.ownerAccount.name }}@{{ video.channel.ownerAccount.host }}/video-channels">
|
||||||
|
({{ video.channel.ownerAccount.name }}@{{ video.channel.ownerAccount.host }})
|
||||||
|
</a>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
{% if video.no_quality_selected and not embed %}
|
{% if video.no_quality_selected and not embed %}
|
||||||
<img height="300" src="https://{{ video.channel.host }}{{ video.thumbnailPath }}">
|
<img height="300" src="https://{{ video.channel.host }}{{ video.thumbnailPath }}">
|
||||||
|
|
9
templates/video_channels/about.html
Normal file
9
templates/video_channels/about.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "video_channels/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block sub_content %}
|
||||||
|
|
||||||
|
Coming Soon!
|
||||||
|
|
||||||
|
{% endblock %}
|
35
templates/video_channels/base.html
Normal file
35
templates/video_channels/base.html
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://{{ video_channel.host }}{{ video_channel.avatar.path }}" height="100"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b>{{ video_channel.displayName }}</b> {{ video_channel.name }}
|
||||||
|
<br>
|
||||||
|
{{ video_channel.followersCount }} Followers
|
||||||
|
<br>
|
||||||
|
Created By
|
||||||
|
<a href="/{{ domain }}/accounts/{{ video_channel.ownerAccount.name }}@{{ video_channel.ownerAccount.host }}"> {{ video_channel.ownerAccount.name }}</a>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<a href="/{{ domain }}/video-channels/{{ name }}/videos">Videos</a>
|
||||||
|
<b> | </b>
|
||||||
|
<a href="/{{ domain }}/video-channels/{{ name }}/video-playlists">Video Playlists</a>
|
||||||
|
<b> | </b>
|
||||||
|
<a href="/{{ domain }}/video-channels/{{ name }}/about">About</a>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
{% block sub_content %}{% endblock %}
|
||||||
|
|
||||||
|
{% endblock %}
|
27
templates/video_channels/video_playlists.html
Normal file
27
templates/video_channels/video_playlists.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{% extends "video_channels/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block sub_content %}
|
||||||
|
|
||||||
|
{{ video_playlists.total }} Playlists
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{% for playlist in video_playlists.data %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="https://{{ domain }}{{ playlist.thumbnailPath }}" height="150"/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b>{{ playlist.displayName }}</b>
|
||||||
|
<br>
|
||||||
|
{{ playlist.videosLength }} Videos
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
32
templates/video_channels/videos.html
Normal file
32
templates/video_channels/videos.html
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{% extends "video_channels/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}{{ domain }}{% endblock %}
|
||||||
|
|
||||||
|
{% block sub_content %}
|
||||||
|
|
||||||
|
{{ videos.total }} Videos
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
{% for video in videos.data %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/{{ domain }}/videos/watch/{{ video.uuid }}">
|
||||||
|
<img src="https://{{ domain }}{{ video.thumbnailPath }}" height="150"/>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/{{ domain }}/videos/watch/{{ video.uuid }}">{{ video.name }}</a>
|
||||||
|
<br>
|
||||||
|
{{ video.views }} Views
|
||||||
|
<br>
|
||||||
|
<b>{{ video.channel.displayName }}</b>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue