mirror of https://gitlab.com/bashrc2/epicyon
Media timeline
parent
160f272b5d
commit
8ed3f132be
73
daemon.py
73
daemon.py
|
@ -85,6 +85,7 @@ from webinterface import htmlAbout
|
|||
from webinterface import htmlRemoveSharedItem
|
||||
from webinterface import htmlInboxDMs
|
||||
from webinterface import htmlInboxReplies
|
||||
from webinterface import htmlInboxMedia
|
||||
from webinterface import htmlUnblockConfirm
|
||||
from webinterface import htmlPersonOptions
|
||||
from webinterface import htmlIndividualPost
|
||||
|
@ -1478,6 +1479,7 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self._404()
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
|
||||
# get replies to a post /users/nickname/statuses/number/replies
|
||||
if self.path.endswith('/replies') or '/replies?page=' in self.path:
|
||||
if '/statuses/' in self.path and '/users/' in self.path:
|
||||
|
@ -1941,6 +1943,77 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
self.server.GETbusy=False
|
||||
return
|
||||
|
||||
# get the media for a given person
|
||||
if self.path.endswith('/tlmedia') or '/tlmedia?page=' in self.path:
|
||||
if '/users/' in self.path:
|
||||
if authorized:
|
||||
inboxMediaFeed= \
|
||||
personBoxJson(self.server.baseDir, \
|
||||
self.server.domain, \
|
||||
self.server.port, \
|
||||
self.path, \
|
||||
self.server.httpPrefix, \
|
||||
maxPostsInFeed, 'tlmedia', \
|
||||
True,self.server.ocapAlways)
|
||||
if not inboxMediaFeed:
|
||||
inboxMediaFeed=[]
|
||||
if self._requestHTTP():
|
||||
nickname=self.path.replace('/users/','').replace('/tlmedia','')
|
||||
pageNumber=1
|
||||
if '?page=' in nickname:
|
||||
pageNumber=nickname.split('?page=')[1]
|
||||
nickname=nickname.split('?page=')[0]
|
||||
if pageNumber.isdigit():
|
||||
pageNumber=int(pageNumber)
|
||||
else:
|
||||
pageNumber=1
|
||||
if 'page=' not in self.path:
|
||||
# if no page was specified then show the first
|
||||
inboxMediaFeed= \
|
||||
personBoxJson(self.server.baseDir, \
|
||||
self.server.domain, \
|
||||
self.server.port, \
|
||||
self.path+'?page=1', \
|
||||
self.server.httpPrefix, \
|
||||
maxPostsInFeed, 'tlmedia', \
|
||||
True,self.server.ocapAlways)
|
||||
msg=htmlInboxMedia(self.server.translate, \
|
||||
pageNumber,maxPostsInFeed, \
|
||||
self.server.session, \
|
||||
self.server.baseDir, \
|
||||
self.server.cachedWebfingers, \
|
||||
self.server.personCache, \
|
||||
nickname, \
|
||||
self.server.domain, \
|
||||
self.server.port, \
|
||||
inboxMediaFeed, \
|
||||
self.server.allowDeletion, \
|
||||
self.server.httpPrefix, \
|
||||
self.server.projectVersion).encode('utf-8')
|
||||
self._set_headers('text/html',len(msg),cookie)
|
||||
self.wfile.write(msg)
|
||||
else:
|
||||
# don't need authenticated fetch here because there is
|
||||
# already the authorization check
|
||||
msg=json.dumps(inboxMediaFeed).encode('utf-8')
|
||||
self._set_headers('application/json',len(msg),None)
|
||||
self.wfile.write(msg)
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
else:
|
||||
if self.server.debug:
|
||||
nickname=self.path.replace('/users/','').replace('/tlmedia','')
|
||||
print('DEBUG: '+nickname+ \
|
||||
' was not authorized to access '+self.path)
|
||||
if self.path!='/tlmedia':
|
||||
# not the media inbox
|
||||
if self.server.debug:
|
||||
print('DEBUG: GET access to inbox is unauthorized')
|
||||
self.send_response(405)
|
||||
self.end_headers()
|
||||
self.server.GETbusy=False
|
||||
return
|
||||
|
||||
# get outbox feed for a person
|
||||
outboxFeed=personBoxJson(self.server.baseDir,self.server.domain, \
|
||||
self.server.port,self.path, \
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
--button-height: 10px;
|
||||
--button-height-padding-mobile: 20px;
|
||||
--button-height-padding: 10px;
|
||||
--gallery-border: #ccc;
|
||||
--gallery-hover: #777;
|
||||
}
|
||||
|
||||
body, html {
|
||||
|
@ -760,10 +762,35 @@ input[type=checkbox]
|
|||
transform: translateY(-10%);
|
||||
}
|
||||
|
||||
div.gallery {
|
||||
margin: 5px;
|
||||
border: 1px solid var(--gallery-border);
|
||||
float: left;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
div.gallery:hover {
|
||||
border: 1px solid var(--gallery-hover);
|
||||
}
|
||||
|
||||
div.gallery img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
div.imagedesc {
|
||||
padding: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 400px) {
|
||||
body, html {
|
||||
font-size: 22px;
|
||||
}
|
||||
div.imagedesc {
|
||||
padding: 22px;
|
||||
text-align: center;
|
||||
}
|
||||
.container img {
|
||||
float: left;
|
||||
max-width: 400px;
|
||||
|
@ -989,6 +1016,10 @@ input[type=checkbox]
|
|||
body, html {
|
||||
font-size: 35px;
|
||||
}
|
||||
div.imagedesc {
|
||||
padding: 35px;
|
||||
text-align: center;
|
||||
}
|
||||
.container img {
|
||||
float: left;
|
||||
max-width: 400px;
|
||||
|
|
45
posts.py
45
posts.py
|
@ -1585,6 +1585,11 @@ def createRepliesTimeline(baseDir: str,nickname: str,domain: str,port: int,httpP
|
|||
return createBoxBase(baseDir,'tlreplies',nickname,domain,port,httpPrefix, \
|
||||
itemsPerPage,headerOnly,True,ocapAlways,pageNumber)
|
||||
|
||||
def createMediaTimeline(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
|
||||
itemsPerPage: int,headerOnly: bool,ocapAlways: bool,pageNumber=None) -> {}:
|
||||
return createBoxBase(baseDir,'tlmedia',nickname,domain,port,httpPrefix, \
|
||||
itemsPerPage,headerOnly,True,ocapAlways,pageNumber)
|
||||
|
||||
def createOutbox(baseDir: str,nickname: str,domain: str,port: int,httpPrefix: str, \
|
||||
itemsPerPage: int,headerOnly: bool,authorized: bool,pageNumber=None) -> {}:
|
||||
return createBoxBase(baseDir,'outbox',nickname,domain,port,httpPrefix, \
|
||||
|
@ -1684,6 +1689,30 @@ def isDM(postJsonObject: {}) -> bool:
|
|||
return False
|
||||
return True
|
||||
|
||||
def isImageMedia(postJsonObject: {}) -> bool:
|
||||
"""Returns true if the given post has attached image media
|
||||
"""
|
||||
if postJsonObject['type']!='Create':
|
||||
return False
|
||||
if not postJsonObject.get('object'):
|
||||
return False
|
||||
if not isinstance(postJsonObject['object'], dict):
|
||||
return False
|
||||
if postJsonObject['object']['type']!='Note':
|
||||
return False
|
||||
if not postJsonObject['object'].get('attachment'):
|
||||
return False
|
||||
if not isinstance(postJsonObject['object']['attachment'], list):
|
||||
return False
|
||||
if len(postJsonObject['object']['attachment'])==0:
|
||||
return False
|
||||
for attach in postJsonObject['object']['attachment']:
|
||||
if attach.get('mediaType') and attach.get('url'):
|
||||
mediaType=attach['mediaType']
|
||||
if mediaType.startswith('image/'):
|
||||
return True
|
||||
return False
|
||||
|
||||
def isReply(postJsonObject: {},actor: str) -> bool:
|
||||
"""Returns true if the given post is a reply to the given actor
|
||||
"""
|
||||
|
@ -1707,15 +1736,16 @@ def createBoxBase(baseDir: str,boxname: str, \
|
|||
ocapAlways: bool,pageNumber=None) -> {}:
|
||||
"""Constructs the box feed for a person with the given nickname
|
||||
"""
|
||||
if boxname!='inbox' and boxname!='dm' and boxname!='tlreplies' and boxname!='outbox':
|
||||
if boxname!='inbox' and boxname!='dm' and \
|
||||
boxname!='tlreplies' and boxname!='tlmedia' and boxname!='outbox':
|
||||
return None
|
||||
if boxname!='dm' and boxname!='tlreplies':
|
||||
if boxname!='dm' and boxname!='tlreplies' and boxname!='tlmedia':
|
||||
boxDir = createPersonDir(nickname,domain,baseDir,boxname)
|
||||
else:
|
||||
# extract DMs or replies from the inbox
|
||||
boxDir = createPersonDir(nickname,domain,baseDir,'inbox')
|
||||
sharedBoxDir=None
|
||||
if boxname=='inbox' or boxname=='tlreplies':
|
||||
if boxname=='inbox' or boxname=='tlreplies' or boxname=='tlmedia':
|
||||
sharedBoxDir = createPersonDir('inbox',domain,baseDir,boxname)
|
||||
|
||||
if port:
|
||||
|
@ -1865,7 +1895,7 @@ def createBoxBase(baseDir: str,boxname: str, \
|
|||
# get the post as json
|
||||
p = json.loads(postStr)
|
||||
|
||||
if (boxname!='dm' and boxname!='tlreplies'):
|
||||
if (boxname!='dm' and boxname!='tlreplies' and boxname!='tlmedia'):
|
||||
isTimelinePost=True
|
||||
else:
|
||||
if boxname=='dm':
|
||||
|
@ -1874,6 +1904,9 @@ def createBoxBase(baseDir: str,boxname: str, \
|
|||
elif boxname=='tlreplies':
|
||||
if isDM(p) or isReply(p,boxActor):
|
||||
isTimelinePost=True
|
||||
elif boxname=='tlmedia':
|
||||
if isImageMedia(p):
|
||||
isTimelinePost=True
|
||||
|
||||
if isTimelinePost and currPage == pageNumber:
|
||||
# remove any capability so that it's not displayed
|
||||
|
@ -2084,7 +2117,9 @@ def sendCapabilitiesUpdate(session,baseDir: str,httpPrefix: str, \
|
|||
sendThreads,postLog,cachedWebfingers, \
|
||||
personCache,debug,projectVersion)
|
||||
|
||||
def populateRepliesJson(baseDir: str,nickname: str,domain: str,postRepliesFilename: str,authorized: bool,repliesJson: {}) -> None:
|
||||
def populateRepliesJson(baseDir: str,nickname: str,domain: str, \
|
||||
postRepliesFilename: str,authorized: bool, \
|
||||
repliesJson: {}) -> None:
|
||||
# populate the items list with replies
|
||||
repliesBoxes=['outbox','inbox']
|
||||
with open(postRepliesFilename,'r') as repliesFile:
|
||||
|
|
|
@ -1666,6 +1666,7 @@ def individualPostAsHtml(iconsDir: str,translate: {}, \
|
|||
showDMicon=True
|
||||
|
||||
titleStr=''
|
||||
galleryStr=''
|
||||
isAnnounced=False
|
||||
if postJsonObject['type']=='Announce':
|
||||
if postJsonObject.get('object'):
|
||||
|
@ -1875,6 +1876,17 @@ def individualPostAsHtml(iconsDir: str,translate: {}, \
|
|||
attach['url'].endswith('.gif'):
|
||||
if attachmentCtr>0:
|
||||
attachmentStr+='<br>'
|
||||
if boxName=='tlmedia':
|
||||
galleryStr+= \
|
||||
'<div class="gallery">\n' \
|
||||
' <a target="_blank" href="'+attach['url']+'">\n' \
|
||||
' <img src="'+attach['url']+'" alt="'+imageDescription+'" title="'+imageDescription+'" width="600" height="400">\n' \
|
||||
' </a>\n'
|
||||
if postJsonObject['object'].get('content'):
|
||||
galleryStr+= \
|
||||
' <div class="imagedesc">'+postJsonObject['object']['content']+'</div>\n'
|
||||
galleryStr+= \
|
||||
'</div>\n' \
|
||||
attachmentStr+= \
|
||||
'<a href="'+attach['url']+'">' \
|
||||
'<img src="'+attach['url']+'" alt="'+imageDescription+'" title="'+imageDescription+'" class="attachment"></a>\n'
|
||||
|
@ -2064,12 +2076,15 @@ def individualPostAsHtml(iconsDir: str,translate: {}, \
|
|||
|
||||
contentStr='<div class="message">'+contentStr+'</div>'
|
||||
|
||||
return \
|
||||
'<div class="'+containerClass+'">\n'+ \
|
||||
avatarImageInPost+ \
|
||||
'<p class="post-title">'+titleStr+replyAvatarImageInPost+'</p>'+ \
|
||||
contentStr+footerStr+ \
|
||||
'</div>\n'
|
||||
if boxName!='tlmedia':
|
||||
return \
|
||||
'<div class="'+containerClass+'">\n'+ \
|
||||
avatarImageInPost+ \
|
||||
'<p class="post-title">'+titleStr+replyAvatarImageInPost+'</p>'+ \
|
||||
contentStr+footerStr+ \
|
||||
'</div>\n'
|
||||
else:
|
||||
return galleryStr
|
||||
|
||||
def isQuestion(postObjectJson: {}) -> bool:
|
||||
""" is the given post a question?
|
||||
|
@ -2106,6 +2121,7 @@ def htmlTimeline(translate: {},pageNumber: int, \
|
|||
inboxButton='button'
|
||||
dmButton='button'
|
||||
repliesButton='button'
|
||||
mediaButton='button'
|
||||
sentButton='button'
|
||||
moderationButton='button'
|
||||
if boxName=='inbox':
|
||||
|
@ -2114,6 +2130,8 @@ def htmlTimeline(translate: {},pageNumber: int, \
|
|||
dmButton='buttonselected'
|
||||
elif boxName=='tlreplies':
|
||||
repliesButton='buttonselected'
|
||||
elif boxName=='tlmedia':
|
||||
mediaButton='buttonselected'
|
||||
elif boxName=='outbox':
|
||||
sentButton='buttonselected'
|
||||
elif boxName=='moderation':
|
||||
|
@ -2125,7 +2143,8 @@ def htmlTimeline(translate: {},pageNumber: int, \
|
|||
showIndividualPostIcons=True
|
||||
|
||||
followApprovals=''
|
||||
followRequestsFilename=baseDir+'/accounts/'+nickname+'@'+domain+'/followrequests.txt'
|
||||
followRequestsFilename= \
|
||||
baseDir+'/accounts/'+nickname+'@'+domain+'/followrequests.txt'
|
||||
if os.path.isfile(followRequestsFilename):
|
||||
with open(followRequestsFilename,'r') as f:
|
||||
for line in f:
|
||||
|
@ -2160,6 +2179,7 @@ def htmlTimeline(translate: {},pageNumber: int, \
|
|||
' <a href="'+actor+'/inbox"><button class="'+inboxButton+'"><span>'+translate['Inbox']+'</span></button></a>' \
|
||||
' <a href="'+actor+'/dm"><button class="'+dmButton+'"><span>'+translate['DM']+'</span></button></a>' \
|
||||
' <a href="'+actor+'/tlreplies"><button class="'+repliesButton+'"><span>'+translate['Replies']+'</span></button></a>' \
|
||||
' <a href="'+actor+'/tlmedia"><button class="'+mediaButton+'"><span>'+translate['Media']+'</span></button></a>' \
|
||||
' <a href="'+actor+'/outbox"><button class="'+sentButton+'"><span>'+translate['Outbox']+'</span></button></a>'+ \
|
||||
moderationButtonStr+newPostButtonStr+ \
|
||||
' <a href="'+actor+'/search"><img src="/'+iconsDir+'/search.png" title="'+translate['Search and follow']+'" alt="'+translate['Search and follow']+'" class="right"/></a>'+ \
|
||||
|
@ -2250,6 +2270,18 @@ def htmlInboxReplies(translate: {},pageNumber: int,itemsPerPage: int, \
|
|||
nickname,domain,port,inboxJson,'tlreplies',allowDeletion, \
|
||||
httpPrefix,projectVersion,False)
|
||||
|
||||
def htmlInboxMedia(translate: {},pageNumber: int,itemsPerPage: int, \
|
||||
session,baseDir: str,wfRequest: {},personCache: {}, \
|
||||
nickname: str,domain: str,port: int,inboxJson: {}, \
|
||||
allowDeletion: bool, \
|
||||
httpPrefix: str,projectVersion: str) -> str:
|
||||
"""Show the media timeline as html
|
||||
"""
|
||||
return htmlTimeline(translate,pageNumber, \
|
||||
itemsPerPage,session,baseDir,wfRequest,personCache, \
|
||||
nickname,domain,port,inboxJson,'tlmedia',allowDeletion, \
|
||||
httpPrefix,projectVersion,False)
|
||||
|
||||
def htmlModeration(translate: {},pageNumber: int,itemsPerPage: int, \
|
||||
session,baseDir: str,wfRequest: {},personCache: {}, \
|
||||
nickname: str,domain: str,port: int,inboxJson: {}, \
|
||||
|
|
Loading…
Reference in New Issue