Merge pull request #33 from rayanfer32/master

UI improvements + patch for avoiding alias duplication
This commit is contained in:
Christy Roys 2021-06-13 12:39:04 +05:30 committed by GitHub
commit 9eabc78872
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 206 additions and 67 deletions

2
.gitignore vendored
View File

@ -7,5 +7,5 @@ tests/
logo/
app.json
Procfile
.vscode
.vscode/
.gitignore

View File

@ -8,7 +8,8 @@ import os
try:
port = int(os.environ.get("PORT", "8080"))
except ValueError:
except Exception as e:
print(e)
port = -1
if not 1 <= port <= 65535:
print(

View File

@ -30,6 +30,8 @@ async def setup_routes(app, handler):
web.get(p + r"/{id:\d+}/download", h.download_get),
web.head(p + r"/{id:\d+}/download", h.download_head),
web.get(p + r"/{id:\d+}/thumbnail", h.thumbnail_get),
web.get(p + r"/{id:\d+}/v.mp4", h.download_get),
web.head(p + r"/{id:\d+}/v.mp4", h.download_head),
]
if index_all:
# print(await client.get_dialogs())

View File

@ -7,6 +7,24 @@
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<script src="https://cdn.fluidplayer.com/v3/current/fluidplayer.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css?family=PT+Sans&display=swap');
* {
font-family: 'PT Sans';
}
</style>
<script>
window.onload = () => {
// set title as host url
const titleA = document.getElementById("title-a")
titleA.innerHTML = document.location.host
}
</script>
<title>
{% if title %} {{title}} {% else %} Telegram Index {% endif %}
</title>
@ -15,9 +33,9 @@
<body>
<header class="bg-red-600 text-white mb-2 p-4 w-full shadow">
<header class="bg-blue-300 text-white mb-2 p-4 w-full shadow">
<div class="mx-auto flex justify-between content-center max-w-screen-xl">
<a href="/" class="text-left text-xl lg:text-2xl xl:text-3xl"> Telegram Index </a>
<a href="/" id="title-a" class="text-left text-xl lg:text-2xl xl:text-3xl"> Telegram index </a>
{% if authenticated %} <a href="/logout" class="text-right"> Logout </a> {% else %} {%
endif %}
</div>

View File

@ -8,7 +8,7 @@
<div class="block p-4 md:flex md:flex-wrap md:justify-items-center w-full text-center break-words">
{% for chat in chats %}
<a title="{{chat.name}}" href="/{{chat.page_id}}"
class="mx-auto flex flex-col justify-items-center w-2/3 min-h-full md:w-2/5 lg:w-1/6 rounded my-2 p-2 shadow-md hover:shadow-lg hover:border hover:border-blue-300 hover:bg-blue-100">
class="mx-auto flex flex-col justify-items-center w-2/3 min-h-full md:w-2/5 lg:w-1/6 rounded my-2 p-2 shadow hover:shadow-md hover:border hover:border-blue-300 hover:bg-blue-100">
<img src="/{{chat.page_id}}/logo?big=1" class="w-full rounded-full ">
<div class="p-4 rounded">{{chat.name}}</div>

View File

@ -1,59 +1,143 @@
{% include 'header.html' %}
<div class="block md:flex justify-between items-center px-4 text-center border-b-2">
<div class="m-2 block md:flex items-center justify-center md:justify-start text-2xl md:text-right font-bold text-blue-500">
<img class="mx-auto md:ml-0 md:mr-1 my-2 w-16 h-16 rounded-full bg-black outline-none" src="{{logo}}">
<h1> {{name}} </h1>
</div>
<div class="m-2">
<form class="">
<input class="border rounded-full px-4 py-2 border-indigo-500 placeholder-indigo-500 text-indigo-500 outline-none" type="text" name="search" value="{% if search %}{{search}}{% endif %}" placeholder="search...">
</form>
</div>
</div>
{% if item_list %}
<div class="mx-auto my-2 w-full px-4">
<div class="block md:flex md:flex-wrap md:justify-center text-center break-all">
{% for item in item_list %}
<a title="{% if item.media %} {{item.mime_type}} | {{item.human_size}} {% else %} Text message {% endif %}" href="{{item.url}}" class="flex flex-col items-center justify-center w-full min-h-full md:w-1/5 lg:w-1/6 rounded my-4 md:mx-1 shadow-md hover:shadow-lg hover:bg-blue-100 hover:border hover:border-blue-200">
{% if item.media %}
<img src="{{item.thumbnail}}" class="w-full rounded">
<div class="p-4 rounded">{{item.insight}}</div>
{% else %}
<div class="p-4 rounded">{{item.insight}}</div>
{% endif %}
</a>
{% endfor %}
{% block javascript %}
<script type="text/javascript">
{% include "./js/filesaver.min.js" %}
{% include "./js/playlist.js" %}
</script>
{% endblock %}
<div class="block md:flex justify-between items-center px-4 text-center border-b-2">
<div
class="m-2 block md:flex items-center justify-center md:justify-start text-2xl md:text-right font-bold text-blue-500">
<img class="mx-auto md:ml-0 md:mr-1 my-2 w-16 h-16 rounded-full bg-black outline-none" src="{{logo}}">
<h1> {{name}} </h1>
</div>
<div class="m-2">
<form class="">
<div class="p-0">
<div class=" flex items-center rounded-full shadow">
<input class=" rounded-l-full w-full py-1 px-6 text-gray-700 leading-tight focus:outline-none"
name="search" id="search" value="{% if search %}{{search}}{% endif %}" type="text"
placeholder="Search">
<div class="p-1">
<button
class="bg-blue-500 text-white rounded-full p-2 hover:bg-blue-400 focus:outline-none w-12 h-12 flex items-center justify-center">
<div><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg></div>
</button>
</div>
</div>
</div>
</form>
</div>
</div>
{% if item_list %}
<div class="mx-auto my-2 w-full px-4 ">
<div class="block md:flex md:flex-wrap md:justify-center text-center break-all ">
{% for item in item_list %}
<!-- Card -->
<div title="{% if item.media %} {{item.mime_type}} | {{item.human_size}} {% else %} Text message {% endif %}"
href="{{item.url}}"
class="text-sm flex flex-col items-center justify-center w-full min-h-full md:w-1/5 lg:w-1/6 rounded my-4 md:mx-1 shadow hover:shadow-md border-solid ">
<div class="bg-blue-500 rounded text-white my-1 py-0 px-1">{{item.file_id}}</div>
{% if item.media %}
<a href="{{item.url}}"><img src="{{item.thumbnail}}" class="w-full rounded shadow-inner"></a>
<!-- Buttons container -->
<span class="item-buttons my-1 rounded shadow-inner">
<div class="p-4 text-dark py-0 px-2 my-1 ">{{item.insight}}</div>
<!-- Direct file download button -->
<a href="{{item.download}}"
class=" hover:bg-blue-300 text-gray-900 font-semibold py-1 px-2 rounded inline-flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 13l-3 3m0 0l-3-3m3 3V8m0 13a9 9 0 110-18 9 9 0 010 18z" />
</svg>
</a>
<!-- Kodi/media player supported url ending with v.mp4 -->
<a title="v.mp4" href="{{item.vlc}}"
class=" hover:bg-blue-300 text-gray-900 font-semibold py-1 px-2 rounded inline-flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</a>
<!-- One click single item playlist Download -->
<button title="{{item.insight}}.m3u" onclick='singleItemPlaylist("{{item.vlc}}","{{item.insight}}")'
class=" hover:bg-blue-300 text-gray-900 font-semibold py-1 px-2 rounded inline-flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M3 4h13M3 8h9m-9 4h9m5-4v12m0 0l-4-4m4 4l4-4" />
</svg>
</button>
</span>
<p class="my-2 text-center font-semibold">
{{item_list|length}} items
</p>
<div class="mx-auto my-2 text-center flex text-white content-center justify-center">
{% if prev_page %}
<a title="Previous page" class="mx-2 p-2 border rounded bg-green-500 hover:border-green-500 hover:text-green-500 hover:bg-white" href="{{prev_page.url}}">Page {{prev_page.no}}</a>
{% endif %}
<p class="mx-2 p-2 border rounded border-green-500 text-green-500 hover:border-green-500 hover:text-green-500 hover:bg-white">Page {{cur_page}}</p>
{% if next_page %}
<a title="Next page" class="mx-2 p-2 border rounded bg-green-500 hover:border-green-500 hover:text-green-500 hover:bg-white" href="{{next_page.url}}">Page {{next_page.no}}</a>
{% endif %}
</div>
{% else %}
<p class="my-4 text-center text-2xl md:text-3xl lg:text-4xl xl:text-5xl">
No message to display!
</p>
<a href={{item.url}}>
<div class="p-4 rounded shadow-inner rounded text-dark py-0 px-2">{{item.insight}}</div>
</a>
{% endif %}
{% include 'footer.html' %}
</div>
{% endfor %}
</div>
</div>
<p class="my-2 text-center font-semibold">
{{item_list|length}} items
</p>
<div class="mx-auto my-2 text-center flex text-white content-center justify-center">
{% if prev_page %}
<a title="Previous page"
class="mx-2 p-2 border rounded bg-green-500 hover:border-green-500 hover:text-green-500 hover:bg-white"
href="{{prev_page.url}}">Page {{prev_page.no}}</a>
{% endif %}
<p
class="mx-2 p-2 border rounded border-green-500 text-green-500 hover:border-green-500 hover:text-green-500 hover:bg-white">
Page {{cur_page}}</p>
{% if next_page %}
<a title="Next page"
class="mx-2 p-2 border rounded bg-green-500 hover:border-green-500 hover:text-green-500 hover:bg-white"
href="{{next_page.url}}">Page {{next_page.no}}</a>
{% endif %}
</div>
{% else %}
<p class="my-4 text-center text-2xl md:text-3xl lg:text-4xl xl:text-5xl">
No message to display!
</p>
{% endif %}
{% include 'footer.html' %}

2
app/templates/js/filesaver.min.js vendored Normal file
View File

@ -0,0 +1,2 @@
//# sourceMappingURL=FileSaver.min.js.map
(function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});

View File

@ -0,0 +1,26 @@
function singleItemPlaylist(file,name){
let hostUrl = 'http://' + window.location.host
let pd = ""
pd += '#EXTM3U\n'
pd += `#EXTINF: ${name}\n`
pd += `${hostUrl}/${file}\n`
let blob = new Blob([pd], { endings: "native" });
saveAs(blob, `${name}.m3u`);
}
// function createPlaylist(indexSite, id, playlistName = "Playlist", duration = 60) {
// let pd = ""
// name = playlistName
// pd += '#EXTM3U\n'
// pd += `#EXTINF: ${duration * 60} | ${name}\n`
// pd += `${indexSite}/${id}/v.mp4\n`
// return pd
// }
// function playlist(id, name) {
// hostUrl = 'https://' + window.location.host
// playlistData = createPlaylist(hostUrl, id, name);
// let blob = new Blob([playlistData], { endings: "native" });
// saveAs(blob, `${name}.m3u`);
// }

View File

@ -31,24 +31,23 @@ class Views(
):
def __init__(self, client):
self.client = client
self.url_len = SHORT_URL_LEN
self.chat_ids = {}
def generate_alias_id(self, chat):
chat_id = chat.id
title = chat.title
while True:
# alias_id = "".join(
# [
# random.choice(string.ascii_letters + string.digits)
# for _ in range(len(str(chat_id)))
# ]
# )
orig_id = f"{title}{chat_id}" # the original id
alias_id = base64.urlsafe_b64encode(hashlib.md5(orig_id.encode()).digest())[:SHORT_URL_LEN].decode()
while True:
orig_id = f"{chat_id}" # the original id
unique_hash = hashlib.md5(orig_id.encode()).digest()
alias_id = base64.urlsafe_b64encode(unique_hash).decode()[:self.url_len]
if alias_id in self.chat_ids:
self.url_len += 1 # increment url_len just incase the hash is already used.
continue
elif (self.url_len > SHORT_URL_LEN): # reset url_len to initial if hash was unique.
self.url_len = SHORT_URL_LEN
self.chat_ids[alias_id] = {
"chat_id": chat_id,

View File

@ -59,6 +59,8 @@ class IndexView:
insight=get_file_name(m),
human_size=get_human_size(m.file.size),
url=f"/{alias_id}/{m.id}/view",
download=f"{alias_id}/{m.id}/download",
vlc = f"{alias_id}/{m.id}/v.mp4",
)
elif m.message:
entry = dict(

View File

@ -46,7 +46,12 @@ class ThumbnailView:
body = temp.getvalue()
else:
thumb_pos = int(len(thumbnails) / 2)
thumbnail = self.client._get_thumb(thumbnails, thumb_pos)
try:
thumbnail = self.client._get_thumb(thumbnails, thumb_pos)
except Exception as e:
logging.debug(e)
thumbnail = None
if not thumbnail or isinstance(thumbnail, types.PhotoSizeEmpty):
return web.Response(
status=410,