From 3ebf9785da4aa63d7382180bf995d3ca07d51baa Mon Sep 17 00:00:00 2001 From: Wim Brand Date: Tue, 4 Feb 2020 19:37:46 +0100 Subject: [PATCH] support skynet --- go.mod | 16 +- go.sum | 32 +++ pixelapi/pixelapi.go | 3 +- res/include/script/dependencies/util.js | 11 + .../script/file_manager/DirectoryElement.js | 7 +- .../script/file_viewer/DetailsWindow.js | 96 +++---- .../script/file_viewer/ListNavigator.js | 156 +++++------ res/include/script/file_viewer/Toolbar.js | 170 ++++++------ res/include/script/file_viewer/Viewer.js | 213 +++++++++------ .../file_viewer/viewer_scripts/AudioViewer.js | 46 ++-- .../file_viewer/viewer_scripts/FileViewer.js | 34 +-- .../file_viewer/viewer_scripts/ImageViewer.js | 106 ++++---- .../file_viewer/viewer_scripts/PDFViewer.js | 15 +- .../file_viewer/viewer_scripts/TextViewer.js | 64 ++--- .../file_viewer/viewer_scripts/VideoViewer.js | 30 +-- res/include/script/history.js | 79 +++--- res/include/script/homepage.js | 247 ++++++++++-------- webcontroller/admin_panel.go | 42 +++ webcontroller/file_viewer.go | 91 +++++++ webcontroller/web_controller.go | 5 + 20 files changed, 852 insertions(+), 611 deletions(-) diff --git a/go.mod b/go.mod index 944be5d..ed98957 100644 --- a/go.mod +++ b/go.mod @@ -6,24 +6,10 @@ require ( fornaxian.com/pixeldrain-api v0.0.0-20191216095319-0533f903c681 github.com/Fornaxian/config v0.0.0-20180915150834-ac41cf746a70 github.com/Fornaxian/log v0.0.0-20190617093801-1c7ce9a7c9b3 + github.com/Fornaxian/pd_mime_type v0.0.0-20200204165508-2815edf3a145 github.com/google/uuid v1.1.1 - github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de // indirect github.com/julienschmidt/httprouter v1.3.0 - github.com/k0kubun/pp v3.0.1+incompatible // indirect - github.com/kisielk/gotool v1.0.0 // indirect - github.com/mattn/go-colorable v0.1.4 // indirect - github.com/mattn/go-isatty v0.0.11 // indirect github.com/microcosm-cc/bluemonday v1.0.2 - github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 // indirect - github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab // indirect - github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect - github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/spf13/cobra v0.0.5 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/timakin/gonvert v0.0.0-20170112000238-5dce59dbd0d8 - golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 // indirect - golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 // indirect - golang.org/x/tools v0.0.0-20200114052453-d31a08c2edf2 // indirect gopkg.in/russross/blackfriday.v2 v2.0.0 ) diff --git a/go.sum b/go.sum index 0e9f7da..569b4b2 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,10 @@ github.com/Fornaxian/config v0.0.0-20180915150834-ac41cf746a70 h1:yRkXab8h+BAWEp github.com/Fornaxian/config v0.0.0-20180915150834-ac41cf746a70/go.mod h1:Ig5am30IOP/eqsjogI1TuSlOTIeTPHoMOpYYM1bisww= github.com/Fornaxian/log v0.0.0-20190617093801-1c7ce9a7c9b3 h1:PfKr7anK3z4kLG9V6BbbKOVFhVaGEAJi4HxXCAa+QeU= github.com/Fornaxian/log v0.0.0-20190617093801-1c7ce9a7c9b3/go.mod h1:jdnyerqAlXJJpQmpyrdmSYMitRaRZ8RejEXuXz6n5QY= +github.com/Fornaxian/pd_mime_type v0.0.0-20200204164318-fc5d8b4479f9 h1:8cg0suW9Ny88xGYnaFyfXG5CH7Vxu8jm8PAwnZM4JOk= +github.com/Fornaxian/pd_mime_type v0.0.0-20200204164318-fc5d8b4479f9/go.mod h1:Ew6h8nlacK6H8aABMDUYN3uaO4Rpw2HLKQZ2ntEybqM= +github.com/Fornaxian/pd_mime_type v0.0.0-20200204165508-2815edf3a145 h1:2a8cFtVwEvK7NeimwAEoSUdf4hC80cXpnj3s4pHga+c= +github.com/Fornaxian/pd_mime_type v0.0.0-20200204165508-2815edf3a145/go.mod h1:Ew6h8nlacK6H8aABMDUYN3uaO4Rpw2HLKQZ2ntEybqM= github.com/Fornaxian/unifilter v0.0.0-20180623154047-e65e144d5942/go.mod h1:ofV5syadd2nI4gOc/rP1yPnXkARgm+E1D/U38mbUj44= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -17,6 +21,7 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/threefish v0.0.0-20120919164726-3ecf4c494abf/go.mod h1:bXVurdTuvOiJu7NHALemFe0JMvC2UmwYHW+7fcZaZ2M= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= @@ -25,6 +30,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20191106031601-ce3c9ade29de h1:F7WD09S8QB4LrkEpka0dFPLSotH11HRpCsLIbIcJ7sU= @@ -45,6 +51,9 @@ github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -67,9 +76,12 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= +github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -86,7 +98,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/timakin/gonvert v0.0.0-20170112000238-5dce59dbd0d8 h1:gw/M1/pCu7oELGHZ6rvktNmMbdWhf9kHc7WYrbLeKdo= github.com/timakin/gonvert v0.0.0-20170112000238-5dce59dbd0d8/go.mod h1:oqLl90kSlp4+8wMQKql9ZdQGa4/5pVCxOOpTVWkoyV0= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -104,6 +118,7 @@ gitlab.com/NebulousLabs/threadgroup v0.0.0-20180716154133-88a11db9e46c/go.mod h1 gitlab.com/NebulousLabs/writeaheadlog v0.0.0-20190703190009-cb822c37bc94/go.mod h1:Lhpa9AcbWcYKcc4amZsOHqJdQglnkWrGuUI68XC7U2Q= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= @@ -112,13 +127,17 @@ golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9Q golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191206065243-da761ea9ff43/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -135,11 +154,24 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20200114052453-d31a08c2edf2 h1:FAGfnR+fyptW02iTeG8Lytc+6v8yqyQJIx/JMZhMA5M= golang.org/x/tools v0.0.0-20200114052453-d31a08c2edf2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130224948-02f1738cbe39 h1:5ERHXLQfA0b8cHOwaOfWaaGekrA4+Ka/N74zilLnsIk= +golang.org/x/tools v0.0.0-20200130224948-02f1738cbe39/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74 h1:KW20qMcLRWuIgjdCpHFJbVZA7zsDKtFXPNcm7/eI5ZA= +golang.org/x/tools/gopls v0.3.0 h1:l9KKK1/n6CIbfgaUvHBWAvCfOxcl1N+KSOK79OlPIao= +golang.org/x/tools/gopls v0.3.0/go.mod h1:vvBkm7WBjHNudDeK7Sg7HeR+sKt6yp5TD/4NQaTZzRs= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/russross/blackfriday.v2 v2.0.0 h1:+FlnIV8DSQnT7NZ43hcVKcdJdzZoeCmJj4Ql8gq5keA= gopkg.in/russross/blackfriday.v2 v2.0.0/go.mod h1:6sSBNz/GtOm/pJTuh5UmBK2ZHfmnxGbl2NZg1UliSOI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA= +mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E= diff --git a/pixelapi/pixelapi.go b/pixelapi/pixelapi.go index f7cdd3f..78ca2f6 100644 --- a/pixelapi/pixelapi.go +++ b/pixelapi/pixelapi.go @@ -7,11 +7,12 @@ import ( "net/http" "net/url" "strings" + "time" "github.com/Fornaxian/log" ) -var client = &http.Client{} +var client = &http.Client{Timeout: time.Minute * 5} // PixelAPI is the Pixeldrain API client type PixelAPI struct { diff --git a/res/include/script/dependencies/util.js b/res/include/script/dependencies/util.js index f0694c7..769ae7f 100644 --- a/res/include/script/dependencies/util.js +++ b/res/include/script/dependencies/util.js @@ -22,6 +22,17 @@ function addUploadHistory(fileID) { localStorage.setItem("uploaded_files", fileID + "," + uploads); } +function printDate(date, hours, minutes, seconds) { + let dateStr = date.getFullYear() + +"-"+("00"+(date.getMonth()+1)).slice(-2) + +"-"+("00"+date.getDate()).slice(-2) + + if (hours) { dateStr += " "+("00"+date.getHours()).slice(-2) } + if (minutes) { dateStr += ":"+("00"+date.getMinutes()).slice(-2) } + if (seconds) { dateStr += ":"+("00"+date.getMinutes()).slice(-2) } + return dateStr +} + function copyText(text) { // Create a textarea to copy the text from let ta = document.createElement("textarea"); diff --git a/res/include/script/file_manager/DirectoryElement.js b/res/include/script/file_manager/DirectoryElement.js index b9f544a..7c8c994 100644 --- a/res/include/script/file_manager/DirectoryElement.js +++ b/res/include/script/file_manager/DirectoryElement.js @@ -190,12 +190,7 @@ DirectoryElement.prototype.createFileButton = function(file, index) { let cell = document.createElement("div") cell.style.width = this.fieldDateWidth let label = document.createElement("span") - let date = new Date(file.dateCreated) - label.innerText = date.getFullYear() - +"-"+("00"+(date.getMonth()+1)).slice(-2) - +"-"+("00"+date.getDate()).slice(-2) - +" "+("00"+date.getHours()).slice(-2) - +":"+("00"+date.getMinutes()).slice(-2) + label.innerText = printDate(new Date(file.dateCreated), true, true, false) cell.appendChild(label) el.appendChild(cell) } diff --git a/res/include/script/file_viewer/DetailsWindow.js b/res/include/script/file_viewer/DetailsWindow.js index 5dbb51f..66325e2 100644 --- a/res/include/script/file_viewer/DetailsWindow.js +++ b/res/include/script/file_viewer/DetailsWindow.js @@ -1,86 +1,86 @@ function DetailsWindow(viewer) { - this.viewer = viewer; - this.visible = false; - this.fileID = ""; - this.graph = 0; + this.viewer = viewer + this.visible = false + this.fileID = "" + this.graph = 0 - this.divPopup = document.getElementById("details_popup"); - this.btnDetails = document.getElementById("btn_details"); - this.btnCloseDetails = document.getElementById("btn_close_details"); - this.divFileDetails = document.getElementById("info_file_details"); + this.divPopup = document.getElementById("details_popup") + this.btnDetails = document.getElementById("btn_details") + this.btnCloseDetails = document.getElementById("btn_close_details") + this.divFileDetails = document.getElementById("info_file_details") - this.btnDetails.addEventListener("click", () => { this.toggle(); }); - this.btnCloseDetails.addEventListener("click", () => { this.toggle(); }); + this.btnDetails.addEventListener("click", () => { this.toggle() }) + this.btnCloseDetails.addEventListener("click", () => { this.toggle() }) } DetailsWindow.prototype.toggle = function() { if (this.visible) { - this.divPopup.style.opacity = "0"; - this.divPopup.style.visibility = "hidden"; - this.btnDetails.classList.remove("button_highlight"); - this.visible = false; + this.divPopup.style.opacity = "0" + this.divPopup.style.visibility = "hidden" + this.btnDetails.classList.remove("button_highlight") + this.visible = false } else { - this.divPopup.style.opacity = "1"; - this.divPopup.style.visibility = "visible"; - this.btnDetails.classList.add("button_highlight"); - this.visible = true; + this.divPopup.style.opacity = "1" + this.divPopup.style.visibility = "visible" + this.btnDetails.classList.add("button_highlight") + this.visible = true // This is a workaround for a chrome bug which makes it so hidden // windows can't be scrolled after they are shown - this.divPopup.focus(); + this.divPopup.focus() if (this.graph === 0) { - this.renderGraph(); + this.renderGraph() } - this.updateGraph(this.fileID); + this.updateGraph(this.fileID) } } DetailsWindow.prototype.setDetails = function(file) { - let desc = ""; + let desc = "" if (this.viewer.isList) { - desc = file.description; + desc = file.description } - this.fileID = file.id; + this.fileID = file.id this.divFileDetails.innerHTML = "" + "" - + "" + + "" + "" + "" + "" + "" - + "" + + "" + "" - + "
Name" + escapeHTML(file.name) + "
URL"+domainURL()+"/u/" + file.id + "
URL"+file.link+"
Mime Type" + escapeHTML(file.mime_type) + "
ID" + file.id + "
Size" + formatDataVolume(file.size, 4) + "
Bandwidth" + formatDataVolume(file.bandwidth_used, 4) + "
Upload Date" + file.date_upload + "
Upload Date" + printDate(file.date_created, true, true, true) + "
Description" + escapeHTML(desc) + "
"; + + "" - if(this.visible) { - this.updateGraph(file.id); + if(this.visible && file.timeseries_href !== "") { + this.updateGraph(file) } } -DetailsWindow.prototype.updateGraph = function(fileID) { - console.log("updating graph "+fileID); - fetch(apiEndpoint+"/file/" + fileID + "/timeseries?interval=60?days=14").then(resp => { - if (!resp.ok) {return null;} - return resp.json(); +DetailsWindow.prototype.updateGraph = function(file) { + console.log("updating graph") + fetch(file.timeseries_href+"?interval=60?days=14").then(resp => { + if (!resp.ok) {return null} + return resp.json() }).then(resp => { - this.graph.data.labels = resp.labels; - this.graph.data.datasets[0].data = resp.downloads; - this.graph.data.datasets[1].data = resp.views; - this.graph.update(); + this.graph.data.labels = resp.labels + this.graph.data.datasets[0].data = resp.downloads + this.graph.data.datasets[1].data = resp.views + this.graph.update() }) } DetailsWindow.prototype.renderGraph = function() { - console.log("rendering graph"); - Chart.defaults.global.defaultFontColor = "#b3b3b3"; - Chart.defaults.global.defaultFontSize = 15; - Chart.defaults.global.defaultFontFamily = "Ubuntu"; - Chart.defaults.global.aspectRatio = 2.5; - Chart.defaults.global.elements.point.radius = 0; - Chart.defaults.global.tooltips.mode = "index"; - Chart.defaults.global.tooltips.axis = "x"; - Chart.defaults.global.tooltips.intersect = false; + console.log("rendering graph") + Chart.defaults.global.defaultFontColor = "#b3b3b3" + Chart.defaults.global.defaultFontSize = 15 + Chart.defaults.global.defaultFontFamily = "Ubuntu" + Chart.defaults.global.aspectRatio = 2.5 + Chart.defaults.global.elements.point.radius = 0 + Chart.defaults.global.tooltips.mode = "index" + Chart.defaults.global.tooltips.axis = "x" + Chart.defaults.global.tooltips.intersect = false this.graph = new Chart( document.getElementById('bandwidth_chart'), { @@ -148,5 +148,5 @@ DetailsWindow.prototype.renderGraph = function() { } } } - ); + ) } diff --git a/res/include/script/file_viewer/ListNavigator.js b/res/include/script/file_viewer/ListNavigator.js index b514d7e..990331f 100644 --- a/res/include/script/file_viewer/ListNavigator.js +++ b/res/include/script/file_viewer/ListNavigator.js @@ -1,178 +1,178 @@ function ListNavigator(viewer, files) { - this.viewer = viewer; - this.files = files; - this.length = files.length; - this.position = 0; - this.history = []; - this.shuffle = false; + this.viewer = viewer + this.files = files + this.length = files.length + this.position = 0 + this.history = [] + this.shuffle = false - this.divListNavigator = document.getElementById("list_navigator"); + this.divListNavigator = document.getElementById("list_navigator") - this.btnDownloadList = document.getElementById("btn_download_list"); + this.btnDownloadList = document.getElementById("btn_download_list") if (files.id !== "") { - this.btnDownloadList.style.display = ""; - this.btnDownloadList.addEventListener("click", () => { this.downloadList(); }); + this.btnDownloadList.style.display = "" + this.btnDownloadList.addEventListener("click", () => { this.downloadList() }) } - this.btnShuffle = document.getElementById("btn_shuffle"); - this.btnShuffle.style.display = ""; - this.btnShuffle.addEventListener("click", () => { this.toggleShuffle(); }); + this.btnShuffle = document.getElementById("btn_shuffle") + this.btnShuffle.style.display = "" + this.btnShuffle.addEventListener("click", () => { this.toggleShuffle() }) // Render list contents in list navigator div files.forEach((item, i) => { - let filename; + let filename if(item.name !== "null"){ - filename = item.name; + filename = item.name }else{ - filename = "Removed File"; + filename = "Removed File" } - let d = document.createElement("div"); - d.classList = "file_button list_item"; - d.addEventListener("click", () => { this.setItem(i); }); - d.innerText = filename; - this.divListNavigator.appendChild(d); - }); + let d = document.createElement("div") + d.classList = "file_button list_item" + d.addEventListener("click", () => { this.setItem(i) }) + d.innerText = filename + this.divListNavigator.appendChild(d) + }) // Make the navigator visible - this.divListNavigator.style.display = "inline-block"; + this.divListNavigator.style.display = "inline-block" // Skip to the file defined in the link hash - let matches = location.hash.match(new RegExp('item=([^&]*)')); - let hashID = matches ? matches[1] : null; + let matches = location.hash.match(new RegExp('item=([^&]*)')) + let hashID = matches ? matches[1] : null if(Number.isInteger(parseInt(hashID))){ - this.setItem(parseInt(hashID)); + this.setItem(parseInt(hashID)) }else{ - this.setItem(0); + this.setItem(0) } } ListNavigator.prototype.nextItem = function() { if(this.shuffle){ - this.randItem(); - return; + this.randItem() + return } if (this.position >= this.length) { - this.position = 0; + this.position = 0 } else { - this.position++; + this.position++ } - this.setItem(this.position); + this.setItem(this.position) } ListNavigator.prototype.previousItem = function() { if(this.position === 0){ - this.position = this.length - 1; + this.position = this.length - 1 }else{ - this.position--; + this.position-- } - this.setItem(this.position); + this.setItem(this.position) } ListNavigator.prototype.randItem = function() { // Avoid viewing the same file multiple times - let rand; + let rand do { - rand = Math.round(Math.random() * this.length); - console.log("rand is " + rand); - } while(this.history.indexOf(rand) > -1); + rand = Math.round(Math.random() * this.length) + console.log("rand is " + rand) + } while(this.history.indexOf(rand) > -1) - this.setItem(rand); + this.setItem(rand) } ListNavigator.prototype.setItem = function(index) { if(index >= this.length){ - this.position = 0; + this.position = 0 }else{ - this.position = index; + this.position = index } // Set the URL hash - location.hash = "item=" + this.position; - this.viewer.setFile(this.files[this.position]); + location.hash = "item=" + this.position + this.viewer.setFile(this.files[this.position]) - this.addToHistory(index); - this.loadThumbnails(index); + this.addToHistory(index) + this.loadThumbnails(index) document.querySelectorAll("#list_navigator > .file_button_selected").forEach(el => { - el.classList.remove("file_button_selected"); - }); + el.classList.remove("file_button_selected") + }) - let selectedItem = this.divListNavigator.children[this.position]; - selectedItem.classList.add("file_button_selected"); + let selectedItem = this.divListNavigator.children[this.position] + selectedItem.classList.add("file_button_selected") - let cst = window.getComputedStyle(selectedItem); - let itemWidth = selectedItem.offsetWidth + parseInt(cst.marginLeft) + parseInt(cst.marginRight); + let cst = window.getComputedStyle(selectedItem) + let itemWidth = selectedItem.offsetWidth + parseInt(cst.marginLeft) + parseInt(cst.marginRight) - let start = this.divListNavigator.scrollLeft; - let end = ((this.position * itemWidth) + (itemWidth / 2)) - (this.divListNavigator.clientWidth / 2); - let steps = 60; // One second - let stepSize = (end - start)/steps; + let start = this.divListNavigator.scrollLeft + let end = ((this.position * itemWidth) + (itemWidth / 2)) - (this.divListNavigator.clientWidth / 2) + let steps = 60 // One second + let stepSize = (end - start)/steps let animateScroll = (pos, step) => { - this.divListNavigator.scrollLeft = pos; + this.divListNavigator.scrollLeft = pos if (step < steps) { requestAnimationFrame(() => { - animateScroll(pos+stepSize, step+1); - }); + animateScroll(pos+stepSize, step+1) + }) } - }; - animateScroll(start, 0); + } + animateScroll(start, 0) } ListNavigator.prototype.downloadList = function() { - document.getElementById("download_frame").src = "/api/list/" + this.viewer.listId + "/zip"; + document.getElementById("download_frame").src = "/api/list/" + this.viewer.listId + "/zip" } ListNavigator.prototype.addToHistory = function(index) { if(this.history.length >= (this.length - 6)){ - this.history.shift(); + this.history.shift() } - this.history.push(index); + this.history.push(index) } ListNavigator.prototype.toggleShuffle = function() { - this.shuffle = !this.shuffle; // :P + this.shuffle = !this.shuffle // :P if(this.shuffle){ - document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☑"; // Check icon - this.btnShuffle.classList.add("button_highlight"); + document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☑" // Check icon + this.btnShuffle.classList.add("button_highlight") }else{ - document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☐"; // Empty checkbox - this.btnShuffle.classList.remove("button_highlight"); + document.querySelector("#btn_shuffle > span").innerHTML = "Shuffle ☐" // Empty checkbox + this.btnShuffle.classList.remove("button_highlight") } } ListNavigator.prototype.loadThumbnails = function(index) { - let startPos = +index - 50; - let endPos = +index + 50; + let startPos = +index - 50 + let endPos = +index + 50 // fyi, the + is to let javascript know it's actually a number instead of a string if(startPos < 0){ - startPos = 0; + startPos = 0 } if(endPos >= this.length){ - endPos = this.length - 1; + endPos = this.length - 1 } let navigatorItems = document.getElementById("list_navigator").children for (let i = startPos; i <= endPos; i++){ if (navigatorItems[i].innerHTML.includes("list_item_thumbnail")) { - continue; // Thumbnail already loaded + continue // Thumbnail already loaded } - let thumb = "/api/file/" + this.files[i].id + "/thumbnail?width=48&height=48"; - let name = this.files[i].name; + let thumb = "/api/file/" + this.files[i].id + "/thumbnail?width=48&height=48" + let name = this.files[i].name let itemHtml = "\""" - + escapeHTML(name); + + escapeHTML(name) - navigatorItems[i].innerHTML = itemHtml; + navigatorItems[i].innerHTML = itemHtml } } diff --git a/res/include/script/file_viewer/Toolbar.js b/res/include/script/file_viewer/Toolbar.js index bd9b777..ce0cfc6 100644 --- a/res/include/script/file_viewer/Toolbar.js +++ b/res/include/script/file_viewer/Toolbar.js @@ -1,41 +1,49 @@ function Toolbar(viewer) { - this.viewer = viewer; - this.visible = false; - this.sharebarVisible = false; + this.viewer = viewer + this.visible = false + this.sharebarVisible = false + this.currentFile = null - this.divToolbar = document.getElementById("toolbar"); - this.divFilePreview = document.getElementById("filepreview"); - this.downloadFrame = document.getElementById("download_frame"); - this.spanViews = document.getElementById("stat_views"); - this.spanDownloads = document.getElementById("stat_downloads"); - this.spanSize = document.getElementById("stat_size"); + this.divToolbar = document.getElementById("toolbar") + this.divFilePreview = document.getElementById("filepreview") + this.downloadFrame = document.getElementById("download_frame") + this.spanViews = document.getElementById("stat_views") + this.spanDownloads = document.getElementById("stat_downloads") + this.spanSize = document.getElementById("stat_size") - this.btnToggleToolbar = document.getElementById("btn_toggle_toolbar"); - this.btnDownload = document.getElementById("btn_download"); - this.btnCopyLink = document.getElementById("btn_copy"); - this.spanCopyLink = document.querySelector("#btn_copy > span"); - this.btnShare = document.getElementById("btn_share"); - this.divSharebar = document.getElementById("sharebar"); + this.btnToggleToolbar = document.getElementById("btn_toggle_toolbar") + this.btnDownload = document.getElementById("btn_download") + this.btnCopyLink = document.getElementById("btn_copy") + this.spanCopyLink = document.querySelector("#btn_copy > span") + this.btnShare = document.getElementById("btn_share") + this.divSharebar = document.getElementById("sharebar") - this.btnToggleToolbar.addEventListener("click", () => { this.toggle(); }); - this.btnDownload.addEventListener("click", () => { this.download(); }); - this.btnCopyLink.addEventListener("click", () => { this.copyUrl(); }); - this.btnShare.addEventListener("click", () => { this.toggleSharebar(); }); + this.btnToggleToolbar.addEventListener("click", () => { this.toggle() }) + this.btnDownload.addEventListener("click", () => { this.download() }) + this.btnCopyLink.addEventListener("click", () => { this.copyUrl() }) + this.btnShare.addEventListener("click", () => { this.toggleSharebar() }) +} + +Toolbar.prototype.setFile = function(file) { + this.currentFile = file + this.spanViews.innerText = file.views + this.spanDownloads.innerText = Math.round((file.bandwidth_used/file.size)*10)/10 + this.spanSize.innerText = formatDataVolume(file.size, 3) } Toolbar.prototype.toggle = function() { if (this.visible) { - if (this.sharebarVisible) { this.toggleSharebar(); } + if (this.sharebarVisible) { this.toggleSharebar() } - this.divToolbar.style.left = "-8em"; - this.divFilePreview.style.left = "0px"; - this.btnToggleToolbar.classList.remove("button_highlight"); - this.visible = false; + this.divToolbar.style.left = "-8em" + this.divFilePreview.style.left = "0px" + this.btnToggleToolbar.classList.remove("button_highlight") + this.visible = false } else { - this.divToolbar.style.left = "0px"; - this.divFilePreview.style.left = "8em"; - this.btnToggleToolbar.classList.add("button_highlight"); - this.visible = true; + this.divToolbar.style.left = "0px" + this.divFilePreview.style.left = "8em" + this.btnToggleToolbar.classList.add("button_highlight") + this.visible = true } } @@ -45,132 +53,124 @@ Toolbar.prototype.toggleSharebar = function() { title: this.viewer.title, text: "Download " + this.viewer.title + " here", url: window.location.href - }); - return; + }) + return } if(this.sharebarVisible){ - this.divSharebar.style.left = "-8em"; + this.divSharebar.style.left = "-8em" this.btnShare.classList.remove("button_highlight") - this.sharebarVisible = false; + this.sharebarVisible = false }else{ - this.divSharebar.style.left = "8em"; + this.divSharebar.style.left = "8em" this.btnShare.classList.add("button_highlight") - this.sharebarVisible = true; + this.sharebarVisible = true } } Toolbar.prototype.download = function() { let triggerDL = (captchaResp = "") => { if (captchaResp === "") { - this.downloadFrame.src = apiEndpoint+"/file/"+ - this.viewer.currentFile+"?download"; + this.downloadFrame.src = this.currentFile.download_href } else { - this.downloadFrame.src = apiEndpoint+"/file/"+ - this.viewer.currentFile+"?download&recaptcha_response="+captchaResp; + this.downloadFrame.src = this.currentFile.download_href+"&recaptcha_response="+captchaResp } } - if (captchaKey === "none"){ + if (captchaKey === "none" || captchaKey === ""){ // If the server doesn't support captcha there's no use in checking // availability - triggerDL(); - return; + triggerDL() + return } if (recaptchaResponse !== "") { // Captcha already filled in. Use the saved captcha responsse to // download the file - triggerDL(recaptchaResponse); + triggerDL(recaptchaResponse) // Reset the key - recaptchaResponse = ""; - return; + recaptchaResponse = "" + return } - fetch(apiEndpoint+"/file/"+this.viewer.currentFile+"/availability").then(resp => { - return resp.json(); + fetch(this.currentFile.file_availability_href).then(resp => { + return resp.json() }).then(resp => { - let popupDiv = document.getElementById("captcha_popup"); - let popupTitle = document.getElementById("captcha_popup_title"); - let popupContent = document.getElementById("captcha_popup_content"); + let popupDiv = document.getElementById("captcha_popup") + let popupTitle = document.getElementById("captcha_popup_title") + let popupContent = document.getElementById("captcha_popup_content") let showCaptcha = () => { // Load the recaptcha script with a load function - let script = document.createElement("script"); - script.src = "https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit"; - document.body.appendChild(script); + let script = document.createElement("script") + script.src = "https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit" + document.body.appendChild(script) // Show the popup - popupDiv.style.opacity = "1"; - popupDiv.style.visibility = "visible"; + popupDiv.style.opacity = "1" + popupDiv.style.visibility = "visible" } if (resp.value === "file_rate_limited_captcha_required") { - popupTitle.innerText = "Rate limiting enabled!"; + popupTitle.innerText = "Rate limiting enabled!" popupContent.innerText = "This file is using a suspicious "+ "amount of bandwidth relative to its popularity. To "+ "continue downloading this file you will have to "+ - "prove that you're a human first."; - showCaptcha(); + "prove that you're a human first." + showCaptcha() } else if (resp.value === "virus_detected_captcha_required") { - popupTitle.innerText = "Malware warning!"; + popupTitle.innerText = "Malware warning!" popupContent.innerText = "According to our scanning "+ "systems this file may contain a virus of type '"+ resp.extra+"'. You can continue downloading this file at "+ "your own risk, but you will have to prove that you're a "+ - "human first."; - showCaptcha(); + "human first." + showCaptcha() } else { - console.warn("resp.value not valid: "+resp.value); - triggerDL(); + console.warn("resp.value not valid: "+resp.value) + triggerDL() } }).catch(e => { - console.warn("fetch availability failed: "+e); - triggerDL(); - }); + console.warn("fetch availability failed: "+e) + triggerDL() + }) } Toolbar.prototype.copyUrl = function() { if(copyText(window.location.href)) { - console.log('Text copied'); - this.spanCopyLink.innerText = "Copied!"; + console.log('Text copied') + this.spanCopyLink.innerText = "Copied!" this.btnCopyLink.classList.add("button_highlight") } else { - console.log('Copying not supported'); - this.spanCopyLink.innerText = "Error!"; - alert("Your browser does not support copying text."); + console.log('Copying not supported') + this.spanCopyLink.innerText = "Error!" + alert("Your browser does not support copying text.") } // Return to normal setTimeout(() => { - this.spanCopyLink.innerText = "Copy"; + this.spanCopyLink.innerText = "Copy" this.btnCopyLink.classList.remove("button_highlight") - }, 60000); -} - -Toolbar.prototype.setStats = function(file) { - this.spanViews.innerText = file.views - this.spanDownloads.innerText = Math.round((file.bandwidth_used/file.size)*10)/10; - this.spanSize.innerText = formatDataVolume(file.size, 3); + }, 60000) } // Called by the google recaptcha script -let recaptchaResponse = ""; +let recaptchaResponse = "" function loadCaptcha(){ grecaptcha.render("captcha_popup_captcha", { sitekey: captchaKey, theme: "dark", callback: token => { - recaptchaResponse = token; - document.getElementById("btn_download").click(); + recaptchaResponse = token + document.getElementById("btn_download").click() // Hide the popup setTimeout(() => { - let popupDiv = document.getElementById("captcha_popup"); - popupDiv.style.opacity = "0"; - popupDiv.style.visibility = "hidden"; + let popupDiv = document.getElementById("captcha_popup") + popupDiv.style.opacity = "0" + popupDiv.style.visibility = "hidden" }, 1000) } - }); + }) } diff --git a/res/include/script/file_viewer/Viewer.js b/res/include/script/file_viewer/Viewer.js index 9ae714d..bf0c77e 100644 --- a/res/include/script/file_viewer/Viewer.js +++ b/res/include/script/file_viewer/Viewer.js @@ -1,27 +1,26 @@ function Viewer(type, viewToken, data) { // Set defaults - this.toolbar = null; - this.listNavigator = null; - this.detailsWindow = null; - this.divFilepreview = null; - this.currentFile = ""; - this.title = ""; // Contains either the file name or list title - this.listId = ""; - this.viewToken = ""; - this.isList = false; - this.isFile = false; - this.initialized = false; + this.toolbar = null + this.listNavigator = null + this.detailsWindow = null + this.divFilepreview = null + this.title = "" // Contains either the file name or list title + this.listId = "" + this.viewToken = "" + this.isList = false + this.isFile = false + this.initialized = false - this.viewToken = viewToken; - this.toolbar = new Toolbar(this); - this.detailsWindow = new DetailsWindow(this); + this.viewToken = viewToken + this.toolbar = new Toolbar(this) + this.detailsWindow = new DetailsWindow(this) - this.divFilepreview = document.getElementById("filepreview"); + this.divFilepreview = document.getElementById("filepreview") // On small screens the toolbar takes too much space, so it collapses // automatically if (this.divFilepreview.clientWidth > 600 && !this.toolbar.visible) { - this.toolbar.toggle(); + this.toolbar.toggle() } // The close button only works if the window has an opener. So we hide @@ -31,106 +30,122 @@ function Viewer(type, viewToken, data) { } if (type === "file") { - this.isFile = true; - this.currentFile = data.id; - this.title = data.name; - this.setFile(data); + this.isFile = true + this.title = data.name + this.setFile(fileFromAPIResp(data)) } else if (type === "list") { - this.isList = true; - this.listId = data.id; - this.title = data.title; - this.listNavigator = new ListNavigator(this, data.files); + this.isList = true + this.listId = data.id + this.title = data.title + + let files = [] + for (let i in data.files) { + files.push(fileFromAPIResp(data.files[i])) + } + this.listNavigator = new ListNavigator(this, files) + } else if (type === "skylink") { + this.isFile = true + this.title = data.name + document.getElementById("btn_details").remove() + document.getElementById("stat_views_label").remove() + document.getElementById("stat_views").remove() + document.getElementById("stat_downloads_label").remove() + document.getElementById("stat_downloads").remove() + + let file = fileFromSkyNet(data) + console.log(file) + this.setFile(file) } - this.renderSponsors(); - window.addEventListener("resize", e => { this.renderSponsors(e); }); + this.renderSponsors() + window.addEventListener("resize", e => { this.renderSponsors(e) }) // Register keyboard shortcuts - document.addEventListener("keydown", e => { this.keyboardEvent(e); }); + document.addEventListener("keydown", e => { this.keyboardEvent(e) }) - this.initialized = true; + this.initialized = true } Viewer.prototype.setFile = function(file) { - this.currentFile = file.id; if (this.isList) { - document.getElementById("file_viewer_headerbar_title").style.lineHeight = "1em"; - document.getElementById("file_viewer_list_title").innerText = this.title; - document.getElementById("file_viewer_file_title").innerText = file.name; - document.title = this.title + " ~ " + file.name + " ~ pixeldrain"; + document.getElementById("file_viewer_headerbar_title").style.lineHeight = "1em" + document.getElementById("file_viewer_list_title").innerText = this.title + document.getElementById("file_viewer_file_title").innerText = file.name + document.title = this.title + " ~ " + file.name + " ~ pixeldrain" } else { - document.getElementById("file_viewer_file_title").innerText = file.name; - document.title = file.name + " ~ pixeldrain"; + document.getElementById("file_viewer_file_title").innerText = file.name + document.title = file.name + " ~ pixeldrain" } // Update the file details - this.detailsWindow.setDetails(file); - this.toolbar.setStats(file); + this.detailsWindow.setDetails(file) + this.toolbar.setFile(file) // Register a new view. We don't care what this returns becasue we can't // do anything about it anyway - fetch(apiEndpoint+"/file/"+file.id+"/view", - { - method: "POST", - headers: {"Content-Type": "application/x-www-form-urlencoded"}, - body: "token="+this.viewToken - } - ); + if (file.view_href !== "") { + fetch(file.view_href, { + method: "POST", + headers: {"Content-Type": "application/x-www-form-urlencoded"}, + body: "token="+this.viewToken + } + ) + } // Clear the canvas - this.divFilepreview.innerHTML = ""; + this.divFilepreview.innerHTML = "" let nextItem = () => { if (this.listNavigator !== null) { - this.listNavigator.nextItem(); + this.listNavigator.nextItem() } - }; + } if ( file.mime_type.startsWith("image") ) { - new ImageViewer(this, file).render(this.divFilepreview); + new ImageViewer(this, file).render(this.divFilepreview) } else if ( file.mime_type.startsWith("video") || file.mime_type === "application/matroska" || file.mime_type === "application/x-matroska" ) { - new VideoViewer(this, file, nextItem).render(this.divFilepreview); + new VideoViewer(this, file, nextItem).render(this.divFilepreview) } else if ( file.mime_type.startsWith("audio") || file.mime_type === "application/ogg" || file.name.endsWith(".mp3") ) { - new AudioViewer(this, file, nextItem).render(this.divFilepreview); + new AudioViewer(this, file, nextItem).render(this.divFilepreview) } else if ( file.mime_type === "application/pdf" || file.mime_type === "application/x-pdf" ) { - new PDFViewer(this, file).render(this.divFilepreview); + new PDFViewer(this, file).render(this.divFilepreview) } else if ( file.mime_type.startsWith("text") || file.id === "demo" ) { - new TextViewer(this, file).render(this.divFilepreview); + new TextViewer(this, file).render(this.divFilepreview) } else { - new FileViewer(this, file).render(this.divFilepreview); + new FileViewer(this, file).render(this.divFilepreview) } } Viewer.prototype.renderSponsors = function() { - let scale = 1; - let scaleWidth = 1; - let scaleHeight = 1; - let minWidth = 728; - let minHeight = 800; + let scale = 1 + let scaleWidth = 1 + let scaleHeight = 1 + let minWidth = 728 + let minHeight = 800 if (window.innerWidth < minWidth) { - scaleWidth = window.innerWidth/minWidth; + scaleWidth = window.innerWidth/minWidth } if (window.innerHeight < minHeight) { - scaleHeight = window.innerHeight/minHeight; + scaleHeight = window.innerHeight/minHeight } - scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight; + scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight // Because of the scale transformation the automatic margins don't work // anymore. So we have to maunally calculate the margin. Where we take the @@ -141,14 +156,14 @@ Viewer.prototype.renderSponsors = function() { if (offset < 0) { offset = 0 } - document.querySelector(".sponsors > iframe").style.marginLeft = offset+"px"; + document.querySelector(".sponsors > iframe").style.marginLeft = offset+"px" if (scale == 1) { - document.querySelector(".sponsors > iframe").style.transform = "none"; - document.querySelector(".sponsors").style.height = "90px"; + document.querySelector(".sponsors > iframe").style.transform = "none" + document.querySelector(".sponsors").style.height = "90px" } else { - document.querySelector(".sponsors > iframe").style.transform = "scale("+scale+")"; - document.querySelector(".sponsors").style.height = (scale*90)+"px"; + document.querySelector(".sponsors > iframe").style.transform = "scale("+scale+")" + document.querySelector(".sponsors").style.height = (scale*90)+"px" } } @@ -161,36 +176,36 @@ Viewer.prototype.keyboardEvent = function(evt) { case 65: // A or left arrow key go to previous file case 37: if (this.listNavigator != null) { - this.listNavigator.previousItem(); + this.listNavigator.previousItem() } - break; + break case 68: // D or right arrow key go to next file case 39: if (this.listNavigator != null) { - this.listNavigator.nextItem(); + this.listNavigator.nextItem() } - break; + break case 83: if (evt.shiftKey) { - this.listNavigator.downloadList(); // SHIFT + S downloads all files in list + this.listNavigator.downloadList() // SHIFT + S downloads all files in list } else { - this.toolbar.download(); // S to download the current file + this.toolbar.download() // S to download the current file } - break; + break case 82: // R to toggle list shuffle if (this.listNavigator != null) { - this.listNavigator.toggleShuffle(); + this.listNavigator.toggleShuffle() } - break; + break case 67: // C to copy to clipboard - this.toolbar.copyUrl(); - break; + this.toolbar.copyUrl() + break case 73: // I to open the details window - this.detailsWindow.toggle(); - break; + this.detailsWindow.toggle() + break case 81: // Q to close the window - window.close(); - break; + window.close() + break } } @@ -203,3 +218,39 @@ function escapeHTML(str) { .replace(/>/g, '>') .replace(/"/g, '"'); } + +function fileFromAPIResp(resp) { + let file = { + id: resp.id, + name: resp.name, + mime_type: resp.mime_type, + size: resp.size, + date_created: new Date(resp.date_upload), + date_last_view: new Date(resp.date_last_view), + views: resp.views, + bandwidth_used: resp.bandwidth_used, + description: "", + icon_href: apiEndpoint+"/file/"+resp.id+"/thumbnail", + get_href: apiEndpoint+"/file/"+resp.id, + download_href: apiEndpoint+"/file/"+resp.id+"?download", + availability_href: apiEndpoint+"/file/"+resp.id+"/availability", + view_href: apiEndpoint+"/file/"+resp.id+"/view", + timeseries_href: apiEndpoint+"/file/"+resp.id+"/timeseries", + link: domainURL()+"/u/"+resp.id, + } + if (resp.description !== undefined) { + file.description = resp.description + } + return file +} +function fileFromSkyNet(resp) { + let file = fileFromAPIResp(resp) + file.icon_href = "/res/img/mime/empty.png" + file.get_href = "https://siasky.net/"+resp.id + file.download_href = "https://siasky.net/"+resp.id + file.availability_href = "" + file.view_href = "" + file.timeseries_href = "" + file.link = domainURL()+"/s/"+resp.id + return file +} diff --git a/res/include/script/file_viewer/viewer_scripts/AudioViewer.js b/res/include/script/file_viewer/viewer_scripts/AudioViewer.js index a782137..0e24492 100644 --- a/res/include/script/file_viewer/viewer_scripts/AudioViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/AudioViewer.js @@ -1,33 +1,33 @@ function AudioViewer(viewer, file, next) { - this.viewer = viewer; - this.file = file; - this.next = next; + this.viewer = viewer + this.file = file + this.next = next - this.container = document.createElement("div"); - this.container.classList = "image-container"; - this.container.appendChild(document.createElement("br")); + this.container = document.createElement("div") + this.container.classList = "image-container" + this.container.appendChild(document.createElement("br")) - this.icon = document.createElement("img"); - this.icon.src = "/res/img/mime/audio.png"; - this.container.appendChild(this.icon); + this.icon = document.createElement("img") + this.icon.src = "/res/img/mime/audio.png" + this.container.appendChild(this.icon) - this.container.appendChild(document.createElement("br")); - this.container.appendChild(document.createTextNode(file.name)); - this.container.appendChild(document.createElement("br")); - this.container.appendChild(document.createElement("br")); + this.container.appendChild(document.createElement("br")) + this.container.appendChild(document.createTextNode(this.file.name)) + this.container.appendChild(document.createElement("br")) + this.container.appendChild(document.createElement("br")) - this.element = document.createElement("audio"); - this.element.autoplay = "autoplay"; - this.element.controls = "controls"; - this.element.style.width = "90%"; - this.element.addEventListener("ended", () => { this.next(); }, false); + this.element = document.createElement("audio") + this.element.autoplay = "autoplay" + this.element.controls = "controls" + this.element.style.width = "90%" + this.element.addEventListener("ended", () => { this.next() }, false) - this.source = document.createElement("source"); - this.source.src = apiEndpoint+"/file/"+this.file.id; - this.element.appendChild(this.source); - this.container.appendChild(this.element); + this.source = document.createElement("source") + this.source.src = this.file.get_href + this.element.appendChild(this.source) + this.container.appendChild(this.element) } AudioViewer.prototype.render = function(parent) { - parent.appendChild(this.container); + parent.appendChild(this.container) } diff --git a/res/include/script/file_viewer/viewer_scripts/FileViewer.js b/res/include/script/file_viewer/viewer_scripts/FileViewer.js index c634832..1d7d20c 100644 --- a/res/include/script/file_viewer/viewer_scripts/FileViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/FileViewer.js @@ -1,27 +1,27 @@ function FileViewer(viewer, file, next) { - this.viewer = viewer; - this.file = file; - this.next = next; + this.viewer = viewer + this.file = file + this.next = next - this.container = document.createElement("div"); - this.container.classList = "image-container"; - this.container.appendChild(document.createElement("br")); + this.container = document.createElement("div") + this.container.classList = "image-container" + this.container.appendChild(document.createElement("br")) - this.icon = document.createElement("img"); - this.icon.src = apiEndpoint+"/"+file.thumbnail_href; - this.container.appendChild(this.icon); + this.icon = document.createElement("img") + this.icon.src = this.file.icon_href + this.container.appendChild(this.icon) - this.container.appendChild(document.createElement("br")); - this.container.appendChild(document.createTextNode(file.name)); - this.container.appendChild(document.createElement("br")); - this.container.appendChild(document.createTextNode("Type: "+file.mime_type)); - this.container.appendChild(document.createElement("br")); - this.container.appendChild(document.createElement("br")); + this.container.appendChild(document.createElement("br")) + this.container.appendChild(document.createTextNode(file.name)) + this.container.appendChild(document.createElement("br")) + this.container.appendChild(document.createTextNode("Type: "+file.mime_type)) + this.container.appendChild(document.createElement("br")) + this.container.appendChild(document.createElement("br")) this.container.appendChild(document.createTextNode( "Press the 'Download' button in the menu to download this file" - )); + )) } FileViewer.prototype.render = function(parent) { - parent.appendChild(this.container); + parent.appendChild(this.container) } diff --git a/res/include/script/file_viewer/viewer_scripts/ImageViewer.js b/res/include/script/file_viewer/viewer_scripts/ImageViewer.js index a916ab9..600c468 100644 --- a/res/include/script/file_viewer/viewer_scripts/ImageViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/ImageViewer.js @@ -1,88 +1,86 @@ function ImageViewer(viewer, file) { - this.viewer = viewer; - this.file = file; - this.zoomed = false; - this.x = 0; - this.y = 0; - this.dragging = false; + this.viewer = viewer + this.file = file + this.zoomed = false + this.x = 0 + this.y = 0 + this.dragging = false - this.container = document.createElement("dv"); - this.container.classList = "image-container"; - // this.container.style.lineHeight = "0"; + this.container = document.createElement("dv") + this.container.classList = "image-container" - this.element = document.createElement("img"); - this.element.classList = "pannable center drop-shadow"; - this.element.src = apiEndpoint+"/file/"+this.file.id; - this.element.addEventListener("dblclick", (e) => { return this.doubleclick(e); }); - this.element.addEventListener("doubletap", (e) => { return this.doubleclick(e); }); - this.element.addEventListener("mousedown", (e) => { return this.mousedown(e); }); - document.addEventListener("mousemove", (e) => { return this.mousemove(e); }); - document.addEventListener("mouseup", (e) => { return this.mouseup(e); }); + this.element = document.createElement("img") + this.element.classList = "pannable center drop-shadow" + this.element.src = this.file.get_href + this.element.addEventListener("dblclick", (e) => { return this.doubleclick(e) }) + this.element.addEventListener("doubletap", (e) => { return this.doubleclick(e) }) + this.element.addEventListener("mousedown", (e) => { return this.mousedown(e) }) + document.addEventListener("mousemove", (e) => { return this.mousemove(e) }) + document.addEventListener("mouseup", (e) => { return this.mouseup(e) }) - this.container.appendChild(this.element); + this.container.appendChild(this.element) } ImageViewer.prototype.render = function(parent) { - parent.appendChild(this.container); + parent.appendChild(this.container) } ImageViewer.prototype.doubleclick = function(e) { if (this.zoomed) { - this.element.style.maxWidth = "100%"; - this.element.style.maxHeight = "100%"; - this.element.style.top = "50%"; - this.element.style.left = "auto"; - this.element.style.transform = "translateY(-50%)"; - this.container.style.overflow = "hidden"; - this.zoomed = false; + this.element.style.maxWidth = "100%" + this.element.style.maxHeight = "100%" + this.element.style.top = "50%" + this.element.style.left = "auto" + this.element.style.transform = "translateY(-50%)" + this.container.style.overflow = "hidden" + this.zoomed = false } else { - this.element.style.maxWidth = "none"; - this.element.style.maxHeight = "none"; - this.element.style.top = "0"; - this.element.style.left = ""; - this.element.style.transform = "none"; - this.container.style.overflow = "scroll"; - this.zoomed = true; + this.element.style.maxWidth = "none" + this.element.style.maxHeight = "none" + this.element.style.top = "0" + this.element.style.left = "" + this.element.style.transform = "none" + this.container.style.overflow = "scroll" + this.zoomed = true } - e.preventDefault(); - e.stopPropagation(); - return false; + e.preventDefault() + e.stopPropagation() + return false } ImageViewer.prototype.mousedown = function(e) { if (!this.dragging && e.which === 1 && this.zoomed) { - this.x = e.pageX; - this.y = e.pageY; - this.dragging = true; + this.x = e.pageX + this.y = e.pageY + this.dragging = true - e.preventDefault(); - e.stopPropagation(); - return false; + e.preventDefault() + e.stopPropagation() + return false } } ImageViewer.prototype.mousemove = function(e) { if (this.dragging) { - this.container.scrollLeft = this.container.scrollLeft - (e.pageX - this.x); - this.container.scrollTop = this.container.scrollTop - (e.pageY - this.y); + this.container.scrollLeft = this.container.scrollLeft - (e.pageX - this.x) + this.container.scrollTop = this.container.scrollTop - (e.pageY - this.y) - this.x = e.pageX; - this.y = e.pageY; + this.x = e.pageX + this.y = e.pageY - e.preventDefault(); - e.stopPropagation(); - return false; + e.preventDefault() + e.stopPropagation() + return false } - } ImageViewer.prototype.mouseup = function(e) { if (this.dragging) { - this.dragging = false; + this.dragging = false - e.preventDefault(); - e.stopPropagation(); - return false; + e.preventDefault() + e.stopPropagation() + return false } } diff --git a/res/include/script/file_viewer/viewer_scripts/PDFViewer.js b/res/include/script/file_viewer/viewer_scripts/PDFViewer.js index 7e79c60..00bb7d1 100644 --- a/res/include/script/file_viewer/viewer_scripts/PDFViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/PDFViewer.js @@ -1,13 +1,12 @@ function PDFViewer(viewer, file) { - this.viewer = viewer; - this.file = file; + this.viewer = viewer + this.file = file - this.container = document.createElement("iframe"); - this.container.classList = "image-container"; - this.container.style.border = "none"; - this.container.src = "/res/misc/pdf-viewer/web/viewer.html?file="+apiEndpoint+"/file/"+file.id; + this.container = document.createElement("iframe") + this.container.classList = "image-container" + this.container.style.border = "none" + this.container.src = "/res/misc/pdf-viewer/web/viewer.html?file="+this.file.get_href } - PDFViewer.prototype.render = function(parent) { - parent.appendChild(this.container); + parent.appendChild(this.container) } diff --git a/res/include/script/file_viewer/viewer_scripts/TextViewer.js b/res/include/script/file_viewer/viewer_scripts/TextViewer.js index 867ed0f..c182a09 100644 --- a/res/include/script/file_viewer/viewer_scripts/TextViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/TextViewer.js @@ -1,56 +1,58 @@ function TextViewer(viewer, file) { - this.viewer = viewer; - this.file = file; - this.pre = null; - this.prettyprint = null; + this.viewer = viewer + this.file = file + this.pre = null + this.prettyprint = null - this.container = document.createElement("div"); - this.container.classList = "text-container"; + this.container = document.createElement("div") + this.container.classList = "text-container" - if (file.name.endsWith(".md") || file.name.endsWith(".markdown") || file.id === "demo") { - this.getMarkdown(); + if (this.file.name.endsWith(".md") || this.file.name.endsWith(".markdown") || file.mime_type === "text/demo") { + this.getMarkdown() } else { - this.getText(); + this.getText() } } TextViewer.prototype.getText = function() { - this.pre = document.createElement("pre"); - this.pre.classList = "pre-container prettyprint linenums"; - this.pre.innerText = "Loading..."; - this.container.appendChild(this.pre); + this.pre = document.createElement("pre") + this.pre.classList = "pre-container prettyprint linenums" + this.pre.innerText = "Loading..." + this.container.appendChild(this.pre) if (this.file.size > 1<<20) { // File larger than 1 MiB - this.pre.innerText = "File is too large to view online.\nPlease download and view it locally."; - return; + this.pre.innerText = "File is too large to view online.\nPlease download and view it locally." + return } - fetch(apiEndpoint+"/file/"+this.file.id).then(resp => { - if (!resp.ok) { return Promise.reject(resp.status); } - return resp.text(); + fetch(this.file.get_href).then(resp => { + if (!resp.ok) { return Promise.reject(resp.status) } + return resp.text() }).then(resp => { - this.pre.innerText = resp; + this.pre.innerText = resp // Load prettyprint script - this.prettyprint = document.createElement("script"); - this.prettyprint.src = "https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=desert"; - this.container.appendChild(this.prettyprint); + this.prettyprint = document.createElement("script") + this.prettyprint.src = "https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?skin=desert" + this.container.appendChild(this.prettyprint) }).catch(err => { - this.pre.innerText = "Error loading file: "+err; - }); + this.pre.innerText = "Error loading file: "+err + }) } TextViewer.prototype.getMarkdown = function() { - fetch("/u/"+this.file.id+"/preview").then(resp => { - if (!resp.ok) { return Promise.reject(resp.status); } - return resp.text(); + fetch( + domainURL()+window.location.pathname+"/preview" + ).then(resp => { + if (!resp.ok) { return Promise.reject(resp.status) } + return resp.text() }).then(resp => { - this.container.innerHTML = resp; + this.container.innerHTML = resp }).catch(err => { - this.container.innerText = "Error loading file: "+err; - }); + this.container.innerText = "Error loading file: "+err + }) } TextViewer.prototype.render = function(parent) { - parent.appendChild(this.container); + parent.appendChild(this.container) } diff --git a/res/include/script/file_viewer/viewer_scripts/VideoViewer.js b/res/include/script/file_viewer/viewer_scripts/VideoViewer.js index bc9a467..48716df 100644 --- a/res/include/script/file_viewer/viewer_scripts/VideoViewer.js +++ b/res/include/script/file_viewer/viewer_scripts/VideoViewer.js @@ -1,24 +1,24 @@ function VideoViewer(viewer, file, next) { - this.viewer = viewer; - this.file = file; - this.next = next; + this.viewer = viewer + this.file = file + this.next = next - this.vidContainer = document.createElement("div"); - this.vidContainer.classList = "image-container"; + this.vidContainer = document.createElement("div") + this.vidContainer.classList = "image-container" - this.vidElement = document.createElement("video"); - this.vidElement.autoplay = "autoplay"; - this.vidElement.controls = "controls"; - this.vidElement.classList = "center drop-shadow"; - this.vidElement.addEventListener("ended", () => { this.next(); }, false); + this.vidElement = document.createElement("video") + this.vidElement.autoplay = "autoplay" + this.vidElement.controls = "controls" + this.vidElement.classList = "center drop-shadow" + this.vidElement.addEventListener("ended", () => { this.next() }, false) - this.videoSource = document.createElement("source"); - this.videoSource.src = apiEndpoint+"/file/"+this.file.id; + this.videoSource = document.createElement("source") + this.videoSource.src = this.file.get_href - this.vidElement.appendChild(this.videoSource); - this.vidContainer.appendChild(this.vidElement); + this.vidElement.appendChild(this.videoSource) + this.vidContainer.appendChild(this.vidElement) } VideoViewer.prototype.render = function(parent) { - parent.appendChild(this.vidContainer); + parent.appendChild(this.vidContainer) } diff --git a/res/include/script/history.js b/res/include/script/history.js index 5656eab..f35b496 100644 --- a/res/include/script/history.js +++ b/res/include/script/history.js @@ -1,78 +1,77 @@ function renderFileButton(apiURL, id, title, subtitle) { - let btn = document.createElement("a"); - btn.classList = "file_button"; - btn.href = "/u/"+id; - btn.target = "_blank"; - let thumbnail = document.createElement("img"); - thumbnail.src = apiURL+"/file/"+id+"/thumbnail?width=80&height=80"; - thumbnail.alt = title; - let titleSpan = document.createElement("span"); - titleSpan.classList = "file_button_title"; - titleSpan.innerText = title; - let br = document.createElement("br"); - let subtitleSpan = document.createElement("span"); - subtitleSpan.classList = "file_button_subtitle"; - subtitleSpan.innerText = subtitle; + let btn = document.createElement("a") + btn.classList = "file_button" + btn.href = "/u/"+id + btn.target = "_blank" + let thumbnail = document.createElement("img") + thumbnail.src = apiURL+"/file/"+id+"/thumbnail?width=80&height=80" + thumbnail.alt = title + let titleSpan = document.createElement("span") + titleSpan.classList = "file_button_title" + titleSpan.innerText = title + let br = document.createElement("br") + let subtitleSpan = document.createElement("span") + subtitleSpan.classList = "file_button_subtitle" + subtitleSpan.innerText = subtitle - btn.appendChild(thumbnail); - btn.appendChild(titleSpan); - btn.appendChild(br); - btn.appendChild(subtitleSpan); - return btn; + btn.appendChild(thumbnail) + btn.appendChild(titleSpan) + btn.appendChild(br) + btn.appendChild(subtitleSpan) + return btn } function getCookie(name) { - var result = new RegExp('(?:^|; )' + encodeURIComponent(name) + '=([^;]*)').exec(document.cookie); - return result ? result[1] : null; + var result = new RegExp('(?:^|; )' + encodeURIComponent(name) + '=([^;]*)').exec(document.cookie) + return result ? result[1] : null } // Get the uploads from localstorage -let uploadsStr = localStorage.getItem("uploaded_files"); -if (uploadsStr === null) { uploadsStr = ""; } +let uploadsStr = localStorage.getItem("uploaded_files") +if (uploadsStr === null) { uploadsStr = "" } -let uploads = Array(); +let uploads = Array() if (uploadsStr != "") { - uploadsStr = uploadsStr.slice(0, -1); // Strip the trailing comma - uploads = uploadsStr.split(","); + uploadsStr = uploadsStr.slice(0, -1) // Strip the trailing comma + uploads = uploadsStr.split(",") } // Get the uploads from a cookie -uploadsStr = getCookie("pduploads"); -if (uploadsStr === null) { uploadsStr = ""; } +uploadsStr = getCookie("pduploads") +if (uploadsStr === null) { uploadsStr = "" } if (uploadsStr != "") { - uploadsStr = uploadsStr.slice(0, -1); // Strip the trailing dot - uploads.push(uploadsStr.split(".").reverse()); + uploadsStr = uploadsStr.slice(0, -1) // Strip the trailing dot + uploads.push(uploadsStr.split(".").reverse()) } // Render all the items function getHistoryItem() { - let item = uploads.shift(); - if (item === undefined || item === "") { return; } + let item = uploads.shift() + if (item === undefined || item === "") { return } fetch( apiEndpoint+"/file/"+item+"/info" ).then(resp => { if (!resp.ok) { - return Promise.reject(); + return Promise.reject() } - return resp.json(); + return resp.json() }).then(resp => { - let date = new Date(resp.date_upload); document.getElementById("uploaded_files").appendChild( renderFileButton( apiEndpoint, resp.id, resp.name, - date.getFullYear()+"-"+("00"+(date.getMonth()+1)).slice(-2)+"-"+("00"+date.getDate()).slice(-2) + printDate(new Date(resp.date_upload), true, true, true), ) - ); - getHistoryItem(); + ) + getHistoryItem() }).catch(err => { console.log("Fetch failed: "+err) - getHistoryItem(); + getHistoryItem() }) } -getHistoryItem(); +getHistoryItem() diff --git a/res/include/script/homepage.js b/res/include/script/homepage.js index bf91592..a74ce7f 100644 --- a/res/include/script/homepage.js +++ b/res/include/script/homepage.js @@ -1,27 +1,27 @@ function UploadProgressBar(uploadManager, queueDiv, file){ - this.uploadManager = uploadManager; - this.file = file; - this.name = file.name; + this.uploadManager = uploadManager + this.file = file + this.name = file.name - this.uploadDiv = document.createElement("a"); - this.uploadDiv.classList.add("file_button"); - this.uploadDiv.style.opacity = "0"; - this.uploadDiv.innerText = "Queued\n" + this.file.name; - queueDiv.appendChild(this.uploadDiv); + this.uploadDiv = document.createElement("a") + this.uploadDiv.classList.add("file_button") + this.uploadDiv.style.opacity = "0" + this.uploadDiv.innerText = "Queued\n" + this.file.name + queueDiv.appendChild(this.uploadDiv) // Start uploading the file this.uploadManager.addFile( this.file, this.name, - (progress) => { this.onProgress(progress); }, - (id) => { this.onFinished(id); }, - (val, msg) => { this.onFailure(val, msg); } - ); + (progress) => { this.onProgress(progress) }, + (id) => { this.onFinished(id) }, + (val, msg) => { this.onFailure(val, msg) } + ) // Browsers don't render the transition if the opacity is set and // updated in the same frame. So we have to wait a frame (or more) // before changing the opacity to make sure the transition triggers - window.setTimeout(() => {this.uploadDiv.style.opacity = "1";}, 100) + window.setTimeout(() => {this.uploadDiv.style.opacity = "1"}, 100) } UploadProgressBar.prototype.onProgress = function(progress){ @@ -33,7 +33,7 @@ UploadProgressBar.prototype.onProgress = function(progress){ +'var(--file_background_color) '+ ((progress*100)+1) +'%)' } UploadProgressBar.prototype.onFinished = function(id){ - console.log("Upload finished: "+this.file.name+" "+id); + console.log("Upload finished: "+this.file.name+" "+id) this.uploadDiv.style.background = 'var(--file_background_color)' this.uploadDiv.href = '/u/'+id @@ -55,7 +55,7 @@ UploadProgressBar.prototype.onFinished = function(id){ } UploadProgressBar.prototype.onFailure = function(val, msg) { if (val === "") { - val = "Could not connect to server"; + val = "Could not connect to server" } this.uploadDiv.innerHTML = "" // Remove uploading progress @@ -65,21 +65,21 @@ UploadProgressBar.prototype.onFailure = function(val, msg) { this.uploadDiv.appendChild(document.createTextNode(msg+" ("+val+")")) this.uploadDiv.appendChild(document.createElement("br")) this.uploadDiv.appendChild(document.createTextNode(this.file.name)) - console.log(msg); + console.log(msg) } -let uploader = null; -let shareTitle = ""; -let shareLink = ""; +let uploader = null +let shareTitle = "" +let shareLink = "" function handleUploads(files) { if (uploader === null){ - uploader = new UploadManager(apiEndpoint, uploadsFinished); + uploader = new UploadManager(apiEndpoint, uploadsFinished) } if (files.length === 0) { - return; + return } for (let i = 0; i < files.length; i++) { @@ -87,10 +87,10 @@ function handleUploads(files) { uploader, document.getElementById("uploads_queue"), files.item(i) - ); + ) } - hideShareButtons(); + hideShareButtons() } function uploadsFinished() { @@ -98,35 +98,35 @@ function uploadsFinished() { shareTitle = "" // Get the finished uploads from the uploader - let uploadLog = uploader.finishedUploads(); + let uploadLog = uploader.finishedUploads() if (uploadLog.length === 1) { - shareTitle = "Download "+uploadLog[0].fileName+" here"; - shareLink = domainURL()+"/u/"+uploadLog[0].fileID; + shareTitle = "Download "+uploadLog[0].fileName+" here" + shareLink = domainURL()+"/u/"+uploadLog[0].fileID - showShareButtons(); + showShareButtons() } else if (uploadLog.length > 1) { - let title = uploadLog.length + " files"; + let title = uploadLog.length + " files" createList( title, true, ).then(resp => { - console.log("Automatic list ID "+resp.id); - shareTitle = "View "+title+" here"; - shareLink = domainURL()+"/l/"+resp.id; + console.log("Automatic list ID "+resp.id) + shareTitle = "View "+title+" here" + shareLink = domainURL()+"/l/"+resp.id - showShareButtons(); + showShareButtons() }).catch(err => { - alert("Failed to generate link. Please check your internet connection and try again.\nError: "+err); - }); + alert("Failed to generate link. Please check your internet connection and try again.\nError: "+err) + }) } } function createList(title, anonymous) { - let uploads = uploader.finishedUploads(); - let files = Array(); + let uploads = uploader.finishedUploads() + let files = Array() for (let i = 0; i < uploads.length; i++) { - files.push({ "id": uploads[i].fileID }); + files.push({ "id": uploads[i].fileID }) } return fetch( @@ -142,34 +142,34 @@ function createList(title, anonymous) { } ).then(resp => { if (!resp.ok) { - return Promise.reject("HTTP error: "+resp.status); + return Promise.reject("HTTP error: "+resp.status) } - return resp.json(); + return resp.json() }) } function hideShareButtons() { - document.getElementById("instruction_3_after").style.display = "none"; + document.getElementById("instruction_3_after").style.display = "none" } function showShareButtons() { - document.getElementById("instruction_3_after").style.display = ""; + document.getElementById("instruction_3_after").style.display = "" if (window.navigator && window.navigator.share) { - document.getElementById("social_buttons").style.display = "none"; + document.getElementById("social_buttons").style.display = "none" } else { - document.getElementById("navigator_share_button").style.display = "none"; + document.getElementById("navigator_share_button").style.display = "none" } } function copyLink() { if(copyText(shareLink)) { - console.log('Text copied'); - document.querySelector("#btn_copy_link>span").textContent = "Copied!"; - document.getElementById("btn_copy_link").classList.add("button_highlight"); + console.log('Text copied') + document.querySelector("#btn_copy_link>span").textContent = "Copied!" + document.getElementById("btn_copy_link").classList.add("button_highlight") } else { - console.log('Copying not supported'); - alert("Your browser does not support copying text."); + console.log('Copying not supported') + alert("Your browser does not support copying text.") } } @@ -179,33 +179,39 @@ function copyLink() { // Relay click event to hidden file field document.getElementById("upload_file_button").onclick = function() { - document.getElementById("file_input_field").click(); + document.getElementById("file_input_field").click() } document.getElementById("file_input_field").onchange = function(evt){ // Start uploading the files async - window.setTimeout(handleUploads(evt.target.files), 1); + window.setTimeout(handleUploads(evt.target.files), 1) // This resets the file input field - document.getElementById("file_input_field").nodeValue = ""; + document.getElementById("file_input_field").nodeValue = "" } document.getElementById("upload_text_button").onclick = function() { - window.location.href = '/t/'; + window.location.href = '/t/' } /* * Drag 'n Drop upload handlers */ -document.ondragover = function(e) { e.preventDefault(); e.stopPropagation(); } -document.ondragenter = function(e) { e.preventDefault(); e.stopPropagation(); } +document.ondragover = function(e) { + e.preventDefault() + e.stopPropagation() +} +document.ondragenter = function(e) { + e.preventDefault() + e.stopPropagation() +} document.addEventListener('drop', function(e){ if (e.dataTransfer && e.dataTransfer.files.length > 0) { e.preventDefault() e.stopPropagation() // Run async to not freeze the page - window.setTimeout(handleUploads(e.dataTransfer.files), 1); + window.setTimeout(handleUploads(e.dataTransfer.files), 1) } }) @@ -218,42 +224,65 @@ document.getElementById("btn_social_share").addEventListener("click", function() title: "Pixeldrain", text: shareTitle, url: shareLink - }); -}); + }) +}) document.getElementById("btn_copy_link").addEventListener("click", function() { - copyLink(); -}); + copyLink() +}) document.getElementById("btn_open_link").addEventListener("click", function() { - window.open(shareLink, '_blank'); -}); + window.open(shareLink, '_blank') +}) document.getElementById("btn_social_email").addEventListener("click", function() { - window.open('mailto:please@set.address?subject=File%20on%20pixeldrain&body=' + shareLink); -}); + window.open('mailto:please@set.address?subject=File%20on%20pixeldrain&body=' + shareLink) +}) document.getElementById("btn_social_twitter").addEventListener("click", function() { - window.open('https://twitter.com/share?url=' + shareLink); -}); + window.open('https://twitter.com/share?url=' + shareLink) +}) document.getElementById("btn_social_facebook").addEventListener("click", function() { - window.open('http://www.facebook.com/sharer.php?u=' + shareLink); -}); + window.open('http://www.facebook.com/sharer.php?u=' + shareLink) +}) document.getElementById("btn_social_reddit").addEventListener("click", function() { - window.open('https://www.reddit.com/submit?url=' + shareLink); -}); + window.open('https://www.reddit.com/submit?url=' + shareLink) +}) document.getElementById("btc_social_tumblr").addEventListener("click", function() { - window.open('http://www.tumblr.com/share/link?url=' + shareLink); -}); + window.open('http://www.tumblr.com/share/link?url=' + shareLink) +}) /* * Link copy buttons */ +function renderListButton(apiURL, id, title, subtitle) { + let btn = document.createElement("a") + btn.classList = "file_button" + btn.href = "/l/"+id + btn.target = "_blank" + let thumbnail = document.createElement("img") + thumbnail.src = apiURL+"/list/"+id+"/thumbnail?width=80&height=80" + thumbnail.alt = title + let titleSpan = document.createElement("span") + titleSpan.classList = "file_button_title" + titleSpan.innerText = title + let br = document.createElement("br") + let subtitleSpan = document.createElement("span") + subtitleSpan.classList = "file_button_subtitle" + subtitleSpan.innerText = subtitle + + btn.appendChild(thumbnail) + btn.appendChild(titleSpan) + btn.appendChild(br) + btn.appendChild(subtitleSpan) + return btn +} + // Create list button document.getElementById("btn_create_list").addEventListener("click", function(evt) { let title = prompt( "You are creating a list containing " + uploader.finishedUploads().length + " files.\n" + "What do you want to call it?", "My New Album" - ); + ) if(title === null){ - return; + return } createList(title, false).then(resp => { document.getElementById("created_lists").appendChild( @@ -263,91 +292,91 @@ document.getElementById("btn_create_list").addEventListener("click", function(ev domainURL()+'/l/'+resp.id, "List creation finished!", ) - ); - window.open('/l/'+resp.id, '_blank'); + ) + window.open('/l/'+resp.id, '_blank') }).catch(err => { let div = document.createElement("div") - div.className = "file_button"; + div.className = "file_button" div.innerHTML = "List creation failed
" + "The server responded with:
" - + err; - document.getElementById("created_lists").append(div); - }); -}); + + err + document.getElementById("created_lists").append(div) + }) +}) -let btnCopyLinks = document.getElementById("btn_copy_links"); +let btnCopyLinks = document.getElementById("btn_copy_links") btnCopyLinks.addEventListener("click", function(){ - let text = ""; - let uploads = uploader.finishedUploads(); + let text = "" + let uploads = uploader.finishedUploads() // Add the text to the textarea for (let i = 0; i < uploads.length; i++) { // Example: https://pixeldrain.com/u/abcd1234: Some_file.png - text += domainURL()+"/u/"+uploads[i].fileID+" "+uploads[i].fileName+"\n"; + text += domainURL()+"/u/"+uploads[i].fileID+" "+uploads[i].fileName+"\n" } if (shareLink.includes("/l/")) { - text += "\n"+shareLink+" All "+uploads.length+" files\n"; + text += "\n"+shareLink+" All "+uploads.length+" files\n" } // Copy the selected text if(copyText(text)){ - btnCopyLinks.classList.add("button_highlight"); + btnCopyLinks.classList.add("button_highlight") btnCopyLinks.innerHTML = "Links copied to clipboard!" }else{ - btnCopyLinks.classList.add("button_red"); + btnCopyLinks.classList.add("button_red") btnCopyLinks.innerHTML = "Copying links failed" } -}); +}) -let btnCopyBBCode = document.getElementById("btn_copy_bbcode"); +let btnCopyBBCode = document.getElementById("btn_copy_bbcode") btnCopyBBCode.addEventListener("click", function(){ - let text = ""; - let uploads = uploader.finishedUploads(); + let text = "" + let uploads = uploader.finishedUploads() // Add the text to the textarea for (let i = 0; i < uploads.length; i++) { // Example: [url=https://pixeldrain.com/u/abcd1234]Some_file.png[/url] - text += "[url="+domainURL()+"/u/"+uploads[i].fileID+"]"+uploads[i].fileName+"[/url]\n"; + text += "[url="+domainURL()+"/u/"+uploads[i].fileID+"]"+uploads[i].fileName+"[/url]\n" } if (shareLink.includes("/l/")) { - text += "\n[url="+shareLink+"]All "+uploads.length+" files[/url]\n"; + text += "\n[url="+shareLink+"]All "+uploads.length+" files[/url]\n" } // Copy the selected text if(copyText(text)){ - btnCopyBBCode.classList.add("button_highlight"); + btnCopyBBCode.classList.add("button_highlight") btnCopyBBCode.innerHTML = "BBCode copied to clipboard!" }else{ - btnCopyBBCode.classList.add("button_red"); + btnCopyBBCode.classList.add("button_red") btnCopyBBCode.innerHTML = "Copying links failed" } -}); +}) -let btnCopyMarkdown = document.getElementById("btn_copy_markdown"); +let btnCopyMarkdown = document.getElementById("btn_copy_markdown") btnCopyMarkdown.addEventListener("click", function(){ - let text = ""; - let uploads = uploader.finishedUploads(); + let text = "" + let uploads = uploader.finishedUploads() // Add the text to the textarea for (let i = 0; i < uploads.length; i++) { // Example: * [Some_file.png](https://pixeldrain.com/u/abcd1234) - if (uploads.length > 1) { text += " * "; } - text += "["+uploads[i].fileName+"]("+domainURL()+"/u/"+uploads[i].fileID+")\n"; + if (uploads.length > 1) { text += " * " } + text += "["+uploads[i].fileName+"]("+domainURL()+"/u/"+uploads[i].fileID+")\n" } if (shareLink.includes("/l/")) { - text += " * [All "+uploads.length+" files]("+shareLink+")\n"; + text += " * [All "+uploads.length+" files]("+shareLink+")\n" } // Copy the selected text if(copyText(text)){ - btnCopyMarkdown.classList.add("button_highlight"); + btnCopyMarkdown.classList.add("button_highlight") btnCopyMarkdown.innerHTML = "Markdown copied to clipboard!" }else{ - btnCopyMarkdown.classList.add("button_red"); + btnCopyMarkdown.classList.add("button_red") btnCopyMarkdown.innerHTML = "Copying links failed" } -}); +}) /* @@ -359,13 +388,13 @@ document.addEventListener("keydown", function(event){ } if (event.keyCode === 67) { // c // Copy links to clipboard - document.getElementById("btn_copy_link").click(); + document.getElementById("btn_copy_link").click() } else if (event.keyCode === 85) { // u // Click the upload button - document.getElementById("file_input_field").click(); + document.getElementById("file_input_field").click() } else if (event.keyCode === 84) { // t // Click the text button - document.getElementById("upload_text_button").click(); + document.getElementById("upload_text_button").click() } console.log(event.keyCode) -}); +}) diff --git a/webcontroller/admin_panel.go b/webcontroller/admin_panel.go index 3098170..520b1e4 100644 --- a/webcontroller/admin_panel.go +++ b/webcontroller/admin_panel.go @@ -95,3 +95,45 @@ func (wc *WebController) adminGlobalsForm(td *TemplateData, r *http.Request) (f } return f } + +// func (wc *WebController) adminFileDeleteForm(td *TemplateData, r *http.Request) (f Form) { +// if isAdmin, err := td.PixelAPI.UserIsAdmin(); err != nil { +// td.Title = err.Error() +// return Form{Title: td.Title} +// } else if !isAdmin.IsAdmin { +// td.Title = ";)" +// return Form{Title: td.Title} +// } + +// td.Title = "Admin file removal" +// f = Form{ +// Name: "admin_file_removal", +// Title: td.Title, +// PreFormHTML: template.HTML("

Paste any pixeldrain file links in here to remove them

"), +// Fields: []Field{ +// { +// Name: "files", +// Label: "Files to delete", +// Type: FieldTypeTextarea, +// }, +// }, +// BackLink: "/admin", +// SubmitLabel: "Submit", +// } + +// if f.ReadInput(r) { +// filesText := f.FieldVal("files") + +// // Get all links from the text +// strings.Index(filesText, "/u/") + +// if len(f.SubmitMessages) == 0 { +// // Request was a success +// f.SubmitSuccess = true +// f.SubmitMessages = []template.HTML{template.HTML( +// fmt.Sprintf("Success! %d values updated", successfulUpdates), +// )} +// } +// } +// return f +// } diff --git a/webcontroller/file_viewer.go b/webcontroller/file_viewer.go index 331f8a7..c6432e2 100644 --- a/webcontroller/file_viewer.go +++ b/webcontroller/file_viewer.go @@ -2,10 +2,14 @@ package webcontroller import ( "fmt" + "io/ioutil" "net/http" + "strconv" "strings" "time" + pdmimetype "github.com/Fornaxian/pd_mime_type" + "fornaxian.com/pixeldrain-web/pixelapi" "github.com/Fornaxian/log" "github.com/julienschmidt/httprouter" @@ -152,3 +156,90 @@ func (wc *WebController) serveListViewer(w http.ResponseWriter, r *http.Request, log.Error("Error executing template file_viewer: %s", err) } } + +// ServeFileViewer controller for GET /s/:id +func (wc *WebController) serveSkynetViewer(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + var err error + templateData := wc.newTemplateData(w, r) + + // Get the first few bytes from the file to probe the content type and + // length + rq, err := http.NewRequest("GET", "https://siasky.net/"+p.ByName("id"), nil) + if err != nil { + panic(err) + } + + // Range header limits the number of bytes which will be read + rq.Header.Set("Range", "bytes=0-1023") + + resp, err := wc.httpClient.Do(rq) + if err != nil { + panic(err) + } + defer resp.Body.Close() + + if resp.StatusCode >= 500 { + w.WriteHeader(http.StatusInternalServerError) + wc.templates.Get().ExecuteTemplate(w, "500", templateData) + return + } else if resp.StatusCode >= 400 { + w.WriteHeader(http.StatusNotFound) + wc.templates.Get().ExecuteTemplate(w, "file_not_found", templateData) + return + } + + head, err := ioutil.ReadAll(resp.Body) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + wc.templates.Get().ExecuteTemplate(w, "500", templateData) + return + } + + var fileType = resp.Header.Get("Content-Type") + if fileType == "application/octet-stream" || fileType == "" { + fileType = pdmimetype.Detect(head) + } + + // Now get the size of the file from the content-range header + contentRange := resp.Header.Get("Content-Range") + if contentRange == "" { + w.WriteHeader(http.StatusInternalServerError) + wc.templates.Get().ExecuteTemplate(w, "500", templateData) + return + } + contentRange = strings.TrimPrefix(contentRange, "bytes ") + size, err := strconv.ParseUint(strings.Split(contentRange, "/")[1], 10, 64) + if err != nil { + panic(err) + } + + templateData.OGData = "" + templateData.Title = fmt.Sprintf("Skylink ~ pixeldrain") + templateData.Other = viewerData{ + Type: "skylink", + APIResponse: pixelapi.FileInfo{ + Success: true, + ID: p.ByName("id"), + Name: "skynet_file.dat", + Size: size, + Views: 0, + BandwidthUsed: 0, + DateUpload: time.Now(), + DateLastView: time.Now(), + MimeType: fileType, + MimeImage: "", + ThumbnailHREF: "", + Availability: "", + }, + } + + var templateName = "file_viewer" + if browserCompat(r.UserAgent()) { + templateName = "file_viewer_compat" + } + + err = wc.templates.Get().ExecuteTemplate(w, templateName, templateData) + if err != nil && !strings.Contains(err.Error(), "broken pipe") { + log.Error("Error executing template file_viewer: %s", err) + } +} diff --git a/webcontroller/web_controller.go b/webcontroller/web_controller.go index 6d8e8ef..a7dcc72 100644 --- a/webcontroller/web_controller.go +++ b/webcontroller/web_controller.go @@ -6,6 +6,7 @@ import ( "net/http" "os" "strings" + "time" "github.com/google/uuid" @@ -30,6 +31,8 @@ type WebController struct { // page-specific variables captchaSiteKey string + + httpClient *http.Client } // New initializes a new WebController by registering all the request handlers @@ -50,6 +53,7 @@ func New( apiURLInternal: apiURLInternal, apiURLExternal: apiURLExternal, sessionCookieDomain: sessionCookieDomain, + httpClient: &http.Client{Timeout: time.Minute * 10}, } wc.templates = NewTemplateManager(resourceDir, apiURLExternal, debugMode) wc.templates.ParseTemplates(false) @@ -88,6 +92,7 @@ func New( r.GET(p+"/u/:id" /* */, wc.serveFileViewer) r.GET(p+"/u/:id/preview" /**/, wc.serveFilePreview) r.GET(p+"/l/:id" /* */, wc.serveListViewer) + r.GET(p+"/s/:id" /* */, wc.serveSkynetViewer) r.GET(p+"/t" /* */, wc.serveTemplate("paste", false)) r.GET(p+"/donation" /* */, wc.serveTemplate("donation", false)) r.GET(p+"/widgets" /* */, wc.serveTemplate("widgets", false))