221 Commits
v1.1 ... v2.0.3

Author SHA1 Message Date
Chris
815895a524 Merge branch 'master' of https://github.com/HaschekSolutions/pictshare 2025-05-06 13:42:07 +02:00
Chris
de764c105c cf ip forward 2025-05-05 20:15:39 +02:00
Christian Haschek
749e7f193f Merge pull request #159 from YellingTree/patch-1
Change Input field to password type
2024-11-10 16:17:30 +01:00
Nixie
2cda214f86 Change Input field to password type
Change the input box for UPLOAD_CODE from type 'text' to type 'password' to hide the upload code while on-screen and signal to browsers to prompt to save the code in their password managers
2024-10-30 13:35:09 -04:00
Christian Haschek
f62b30d696 Merge pull request #154 from metalefty/fork-me
Fix dead image reference to "Fork me on GitHub"
2024-04-21 09:02:35 +02:00
Koichiro Iwao
b07a68bb45 Put gh-fork-ribbon locally for GDPR compliance 2024-04-20 21:32:46 +09:00
Koichiro Iwao
2b0dc071a0 Fix dead image reference to "Fork me on GitHub"
Switched to CSS implementation hosted on cdsjs.com. It should be
more permanent than githubusercontent.com.

Resolves: #153
2024-04-20 21:27:01 +09:00
Christian Haschek
f2cf56ceaa Merge pull request #155 from metalefty/passing-null
Fix for deprecated features in PHP 8.1
2024-04-15 13:04:39 +02:00
Koichiro Iwao
783f996e77 Fix for deprecated features in PHP 8.1
Deprecated: strpos(): Passing null to parameter #1 ($haystack) of type string

ref.  https://www.php.net/manual/en/migration81.deprecated.php#migration81.deprecated.core.null-not-nullable-internal
2024-03-07 22:47:39 +09:00
Christian Haschek
17dfb43abd Merge pull request #151 from HaschekSolutions/dependabot/composer/lib/aws/aws-sdk-php-3.288.1
Bump aws/aws-sdk-php from 3.33.4 to 3.288.1 in /lib
2023-12-22 07:53:12 +01:00
dependabot[bot]
1693bcaa78 Bump aws/aws-sdk-php from 3.33.4 to 3.288.1 in /lib
Bumps [aws/aws-sdk-php](https://github.com/aws/aws-sdk-php) from 3.33.4 to 3.288.1.
- [Release notes](https://github.com/aws/aws-sdk-php/releases)
- [Commits](https://github.com/aws/aws-sdk-php/compare/3.33.4...3.288.1)

---
updated-dependencies:
- dependency-name: aws/aws-sdk-php
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-22 00:27:17 +00:00
Chris
bc1eca4014 wrong project 2023-11-13 10:30:25 +01:00
Chris
fc9a7d3072 Merge branch 'master' of https://github.com/HaschekSolutions/pictshare 2023-11-13 10:27:47 +01:00
Chris
67fba8e66b updated CI to include versions 2023-11-13 10:27:40 +01:00
Christian Haschek
7f18a193d4 Update core.php
added override for host if it doesn't contain a port
2023-11-04 18:14:55 +01:00
Christian Haschek
090f452585 fixed start.sh 2023-11-04 18:01:43 +01:00
Chris
819c25374c silent rollout of split data dir 2023-11-03 16:48:12 +01:00
Chris
2388f68d5d preparations for dynamic data directories 2023-11-02 23:20:05 +01:00
Chris
3fe84a63a4 Merge branch 'master' of https://github.com/HaschekSolutions/pictshare 2023-11-02 20:23:16 +01:00
Chris
774c8e0112 disable follow to avoid CVEs 2023-11-02 20:23:01 +01:00
Christian Haschek
63132e1cfb Create SECURITY.md 2023-11-02 16:44:00 +01:00
Chris
d349ee8fc6 added check for private ip range 2023-11-02 08:14:25 +01:00
Chris
5c3ee9e159 preparations for queue-rendering 2023-10-15 20:31:01 +02:00
Chris
cea501d854 more minot php8 warning fixes 2023-10-15 20:30:12 +02:00
Chris
a1bc5b5fa5 minor warning adjustments 2023-10-15 20:17:56 +02:00
Chris
d3d5d1c385 Upgraded to php8.2 🎉🎉🎉 2023-09-14 10:42:35 +02:00
Chris
f000404d5a hardcoded registries and fixed typos 2023-09-13 08:40:34 +02:00
Chris
c777cd62ab missed docker.io url 2023-09-13 08:32:47 +02:00
Chris
06a524ca2f mussing var 2023-09-13 08:32:10 +02:00
Chris
2712946287 changed pipeline so it's also pushed to docker hub 2023-09-13 08:26:42 +02:00
Chris
fffcb13ac9 fixed conversion bug 2023-09-07 17:55:25 +02:00
Chris
307243a5bf only add when upload coede is configured 2023-09-07 17:45:04 +02:00
Chris
61acb5420b implemented UPLOAD_CODE variable
If configured, needs a code as POST/GET variable for every upload. Also adds a input field to the main template
2023-09-06 15:57:15 +02:00
Chris
cccb80de03 remove dynamic extensions 2023-09-06 15:35:12 +02:00
Chris
d0deb6f6c9 noo need to convert anymore since it's the right header now 2023-09-03 10:38:45 +02:00
Chris
e551ef2bb2 added json header closes #146 2023-09-03 10:35:13 +02:00
Chris
21aa1fbb7d added identicons 2023-09-03 10:34:35 +02:00
Chris
4c1124da07 finally removed the static s3php files and replaced with composer 2023-09-03 10:09:43 +02:00
Chris
19d7cb060e added support for dynamic content controllers
Also implemented a placeholder generator to showcase it
2023-08-26 22:39:08 +02:00
Chris
c90a716d45 ALWAYS_WEBP now also for PNG 2023-08-26 11:55:00 +02:00
Chris
4fbf8b31a2 fixed missing config generator 2023-08-25 21:53:55 +02:00
Chris
422c17eb65 Added new setting to force JPGs sent as WebP if supported by the client 2023-08-24 23:09:59 +02:00
Christian Haschek
70cdcf5dcf Merge pull request #150 from beabee-communityrm/feat/jpeg-orientation
Add JPEG EXIF orientation rotation
2023-08-24 21:35:29 +02:00
Will Franklin
7b4b27098d Add support for flipping images too 2023-08-24 16:48:44 +01:00
Will Franklin
2362af1e8c Fix docker build instructions 2023-08-24 15:41:32 +01:00
Will Franklin
28f5677247 Rotate JPEG images if they have an Orientation tag 2023-08-24 15:41:24 +01:00
Christian Haschek
8c2702be96 Merge pull request #147 from gabe565/svg-logo
Add SVG logo
2023-04-17 11:03:30 +02:00
Gabe Cook
452db23c57 Use SVG logo in readme and tweak formatting 2023-04-15 16:45:52 -05:00
Gabe Cook
c6baa6edfa Add SVG logo 2023-04-15 16:45:41 -05:00
Christian Haschek
74ccf9f626 updated info on new docker container source 2023-03-23 09:52:23 +01:00
Christian Haschek
56f89d5610 upgraded login action tag to avoid deprecation 2023-03-23 09:26:43 +01:00
Christian Haschek
0ea4b3c160 is this a magic variable? let's find out 2023-03-22 23:01:41 +01:00
Christian Haschek
93d78d44fe make image name lowercase otherwise will faild github build 2023-03-22 22:57:29 +01:00
Christian Haschek
7dac978d16 dynamic image name based on envs 2023-03-22 22:53:47 +01:00
Christian Haschek
312f18ade2 move to github repository - check 2023-03-22 22:50:13 +01:00
Chris H
cb2d17411c small undefined variable bug fixed 2023-01-16 10:28:54 +01:00
Chris H
9a4a20fb41 typo . fixes #142 2023-01-13 09:01:37 +01:00
Christian Haschek
72394f17ba Merge pull request #140 from FN-Florian/master
Add S3_REDGION varaible
2022-06-27 08:19:06 +02:00
FN-Florian
240c7359a8 Update s3.controller.php 2022-06-27 00:08:24 +02:00
FN-Florian
9d8d5f3d36 Update start.sh 2022-06-27 00:07:32 +02:00
FN-Florian
25b39bbd86 Update CONFIG.md 2022-06-25 23:56:31 +02:00
FN-Florian
4964967524 Update DOCKER.md 2022-06-25 23:55:06 +02:00
FN-Florian
bfb43ab856 Update s3.controller.php
add S3_REGION variable
2022-06-20 08:50:13 +02:00
Christian Haschek
03464199ee Merge pull request #138 from quonic/master
Adds PowerShell script for Greenshot on Windows
2022-05-12 08:10:49 +02:00
Christian Haschek
96e73e2baf Merge branch 'master' into master 2022-05-12 08:10:37 +02:00
Christian Haschek
6ad94f2063 added php function for uploading 2022-05-04 22:46:59 +02:00
Jim Caten
45b2e11729 Adds window style Hidden to PowerShell script 2022-04-21 02:15:26 -05:00
Jim Caten
c7f8f37c62 Adds PowerShell script for Greenshot
Curl is needed as Invoke-WebRequest and Invoke-RestMethod don't like uploading files easily. Curl simplifies the process down to one line of code.
2022-04-21 02:07:01 -05:00
Christian Haschek
6f540ad27e added copy url button closes #112 2022-03-08 22:23:57 +01:00
Christian Haschek
ef1a1ecaff disable debug output 2022-02-23 19:19:53 +01:00
Christian Haschek
be5f601866 disable upload timeout so big uploads wont fail 2022-02-23 19:19:38 +01:00
Christian Haschek
45d933ebf0 fixing gui-upload filesize bug 2022-02-23 19:11:33 +01:00
Christian Haschek
a145ca88cc was meant to strpos 2022-02-19 10:53:26 +01:00
Christian Haschek
cf0effd0e8 allowing for multiple comma separated CIDR ranges 2022-02-19 10:47:07 +01:00
Christian Haschek
8ee26e6922 added small ip debug info output 2022-02-19 10:38:50 +01:00
Christian Haschek
9d1a4db4d2 updated cloudflare ips 2022-02-19 10:36:54 +01:00
Christian Haschek
adb1c468cd added ipv6 support in ALLOWED_SUBNET variable 2022-02-19 08:56:29 +01:00
Christian Haschek
d6f3b7b5df Merge branch 'master' of github.com:HaschekSolutions/pictshare 2022-01-31 10:01:56 +01:00
Christian Haschek
33b08f378d added libz 2022-01-31 10:01:54 +01:00
Christian Haschek
31d2712733 added demo gif again 2022-01-31 09:19:24 +01:00
Christian Haschek
9200d3d93c added setting and possible fix for passive mode. fixes #135 probably 2022-01-24 15:23:38 +01:00
Christian Haschek
b669e69511 if p1 was done then don't ask the server for every individual file again 2021-11-24 23:30:37 +01:00
Christian Haschek
f0cfdeb650 fixed build bug 2021-11-22 12:46:35 +01:00
Christian Haschek
99d9542b80 fixed typo that caused 500 error 2021-11-22 12:43:50 +01:00
Christian Haschek
b65186f77f removed static ffmpeg binary and updated readme files 2021-11-22 11:48:01 +01:00
Christian Haschek
3ee37fe3a2 updates that make life easier on ARM or low memory devices 2021-11-20 23:08:47 +01:00
Christian Haschek
5ecf80bce1 fixed dockerfile path 2021-11-20 01:48:51 +01:00
Christian Haschek
5a5c4a0334 building for arm and x64 now (if it works) 2021-11-20 01:47:17 +01:00
Christian Haschek
7c7358af9c only save one tag per day 2021-11-20 01:25:43 +01:00
Christian Haschek
ebc4ebda03 automatic tags are now yyyymmddhhmmss 2021-11-20 01:21:08 +01:00
Christian Haschek
a4dc4366ba new path for stored files in docker container!!! 2021-11-11 23:42:33 +01:00
Christian Haschek
ea40ffbc46 Unified docker building process. & more updates
- automatic builds
- automated tags on docker
- no more auto update (update your docker containers)
- auto not removed of mp4 anymore
- bug fixes

also closes #85 and closes #124
2021-11-11 23:39:12 +01:00
Christian Haschek
9a7fadb231 streamlined hash detection 2021-11-11 19:17:21 +01:00
Christian Haschek
199f162fdf Merge pull request #128 from ranjit-git/master
Update core.php
2021-06-18 07:46:51 +02:00
ranjit-git
70c06cfa5c Update core.php 2021-06-11 10:15:46 +05:30
Christian Haschek
520099be96 Merge pull request #126 from vikbez/patch-1
"file" command is required
2021-05-22 09:26:58 +02:00
Romain Gay
5cf9b86868 "file" command is required 2021-05-21 22:35:24 +02:00
Christian Haschek
03d4875e92 Update README.md
new hit count
2021-04-23 08:55:50 +02:00
Christian Haschek
726c77effb only use finfo on windows. fixes #125 2021-03-10 08:30:02 +01:00
Christian Haschek
68de83b46a fixed ftp delete 2021-01-19 11:27:21 +01:00
Christian Haschek
77d4023f00 missing part for last fix 2020-07-27 09:40:30 +02:00
Christian Haschek
0119368376 catching non-configured subnet bug 2020-07-15 20:36:55 +02:00
Chris
166ff1da1b fixed filter examples 2020-06-23 12:11:57 +02:00
Chris
7727fc9ea4 filters already implemented 2020-06-23 12:06:24 +02:00
Chris
8de53d1ea7 added warning message if upload forbidden instead of just 401 error 2020-06-23 09:26:39 +02:00
Chris
0250b6a577 slicker check for upload permissions, included http response code 2020-06-23 09:17:49 +02:00
Chris
e13f4816fb allowing multiple ip ranges in checking function 2020-06-15 10:47:57 +02:00
Chris
75784174fa extended subnet access control 2020-06-15 10:38:07 +02:00
Chris
6d504f3a48 added support for cloudflare IP logging 2020-06-11 01:16:55 +02:00
Chris
3a6c987347 allow rendering of existing files 2020-06-11 01:05:11 +02:00
Chris
5861e73848 implemented dynamic content controller loading, enabling whitelisting of content types. closes #87 2020-06-06 13:27:47 +02:00
Chris
a2b7feb6f9 changed to oneliner 2020-06-06 11:53:22 +02:00
Chris
dce00906ec added URI fallback. This enables pictshare to be run directly from "php -S localhost:8000" 2020-06-06 11:52:34 +02:00
Chris
ceffa04b6e implemented tag and last-modified for images. closes #119 2020-06-03 00:38:05 +02:00
Chris
984246912c added possibility to have a notice displayed on the upload form 2020-05-31 19:03:59 +02:00
Chris
3a8ac33dd1 updated encryption md 2020-05-31 17:43:28 +02:00
Chris
7e28024d32 added pasting of images. closes #117 2020-05-13 16:09:57 +02:00
Chris
b149fe88cb added integrations and updated readme 2020-01-13 01:01:56 +01:00
Chris
3a27592d58 fixed queue 2020-01-13 00:31:19 +01:00
Chris
80e210af86 implemented simple queue of hashes that were not successfully uploaded to a storage container 2020-01-13 00:28:44 +01:00
Chris
220a3103fa cleaning of unused scripts 2020-01-13 00:28:23 +01:00
Chris
6ec765024e fixed dev output 2020-01-12 13:38:27 +01:00
Chris
6c556e921f added ftp_ssl support (not sftp!) 2020-01-11 15:20:38 +01:00
Chris
3a90787091 use passive mode by default 2020-01-11 02:40:11 +01:00
Chris
c4087c1e84 fixed bug that wouldnt allow creation of folders name 0 2020-01-11 02:32:53 +01:00
Chris
76c0f6cec1 allow skipping of phase 1 2020-01-11 02:19:08 +01:00
Chris
f01b685820 changed ftp server storage to distribute evenly across directories 2020-01-11 01:54:59 +01:00
Chris
e022227617 typo 2020-01-10 14:32:46 +01:00
Chris
2fc56d438d easier on the eyes 2020-01-10 14:30:07 +01:00
Chris
fb50f23e19 added new storage controller (FTP) and updated config 2020-01-10 14:25:26 +01:00
Chris
40c53173ca updated readme for config info 2020-01-10 12:45:01 +01:00
Chris
30c78ab7da increased default key polls 2020-01-08 22:47:05 +01:00
Chris
5e59d7e80d forgot dev flag on s3 controller 2020-01-08 10:36:57 +01:00
Chris
dd0d274ab1 debug var 2020-01-08 10:31:07 +01:00
Chris
3c7e8bea7c better loop 2020-01-08 10:28:44 +01:00
Chris
1a46209bfe with class name it's easier 2020-01-08 09:28:30 +01:00
Chris
ad04aeb5b6 for status messages 2020-01-08 09:10:43 +01:00
Chris
bbb0b5b111 sync script changed to pull first then push 2020-01-08 00:08:10 +01:00
Chris
a19d0a3d48 sync script added and fixed some controllers 2020-01-07 22:13:29 +01:00
Chris
63fe1b3edd readme link fixed again 2020-01-07 19:08:02 +01:00
Chris
b9e42d0f31 fixed link 2020-01-07 19:07:22 +01:00
Chris
021fbad811 Added encryption based on Libsodium 2020-01-07 19:05:22 +01:00
Chris
6cab15f8e7 added example config setting 2020-01-05 03:13:04 +01:00
Chris
f863045fcf S3/Minio storage controller Support 2020-01-05 03:11:41 +01:00
Christian Haschek
87fa55eae8 Merge pull request #98 from dessalines/master
Add docker-compose.yml
2019-11-07 11:29:04 +01:00
Dessalines
6806e4a15a Add docker-compose.yml
Fixes #93
2019-09-23 13:32:33 -07:00
Chris
82f97479ff Merge branch 'master' of https://github.com/HaschekSolutions/pictshare 2019-08-21 21:06:08 +02:00
Chris
75124102cb added docker shields 2019-08-21 21:05:48 +02:00
Christian Haschek
515e034d91 Merge pull request #86 from thomasjsn/master
Add commandline alias examples and modifiers documentation
2019-03-08 14:04:43 +01:00
Thomas Jensen
2a628e7d7a layout changes to modifiers documentation 2019-03-08 09:50:46 +01:00
Thomas Jensen
8e3cf866a6 add modifisers documentation 2019-03-08 09:48:02 +01:00
Thomas Jensen
6adb557693 Add commandline alias examples 2019-03-08 09:46:35 +01:00
Christian Haschek
c178f3af44 Merge pull request #84 from rumkit/client-subnet-filter
Client subnet filter
2019-02-20 17:18:14 +01:00
Anton Mitsengendler
8da3573ffb added client subnet filter 2019-02-20 17:12:06 +03:00
Chris
5f5b836a22 added base64 readme 2019-01-14 20:42:14 +01:00
Chris
17974088bc dont need to redeclare 2019-01-12 13:41:14 +01:00
Chris
4d5d57df8a fixed altfolder for v2 2019-01-12 13:38:00 +01:00
Christian Haschek
71df6a54c4 Update README.md 2018-12-30 23:40:13 +01:00
Christian Haschek
4a5e29e7c1 Update README.md 2018-12-30 23:37:08 +01:00
Christian Haschek
9d2bf6a931 Update README.md 2018-12-30 23:34:24 +01:00
Christian Haschek
66eebd1445 Update README.md 2018-12-30 23:25:34 +01:00
Christian Haschek
38f6b1c22f Update README.md 2018-12-30 23:24:46 +01:00
Christian Haschek
263f0b762b Update README.md 2018-12-30 23:24:34 +01:00
Christian Haschek
9f9449a58d Update README.md 2018-12-30 23:23:07 +01:00
Christian Haschek
1cb8e28be7 Update README.md 2018-12-30 23:21:25 +01:00
Christian Haschek
37e0ae26f8 Update SCALING.md 2018-12-30 22:50:29 +01:00
Chris
d41e06efa0 clarification 2018-12-30 19:29:51 +01:00
Chris
772860e186 updated readme for image filters 2018-12-30 19:28:29 +01:00
Chris
5cc690bbee added filters 2018-12-30 19:24:56 +01:00
Chris
b2a7c778d8 added new api and updated readme 2018-12-30 12:50:52 +01:00
Chris
771ec3305e typo 2018-12-29 11:17:00 +01:00
Chris
f4cea4ce08 added dependencies thanks to #79 2018-12-29 11:15:55 +01:00
Chris
66570c54d8 more features 2018-12-28 20:48:30 +01:00
Chris
ee0000bf59 hint hint ;D 2018-12-28 20:45:22 +01:00
Chris
5d6b57cabc fixed but which prevented files form being deleted 2018-12-28 18:06:31 +01:00
Chris
b3e777baa3 not dev anymore 2018-12-27 19:40:13 +01:00
Chris
fb25657d2f Merge branch 'v2' 2018-12-27 19:04:54 +01:00
Chris
a58de1f02e better checks for definition 2018-12-27 18:57:11 +01:00
Christian Haschek
3e6cfdfed6 Merge pull request #78 from HaschekSolutions/v2
V2
2018-12-27 18:54:46 +01:00
Chris
7170825166 added more info 2018-12-27 18:54:07 +01:00
Chris
2e6a3313a6 added github link 2018-12-27 18:44:01 +01:00
Chris
b0eafc9474 fixed typo 2018-12-27 13:45:53 +01:00
Chris
d3efbb0d99 added link to API 2018-12-27 13:16:16 +01:00
Chris
c5715182c0 added more documentation 2018-12-27 13:14:37 +01:00
Chris
f7adc73a86 added support for UPLOAD_FORM_LOCATION 2018-12-27 12:37:47 +01:00
Chris
d25d562598 added info on upload size 2018-12-27 10:55:15 +01:00
Chris
28937f4270 added more details on error filetype 2018-12-27 10:49:55 +01:00
Chris
b50e522c0d removed some unused extensions 2018-12-27 09:21:12 +01:00
Chris
5fb9d21016 cleanup 2018-12-26 14:18:00 +01:00
Chris
66fc8aff14 added filetype to json response of duplicates 2018-12-26 13:29:24 +01:00
Chris
b6609b1df2 added upload via base64 and via url 2018-12-25 23:41:22 +01:00
Chris
c649233835 that too 2018-12-25 11:48:30 +01:00
Chris
35ba2c991a added that 2018-12-25 11:48:06 +01:00
Chris
0210507c22 added info on cstom hashes 2018-12-25 11:36:10 +01:00
Chris
b66a1f2a55 added delete codes and fixed various bugs related to custom hashes 2018-12-25 11:34:43 +01:00
Chris
bf13df48aa small addition 2018-12-24 18:29:06 +01:00
Chris
4183b1a2db more readmes 2018-12-24 00:53:25 +01:00
Chris
e922f9c907 more readmes 2018-12-24 00:17:31 +01:00
Chris
801b4acd9d implemented gif2mp4 conversion and added display of max upload size on form 2018-12-23 18:35:37 +01:00
Chris
aa75c56364 implemented image resizing and conversion to webp 2018-12-23 15:35:47 +01:00
Chris
b6612cd838 implemented alt_folder and reorganized interface class code 2018-12-23 11:59:31 +01:00
Chris
3345eb399c added pastebinit support and fixed small errors 2018-12-22 21:38:48 +01:00
Chris
63a28b8b4b actually USE the resized video if already exists 2018-12-22 18:51:44 +01:00
Chris
3e63da324c how the hell did that get in here 2018-12-22 18:49:55 +01:00
Chris
47545e5702 implemented mp4 resizing and added support for custom hashes 2018-12-22 18:37:53 +01:00
Chris
0fe80b29b8 fixed paths 2018-12-22 17:21:56 +01:00
Chris
0b981d52a6 edited video template for correct vars 2018-12-22 17:21:31 +01:00
Chris
16688fae3c added mp4 preview image generation 2018-12-22 17:18:03 +01:00
Chris
00580d8bcc added duplicate detection system 2018-12-22 17:04:32 +01:00
Chris
56654e1ff4 updated readme and added write checks on upload 2018-12-22 15:56:34 +01:00
Chris
24411dfe93 stage 1 of v2 2018-12-21 18:34:03 +01:00
Chris
479798a1d2 added check for ffmpeg binary 2018-12-07 10:23:35 +01:00
Chris
75cde97ae9 fixed small warming 2018-12-07 10:23:12 +01:00
Chris
8f1a4f3af9 added ffmpeg binary location to config file so PictShare will run on a Raspberry Pi fixes #76 2018-11-30 22:41:26 +01:00
Christian Haschek
7adf83cb3a Merge pull request #73 from gabe565/master
Update docker-compose.yml for newer Docker image env vars
2018-11-21 08:58:01 +01:00
Gabe Cook
d292bbf6bd Update docker-compose.yml for newer Docker image env vars 2018-11-17 00:32:45 -06:00
Chris
15af093b27 clearing up language :D 2018-10-24 21:14:43 +02:00
Chris
e9c6795d7d added encoding for alt folder 2018-10-24 21:11:30 +02:00
Chris
977d3f6bda fixed bug in re encode script 2018-10-24 13:42:11 +02:00
Chris
e57360bcfc force re-render after upload so all mp4s can be viewed on mobile 2018-10-24 09:08:45 +02:00
Chris
8586775116 added alt folder support to re-encode script 2018-10-20 11:25:25 +02:00
177 changed files with 17275 additions and 3503 deletions

7
.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
tmp/*
inc/config.inc.php
data/*
lib/vendor
bin
.git
.github

59
.github/workflows/build-docker.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
name: ci
on:
push:
tags:
- "v*.*.*"
pull_request:
branches:
- "master"
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
# list of Docker images to use as base name for tags
images: |
hascheksolutions/pictshare
ghcr.io/hascheksolutions/pictshare
# generate Docker tags based on the following events/attributes
tags: |
type=schedule
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: docker/Dockerfile
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

3
.gitignore vendored
View File

@@ -1 +1,4 @@
test.php
notice.txt
lib/vendor
.vscode

3
CHANGELOG.md Normal file
View File

@@ -0,0 +1,3 @@
# V2.0.0 (Nov 2023)
- Pushed current release to version 2.0
- Updated CI to include versions

View File

@@ -199,4 +199,3 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

434
README.md
View File

@@ -1,318 +1,140 @@
# PictShare
**[Live Demo](https://www.pictshare.net)**
PictShare is a multi lingual, open source image hosting service with a simple resizing and upload API that you can host yourself.
<p align="center">
<a href="" rel="noopener">
<img height=200px src="./css/imgs/logo/logo.svg" alt="PictShare logo">
</a>
</p>
---
[![Apache License](https://img.shields.io/badge/license-Apache-blue.svg?style=flat)](https://github.com/chrisiaut/pictshare/blob/master/LICENSE)
<h1 align="center">PictShare</h1>
<h4 align="center">https://pictshare.net</h4>
<div align="center">
![PictShare](https://www.pictshare.net/39928d8239.gif)
![](https://img.shields.io/badge/php-8.2%2B-brightgreen.svg)
[![](https://img.shields.io/docker/pulls/hascheksolutions/pictshare?color=brightgreen)](https://hub.docker.com/r/hascheksolutions/pictshare)
![](https://github.com/hascheksolutions/pictshare/actions/workflows/build-docker.yml/badge.svg)]
[![Apache License](https://img.shields.io/badge/license-Apache-brightgreen.svg?style=flat)](https://github.com/HaschekSolutions/pictshare/blob/master/LICENSE)
[![Hits](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Fhascheksolutions%2Fpictshare&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false)](https://hits.seeyoufarm.com)
[![](https://img.shields.io/github/stars/HaschekSolutions/pictshare.svg?label=Stars&style=social)](https://github.com/HaschekSolutions/pictshare)
#### Host your own `images` `gifs` `mp4s` `text bins` and stay in control
</div>
-----------------------------------------
<center>
<p align="center">
<img src="https://www.pictshare.net/39928d8239.gif" alt="PictShare demo">
</p>
Table of contents
=================
* [Installation](#installation)
* [Docker](#docker)
* [On nginx](#on-nginx)
* [Docker Compose With Prebuild Image by hascheksolutions](#docker-compose-with-prebuild-image-by-hascheksolutions)
* [Why would I want to host my own images?](#why-would-i-want-to-host-my-own-images)
* [Quick Start](#quickstart)
* [Features](#features)
* [Smart query system](#smart-query-system)
* [Available options](#available-options)
* [How does the external-upload-API work?](#how-does-the-external-upload-api-work)
* [Upload from external URL](#upload-from-external-url)
* [Example:](#example)
* [Upload via POST](#upload-via-post)
* [Upload from base64 string](#upload-from-base64-string)
* [Restriction settings](#restriction-settings)
* [UPLOAD_CODE](#upload_code)
* [IMAGE_CHANGE_CODE](#image_change_code)
* [Security and privacy](#security-and-privacy)
* [Requirements](#requirements)
* [Upgrading](#upgrading)
* [Addons](#addons)
* [Traffic analysis](#traffic-analysis)
* [Coming soon](#coming-soon)
## Installation
### Docker
The fastest way to deploy PictShare is via the [official Docker repo](https://hub.docker.com/r/hascheksolutions/pictshare/)
- [Source code & more examples](https://github.com/HaschekSolutions/PictShare-Docker)
```bash
docker run -d -p 80:80 -e "TITLE=My own PictShare" hascheksolutions/pictshare
```
[![Docker setup](http://www.pictshare.net/b65dea2117.gif)](https://www.pictshare.net/8a1dec0973.mp4)
### Docker Compose With Prebuild Image by hascheksolutions
Run container by docker-compose:
- First, install docker compose:
[Docker official docs](https://docs.docker.com/compose/install/)
- Pull docker-compose file:
```bash
wget https://raw.githubusercontent.com/chrisiaut/pictshare/master/docker-compose.yml
```
- Edit docker-compose file:
```bash
vi docker-compose.yml
```
- Run container by docker-compose:
```bash
docker-compose up
```
By using this compose file, you should know that:
- Will make a directory "volumes" in the same directory where compose file is.
- Change `AUTOUPDATE` to false from true by defalt.
- And...it is highly recommended to build your own image.
### Without Docker
- Make sure you have PHP5 GD libraries installed: ```apt-get install php5-gd```
- Unpack the [PictShare zip](https://github.com/chrisiaut/pictshare/archive/master.zip)
- Rename /inc/example.config.inc.php to /inc/config.inc.php
- ```chmod +x bin/ffmpeg``` if you want to be able to use mp4 uploads
- The provided ffmpeg binary (bin/ffmpeg) is from [here](http://johnvansickle.com/ffmpeg/) and it's a 64bit linux executable. If you need a different one, load yours and overwrite the one provided
- (optional) You can and should put a [nginx](https://www.nginx.com/) proxy before the Apache server. That thing is just insanely fast with static content like images.
- (optional) To secure your traffic I'd highly recommend getting an [SSL Cert](https://letsencrypt.org/) for your server if you don't already have one.
## Why would I want to host my own images?
If you own a server (even a home server) you can host your own PictShare instance so you have full control over your content and can delete images hasslefree.
If you're an **app developer** or **sysadmin** you can use it for a centralized image hosting. With the simple upload API you can upload images to your PictShare instance and get a nice short URL
If you're a blogger like myself, you can use it as storage for your images so the images will still work even if you change blog providers or servers
## Features
- Uploads without logins or validation (that's a good thing, right?)
- Simple API to upload any image from remote servers to your instance [via URL](#upload-from-url) and [via Base64](#upload-from-base64-string)
- 100% file based - no database needed
- Simple album functions with embedding support
- Converts gif to (much smaller) MP4
- MP4 resizing
- PictShare removes all exif data so you can upload photos from your phone and all GPS tags and camera model info get wiped
- Smart [resize, filter and rotation](#smart-query-system) features
- Generate gradients by specifying only a size. eg: https://pictshare.net/800x200
- Duplicates don't take up space. If the exact same images is uploaded twice, the second upload will link to the first
- You can control who can upload images or use filters/resizes by defining an [upload-code](#restriction-settings)
- You can set a code in your ```/inc/config.inc.php``` (MASTER_DELETE_CODE) that, if appended to any URL of an Image, will delete the image and all cached versions of it from the server
- Detailed traffic and view statistics of your images via [Pictshare stats](https://github.com/chrisiaut/pictshare_stats)
- For more configuration possibilities check out the ```/inc/example.config.inc.php``` file
## Smart query system
PictShare images can be changed after upload just by modifying the URL. It works like this:
<span style="color:blue">https://base.domain</span>/<span style="color:red">&lt;options&gt;</span>/<span style="color:green">&lt;image&gt;</span>
For example: https://pictshare.net/100x100/negative/b260e36b60.jpg will show you the uploaded Image ```b260e36b60.jpg``` but resize it to 100x100 pixels and apply the "negative" filter. The original image will stay untouched.
### Available options
Original URL: ```https://www.pictshare.net/b260e36b60.jpg```
Note: If an option needs a value it works like this: ```optionname_value```. Eg: ```pixelate_10```
If there is some option that's not recognized by PictShare it's simply ignored, so this will work: https://www.pictshare.net/pictshare-is-awesome/b260e36b60.jpg and also even this will work: https://www.pictshare.net/b260e36b60.jpg/how-can-this-still/work/
| Option | Parameter | Example URL | Result |
| ------------- | ------------------- | ---------------------- | ----------- |
**Resizing** | | | |
&lt;width&gt;**x**&lt;height&gt; | -none- | https://pictshare.net/20x20/b260e36b60.jpg | ![Resized](https://pictshare.net/20x20/b260e36b60.jpg) |
forcesize | -none- | https://pictshare.net/100x400/forcesize/b260e36b60.jpg | ![Forced size](https://pictshare.net/100x400/forcesize/b260e36b60.jpg) |
**Albums** | | | |
just add multiple image hashes | -none- | https://www.pictshare.net/b260e36b60.jpg/32c9cf77c5.jpg/163484b6b1.jpg | Takes the **images** you put in the URL and makes an album out of them. All filters are supported!
embed | -none- | https://www.pictshare.net/b260e36b60.jpg/32c9cf77c5.jpg/163484b6b1.jpg/embed | Renders the album without CSS and with transparent background so you can embed them easily
responsive | -none- | https://www.pictshare.net/b260e36b60.jpg/32c9cf77c5.jpg/163484b6b1.jpg/responsive | Renders all images responsive (max-width 100%) according to screen size
&lt;width&gt;**x**&lt;height&gt; | -none- | https://www.pictshare.net/b260e36b60.jpg/32c9cf77c5.jpg/163484b6b1.jpg/150x150 | Sets the size for the thumbnails in the album
forcesize | -none- | https://www.pictshare.net/b260e36b60.jpg/32c9cf77c5.jpg/163484b6b1.jpg/100x300/forcesize | Forces thumbnail sizes to the values you provided
**GIF to mp4** | | |
mp4 | -none- | https://www.pictshare.net/mp4/102687fe65.gif | Converts gif to mp4 and displays as that. Note that you can't include that mp4 in an img tag
raw | -none- | https://www.pictshare.net/mp4/raw/102687fe65.gif | Renders the converted mp4 directly. Use with /mp4/
preview | -none- | https://www.pictshare.net/mp4/preview/102687fe65.gif | Renders the first frame of generated MP4 as JPEG. Use with /mp4/
**MP4 options** | | |
-none- | -none- | https://www.pictshare.net/65714d22f0.mp4 | Renders the mp4 embedded in a simple HTML template. This link can't be embedded into video tags, use /raw/ instead if you want to embed
raw | -none- | https://www.pictshare.net/raw/65714d22f0.mp4 | Renders the mp4 video directly so you can link it
preview | -none- | https://www.pictshare.net/preview/65714d22f0.mp4 | Renders the first frame of the MP4 as an JPEG image
**Rotating** | | |
left | -none- | https://pictshare.net/left/b260e36b60.jpg | ![Rotated left](https://pictshare.net/200/left/b260e36b60.jpg)
right | -none- | https://pictshare.net/right/b260e36b60.jpg | ![Rotated right](https://pictshare.net/200/right/b260e36b60.jpg)
upside | -none- | https://pictshare.net/upside/b260e36b60.jpg | ![Upside down](https://pictshare.net/200/upside/b260e36b60.jpg)
**Filters** | | |
negative | -none- | https://pictshare.net/negative/b260e36b60.jpg | ![Negative](https://pictshare.net/negative/200/b260e36b60.jpg)
grayscale | -none- | https://pictshare.net/grayscale/b260e36b60.jpg | ![grayscale](https://pictshare.net/grayscale/200/b260e36b60.jpg)
brightness | -255 to 255 | https://pictshare.net/brightness_100/b260e36b60.jpg | ![brightness](https://pictshare.net/brightness_100/200/b260e36b60.jpg)
edgedetect | -none- | https://pictshare.net/edgedetect/b260e36b60.jpg | ![edgedetect](https://pictshare.net/edgedetect/200/b260e36b60.jpg)
smooth | -10 to 2048 | https://pictshare.net/smooth_3/b260e36b60.jpg | ![smooth](https://pictshare.net/smooth_3/200/b260e36b60.jpg)
contrast | -100 to 100 | https://pictshare.net/contrast_40/b260e36b60.jpg | ![contrast](https://pictshare.net/contrast_40/200/b260e36b60.jpg)
pixelate | 0 to 100 | https://pictshare.net/pixelate_10/b260e36b60.jpg | ![pixelate](https://pictshare.net/pixelate_10/200/b260e36b60.jpg)
blur | -none- or 0 to 5 | https://pictshare.net/blur/b260e36b60.jpg | ![pixelate](https://pictshare.net/blur/200/b260e36b60.jpg)
sepia | -none- | https://pictshare.net/sepia/b260e36b60.jpg | ![instagram filter sepia](https://pictshare.net/200/sepia/b260e36b60.jpg)
sharpen | -none- | https://pictshare.net/sharpen/b260e36b60.jpg | ![instagram filter sharpen](https://pictshare.net/200/sharpen/b260e36b60.jpg)
emboss | -none- | https://pictshare.net/emboss/b260e36b60.jpg | ![instagram filter emboss](https://pictshare.net/200/emboss/b260e36b60.jpg)
cool | -none- | https://pictshare.net/cool/b260e36b60.jpg | ![instagram filter cool](https://pictshare.net/200/cool/b260e36b60.jpg)
light | -none- | https://pictshare.net/light/b260e36b60.jpg | ![instagram filter light](https://pictshare.net/200/light/b260e36b60.jpg)
aqua | -none- | https://pictshare.net/aqua/b260e36b60.jpg | ![instagram filter aqua](https://pictshare.net/200/aqua/b260e36b60.jpg)
fuzzy | -none- | https://pictshare.net/fuzzy/b260e36b60.jpg | ![instagram filter fuzzy](https://pictshare.net/200/fuzzy/b260e36b60.jpg)
boost | -none- | https://pictshare.net/boost/b260e36b60.jpg | ![instagram filter boost](https://pictshare.net/200/boost/b260e36b60.jpg)
gray | -none- | https://pictshare.net/gray/b260e36b60.jpg | ![instagram filter gray](https://pictshare.net/200/gray/b260e36b60.jpg)
You can also combine as many options as you want. Even multiple times! Want your image to be negative, resized, grayscale , with increased brightness and negate it again? No problem: https://pictshare.net/500x500/grayscale/negative/brightness_100/negative/b260e36b60.jpg
## How does the external-upload-API work?
### Upload from external URL
PictShare has a simple REST API to upload remote pictures. The API can be accessed via the backend.php file like this:
```https://pictshare.net/backend.php?getimage=<URL of the image you want to upload>```.
#### Example:
Request: ```https://pictshare.net/backend.php?getimage=https://www.0xf.at/css/imgs/logo.png```
The server will answer with the file name and the server path in JSON:
```json
{"status":"OK","type":"png","hash":"10ba188162.png","url":"https:\/\/pictshare.net\/10ba188162.png"}
```
### Upload via POST
Send a POST request to ```https://pictshare.net/backend.php``` and send the image in the variable ```postimage```.
Server will return JSON of uploaded data like this:
```json
{"status":"OK","type":"png","hash":"2f18a052c4.png","url":"https:\/\/pictshare.net\/2f18a052c4.png","domain":"https:\/\/pictshare.net\/"}
```
### Upload from base64 string
Just send a POST request to ```https://pictshare.net/backend.php``` and send your image in base64 as the variable name ```base64```
Server will automatically try to guess the file type (which should work in 90% of the cases) and if it can't figure it out it'll just upload it as png.
## Restriction settings
In your ```config.inc.php``` there are two values to be set: ```UPLOAD_CODE``` and ```IMAGE_CHANGE_CODE```
Both can be set to strings or multiple strings semi;colon;separated. If there is a semicolon in the string, any of the elements will work
### UPLOAD_CODE
If set, will show users a code field in the upload form. If it doesn't match your setting, files won't be uploaded.
If enabled, the Upload API will need the variable ```upload_code``` via GET (eg: ```https://pictshare.net/backend.php?getimage=https://www.0xf.at/css/imgs/logo.png&upload_code=YourUploadCodeHere```)
### IMAGE_CHANGE_CODE
If set,the [options](#available-options) will only work if the URL got the code in it. You can provide the code as option ```changecode_YourChangeCode```
For example: If enabled the image ```https://www.pictshare.net/negative/b260e36b60.jpg``` won't show the negative version but the original.
If you access the image with the code like this: ```https://www.pictshare.net/changecode_YourChangeCode/b260e36b60.jpg``` it gets cached on the server so the next time someone requests the link without providing the change-code, they'll see the inverted image (because you just created it before by accessing the image with the code)
## Security and privacy
- By hosting your own images you can delete them any time you want
- You can enable or disable upload logging. Don't want to know who uploaded stuff? Just change the setting in inc/config.inc.php
- No exif data is stored on the server, all jpegs get cleaned on upload
- You have full control over your data. PictShare doesn't need remote libaries or tracking crap
## Scaling
You can use **Backblaze Buckets** for storage of images so you can use multiple instances of PictShare and if the image is not found on the instance, it will look in the bucket.
Just add your credentials to the config.inc.php file as described in the ```example.config.inc.php``` file.
## Requirements
- Apache or Nginx Webserver with PHP
- PHP 5 GD library
- A domain or sub-domain since PictShare can't be run from a subfolder of some other domain
## nginx config
This is a simple config file that should make PictShare work on nginx
- Install php fpm: ```apt-get install php-fpm```
- Install php Graphics libraries: ```apt-get install php-gd```
```
server {
listen 80 default_server;
server_name your.awesome.domain.name;
root /var/www/pictshare; # or where ever you put it
index index.php;
location / {
try_files $uri $uri/ /index.php?url=$request_uri; # instead of htaccess mod_rewrite
}
location ~ \.php {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
}
location ~ /(upload|tmp|bin) {
deny all;
return 404;
}
}
```
## Apache config
This is a simple vHost config that should make PictShare work on Apache2.
- Install php5: ```apt-get install php5 libapache2-mod-php5```
- Install php Graphics libraries: ```apt-get install php5-gd```
- enable mod_rewrite
```
<VirtualHost *:80 >
ServerAdmin webmaster@sub.domain.tld
ServerName sub.domain.tld
ServerAlias sub.domain.tld
DocumentRoot /var/www/html
<Directory /var/www/html/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
Allow from All
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
LogLevel warn
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```
## Upgrading
- Just re-download the [PictShare zip](https://github.com/chrisiaut/pictshare/archive/master.zip) file and extract and overwrite existing pictshare files. Uploads and config won't be affected.
- Check if your ```/inc/config.inc.php``` file has all settings required by the ```/inc/example.config.inc.php``` since new options might get added in new versions
Or use these commands:
```bash
# to be run from the directory where your pictshare directory sits in
git clone https://github.com/chrisiaut/pictshare.git temp
cp -r temp/* pictshare/.
rm -rf temp
```
## Addons
- Chrome Browser extension: https://chrome.google.com/webstore/detail/pictshare-1-click-imagesc/mgomffcdpnohakmlhhjmiemlolonpafc
- Source: https://github.com/chrisiaut/PictShare-Chrome-extension
- Plugin to upload images with ShareX: https://github.com/ShareX/CustomUploaders/blob/master/pictshare.net.sxcu
## Traffic analysis
See [Pictshare stats](https://github.com/chrisiaut/pictshare_stats)
## Coming soon
- Delete codes for every uploaded image so users can delete images if no longer needed
- Albums
* [Installation](/rtfm/INSTALL.md)
* [Configuration](/rtfm/CONFIG.md)
* [Docker](/rtfm/DOCKER.md)
* [API](/rtfm/API.md)
* [Addons and integration](/rtfm/INTEGRATIONS.md)
* [Development roadmap](#development-roadmap)
---
## Quickstart
```bash
docker run -d -p 8080:80 --name=pictshare ghcr.io/hascheksolutions/pictshare
```
Then open http://localhost:8080 in your browser
## New Features
- Generate identicons based on strings in the URL [example1](https://pictshare.net/identicon/example1) [example2](https://pictshare.net/identicon/example2)
- Generate placeholder images by specifying the size in the URL. [example](https://pictshare.net/placeholder/555x250/color-white-blue)
- Added support for external storage
- [Encryption of files in external storage](/rtfm/ENCRYPTION.md)
- Added text hosting (like pastebin)
- Added URL shortening
- Added WebP to images (and automatic conversion from jpg, png to webp if the requesting browser supports it)
- Massive code rework. Actually we designed it from the ground up to be more modular and easier to debug
# Features
- Selfhostable
- [Simple upload API](/rtfm/API.md)
- 100% file based - no database needed
- [Scalable hosting](/rtfm/SCALING.md)
- Many [Filters](/rtfm/IMAGEFILTERS.md) for images
- GIF to MP4 conversion
- JPG, PNG to WEBP conversion
- MP4 resizing
- PictShare removes all exif data so you can upload photos from your phone and all GPS tags and camera model info get wiped
- Change and resize your images and videos just by editing the URL
- Duplicates don't take up space. If the exact same file is uploaded twice, the second upload will link to the first
- Many [configuration options](/rtfm/CONFIG.md)
- Full control over your data. Delete images with individual and global delete codes
---
## Development roadmap
- [x] Duplicate detection
- [x] Write permission detection
- [x] Delete codes for every uploaded file
- [x] Upload via link/url
- [x] Upload via base64
- [ ] Autodestruct for every uploaded file
### Config options
Read [here](/rtfm/CONFIG.md) what those options do
- [x] ALT_FOLDER
- [x] URL (instead of FORCE_DOMAIN but mandatory)
- [x] LOG_UPLOADER
- [x] FFMPEG_BINARY
- [x] PNG_COMPRESSION
- [x] JPEG_COMPRESSION
- [x] WEBP_COMPRESSION
- [x] MASTER_DELETE_CODE
- [x] MASTER_DELETE_IP
- [x] UPLOAD_FORM_LOCATION
- [x] S3 Backend
- [x] UPLOAD_CODE
- [ ] UPLOAD_QUOTA
- [ ] LOW_PROFILE
- [ ] IMAGE_CHANGE_CODE
- [ ] MAX_RESIZED_IMAGES
- [ ] ALLOW_BLOATING
### Image hosting
- [x] Resizing
- [x] Filters
- [x] Gif to mp4 conversion
- [x] Upload of images
### Text file hosting
- [x] Upload of text files
- [x] Render template for text files
- [x] Raw data view
- [x] Downloadable
### URL shortening
- [ ] Upload of links to shorten
### MP4 hosting
- [x] Resizing
- [x] Preview image generation
- [x] Upload of videos
- [x] Automatic conversion if not mobile friendly or wrong encoder used
- [x] Render template for videos
---
Design (c) by [Bernhard Moser](mailto://bernhard.moser91@gmail.com)
This is a [HASCHEK SOLUTIONS](https://haschek.solutions) project

11
SECURITY.md Normal file
View File

@@ -0,0 +1,11 @@
# Security Policy
## Supported Versions
PictShare uses rolling releases so the latest version is the only supported one.
## Reporting a Vulnerability
Reports can be made as issues in this repo or in confidence via christian@haschek.at
Pull requests welcome

125
api/base64.php Normal file
View File

@@ -0,0 +1,125 @@
<?php
// basic path definitions
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__).'/..');
header('Content-Type: application/json; charset=utf-8');
//loading default settings if exist
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
//loading core and controllers
include_once(ROOT . DS . 'inc' . DS. 'core.php');
//load external things if existing
if(file_exists(ROOT.'/lib/vendor/autoload.php'))
require ROOT.'/lib/vendor/autoload.php';
loadAllContentControllers();
// check if client has permission to upload
executeUploadPermission();
// check write permissions first
if(!isFolderWritable(getDataDir()))
exit(json_encode(array('status'=>'err','reason'=>'Data directory not writable')));
else if(!isFolderWritable(ROOT.DS.'tmp'))
exit(json_encode(array('status'=>'err','reason'=>'Temp directory not writable')));
$hash = sanatizeString(trim($_REQUEST['hash']))?sanatizeString(trim($_REQUEST['hash'])):false;
// check for POSTed text
if($_REQUEST['base64'])
{
$data = $_REQUEST['base64'];
$format = $_REQUEST['format'];
$tmpfile = ROOT.DS.'tmp'.DS.md5(rand(0,10000).time()).time();
base64ToFile($data, $tmpfile);
//get the file type
$type = getTypeOfFile($tmpfile);
//check for duplicates
$sha1 = sha1_file($tmpfile);
$ehash = sha1Exists($sha1);
if($ehash && file_exists(getDataDir().DS.$ehash.DS.$ehash))
exit(json_encode(array('status'=>'ok','hash'=>$ehash,'filetype'=>$type,'url'=>getURL().$ehash)));
//cross check filetype for controllers
//
//image?
if(in_array($type,(new ImageController)->getRegisteredExtensions()))
{
$answer = (new ImageController())->handleUpload($tmpfile,$hash);
}
//or, a text
else if($type=='text')
{
$answer = (new TextController())->handleUpload($tmpfile,$hash);
}
//or, a video
else if(in_array($type,(new VideoController)->getRegisteredExtensions()))
{
$answer = (new VideoController())->handleUpload($tmpfile,$hash);
}
if(!$answer)
$answer = array('status'=>'err','reason'=>'Unsupported filetype','filetype'=>$type);
if($answer['hash'] && $answer['status']=='ok')
{
$answer['filetype'] = $type;
//add this sha1 to the list
addSha1($answer['hash'],$sha1);
if(getDeleteCodeOfHash($answer['hash']))
{
$answer['delete_code'] = getDeleteCodeOfHash($answer['hash']);
$answer['delete_url'] = getURL().'delete_'.getDeleteCodeOfHash($answer['hash']).'/'.$answer['hash'];
}
storageControllerUpload($answer['hash']);
}
echo json_encode($answer);
}
function base64_to_type($base64_string)
{
$data = explode(',', $base64_string);
$data = $data[1];
$data = str_replace(' ','+',$data);
$data = base64_decode($data);
$info = getimagesizefromstring($data);
trigger_error("########## FILETYPE: ".$info['mime']);
$f = finfo_open();
$type = finfo_buffer($f, $data, FILEINFO_MIME_TYPE);
return $type;
}
function base64ToFile($base64_string, $output_file)
{
$data = explode(',', $base64_string);
$data = $data[1];
$data = str_replace(' ','+',$data);
$data = base64_decode($data);
$ifp = fopen( $output_file, 'wb' );
fwrite( $ifp, $data );
fclose( $ifp );
}

128
api/geturl.php Normal file
View File

@@ -0,0 +1,128 @@
<?php
// basic path definitions
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__).'/..');
header('Content-Type: application/json; charset=utf-8');
//loading default settings if exist
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
//loading core and controllers
include_once(ROOT . DS . 'inc' . DS. 'core.php');
//load external things if existing
if(file_exists(ROOT.'/lib/vendor/autoload.php'))
require ROOT.'/lib/vendor/autoload.php';
loadAllContentControllers();
// check if client has permission to upload
executeUploadPermission();
// check write permissions first
if(!isFolderWritable(getDataDir()))
exit(json_encode(array('status'=>'err','reason'=>'Data directory not writable')));
else if(!isFolderWritable(ROOT.DS.'tmp'))
exit(json_encode(array('status'=>'err','reason'=>'Temp directory not writable')));
$hash = sanatizeString(trim($_REQUEST['hash']))?sanatizeString(trim($_REQUEST['hash'])):false;
$url = trim($_REQUEST['url']);
if(checkURLForPrivateIPRange($url))
exit(json_encode(array('status'=>'err','reason'=>'Private IP range')));
if(!$url || !startsWith($url, 'http'))
exit(json_encode(array('status'=>'err','reason'=>'Invalid URL')));
//@todo: let user decide max upload size via config and set php_ini var
else if(remote_filesize($url)*0.000001 > 20)
exit(json_encode(array('status'=>'err','reason'=>'File too big. 20MB max')));
$name = basename($url);
$tmpfile = ROOT.DS.'tmp'.DS.$name;
$context = stream_context_create(
array(
"http" => array(
"follow_location" => false,
),
)
);
file_put_contents($tmpfile,file_get_contents($url, false, $context));
$type = getTypeOfFile($tmpfile);
//check for duplicates
$sha1 = sha1_file($tmpfile);
$ehash = sha1Exists($sha1);
if($ehash && file_exists(getDataDir().DS.$ehash.DS.$ehash))
exit(json_encode(array('status'=>'ok','hash'=>$ehash,'filetype'=>$type,'url'=>getURL().$ehash)));
//cross check filetype for controllers
//
//image?
if(in_array($type,(new ImageController)->getRegisteredExtensions()))
{
$answer = (new ImageController())->handleUpload($tmpfile,$hash);
}
//or, a text
else if($type=='text')
{
$answer = (new TextController())->handleUpload($tmpfile,$hash);
}
//or, a video
else if(in_array($type,(new VideoController)->getRegisteredExtensions()))
{
$answer = (new VideoController())->handleUpload($tmpfile,$hash);
}
if(!$answer)
$answer = array('status'=>'err','reason'=>'Unsupported filetype','filetype'=>$type);
if($answer['hash'] && $answer['status']=='ok')
{
$answer['filetype'] = $type;
//add this sha1 to the list
addSha1($answer['hash'],$sha1);
if(getDeleteCodeOfHash($answer['hash']))
{
$answer['delete_code'] = getDeleteCodeOfHash($answer['hash']);
$answer['delete_url'] = getURL().'delete_'.getDeleteCodeOfHash($answer['hash']).'/'.$answer['hash'];
}
storageControllerUpload($answer['hash']);
}
if($answer['hash'] && $answer['status']=='ok')
{
//add this sha1 to the list
addSha1($answer['hash'],$sha1);
if(getDeleteCodeOfHash($answer['hash']))
{
$answer['delete_code'] = getDeleteCodeOfHash($answer['hash']);
$answer['delete_url'] = getURL().'delete_'.getDeleteCodeOfHash($answer['hash']).'/'.$answer['hash'];
}
storageControllerUpload($answer['hash']);
}
echo json_encode($answer);
function remote_filesize($url) {
static $regex = '/^Content-Length: *+\K\d++$/im';
if (!$fp = @fopen($url, 'rb'))
return false;
if (
isset($http_response_header) &&
preg_match($regex, implode("\n", $http_response_header), $matches)
)
return (int)$matches[0];
return strlen(stream_get_contents($fp));
}

53
api/info.php Normal file
View File

@@ -0,0 +1,53 @@
<?php
// basic path definitions
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__).'/..');
header('Content-Type: application/json; charset=utf-8');
//loading default settings if exist
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
//loading core and controllers
include_once(ROOT . DS . 'inc' . DS. 'core.php');
//load external things if existing
if(file_exists(ROOT.'/lib/vendor/autoload.php'))
require ROOT.'/lib/vendor/autoload.php';
if($_REQUEST['ip']=='pls') exit(getUserIP());
loadAllContentControllers();
$hash = $_REQUEST['hash'];
if(!isExistingHash($hash))
{
exit(json_encode(array('status'=>'err','reason'=>'File not found')));
}
else
{
$answer = getInfoAboutHash($hash);
$answer['status'] = 'ok';
exit(json_encode($answer));
}
function getInfoAboutHash($hash)
{
$file = getDataDir().DS.$hash.DS.$hash;
if(!file_exists($file))
return array('status'=>'err','reason'=>'File not found');
$size = filesize($file);
$size_hr = renderSize($size);
$content_type = exec("file -bi " . escapeshellarg($file));
if($content_type && strpos($content_type,'/')!==false && strpos($content_type,';')!==false)
{
$type = $content_type;
$c = explode(';',$type);
$type = $c[0];
}
return array('hash'=>$hash,'size_bytes'=>$size,'size_interpreted'=>$size_hr,'type'=>$type,'type_interpreted'=>getTypeOfFile($file));
}

47
api/pastebin.php Normal file
View File

@@ -0,0 +1,47 @@
<?php
// basic path definitions
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__).'/..');
//loading default settings if exist
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
//loading core and controllers
include_once(ROOT . DS . 'inc' . DS. 'core.php');
//load external things if existing
if(file_exists(ROOT.'/lib/vendor/autoload.php'))
require ROOT.'/lib/vendor/autoload.php';
$controllers = loadAllContentControllers();
if(!in_array('TextController',$controllers))
exit(json_encode(array('status'=>'err','reason'=>'Text controller not enabled')));
// check if client has permission to upload
executeUploadPermission();
// check write permissions first
if(!isFolderWritable(getDataDir()))
exit(json_encode(array('status'=>'err','reason'=>'Data directory not writable')));
else if(!isFolderWritable(ROOT.DS.'tmp'))
exit(json_encode(array('status'=>'err','reason'=>'Temp directory not writable')));
// check for POSTed text
if($_REQUEST['api_paste_code'])
{
$hash = getNewHash('txt',$length=10);
$tmpfile = ROOT.DS.'tmp'.DS.$hash;
file_put_contents($tmpfile,$_REQUEST['api_paste_code']);
//check if this exact paste already exists
$sha1 = sha1_file($tmpfile);
$sha_hash = sha1Exists($sha1);
if($sha_hash)
exit(getURL().$sha_hash);
$answer = (new TextController())->handleUpload($tmpfile,$hash);
if($answer['hash'] && $answer['status']=='ok')
addSha1($answer['hash'],$sha1);
echo getURL().$hash;
}

98
api/upload.php Normal file
View File

@@ -0,0 +1,98 @@
<?php
// basic path definitions
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__).DS.'..');
header('Content-Type: application/json; charset=utf-8');
//loading default settings if exist
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
//loading core and controllers
include_once(ROOT . DS . 'inc' . DS. 'core.php');
//load external things if existing
if(file_exists(ROOT.'/lib/vendor/autoload.php'))
require ROOT.'/lib/vendor/autoload.php';
$allowedcontentcontrollers = loadAllContentControllers();
// check write permissions first
if(!isFolderWritable(getDataDir()))
exit(json_encode(array('status'=>'err','reason'=>'Data directory not writable')));
else if(!isFolderWritable(ROOT.DS.'tmp'))
exit(json_encode(array('status'=>'err','reason'=>'Temp directory not writable')));
// check if client has permission to upload
executeUploadPermission();
if(isset($_REQUEST['hash']))
$hash = sanatizeString(trim($_REQUEST['hash']));
else
$hash = false;
// check for POST upload
if ($_FILES['file']["error"] == UPLOAD_ERR_OK)
{
//get the file type
$type = getTypeOfFile($_FILES['file']["tmp_name"]);
//check for duplicates
$sha1 = sha1_file($_FILES['file']["tmp_name"]);
$ehash = sha1Exists($sha1);
if($ehash && file_exists(getDataDir().DS.$ehash.DS.$ehash))
exit(json_encode(array('status'=>'ok','hash'=>$ehash,'filetype'=>$type,'url'=>getURL().$ehash)));
//cross check filetype for controllers
//
//image?
foreach($allowedcontentcontrollers as $cc)
{
if(in_array($type,(new $cc)->getRegisteredExtensions()))
{
$answer = (new $cc())->handleUpload($_FILES['file']['tmp_name'],$hash);
break;
}
}
/*
if(in_array($type,(new ImageController)->getRegisteredExtensions()))
{
$answer = (new ImageController())->handleUpload($_FILES['file']['tmp_name'],$hash);
}
//or, a text
else if($type=='text')
{
$answer = (new TextController())->handleUpload($_FILES['file']['tmp_name'],$hash);
}
//or, a video
else if(in_array($type,(new VideoController)->getRegisteredExtensions()))
{
$answer = (new VideoController())->handleUpload($_FILES['file']['tmp_name'],$hash);
}
*/
if(!$answer)
$answer = array('status'=>'err','reason'=>'Unsupported filetype: '.$type,'filetype'=>$type);
if($answer['hash'] && $answer['status']=='ok')
{
$answer['filetype'] = $type;
//add this sha1 to the list
addSha1($answer['hash'],$sha1);
if(getDeleteCodeOfHash($answer['hash']))
{
$answer['delete_code'] = getDeleteCodeOfHash($answer['hash']);
$answer['delete_url'] = getURL().'delete_'.getDeleteCodeOfHash($answer['hash']).'/'.$answer['hash'];
}
storageControllerUpload($answer['hash']);
}
echo json_encode($answer);
}
else
exit(json_encode(array('status'=>'err','reason'=>'Upload error')));

View File

@@ -1,54 +0,0 @@
<?php
session_cache_limiter("public");
$expiry = 90; //days
session_cache_expire($expiry * 24 * 60);
session_start();
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__));
define('PATH',((dirname($_SERVER['PHP_SELF'])=='/'||dirname($_SERVER['PHP_SELF'])=='\\'||dirname($_SERVER['PHP_SELF'])=='/index.php'||dirname($_SERVER['PHP_SELF'])=='/backend.php')?'/':dirname($_SERVER['PHP_SELF']).'/'));
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
if(FORCE_DOMAIN)
define('DOMAINPATH',FORCE_DOMAIN);
else
define('DOMAINPATH',(isset($_SERVER['HTTPS'])?'https':'http').'://'.$_SERVER['HTTP_HOST']);
error_reporting(E_ALL & ~E_NOTICE);
if(SHOW_ERRORS)
ini_set('display_errors','On');
else ini_set('display_errors','Off');
include_once(ROOT.DS.'inc'.DS.'core.php');
$pm = new PictshareModel();
header('Content-Type: application/json; charset=utf-8');
if(UPLOAD_CODE!=false && !$pm->uploadCodeExists($_REQUEST['upload_code']))
exit(json_encode(array('status'=>'ERR','reason'=>'Wrong upload code provided')));
if($_REQUEST['getimage'])
{
$url = $_REQUEST['getimage'];
echo json_encode($pm->uploadImageFromURL($url));
}
else if($_FILES['postimage'])
{
$image = $_FILES['postimage'];
echo json_encode($pm->processSingleUpload($file,'postimage'));
}
else if($_REQUEST['base64'])
{
$data = $_REQUEST['base64'];
$format = $_REQUEST['format'];
echo json_encode($pm->uploadImageFromBase64($data,$format));
}
else if($_REQUEST['geturlinfo'])
echo json_encode($pm->getURLInfo($_REQUEST['geturlinfo']));
else if($_REQUEST['a']=='oembed')
echo json_encode($pm->oembed($_REQUEST['url'],$_REQUEST['t']));
else
echo json_encode(array('status'=>'ERR','reason'=>'NO_VALID_COMMAND'));

Binary file not shown.

Binary file not shown.

View File

@@ -1,280 +0,0 @@
<?php
/**
* Backblaze B2 wrapper without external depenecies
*
* @author Christian Haschek <christian@haschek.at>
*/
class Backblaze
{
private $token;
private $apiURL;
private $bucket;
private $dlURL;
private $ulURL;
private $ulToken;
private $bucket_name;
private $files;
function __construct()
{
if( BACKBLAZE !== true || !defined('BACKBLAZE_ID') || !defined('BACKBLAZE_KEY') || !defined('BACKBLAZE_BUCKET_ID'))
return;
$this->authorize();
$this->bucket = BACKBLAZE_BUCKET_ID;
$this->bucket_name = (( defined('BACKBLAZE_BUCKET_NAME') && BACKBLAZE_BUCKET_NAME != "")?BACKBLAZE_BUCKET_NAME:$this->bucketIdToName($bucket));
}
function authorize()
{
$account_id = BACKBLAZE_ID; // Obtained from your B2 account page
$application_key = BACKBLAZE_KEY; // Obtained from your B2 account page
$credentials = base64_encode($account_id . ":" . $application_key);
$url = "https://api.backblazeb2.com/b2api/v1/b2_authorize_account";
$session = curl_init($url);
// Add headers
$headers = array();
$headers[] = "Accept: application/json";
$headers[] = "Authorization: Basic " . $credentials;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); // Add headers
curl_setopt($session, CURLOPT_HTTPGET, true); // HTTP GET
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session);
curl_close ($session);
$data = json_decode($server_output,true);
$this->token = $data['authorizationToken'];
$this->apiURL = $data['apiUrl'];
$this->dlURL = $data['downloadUrl'];
}
function upload($hash)
{
if(!$this->ulURL)
$this->getUploadInfo();
$file_name = $hash;
$my_file = ROOT.DS.'upload'.DS.$hash.DS.$hash;
$handle = fopen($my_file, 'r');
$read_file = fread($handle,filesize($my_file));
$upload_url = $this->ulURL; // Provided by b2_get_upload_url
$upload_auth_token = $this->ulToken; // Provided by b2_get_upload_url
$bucket_id = $this->bucket; // The ID of the bucket
$content_type = "text/plain";
$sha1_of_file_data = sha1_file($my_file);
$session = curl_init($upload_url);
// Add read file as post field
curl_setopt($session, CURLOPT_POSTFIELDS, $read_file);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $upload_auth_token;
$headers[] = "X-Bz-File-Name: " . $file_name;
$headers[] = "Content-Type: " . $content_type;
$headers[] = "X-Bz-Content-Sha1: " . $sha1_of_file_data;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
//var_dump($server_output); // Tell me about the rabbits, George!
}
function getUploadInfo()
{
$api_url = $this->apiURL; // From b2_authorize_account call
$auth_token = $this->token; // From b2_authorize_account call
$bucket_id = $this->bucket; // The ID of the bucket you want to upload to
$session = curl_init($api_url . "/b2api/v1/b2_get_upload_url");
// Add post fields
$data = array("bucketId" => $bucket_id);
$post_fields = json_encode($data);
curl_setopt($session, CURLOPT_POSTFIELDS, $post_fields);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $auth_token;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
$data = json_decode($server_output,true); // Tell me about the rabbits, George!
$this->ulURL = $data['uploadUrl'];
//var_dump("upload url at load: ".$data['uploadUrl']);
$this->ulToken = $data['authorizationToken'];
//var_dump($data);
}
function download($hash)
{
if(file_exists(ROOT.DS.'upload'.DS.$hash.DS.$hash)) return false;
$download_url = $this->dlURL; // From b2_authorize_account call
$bucket_name = $this->bucket_name; // The NAME of the bucket you want to download from
$file_name = $hash; // The name of the file you want to download
$auth_token = $this->token; // From b2_authorize_account call
$uri = $download_url . "/file/" . $bucket_name . "/" . $file_name;
$session = curl_init($uri);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $auth_token;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_HTTPGET, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
$is_binary = preg_match('~[^\x20-\x7E\t\r\n]~', $server_output); // Tell me about the rabbits, George!
if(!$is_binary) return false;
mkdir(ROOT.DS.'upload'.DS.$hash);
$file = ROOT.DS.'upload'.DS.$hash.DS.$hash;
file_put_contents($file, $server_output);
return true;
}
function bucketIdToName($bucket)
{
$api_url = $this->apiURL; // From b2_authorize_account call
$auth_token = $this->token; // From b2_authorize_account call
$account_id = BACKBLAZE_ID;
$session = curl_init($api_url . "/b2api/v1/b2_list_buckets");
// Add post fields
$data = array("accountId" => $account_id);
$post_fields = json_encode($data);
curl_setopt($session, CURLOPT_POSTFIELDS, $post_fields);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $auth_token;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
$data = json_decode($server_output,true); // Tell me about the rabbits, George!
if(is_array($data))
foreach($data['buckets'] as $bucket)
{
if($bucket['bucketId']==$this->bucket) return $bucket['bucketName'];
}
return false;
}
function deleteFile($hash,$file_id=false)
{
$api_url = $this->apiURL; // From b2_authorize_account call
$auth_token = $this->token; // From b2_authorize_account call
$file_name = $hash; // The file name of the file you want to delete
if(!$file_id)
$file_id = $this->fileExistsInBucket($hash);
$session = curl_init($api_url . "/b2api/v1/b2_delete_file_version");
// Add post fields
$data = array("fileId" => $file_id, "fileName" => $file_name);
$post_fields = json_encode($data);
curl_setopt($session, CURLOPT_POSTFIELDS, $post_fields);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $auth_token;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
}
function fileExistsInBucket($hash)
{
$api_url = $this->apiURL; // From b2_authorize_account call
$auth_token = $this->token; // From b2_authorize_account call
$bucket_id = $this->bucket; // The ID of the bucket
$session = curl_init($api_url . "/b2api/v1/b2_list_file_names");
// Add post fields
$data = array("bucketId" => $bucket_id,
"startFileName" => $hash);
$post_fields = json_encode($data);
curl_setopt($session, CURLOPT_POSTFIELDS, $post_fields);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $auth_token;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
$data = json_decode($server_output,true);
foreach($data['files'] as $file)
{
//it's either the first one or it doesn't exist
if($file['fileName']==$hash)
return $file['fileId'];
else return false;
}
return false;
}
function getAllFilesInBucket($startFileName=null)
{
$api_url = $this->apiURL; // From b2_authorize_account call
$auth_token = $this->token; // From b2_authorize_account call
$bucket_id = $this->bucket; // The ID of the bucket
$session = curl_init($api_url . "/b2api/v1/b2_list_file_names");
// Add post fields
$data = array("bucketId" => $bucket_id,
"startFileName" => $startFileName);
$post_fields = json_encode($data);
curl_setopt($session, CURLOPT_POSTFIELDS, $post_fields);
// Add headers
$headers = array();
$headers[] = "Authorization: " . $auth_token;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
$data = json_decode($server_output,true);
foreach($data['files'] as $file)
{
$name = $file['fileName'];
$id = $file['fileId'];
$this->files[$name] = $id;
}
if($data['nextFileName'])
$this->getAllFilesInBucket($data['nextFileName']);
return $this->files;
}
}

View File

@@ -1,24 +0,0 @@
<?php
class Crypto
{
function encrypt($inputfile,$outputfile)
{
if(!file_exists($inputfile)) return;
$data = base64_encode(file_get_contents($inputfile));
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox($data, $nonce, ENCRYPTION_KEY);
$encoded = base64_encode($nonce . $ciphertext);
file_put_contents($outputfile,$encoded);
}
function decrypt($inputfile,$outputfile)
{
if(!file_exists($inputfile)) return;
$decoded = base64_decode(file_get_contents($inputfile));
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, ENCRYPTION_KEY);
file_put_contents($outputfile,base64_decode($plaintext));
}
}

View File

@@ -1,220 +0,0 @@
<?php
class Filter
{
/**
* @var resource
*/
private $image;
/**
* Directory for image assets.
* @var string
*/
private $assetDirectory;
/**
* run constructor
* @param resource &$image GD image resource
*/
public function __construct(&$image)
{
$this->image = $image;
$this->assetDirectory = dirname(dirname(dirname(__FILE__))) . '/assets/';
}
/**
* Get the current image resource
*
* @return resource
*/
public function getImage()
{
return $this->image;
}
public function bubbles()
{
$dest = imagecreatefromjpeg($this->assetDirectory . "pattern4.jpg");
$x = imagesx($this->image);
$y = imagesy($this->image);
$x2 = imagesx($dest);
$y2 = imagesy($dest);
$thumb = imagecreatetruecolor($x, $y);
imagecopyresampled($thumb, $dest, 0, 0, 0, 0, $x, $y, $x2, $y2);
imagecopymerge($this->image, $thumb, 0, 0, 0, 0, $x, $y, 20);
imagefilter($this->image, IMG_FILTER_BRIGHTNESS, 40);
imagefilter($this->image, IMG_FILTER_CONTRAST, -10);
return $this;
}
public function colorise()
{
$dest = imagecreatefromjpeg($this->assetDirectory . "pattern5.jpg");
$x = imagesx($this->image);
$y = imagesy($this->image);
$x2 = imagesx($dest);
$y2 = imagesy($dest);
$thumb = imagecreatetruecolor($x, $y);
imagecopyresampled($thumb, $dest, 0, 0, 0, 0, $x, $y, $x2, $y2);
imagecopymerge($this->image, $thumb, 0, 0, 0, 0, $x, $y, 40);
imagefilter($this->image, IMG_FILTER_CONTRAST, -25);
return $this;
}
public function sepia()
{
imagefilter($this->image, IMG_FILTER_GRAYSCALE);
imagefilter($this->image, IMG_FILTER_COLORIZE, 100, 50, 0);
return $this;
}
public function sharpen()
{
$gaussian = array(
array(1.0, 1.0, 1.0),
array(1.0, -7.0, 1.0),
array(1.0, 1.0, 1.0)
);
imageconvolution($this->image, $gaussian, 1, 4);
return $this;
}
public function emboss()
{
$gaussian = array(
array(-2.0, -1.0, 0.0),
array(-1.0, 1.0, 1.0),
array(0.0, 1.0, 2.0)
);
imageconvolution($this->image, $gaussian, 1, 5);
return $this;
}
public function cool()
{
imagefilter($this->image, IMG_FILTER_MEAN_REMOVAL);
imagefilter($this->image, IMG_FILTER_CONTRAST, -50);
return $this;
}
public function old2()
{
$dest = imagecreatefromjpeg($this->assetDirectory . "pattern1.jpg");
$x = imagesx($this->image);
$y = imagesy($this->image);
$x2 = imagesx($dest);
$y2 = imagesy($dest);
$thumb = imagecreatetruecolor($x, $y);
imagecopyresampled($thumb, $dest, 0, 0, 0, 0, $x, $y, $x2, $y2);
imagecopymerge($this->image, $thumb, 0, 0, 0, 0, $x, $y, 40);
return $this;
}
public function old3()
{
imagefilter($this->image, IMG_FILTER_CONTRAST, -30);
$dest = imagecreatefromjpeg($this->assetDirectory . "pattern3.jpg");
$x = imagesx($this->image);
$y = imagesy($this->image);
$x2 = imagesx($dest);
$y2 = imagesy($dest);
$thumb = imagecreatetruecolor($x, $y);
imagecopyresampled($thumb, $dest, 0, 0, 0, 0, $x, $y, $x2, $y2);
imagecopymerge($this->image, $thumb, 0, 0, 0, 0, $x, $y, 50);
return $this;
}
public function old()
{
$dest = imagecreatefromjpeg($this->assetDirectory . "bg1.jpg");
$x = imagesx($this->image);
$y = imagesy($this->image);
$x2 = imagesx($dest);
$y2 = imagesy($dest);
$thumb = imagecreatetruecolor($x, $y);
imagecopyresampled($thumb, $dest, 0, 0, 0, 0, $x, $y, $x2, $y2);
imagecopymerge($this->image, $thumb, 0, 0, 0, 0, $x, $y, 30);
return $this;
}
public function light()
{
imagefilter($this->image, IMG_FILTER_BRIGHTNESS, 10);
imagefilter($this->image, IMG_FILTER_COLORIZE, 100, 50, 0, 10);
return $this;
}
public function aqua()
{
imagefilter($this->image, IMG_FILTER_COLORIZE, 0, 70, 0, 30);
return $this;
}
public function fuzzy()
{
$gaussian = array(
array(1.0, 1.0, 1.0),
array(1.0, 1.0, 1.0),
array(1.0, 1.0, 1.0)
);
imageconvolution($this->image, $gaussian, 9, 20);
return $this;
}
public function boost()
{
imagefilter($this->image, IMG_FILTER_CONTRAST, -35);
imagefilter($this->image, IMG_FILTER_BRIGHTNESS, 10);
return $this;
}
public function gray()
{
imagefilter($this->image, IMG_FILTER_CONTRAST, -60);
imagefilter($this->image, IMG_FILTER_GRAYSCALE);
return $this;
}
}

View File

@@ -1,40 +0,0 @@
<?php
class HTML {
/*
* Characters that will pass:
* a-z
* A-Z
* 0-9
* .
* _
* -
*/
function sanatizeString($string)
{
return preg_replace("/[^a-zA-Z0-9._\-]+/", "", $string);
}
function renderSize($byte)
{
if($byte < 1024) {
$result = round($byte, 2). ' Byte';
}elseif($byte < pow(1024, 2)) {
$result = round($byte/1024, 2).' KB';
}elseif($byte >= pow(1024, 2) and $byte < pow(1024, 3)) {
$result = round($byte/pow(1024, 2), 2).' MB';
}elseif($byte >= pow(1024, 3) and $byte < pow(1024, 4)) {
$result = round($byte/pow(1024, 3), 2).' GB';
}elseif($byte >= pow(1024, 4) and $byte < pow(1024, 5)) {
$result = round($byte/pow(1024, 4), 2).' TB';
}elseif($byte >= pow(1024, 5) and $byte < pow(1024, 6)) {
$result = round($byte/pow(1024, 5), 2).' PB';
}elseif($byte >= pow(1024, 6) and $byte < pow(1024, 7)) {
$result = round($byte/pow(1024, 6), 2).' EB';
}
return $result;
}
}

View File

@@ -1,215 +0,0 @@
<?php
class Image
{
function rotate(&$im,$direction)
{
switch($direction)
{
case 'upside': $angle = 180;break;
case 'left': $angle = 90;break;
case 'right': $angle = -90;break;
default: $angle = 0;break;
}
$im = imagerotate($im,$angle,0);
}
function forceResize(&$img,$size)
{
$pm = new PictshareModel();
$sd = $pm->sizeStringToWidthHeight($size);
$maxwidth = $sd['width'];
$maxheight = $sd['height'];
$width = imagesx($img);
$height = imagesy($img);
$maxwidth = ($maxwidth>$width?$width:$maxwidth);
$maxheight = ($maxheight>$height?$height:$maxheight);
$dst_img = imagecreatetruecolor($maxwidth, $maxheight);
$src_img = $img;
$palsize = ImageColorsTotal($img);
for ($i = 0; $i < $palsize; $i++)
{
$colors = ImageColorsForIndex($img, $i);
ImageColorAllocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
}
imagefill($dst_img, 0, 0, IMG_COLOR_TRANSPARENT);
imagesavealpha($dst_img,true);
imagealphablending($dst_img, true);
$width_new = $height * $maxwidth / $maxheight;
$height_new = $width * $maxheight / $maxwidth;
//if the new width is greater than the actual width of the image, then the height is too large and the rest cut off, or vice versa
if($width_new > $width){
//cut point by height
$h_point = (($height - $height_new) / 2);
//copy image
imagecopyresampled($dst_img, $src_img, 0, 0, 0, $h_point, $maxwidth, $maxheight, $width, $height_new);
}else{
//cut point by width
$w_point = (($width - $width_new) / 2);
imagecopyresampled($dst_img, $src_img, 0, 0, $w_point, 0, $maxwidth, $maxheight, $width_new, $height);
}
$img = $dst_img;
}
/**
* From: https://stackoverflow.com/questions/4590441/php-thumbnail-image-resizing-with-proportions
*/
function resize(&$img,$size)
{
$pm = new PictshareModel();
$sd = $pm->sizeStringToWidthHeight($size);
$maxwidth = $sd['width'];
$maxheight = $sd['height'];
$width = imagesx($img);
$height = imagesy($img);
if(!ALLOW_BLOATING)
{
if($maxwidth>$width)$maxwidth = $width;
if($maxheight>$height)$maxheight = $height;
}
if ($height > $width)
{
$ratio = $maxheight / $height;
$newheight = $maxheight;
$newwidth = $width * $ratio;
}
else
{
$ratio = $maxwidth / $width;
$newwidth = $maxwidth;
$newheight = $height * $ratio;
}
$newimg = imagecreatetruecolor($newwidth,$newheight);
$palsize = ImageColorsTotal($img);
for ($i = 0; $i < $palsize; $i++)
{
$colors = ImageColorsForIndex($img, $i);
ImageColorAllocate($newimg, $colors['red'], $colors['green'], $colors['blue']);
}
imagefill($newimg, 0, 0, IMG_COLOR_TRANSPARENT);
imagesavealpha($newimg,true);
imagealphablending($newimg, true);
imagecopyresampled($newimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
$img = $newimg;
}
/**
* Strong Blur
*
* @param resource $gdImageResource
* @param int $blurFactor optional
* This is the strength of the blur
* 0 = no blur, 3 = default, anything over 5 is extremely blurred
* @return GD image resource
* @author Martijn Frazer, idea based on http://stackoverflow.com/a/20264482
*/
function blur(&$gdImageResource, $blurFactor = 3)
{
if(!$blurFactor)
$blurFactor = 3;
if($blurFactor>6)
$blurFactor = 6;
else if($blurFactor<0)
$blurFactor = 0;
// blurFactor has to be an integer
$blurFactor = round($blurFactor);
$originalWidth = imagesx($gdImageResource);
$originalHeight = imagesy($gdImageResource);
$smallestWidth = ceil($originalWidth * pow(0.5, $blurFactor));
$smallestHeight = ceil($originalHeight * pow(0.5, $blurFactor));
// for the first run, the previous image is the original input
$prevImage = $gdImageResource;
$prevWidth = $originalWidth;
$prevHeight = $originalHeight;
// scale way down and gradually scale back up, blurring all the way
for($i = 0; $i < $blurFactor; $i += 1)
{
// determine dimensions of next image
$nextWidth = $smallestWidth * pow(2, $i);
$nextHeight = $smallestHeight * pow(2, $i);
// resize previous image to next size
$nextImage = imagecreatetruecolor($nextWidth, $nextHeight);
imagecopyresized($nextImage, $prevImage, 0, 0, 0, 0,
$nextWidth, $nextHeight, $prevWidth, $prevHeight);
// apply blur filter
imagefilter($nextImage, IMG_FILTER_GAUSSIAN_BLUR);
// now the new image becomes the previous image for the next step
$prevImage = $nextImage;
$prevWidth = $nextWidth;
$prevHeight = $nextHeight;
}
// scale back to original size and blur one more time
imagecopyresized($gdImageResource, $nextImage,
0, 0, 0, 0, $originalWidth, $originalHeight, $nextWidth, $nextHeight);
imagefilter($gdImageResource, IMG_FILTER_GAUSSIAN_BLUR);
// clean up
imagedestroy($prevImage);
// return result
return $gdImageResource;
}
function filter(&$im,$vars)
{
foreach($vars as $var)
{
if(strpos($var,'_'))
{
$a = explode('_',$var);
$var = $a[0];
$val = $a[1];
}
switch($var)
{
case 'negative': imagefilter($im,IMG_FILTER_NEGATE); break;
case 'grayscale': imagefilter($im,IMG_FILTER_GRAYSCALE); break;
case 'brightness': imagefilter($im,IMG_FILTER_BRIGHTNESS,$val); break;
case 'edgedetect': imagefilter($im,IMG_FILTER_EDGEDETECT); break;
case 'smooth': imagefilter($im,IMG_FILTER_SMOOTH,$val); break;
case 'contrast': imagefilter($im,IMG_FILTER_CONTRAST,$val); break;
case 'pixelate': imagefilter($im,IMG_FILTER_PIXELATE,$val); break;
case 'blur': $this->blur($im,$val); break;
case 'sepia': (new Filter($im))->sepia()->getImage();break;
case 'sharpen':(new Filter($im))->sharpen()->getImage();break;
case 'emboss':(new Filter($im))->emboss()->getImage();break;
case 'cool':(new Filter($im))->cool()->getImage();break;
case 'light':(new Filter($im))->light()->getImage();break;
case 'aqua':(new Filter($im))->aqua()->getImage();break;
case 'fuzzy':(new Filter($im))->fuzzy()->getImage();break;
case 'boost':(new Filter($im))->boost()->getImage();break;
case 'gray':(new Filter($im))->gray()->getImage();break;
}
}
}
}

View File

@@ -1,23 +0,0 @@
<?php
/**
* Model class for all models
*
* @author Christian
*/
class Model// extends SQLQuery
{
protected $_model;
function __construct($id=0)
{
$this->_model = substr(get_class($this),0,-5);
$this->_table = strtolower($this->_model);
$this->_id = $id;
}
function __destruct()
{
}
}

29
cli.php
View File

@@ -1,29 +0,0 @@
<?php
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__));
define('CLI', true);
define('PATH',((dirname($_SERVER['PHP_SELF'])=='/'||dirname($_SERVER['PHP_SELF'])=='\\'||dirname($_SERVER['PHP_SELF'])=='/index.php'||dirname($_SERVER['PHP_SELF'])=='/backend.php')?'/':dirname($_SERVER['PHP_SELF']).'/'));
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
if(FORCE_DOMAIN)
define('DOMAINPATH',FORCE_DOMAIN);
else
define('DOMAINPATH',(isset($_SERVER['HTTPS'])?'https':'http').'://'.$_SERVER['HTTP_HOST']);
error_reporting(E_ALL & ~E_NOTICE);
if(SHOW_ERRORS)
ini_set('display_errors','On');
else ini_set('display_errors','Off');
include_once(ROOT.DS.'inc'.DS.'core.php');
$action = $argv[2];
$params = $argv;
//lose first param (self name)
array_shift($params);
$model = new PictshareModel();
$model->backend($params);

View File

@@ -0,0 +1,38 @@
<?php
use Bitverse\Identicon\Identicon;
use Bitverse\Identicon\Color\Color;
use Bitverse\Identicon\Generator\RingsGenerator;
use Bitverse\Identicon\Preprocessor\MD5Preprocessor;
class IdenticonController implements ContentController
{
public const ctype = 'dynamic';
//returns all extensions registered by this type of content
public function getRegisteredExtensions(){return array('identicon');}
public function handleHash($hash,$url)
{
unset($url[array_search('identicon',$url)]);
$url = array_values($url);
$generator = new RingsGenerator();
$generator->setBackgroundColor(Color::parseHex('#EEEEEE'));
$identicon = new Identicon(new MD5Preprocessor(), $generator);
$icon = $identicon->getIcon($url[0]);
header('Content-type: image/svg+xml');
echo $icon;
}
public function handleUpload($tmpfile,$hash=false)
{
return array('status'=>'err','hash'=>$hash,'reason'=>'Cannot upload to Identicons');
}
}

View File

View File

@@ -0,0 +1,278 @@
<?php
function getFilters()
{
return get_class_methods('Filter');
}
class Filter {
public function sepia($im,$val) {
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_COLORIZE, 100, 50, 0);
return $im;
}
public function sepia2($im,$val) {
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_BRIGHTNESS, -10);
imagefilter($im, IMG_FILTER_CONTRAST, -20);
imagefilter($im, IMG_FILTER_COLORIZE, 60, 30, -15);
return $im;
}
public function sharpen($im,$val) {
$gaussian = array(
array(1.0, 1.0, 1.0),
array(1.0, -7.0, 1.0),
array(1.0, 1.0, 1.0)
);
imageconvolution($im, $gaussian, 1, 4);
return $im;
}
public function emboss($im,$val) {
$gaussian = array(
array(-2.0, -1.0, 0.0),
array(-1.0, 1.0, 1.0),
array(0.0, 1.0, 2.0)
);
imageconvolution($im, $gaussian, 1, 5);
return $im;
}
public function cool($im,$val) {
imagefilter($im, IMG_FILTER_MEAN_REMOVAL);
imagefilter($im, IMG_FILTER_CONTRAST, -50);
return $im;
}
public function light($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, 10);
imagefilter($im, IMG_FILTER_COLORIZE, 100, 50, 0, 10);
return $im;
}
public function aqua($im,$val) {
imagefilter($im, IMG_FILTER_COLORIZE, 0, 70, 0, 30);
return $im;
}
public function fuzzy($im,$val) {
$gaussian = array(
array(1.0, 1.0, 1.0),
array(1.0, 1.0, 1.0),
array(1.0, 1.0, 1.0)
);
imageconvolution($im, $gaussian, 9, 20);
return $im;
}
public function boost($im,$val) {
imagefilter($im, IMG_FILTER_CONTRAST, -35);
imagefilter($im, IMG_FILTER_BRIGHTNESS, 10);
return $im;
}
public function boost2($im,$val) {
imagefilter( $im, IMG_FILTER_CONTRAST, -35);
imagefilter( $im, IMG_FILTER_COLORIZE, 25, 25, 25);
return $im;
}
public function gray($im,$val) {
imagefilter($im, IMG_FILTER_CONTRAST, -60);
imagefilter($im, IMG_FILTER_GRAYSCALE);
return $im;
}
public function antique($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, 0);
imagefilter($im, IMG_FILTER_CONTRAST, -30);
imagefilter($im, IMG_FILTER_COLORIZE, 75, 50, 25);
return $im;
}
public function blackwhite($im,$val) {
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_BRIGHTNESS, 10);
imagefilter($im, IMG_FILTER_CONTRAST, -20);
return $im;
}
public function vintage($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, 10);
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_COLORIZE, 40, 10, -15);
return $im;
}
public function concentrate($im,$val) {
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
imagefilter($im, IMG_FILTER_SMOOTH, -10);
return $im;
}
public function hermajesty($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, -10);
imagefilter($im, IMG_FILTER_CONTRAST, -5);
imagefilter($im, IMG_FILTER_COLORIZE, 80, 0, 60);
return $im;
}
public function everglow($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, -30);
imagefilter($im, IMG_FILTER_CONTRAST, -5);
imagefilter($im, IMG_FILTER_COLORIZE, 30, 30, 0);
return $im;
}
public function freshblue($im,$val) {
imagefilter($im, IMG_FILTER_CONTRAST, -5);
imagefilter($im, IMG_FILTER_COLORIZE, 20, 0, 80, 60);
return $im;
}
public function tender($im,$val) {
imagefilter($im, IMG_FILTER_CONTRAST, 5);
imagefilter($im, IMG_FILTER_COLORIZE, 80, 20, 40, 50);
imagefilter($im, IMG_FILTER_COLORIZE, 0, 40, 40, 100);
imagefilter($im, IMG_FILTER_SELECTIVE_BLUR);
return $im;
}
public function dream($im,$val) {
imagefilter($im, IMG_FILTER_COLORIZE, 150, 0, 0, 50);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_COLORIZE, 0, 50, 0, 50);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
return $im;
}
public function frozen($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, -15);
imagefilter($im, IMG_FILTER_COLORIZE, 0, 0, 100, 50);
imagefilter($im, IMG_FILTER_COLORIZE, 0, 0, 100, 50);
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
return $im;
}
public function forest($im,$val) {
imagefilter($im, IMG_FILTER_COLORIZE, 0, 0, 150, 50);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_COLORIZE, 0, 0, 150, 50);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_SMOOTH, 10);
return $im;
}
public function rain($im,$val) {
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
imagefilter($im, IMG_FILTER_MEAN_REMOVAL);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_COLORIZE, 0, 80, 50, 50);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_SMOOTH, 10);
return $im;
}
public function orangepeel($im,$val) {
imagefilter($im, IMG_FILTER_COLORIZE, 100, 20, -50, 20);
imagefilter($im, IMG_FILTER_SMOOTH, 10);
imagefilter($im, IMG_FILTER_BRIGHTNESS, -10);
imagefilter($im, IMG_FILTER_CONTRAST, 10);
imagegammacorrect($im, 1, 1.2 );
return $im;
}
public function darken($im,$val) {
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_BRIGHTNESS, -50);
return $im;
}
public function summer($im,$val) {
imagefilter($im, IMG_FILTER_COLORIZE, 0, 150, 0, 50);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_COLORIZE, 25, 50, 0, 50);
imagefilter($im, IMG_FILTER_NEGATE);
return $im;
}
public function retro($im,$val) {
imagefilter($im, IMG_FILTER_GRAYSCALE);
imagefilter($im, IMG_FILTER_COLORIZE, 100, 25, 25, 50);
return $im;
}
public function country($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, -30);
imagefilter($im, IMG_FILTER_COLORIZE, 50, 50, 50, 50);
imagegammacorrect($im, 1, 0.3);
return $im;
}
public function washed($im,$val) {
imagefilter($im, IMG_FILTER_BRIGHTNESS, 30);
imagefilter($im, IMG_FILTER_NEGATE);
imagefilter($im, IMG_FILTER_COLORIZE, -50, 0, 20, 50);
imagefilter($im, IMG_FILTER_NEGATE );
imagefilter($im, IMG_FILTER_BRIGHTNESS, 10);
imagegammacorrect($im, 1, 1.2);
return $im;
}
public function pixelate($im,$val) {
if($val==null) $val = 10;
imagefilter($im,IMG_FILTER_PIXELATE,$val);
return $im;
}
public function blur($im,$blurFactor)
{
if(!$blurFactor)
$blurFactor = 3;
if($blurFactor>6)
$blurFactor = 6;
else if($blurFactor<0)
$blurFactor = 0;
// blurFactor has to be an integer
$blurFactor = round($blurFactor);
$originalWidth = imagesx($im);
$originalHeight = imagesy($im);
$smallestWidth = ceil($originalWidth * pow(0.5, $blurFactor));
$smallestHeight = ceil($originalHeight * pow(0.5, $blurFactor));
// for the first run, the previous image is the original input
$prevImage = $im;
$prevWidth = $originalWidth;
$prevHeight = $originalHeight;
// scale way down and gradually scale back up, blurring all the way
for($i = 0; $i < $blurFactor; $i += 1)
{
// determine dimensions of next image
$nextWidth = $smallestWidth * pow(2, $i);
$nextHeight = $smallestHeight * pow(2, $i);
// resize previous image to next size
$nextImage = imagecreatetruecolor($nextWidth, $nextHeight);
imagecopyresized($nextImage, $prevImage, 0, 0, 0, 0,
$nextWidth, $nextHeight, $prevWidth, $prevHeight);
// apply blur filter
imagefilter($nextImage, IMG_FILTER_GAUSSIAN_BLUR);
// now the new image becomes the previous image for the next step
$prevImage = $nextImage;
$prevWidth = $nextWidth;
$prevHeight = $nextHeight;
}
// scale back to original size and blur one more time
imagecopyresized($im, $nextImage,
0, 0, 0, 0, $originalWidth, $originalHeight, $nextWidth, $nextHeight);
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
// clean up
imagedestroy($prevImage);
// return result
return $im;
}
}

View File

@@ -0,0 +1,330 @@
<?php
/**
* @Todo:
* - Resizing
* - Filters
* - Conversion gif to mp4
* - Conversion jpg,png to webp
*/
class ImageController implements ContentController
{
public const ctype = 'static';
//returns all extensions registered by this type of content
public function getRegisteredExtensions(){return array('png','bmp','gif','jpg','jpeg','x-png','webp');}
public function handleUpload($tmpfile,$hash=false)
{
$type = exif_imagetype($tmpfile); //http://www.php.net/manual/en/function.exif-imagetype.php
switch($type)
{
case 1: $ext = 'gif';break; //gif
case 3: $ext = 'png';break; // png
case 6: $ext = 'bmp';break; // bmp
case 17: $ext = 'ico';break; // ico
case 18: $ext = 'webp';break; // webp
case 2:
//we clean up exif data of JPGs so GPS and other data is removed
$res = imagecreatefromjpeg($tmpfile);
// rotate based on EXIF Orientation
$exif = exif_read_data($tmpfile);
if (!empty($exif['Orientation'])) {
switch ($exif['Orientation']) {
case 2:
imageflip($res, IMG_FLIP_HORIZONTAL);
case 1:
// Nothing to do
break;
case 4:
imageflip($res, IMG_FLIP_HORIZONTAL);
// Also rotate
case 3:
$res = imagerotate($res, 180, 0);
break;
case 5:
imageflip($res, IMG_FLIP_VERTICAL);
// Also rotate
case 6:
$res = imagerotate($res, -90, 0);
break;
case 7:
imageflip($res, IMG_FLIP_VERTICAL);
// Also rotate
case 8:
$res = imagerotate($res, 90, 0);
break;
}
}
imagejpeg($res, $tmpfile, (defined('JPEG_COMPRESSION')?JPEG_COMPRESSION:90));
$ext = 'jpg';
break;
default:
return array('status'=>'err','reason'=>'Not a valid image');
}
if($hash===false)
{
$hash = getNewHash($ext,6);
}
else
{
if(!endswith($hash,'.'.$ext))
$hash.='.'.$ext;
if(isExistingHash($hash))
return array('status'=>'err','hash'=>$hash,'reason'=>'Custom hash already exists');
}
storeFile($tmpfile,$hash,true);
return array('status'=>'ok','hash'=>$hash,'url'=>getURL().$hash);
}
public function handleHash($hash,$url)
{
$path = getDataDir().DS.$hash.DS.$hash;
$type = getExtensionOfFilename($hash);
//get all our sub files where all the good functions lie
include_once(dirname(__FILE__).DS.'resize.php');
include_once(dirname(__FILE__).DS.'filters.php');
include_once(dirname(__FILE__).DS.'conversion.php');
//don't do this if it's a gif because PHP can't handle animated gifs
if($type!='gif')
{
$filters = getFilters();
foreach($url as $u)
{
if(isSize($u))
$modifiers['size'] = $u;
else if(isRotation($u))
$modifiers['rotation'] = $u;
else // check for filters
{
foreach($filters as $filter)
{
if(startsWith($u,$filter) && ($u==$filter || startsWith($u,$filter.'_')))
{
$a = explode('_',$u);
$value = $a[1];
if(is_numeric($value))
$modifiers['filters'][] = array('filter'=>$filter,'value'=>$value);
else
$modifiers['filters'][] = array('filter'=>$filter);
}
}
}
}
if( (in_array('webp',$url) && $type!='webp') || ( $this->shouldAlwaysBeWebp() && ($type=='jpg' || $type=='png') ) )
$modifiers['webp'] = true;
if(in_array('forcesize',$url) && $modifiers['size'])
$modifiers['forcesize'] = true;
}
else //gif
{
if(in_array('mp4',$url))
$modifiers['mp4']=true;
}
if($modifiers)
{
//why in gods name would you use http build query here???
//well we want a unique filename for every modied image
//so if we take all parameters in key=>value form and hash it
//we get one nice little hash for every eventuality
$modhash = md5(http_build_query($modifiers,'',','));
$newpath = getDataDir().DS.$hash.DS.$modhash.'_'.$hash;
$im = $this->getObjOfImage($path);
$f = new Filter();
if(!file_exists($newpath))
{
foreach($modifiers as $mod => $val)
{
switch($mod)
{
case 'filters':
foreach($val as $fd)
{
$filter = $fd['filter'];
$value = $fd['value'];
$im = $f->$filter($im,$value);
}
break;
case 'size':
($modifiers['forcesize']?forceResize($im,$val):resize($im,$val));
break;
case 'rotation':
rotate($im,$val);
break;
case 'webp':
$type = 'webp';
break;
case 'mp4':
$mp4path = getDataDir().DS.$hash.DS.$hash.'mp4';
if(!file_exists($mp4path))
$this->gifToMP4($path,$mp4path);
$path = $mp4path;
if(in_array('raw',$url))
(new VideoController())->serveMP4($path,$hash);
else if(in_array('preview',$url))
{
$preview = $path.'_preview.jpg';
if(!file_exists($preview))
{
(new VideoController())->saveFirstFrameOfMP4($path,$preview);
}
header ("Content-type: image/jpeg");
readfile($preview);
exit;
}
else if(in_array('download',$url))
{
if (file_exists($path)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($path).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
readfile($path);
exit;
}
}
else
{
$data = array('url'=>implode('/',$url),'hash'=>$hash,'filesize'=>renderSize(filesize($path)));
renderTemplate('video',$data);
exit;
}
break;
}
}
$this->saveObjOfImage($im,$newpath,$type);
}
else if($modifiers['webp'])
{
$type = 'webp';
}
$path = $newpath;
}
switch($type)
{
case 'jpeg':
case 'jpg':
header ("Content-type: image/jpeg");
header ("Last-Modified: ".gmdate('D, d M Y H:i:s ', filemtime($path)) . 'GMT');
header ("ETag: $hash");
header('Cache-control: public, max-age=31536000');
readfile($path);
break;
case 'png':
header ("Content-type: image/png");
header ("Last-Modified: ".gmdate('D, d M Y H:i:s ', filemtime($path)) . 'GMT');
header ("ETag: $hash");
header('Cache-control: public, max-age=31536000');
readfile($path);
break;
case 'gif':
header ("Content-type: image/gif");
header ("Last-Modified: ".gmdate('D, d M Y H:i:s ', filemtime($path)) . 'GMT');
header ("ETag: $hash");
header('Cache-control: public, max-age=31536000');
readfile($path);
break;
case 'webp':
header ("Content-type: image/webp");
header ("Last-Modified: ".gmdate('D, d M Y H:i:s ', filemtime($path)) . 'GMT');
header ("ETag: $hash");
header('Cache-control: public, max-age=31536000');
readfile($path);
break;
}
}
function getObjOfImage($path)
{
return imagecreatefromstring(file_get_contents($path));
}
function gifToMP4($gifpath,$target)
{
$bin = escapeshellcmd(FFMPEG_BINARY);
$file = escapeshellarg($gifpath);
if(!file_exists($target)) //simple caching.. have to think of something better
{
$cmd = "$bin -f gif -y -i $file -vcodec libx264 -an -profile:v baseline -level 3.0 -pix_fmt yuv420p -vf \"scale=trunc(iw/2)*2:trunc(ih/2)*2\" -f mp4 $target";
system($cmd);
}
return $target;
}
function saveObjOfImage($im,$path,$type)
{
$tmppath = '/tmp/'.getNewHash($type,12);
switch($type)
{
case 'jpeg':
case 'jpg':
imagejpeg($im,$tmppath,(defined('JPEG_COMPRESSION')?JPEG_COMPRESSION:90));
break;
case 'png':
imagepng($im,$tmppath,(defined('PNG_COMPRESSION')?PNG_COMPRESSION:6));
break;
case 'webp':
imagepalettetotruecolor($im);
imagealphablending($im, true);
imagewebp($im,$tmppath,(defined('WEBP_COMPRESSION')?WEBP_COMPRESSION:80));
break;
}
if(file_exists($tmppath) && filesize($tmppath)>0)
{
rename($tmppath,$path);
return $im;
}
else
{
return false;
}
}
function shouldAlwaysBeWebp()
{
//sanity check
if(!$_SERVER['HTTP_ACCEPT']) return false;
if(defined('ALWAYS_WEBP') && ALWAYS_WEBP && strpos( $_SERVER['HTTP_ACCEPT'], 'image/webp' ) !== false )
return true;
else
return false;
}
}

View File

@@ -0,0 +1,120 @@
<?php
function isRotation($var)
{
switch($var)
{
case 'upside':
case 'left':
case 'right': return true;
default: return false;
}
}
function rotate(&$im,$direction)
{
switch($direction)
{
case 'upside': $angle = 180;break;
case 'left': $angle = 90;break;
case 'right': $angle = -90;break;
default: $angle = 0;break;
}
$im = imagerotate($im,$angle,0);
}
function forceResize(&$img,$size)
{
$sd = sizeStringToWidthHeight($size);
$maxwidth = $sd['width'];
$maxheight = $sd['height'];
$width = imagesx($img);
$height = imagesy($img);
$maxwidth = ($maxwidth>$width?$width:$maxwidth);
$maxheight = ($maxheight>$height?$height:$maxheight);
$dst_img = imagecreatetruecolor($maxwidth, $maxheight);
$src_img = $img;
$palsize = ImageColorsTotal($img);
for ($i = 0; $i < $palsize; $i++)
{
$colors = ImageColorsForIndex($img, $i);
ImageColorAllocate($dst_img, $colors['red'], $colors['green'], $colors['blue']);
}
imagefill($dst_img, 0, 0, IMG_COLOR_TRANSPARENT);
imagesavealpha($dst_img,true);
imagealphablending($dst_img, true);
$width_new = $height * $maxwidth / $maxheight;
$height_new = $width * $maxheight / $maxwidth;
//if the new width is greater than the actual width of the image, then the height is too large and the rest cut off, or vice versa
if($width_new > $width){
//cut point by height
$h_point = (($height - $height_new) / 2);
//copy image
imagecopyresampled($dst_img, $src_img, 0, 0, 0, $h_point, $maxwidth, $maxheight, $width, $height_new);
}else{
//cut point by width
$w_point = (($width - $width_new) / 2);
imagecopyresampled($dst_img, $src_img, 0, 0, $w_point, 0, $maxwidth, $maxheight, $width_new, $height);
}
$img = $dst_img;
}
/**
* From: https://stackoverflow.com/questions/4590441/php-thumbnail-image-resizing-with-proportions
*/
function resize(&$img,$size)
{
$sd = sizeStringToWidthHeight($size);
$maxwidth = $sd['width'];
$maxheight = $sd['height'];
$width = imagesx($img);
$height = imagesy($img);
if(defined('ALLOW_BLOATING') && !ALLOW_BLOATING)
{
if($maxwidth>$width)$maxwidth = $width;
if($maxheight>$height)$maxheight = $height;
}
if ($height > $width)
{
$ratio = $maxheight / $height;
$newheight = intval($maxheight);
$newwidth = intval($width * $ratio) ;
}
else
{
$ratio = $maxwidth / $width;
$newwidth = intval($maxwidth) ;
$newheight = intval($height * $ratio);
}
$newimg = imagecreatetruecolor($newwidth,$newheight);
$palsize = ImageColorsTotal($img);
for ($i = 0; $i < $palsize; $i++)
{
$colors = ImageColorsForIndex($img, $i);
ImageColorAllocate($newimg, $colors['red'], $colors['green'], $colors['blue']);
}
imagefill($newimg, 0, 0, IMG_COLOR_TRANSPARENT);
imagesavealpha($newimg,true);
imagealphablending($newimg, true);
imagecopyresampled($newimg, $img, 0, 0, 0, 0, $newwidth, $newheight, $width, $height);
$img = $newimg;
}

View File

@@ -0,0 +1,52 @@
<?php
class PlaceholderController implements ContentController
{
public const ctype = 'dynamic';
//returns all extensions registered by this type of content
public function getRegisteredExtensions(){return array('placeholder');}
public function handleHash($hash,$url)
{
$path = getDataDir().DS.$hash.DS.$hash;
include_once(dirname(__FILE__).DS.'placeholdergenerator.php');
$pg = new PlaceholderGenerator();
foreach($url as $u)
{
if(isSize($u))
$modifiers['size'] = $u;
if(startsWith($u,'color-'))
{
$u = substr($u,6);
$colors = explode('-',$u);
foreach($colors as $c)
if(isColor($c))
$modifiers['colors'][] = (ctype_xdigit($c)?$c:color_name_to_hex($c));
if(count($modifiers['colors'])>4)
$modifiers['colors'] = array_slice($modifiers['colors'],0,4);
}
}
$img = $pg->generateImage($modifiers);
$img = $pg->gradient($img, $modifiers['colors']);
$img = $pg->addSizeText($img,$modifiers);
header ("Content-type: image/jpeg");
header ("ETag: $hash");
header('Cache-control: public, max-age=31536000');
imagejpeg($img,null,(defined('JPEG_COMPRESSION')?JPEG_COMPRESSION:90));
}
public function handleUpload($tmpfile,$hash=false)
{
return array('status'=>'err','hash'=>$hash,'reason'=>'Cannot upload to placeholder image');
}
}

View File

@@ -0,0 +1,88 @@
<?php
class PlaceholderGenerator {
function generateImage($modifiers)
{
$size = ($modifiers['size']?:'800x600');
$sd = sizeStringToWidthHeight($size);
$width = $sd['width'];
$height = $sd['height'];
$im = imagecreatetruecolor($width, $height);
return $im;
}
function addSizeText($im,$modifiers)
{
$size = imagesx($im).'x'.imagesy($im);
$text = $size;
//add the size as text in the center of the image
$textcolor = imagecolorallocate($im, 0, 0, 0);
$font = dirname(__FILE__).DS.'fonts/RonysiswadiArchitect5-1GErv.ttf';
//calculate the size of the text to make sure it will alway be visible
$fontsize = 20;
$textsize = imagettfbbox($fontsize, 0, $font, $text);
$scaleX = imagesx($im) / ($textsize[2] - $textsize[0] + 25);
$scaleY = imagesy($im) / ($textsize[1] - $textsize[7] + 25);
$scale = min($scaleX,$scaleY);
$fontsize = 20 * $scale;
$textsize = imagettfbbox($fontsize, 0, $font, $text);
$textwidth = $textsize[2] - $textsize[0];
$textheight = $textsize[1] - $textsize[7];
if($textwidth > imagesx($im) || $textheight > imagesy($im))
return $im;
$x = intval((imagesx($im) - $textwidth) / 2);
$y = intval((imagesy($im) - $textheight) / 2 + $textheight);
imagettftext($im, $fontsize, 0, $x, $y, $textcolor, $font, $text);
return $im;
}
function gradient($im, $c) {
$w = imagesx($im);
$h = imagesy($im);
if(!$c[0]) $c = ['ffffff','ffffff','ffffff','ffffff'];
else if(!$c[1]) $c = [$c[0],$c[0],$c[0],$c[0]];
else if(!$c[2]) $c = [$c[0],$c[0],$c[1],$c[1]];
else if(!$c[3]) $c = [$c[0],$c[1],$c[2],$c[0]];
for($i=0;$i<=3;$i++) {
$c[$i]=$this->hex2rgb($c[$i]);
}
$rgb=$c[0]; // start with top left color
for($x=0;$x<=$w;$x++) { // loop columns
for($y=0;$y<=$h;$y++) { // loop rows
// set pixel color
$col=imagecolorallocate($im,intval($rgb[0]),intval($rgb[1]),intval($rgb[2]));
imagesetpixel($im,$x-1,$y-1,$col);
// calculate new color
for($i=0;$i<=2;$i++) {
$rgb[$i]=
$c[0][$i]*(($w-$x)*($h-$y)/($w*$h)) +
$c[1][$i]*($x *($h-$y)/($w*$h)) +
$c[2][$i]*(($w-$x)*$y /($w*$h)) +
$c[3][$i]*($x *$y /($w*$h));
}
}
}
return $im;
}
function hex2rgb($hex)
{
$rgb[0]=hexdec(substr($hex,0,2));
$rgb[1]=hexdec(substr($hex,2,2));
$rgb[2]=hexdec(substr($hex,4,2));
return($rgb);
}
}

View File

@@ -0,0 +1,60 @@
<?php
class TextController implements ContentController
{
public const ctype = 'static';
//returns all extensions registered by this type of content
public function getRegisteredExtensions(){return array('txt','text','csv');}
public function handleHash($hash,$url)
{
$path = getDataDir().DS.$hash.DS.$hash;
if(in_array('raw',$url))
{
header('Content-Type: text/plain; charset=utf-8');
echo file_get_contents($path);
}
else if(in_array('download',$url))
{
if (file_exists($path)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($path).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
readfile($path);
exit;
}
}
else
renderTemplate('text',array('hash'=>$hash,'content'=>htmlentities(file_get_contents($path))));
}
public function handleUpload($tmpfile,$hash=false)
{
if($hash===false)
{
$hash = getNewHash('txt',6);
}
else
{
if(!endswith($hash,'.txt'))
$hash.='.txt';
if(isExistingHash($hash))
return array('status'=>'err','hash'=>$hash,'reason'=>'Custom hash already exists');
}
storeFile($tmpfile,$hash,true);
return array('status'=>'ok','hash'=>$hash,'url'=>getURL().$hash);
}
function getTypeOfText($hash)
{
return file_get_contents(getDataDir().DS.$hash.DS.'type');
}
}

View File

@@ -0,0 +1,11 @@
<?php
class UrlController implements ContentController
{
public const ctype = 'static';
//returns all extensions registered by this type of content
public function getRegisteredExtensions(){return array('url');}
public function handleHash($hash,$url){}
public function handleUpload($tmpfile,$hash=false){}
}

View File

@@ -0,0 +1,217 @@
<?php
class VideoController implements ContentController
{
public const ctype = 'static';
//returns all extensions registered by this type of content
public function getRegisteredExtensions(){return array('mp4');}
public function handleHash($hash,$url)
{
$path = getDataDir().DS.$hash.DS.$hash;
//@todo: - resize by changing $path
//check if video should be resized
foreach($url as $u)
if(isSize($u)==true)
$size = $u;
if($size)
{
$s = sizeStringToWidthHeight($size);
$width = $s['width'];
$newpath = getDataDir().DS.$hash.DS.$width.'_'.$hash;
if(!file_exists($newpath))
$this->resize($path,$newpath,$width);
$path = $newpath;
}
if(in_array('raw',$url))
$this->serveMP4($path,$hash);
else if(in_array('preview',$url))
{
$preview = $path.'_preview.jpg';
if(!file_exists($preview))
{
$this->saveFirstFrameOfMP4($path,$preview);
}
header ("Content-type: image/jpeg");
readfile($preview);
}
else if(in_array('download',$url))
{
if (file_exists($path)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($path).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($path));
readfile($path);
exit;
}
}
else
{
$data = array('url'=>implode('/',$url),'hash'=>$hash,'filesize'=>renderSize(filesize($path)));
renderTemplate('video',$data);
}
}
public function handleUpload($tmpfile,$hash=false)
{
if($hash===false)
$hash = getNewHash('mp4',6);
else
{
$hash.='.mp4';
if(isExistingHash($hash))
return array('status'=>'err','hash'=>$hash,'reason'=>'Custom hash already exists');
}
$file = storeFile($tmpfile,$hash,true);
if(!$this->rightEncodedMP4($file))
system("nohup php ".ROOT.DS.'tools'.DS.'re-encode_mp4.php force '.$hash." > /dev/null 2> /dev/null &");
return array('status'=>'ok','hash'=>$hash,'url'=>getURL().$hash);
}
//via gist: https://gist.github.com/codler/3906826
function serveMP4($path,$hash)
{
if ($fp = fopen($path, "rb"))
{
$size = filesize($path);
$length = $size;
$start = 0;
$end = $size - 1;
header('Content-type: video/mp4');
header('Cache-control: public, max-age=31536000');
header("Accept-Ranges: 0-$length");
if (isset($_SERVER['HTTP_RANGE'])) {
$c_start = $start;
$c_end = $end;
list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
if (strpos($range, ',') !== false) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
if ($range == '-') {
$c_start = $size - substr($range, 1);
} else {
$range = explode('-', $range);
$c_start = $range[0];
$c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size;
}
$c_end = ($c_end > $end) ? $end : $c_end;
if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) {
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header("Content-Range: bytes $start-$end/$size");
exit;
}
$start = $c_start;
$end = $c_end;
$length = $end - $start + 1;
fseek($fp, $start);
header('HTTP/1.1 206 Partial Content');
}
header("Content-Range: bytes $start-$end/$size");
header("Content-Length: ".$length);
$buffer = 1024 * 8;
while(!feof($fp) && ($p = ftell($fp)) <= $end) {
if ($p + $buffer > $end) {
$buffer = $end - $p + 1;
}
set_time_limit(0);
echo fread($fp, $buffer);
flush();
}
fclose($fp);
exit();
} else die('file not found');
}
function isProperMP4($filename)
{
$file = escapeshellarg($filename);
$tmp = ROOT.DS.'tmp'.DS.md5(time()+rand(1,10000)).'.'.rand(1,10000).'.log';
$bin = escapeshellcmd(FFMPEG_BINARY);
$cmd = "$bin -i $file > $tmp 2>> $tmp";
system($cmd);
//var_dump(system( "$bin -i $file "));
$answer = file($tmp);
unlink($tmp);
$ismp4 = false;
if(is_array($answer))
foreach($answer as $line)
{
$line = trim($line);
if(strpos($line,'Duration: 00:00:00')) return false;
if(strpos($line, 'Video: h264'))
$ismp4 = true;
}
return $ismp4;
}
function rightEncodedMP4($file)
{
$hash = md5($file);
$cmd = FFMPEG_BINARY." -i $file -hide_banner 2> ".ROOT.DS.'tmp'.DS.$hash.'.txt';
system($cmd);
$results = file(ROOT.DS.'tmp'.DS.$hash.'.txt');
foreach($results as $l)
{
$elements = explode(':',trim($l));
$key=trim(array_shift($elements));
$value = trim(implode(':',$elements));
if($key=='encoder')
{
if(startsWith(strtolower($value),'lav'))
{
return true;
} else return false;
}
}
unlink(ROOT.DS.'tmp'.DS.$hash.'.txt');
return false;
}
function saveFirstFrameOfMP4($path,$target)
{
$bin = escapeshellcmd(FFMPEG_BINARY);
$file = escapeshellarg($path);
$cmd = "$bin -y -i $file -vframes 1 -f image2 $target";
system($cmd);
}
function resize($in,$out,$width)
{
$file = escapeshellarg($in);
$tmp = '/dev/null';
$bin = escapeshellcmd(FFMPEG_BINARY);
$addition = '-c:v libx264 -profile:v baseline -level 3.0 -pix_fmt yuv420p';
$height = 'trunc(ow/a/2)*2';
$cmd = "$bin -i $file -y -vf scale=\"$width:$height\" $addition $out";
system($cmd);
return (file_exists($out) && filesize($out)>0);
}
}

388
css/dropzone.css Normal file
View File

@@ -0,0 +1,388 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
@-webkit-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@-moz-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@-webkit-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@-moz-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@-webkit-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
@-moz-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
@keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
.dropzone, .dropzone * {
box-sizing: border-box; }
.dropzone {
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px; }
.dropzone.dz-clickable {
cursor: pointer; }
.dropzone.dz-clickable * {
cursor: default; }
.dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * {
cursor: pointer; }
.dropzone.dz-started .dz-message {
display: none; }
.dropzone.dz-drag-hover {
border-style: solid; }
.dropzone.dz-drag-hover .dz-message {
opacity: 0.5; }
.dropzone .dz-message {
text-align: center;
margin: 2em 0; }
.dropzone .dz-preview {
position: relative;
display: inline-block;
vertical-align: top;
margin: 16px;
min-height: 100px; }
.dropzone .dz-preview:hover {
z-index: 1000; }
.dropzone .dz-preview:hover .dz-details {
opacity: 1; }
.dropzone .dz-preview.dz-file-preview .dz-image {
border-radius: 20px;
background: #999;
background: linear-gradient(to bottom, #eee, #ddd); }
.dropzone .dz-preview.dz-file-preview .dz-details {
opacity: 1; }
.dropzone .dz-preview.dz-image-preview {
background: white; }
.dropzone .dz-preview.dz-image-preview .dz-details {
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-ms-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear; }
.dropzone .dz-preview .dz-remove {
font-size: 14px;
text-align: center;
display: block;
cursor: pointer;
border: none; }
.dropzone .dz-preview .dz-remove:hover {
text-decoration: underline; }
.dropzone .dz-preview:hover .dz-details {
opacity: 1; }
.dropzone .dz-preview .dz-details {
z-index: 20;
position: absolute;
top: 0;
left: 0;
opacity: 0;
font-size: 13px;
min-width: 100%;
max-width: 100%;
padding: 2em 1em;
text-align: center;
color: rgba(0, 0, 0, 0.9);
line-height: 150%; }
.dropzone .dz-preview .dz-details .dz-size {
margin-bottom: 1em;
font-size: 16px; }
.dropzone .dz-preview .dz-details .dz-filename {
white-space: nowrap; }
.dropzone .dz-preview .dz-details .dz-filename:hover span {
border: 1px solid rgba(200, 200, 200, 0.8);
background-color: rgba(255, 255, 255, 0.8); }
.dropzone .dz-preview .dz-details .dz-filename:not(:hover) {
overflow: hidden;
text-overflow: ellipsis; }
.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span {
border: 1px solid transparent; }
.dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span {
background-color: rgba(255, 255, 255, 0.4);
padding: 0 0.4em;
border-radius: 3px; }
.dropzone .dz-preview:hover .dz-image img {
-webkit-transform: scale(1.05, 1.05);
-moz-transform: scale(1.05, 1.05);
-ms-transform: scale(1.05, 1.05);
-o-transform: scale(1.05, 1.05);
transform: scale(1.05, 1.05);
-webkit-filter: blur(8px);
filter: blur(8px); }
.dropzone .dz-preview .dz-image {
border-radius: 20px;
overflow: hidden;
width: 120px;
height: 120px;
position: relative;
display: block;
z-index: 10; }
.dropzone .dz-preview .dz-image img {
display: block; }
.dropzone .dz-preview.dz-success .dz-success-mark {
-webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); }
.dropzone .dz-preview.dz-error .dz-error-mark {
opacity: 1;
-webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); }
.dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark {
pointer-events: none;
opacity: 0;
z-index: 500;
position: absolute;
display: block;
top: 50%;
left: 50%;
margin-left: -27px;
margin-top: -27px; }
.dropzone .dz-preview .dz-success-mark svg, .dropzone .dz-preview .dz-error-mark svg {
display: block;
width: 54px;
height: 54px; }
.dropzone .dz-preview.dz-processing .dz-progress {
opacity: 1;
-webkit-transition: all 0.2s linear;
-moz-transition: all 0.2s linear;
-ms-transition: all 0.2s linear;
-o-transition: all 0.2s linear;
transition: all 0.2s linear; }
.dropzone .dz-preview.dz-complete .dz-progress {
opacity: 0;
-webkit-transition: opacity 0.4s ease-in;
-moz-transition: opacity 0.4s ease-in;
-ms-transition: opacity 0.4s ease-in;
-o-transition: opacity 0.4s ease-in;
transition: opacity 0.4s ease-in; }
.dropzone .dz-preview:not(.dz-processing) .dz-progress {
-webkit-animation: pulse 6s ease infinite;
-moz-animation: pulse 6s ease infinite;
-ms-animation: pulse 6s ease infinite;
-o-animation: pulse 6s ease infinite;
animation: pulse 6s ease infinite; }
.dropzone .dz-preview .dz-progress {
opacity: 1;
z-index: 1000;
pointer-events: none;
position: absolute;
height: 16px;
left: 50%;
top: 50%;
margin-top: -8px;
width: 80px;
margin-left: -40px;
background: rgba(255, 255, 255, 0.9);
-webkit-transform: scale(1);
border-radius: 8px;
overflow: hidden; }
.dropzone .dz-preview .dz-progress .dz-upload {
background: #333;
background: linear-gradient(to bottom, #666, #444);
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 0;
-webkit-transition: width 300ms ease-in-out;
-moz-transition: width 300ms ease-in-out;
-ms-transition: width 300ms ease-in-out;
-o-transition: width 300ms ease-in-out;
transition: width 300ms ease-in-out; }
.dropzone .dz-preview.dz-error .dz-error-message {
display: block; }
.dropzone .dz-preview.dz-error:hover .dz-error-message {
opacity: 1;
pointer-events: auto; }
.dropzone .dz-preview .dz-error-message {
pointer-events: none;
z-index: 1000;
position: absolute;
display: block;
display: none;
opacity: 0;
-webkit-transition: opacity 0.3s ease;
-moz-transition: opacity 0.3s ease;
-ms-transition: opacity 0.3s ease;
-o-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
border-radius: 8px;
font-size: 13px;
top: 130px;
left: -10px;
width: 140px;
background: #be2626;
background: linear-gradient(to bottom, #be2626, #a92222);
padding: 0.5em 1.2em;
color: white; }
.dropzone .dz-preview .dz-error-message:after {
content: '';
position: absolute;
top: -6px;
left: 64px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #be2626; }

5
css/gh-fork-ribbon.min.css vendored Normal file
View File

@@ -0,0 +1,5 @@
/*!
* "Fork me on GitHub" CSS ribbon v0.2.3 | MIT License
* https://github.com/simonwhitaker/github-fork-ribbon-css
*/.github-fork-ribbon{width:12.1em;height:12.1em;position:absolute;overflow:hidden;top:0;right:0;z-index:9999;pointer-events:none;font-size:13px;text-decoration:none;text-indent:-999999px}.github-fork-ribbon.fixed{position:fixed}.github-fork-ribbon:active,.github-fork-ribbon:hover{background-color:rgba(0,0,0,0)}.github-fork-ribbon:after,.github-fork-ribbon:before{position:absolute;display:block;width:15.38em;height:1.54em;top:3.23em;right:-3.23em;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.github-fork-ribbon:before{content:"";padding:.38em 0;background-color:#a00;background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,0)),to(rgba(0,0,0,.15)));background-image:-webkit-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-moz-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-ms-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:-o-linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,.15));background-image:linear-gradient(to bottom,rgba(0,0,0,0),rgba(0,0,0,.15));-webkit-box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);-moz-box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);box-shadow:0 .15em .23em 0 rgba(0,0,0,.5);pointer-events:auto}.github-fork-ribbon:after{content:attr(data-ribbon);color:#fff;font:700 1em "Helvetica Neue",Helvetica,Arial,sans-serif;line-height:1.54em;text-decoration:none;text-shadow:0 -.08em rgba(0,0,0,.5);text-align:center;text-indent:0;padding:.15em 0;margin:.15em 0;border-width:.08em 0;border-style:dotted;border-color:#fff;border-color:rgba(255,255,255,.7)}.github-fork-ribbon.left-bottom,.github-fork-ribbon.left-top{right:auto;left:0}.github-fork-ribbon.left-bottom,.github-fork-ribbon.right-bottom{top:auto;bottom:0}.github-fork-ribbon.left-bottom:after,.github-fork-ribbon.left-bottom:before,.github-fork-ribbon.left-top:after,.github-fork-ribbon.left-top:before{right:auto;left:-3.23em}.github-fork-ribbon.left-bottom:after,.github-fork-ribbon.left-bottom:before,.github-fork-ribbon.right-bottom:after,.github-fork-ribbon.right-bottom:before{top:auto;bottom:3.23em}.github-fork-ribbon.left-top:after,.github-fork-ribbon.left-top:before,.github-fork-ribbon.right-bottom:after,.github-fork-ribbon.right-bottom:before{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}
/*# sourceMappingURL=gh-fork-ribbon.min.css.map */

1
css/imgs/logo/logo.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2" viewBox="0 0 318.8 194"><circle cx="97" cy="97" r="97" style="fill:url(#a)"/><path d="M97.3 6.8c50 0 90.5 40.3 90.5 90s-40.5 90-90.5 90-90.5-40.3-90.5-90 40.5-90 90.5-90Zm69.8 140.7a85.2 85.2 0 0 0 16.6-50.6A86.2 86.2 0 0 0 97.3 11 86.2 86.2 0 0 0 11 96.9c0 17 5 32.8 13.5 46.2 36.3-67.4 36.2-74.7 45.3-74.7 8.8 0 10.3 7.6 43.3 71.4 16.7-25.9 18.9-30.4 24.3-30.4 6.7 0 8 5 29.7 38Zm-29.3-68.2a10.6 10.6 0 1 1 0 21.2 10.6 10.6 0 0 1 0-21.2Z" style="fill:url(#b)"/><path d="M253 37.1a33 33 0 1 1 10.4 27l-69.7 26.1-6.4-28.5L253 37.1Z" style="fill:url(#c)"/><path d="M263.4 129.3a32.9 32.9 0 0 1 55.4 24.2 33 33 0 0 1-65.8 3.2l-65.6-24.8 6.4-28.9 69.6 26.3Z" style="fill:url(#d)"/><defs><radialGradient id="a" cx="0" cy="0" r="1" gradientTransform="matrix(79 0 0 -73 97.3 77.6)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#867278;stop-opacity:1"/><stop offset=".5" style="stop-color:#5c4955;stop-opacity:1"/><stop offset="1" style="stop-color:#433545;stop-opacity:1"/></radialGradient><radialGradient id="c" cx="0" cy="0" r="1" gradientTransform="matrix(55 0 0 -55 253 48.6)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#867278;stop-opacity:1"/><stop offset=".5" style="stop-color:#5c4955;stop-opacity:1"/><stop offset="1" style="stop-color:#433545;stop-opacity:1"/></radialGradient><radialGradient id="d" cx="0" cy="0" r="1" gradientTransform="matrix(55 0 0 -56 253.1 144.8)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#867278;stop-opacity:1"/><stop offset=".5" style="stop-color:#5c4955;stop-opacity:1"/><stop offset="1" style="stop-color:#433545;stop-opacity:1"/></radialGradient><linearGradient id="b" x1="0" x2="1" y1="0" y2="0" gradientTransform="matrix(97 0 0 97 53.6 97)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#40a1d4;stop-opacity:1"/><stop offset="1" style="stop-color:#2971c2;stop-opacity:1"/></linearGradient></defs></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -26,3 +26,10 @@ body {
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.05);
box-shadow: inset 0 1px 1px rgba(0,0,0,.05);
}
.box__dragndrop,
.box__uploading,
.box__success,
.box__error {
display: none;
}

View File

@@ -2,5 +2,3 @@
*
# Except this file
!.gitignore
# And except deletecodes folder
!deletecodes

View File

@@ -1,24 +0,0 @@
version: '2'
services:
pictshare:
restart: always
image: hascheksolutions/pictshare:latest
volumes:
- ./volumes/upload:/usr/share/nginx/html/upload
ports:
- "80:80"
- "443:443"
environment:
- TITLE=
- AUTOUPDATE=false
- MAXUPLOADSIZE=
- MASTERDELETECODE=
- BLOATING=
- UPLOADCODE=
- UPLOADPATH=
- IMAGECHANGECODE=
- LOGUPLOADER=
- MAXRESIZEDIMAGES=
- DOMAIN=
- SHOWERRORS=

69
docker/Dockerfile Normal file
View File

@@ -0,0 +1,69 @@
FROM alpine:3.18
RUN apk add --no-cache bash socat wget curl nginx file ffmpeg unzip zlib redis \
php82-fileinfo \
php82-session \
php \
php-curl \
php-openssl \
php-mbstring \
php-json \
php-gd \
php-dom \
php-fpm \
php82 \
php82-pdo \
php82-exif \
php82-curl \
php82-gd \
php82-json \
php82-phar \
php82-fpm \
php82-openssl \
php82-ctype \
php82-opcache \
php82-mbstring \
php82-sodium \
php82-xml \
php82-ftp \
php82-simplexml \
php82-session \
php82-fileinfo \
php82-pcntl \
php82-pecl-redis
RUN ln -s /usr/bin/php82 /usr/bin/php
RUN curl -sS https://getcomposer.org/installer | /usr/bin/php -- --install-dir=/usr/bin --filename=composer
RUN mkdir -p /var/www
WORKDIR /var/www
ADD . /var/www/.
ADD docker/rootfs/start.sh /etc/start.sh
RUN chmod +x /etc/start.sh
# Composer intall
WORKDIR /var/www/lib
RUN composer install --no-dev --no-interaction --no-progress --optimize-autoloader
# nginx stuff
WORKDIR /var/www
ADD docker/rootfs/nginx.conf /etc/nginx/http.d/default.conf
RUN mkdir -p /run/nginx
RUN mkdir -p /var/log/nginx
RUN sed -i 's/nobody/nginx/g' /etc/php82/php-fpm.d/www.conf
# Since requests can trigger conversion, let's give the server enough time to respond
RUN sed -i "/max_execution_time/c\max_execution_time=3600" /etc/php82/php.ini
RUN sed -i "/max_input_time/c\max_input_time=3600" /etc/php82/php.ini
WORKDIR /var/www/
# Volumes to mount
#VOLUME /var/lib/influxdb
VOLUME /var/www/data
EXPOSE 80
ENTRYPOINT ["/etc/start.sh"]

73
docker/rootfs/nginx.conf Normal file
View File

@@ -0,0 +1,73 @@
server {
listen 80 default_server;
set $base /var/www;
root /var/www/;
index index.php;
client_max_body_size 50M;
location / {
try_files $uri $uri/ /index.php?url=$request_uri;
}
location ~ /(data|tmp|bin|content-controllers|inc|interfaces|storage-controllers|templates|tools|docker) {
deny all;
return 404;
}
# logging
access_log /var/log/nginx/pictshare/access.log;
error_log /var/log/nginx/pictshare/error.log warn;
location ~ \.php$ {
# 404
try_files $fastcgi_script_name =404;
# default fastcgi_params
include fastcgi_params;
# fastcgi settings
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_max_temp_file_size 0; # caching files to disk while uploading. this will help low-memory devices
fastcgi_read_timeout 1d; # we set the timeout to 1 day so big uploads and have enough time to be delivered
fastcgi_send_timeout 1d; # it's especially important if you want to use storage controllers like S3 or FTP
fastcgi_request_buffering off; # disabbling buffering which will send the uploaded data right to PHP
# fastcgi params
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param PHP_ADMIN_VALUE "open_basedir=$base/:/usr/lib/php/:/tmp/";
}
location /favicon.ico {
log_not_found off;
}
# security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# svg, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
add_header Access-Control-Allow-Origin "*";
expires 7d;
access_log off;
}
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;
}

96
docker/rootfs/start.sh Normal file
View File

@@ -0,0 +1,96 @@
#!/bin/bash
######### functions
_maxUploadSize() {
echo "[i] Setting uploadsize to ${MAX_UPLOAD_SIZE}M"
sed -i "/post_max_size/c\post_max_size=${MAX_UPLOAD_SIZE}M" /etc/php82/php.ini
sed -i "/upload_max_filesize/c\upload_max_filesize=${MAX_UPLOAD_SIZE}M" /etc/php82/php.ini
# set error reporting no notices, no warnings
sed -i "/^error_reporting/c\error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_WARNING & ~E_NOTICE" /etc/php82/php.ini
sed -i -e "s/50M/${MAX_UPLOAD_SIZE}M/g" /etc/nginx/http.d/default.conf
MAX_RAM=$((MAX_UPLOAD_SIZE + 30)) # 30megs more than the upload size
echo "[i] Also changing memory limit of PHP to ${MAX_RAM}M"
sed -i -e "s/128M/${MAX_RAM}M/g" /etc/php82/php.ini
sed -i "/memory_limit/c\memory_limit=${MAX_RAM}M" /etc/php82/php.ini
}
_filePermissions() {
chown -R nginx:nginx /var/www
touch data/sha1.csv
chown nginx:nginx data/sha1.csv
}
_buildConfig() {
echo "<?php"
echo "define('URL', '${URL:-}');"
echo "define('TITLE', '${TITLE:-PictShare}');"
echo "define('ALLOWED_SUBNET', '${ALLOWED_SUBNET:-}');"
echo "define('CONTENTCONTROLLERS', '${CONTENTCONTROLLERS:-}');"
echo "define('MASTER_DELETE_CODE', '${MASTER_DELETE_CODE:-}');"
echo "define('MASTER_DELETE_IP', '${MASTER_DELETE_IP:-}');"
echo "define('UPLOAD_FORM_LOCATION', '${UPLOAD_FORM_LOCATION:-}');"
echo "define('UPLOAD_CODE', '${UPLOAD_CODE:-}');"
echo "define('LOG_UPLOADER', ${LOG_UPLOADER:-false});"
echo "define('MAX_RESIZED_IMAGES',${MAX_RESIZED_IMAGES:--1});"
echo "define('ALLOW_BLOATING', ${ALLOW_BLOATING:-false});"
echo "define('SHOW_ERRORS', ${SHOW_ERRORS:-false});"
echo "define('JPEG_COMPRESSION', ${JPEG_COMPRESSION:-90});"
echo "define('PNG_COMPRESSION', ${PNG_COMPRESSION:-6});"
echo "define('ALT_FOLDER', '${ALT_FOLDER:-}');"
echo "define('S3_BUCKET', '${S3_BUCKET:-}');"
echo "define('S3_ACCESS_KEY', '${S3_ACCESS_KEY:-}');"
echo "define('S3_SECRET_KEY', '${S3_SECRET_KEY:-}');"
echo "define('S3_ENDPOINT', '${S3_ENDPOINT:-}');"
echo "define('S3_REGION', '${S3_REGION:-}');"
echo "define('FTP_SERVER', '${FTP_SERVER:-}');"
echo "define('FTP_PORT', ${FTP_PORT:-21});"
echo "define('FTP_USER', '${FTP_USER:-}');"
echo "define('FTP_PASS', '${FTP_PASS:-}');"
echo "define('FTP_PASSIVEMODE', ${FTP_PASSIVEMODE:-true});"
echo "define('FTP_SSL', ${FTP_SSL:-false});"
echo "define('FTP_BASEDIR', '${FTP_BASEDIR:-}');"
echo "define('ENCRYPTION_KEY', '${ENCRYPTION_KEY:-}');"
echo "define('FFMPEG_BINARY', '${FFMPEG_BINARY:-/usr/bin/ffmpeg}');"
echo "define('ALWAYS_WEBP', ${ALWAYS_WEBP:-false});"
echo "define('ALLOWED_DOMAINS', '${ALLOWED_DOMAINS:-}');"
echo "define('SPLIT_DATA_DIR', ${SPLIT_DATA_DIR:-false});"
}
######### main
echo 'Starting Pictshare'
cd /var/www/
if [[ ${MAX_UPLOAD_SIZE:=100} =~ ^[0-9]+$ ]]; then
_maxUploadSize
fi
# run _filePermissions function unless SKIP_FILEPERMISSIONS is set to true
if [[ ${SKIP_FILEPERMISSIONS:=false} != true ]]; then
_filePermissions
fi
echo ' [+] Starting php'
php-fpm82
echo ' [+] Creating config'
_buildConfig > inc/config.inc.php
echo ' [+] Starting nginx'
mkdir -p /var/log/nginx/pictshare
touch /var/log/nginx/pictshare/access.log
touch /var/log/nginx/pictshare/error.log
nginx
tail -f /var/log/nginx/pictshare/*.log

1
inc/.gitignore vendored
View File

@@ -1,2 +1 @@
# don#t track the active config
config.inc.php

File diff suppressed because it is too large Load Diff

85
inc/encryption.php Normal file
View File

@@ -0,0 +1,85 @@
<?php
class Encryption{
/**
* $key must have been generated at some point with: random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES)
*/
function encryptText($text,$key)
{
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = sodium_crypto_secretbox($text, $nonce, $key);
$encoded = base64_encode($nonce . $ciphertext);
return $encoded;
}
/**
* $key must have been generated at some point with: random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES)
*/
function decryptText($encoded,$key)
{
$decoded = base64_decode($encoded);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
return $plaintext;
}
/**
* $key must have been generated at some point with: sodium_crypto_secretstream_xchacha20poly1305_keygen();
*/
function encryptFile($infile,$enc_outfile,$key)
{
$chunk_size = 4096;
$fd_in = fopen($infile, 'rb');
$fd_out = fopen($enc_outfile, 'wb');
list($stream, $header) = sodium_crypto_secretstream_xchacha20poly1305_init_push($key);
fwrite($fd_out, $header);
$tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;
do {
$chunk = fread($fd_in, $chunk_size);
if (feof($fd_in)) {
$tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL;
}
$encrypted_chunk = sodium_crypto_secretstream_xchacha20poly1305_push($stream, $chunk, '', $tag);
fwrite($fd_out, $encrypted_chunk);
} while ($tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);
fclose($fd_out);
fclose($fd_in);
}
/**
* $key must have been generated at some point with: sodium_crypto_secretstream_xchacha20poly1305_keygen();
*/
function decryptFile($enc_infile,$outfile,$key)
{
$fd_in = fopen($enc_infile, 'rb');
$fd_out = fopen($outfile, 'wb');
$chunk_size = 4096;
$header = fread($fd_in, SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES);
$stream = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key);
do {
$chunk = fread($fd_in, $chunk_size + SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES);
list($decrypted_chunk, $tag) = sodium_crypto_secretstream_xchacha20poly1305_pull($stream, $chunk);
fwrite($fd_out, $decrypted_chunk);
} while (!feof($fd_in) && $tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);
$ok = feof($fd_in);
fclose($fd_out);
fclose($fd_in);
if (!$ok) {
die('Invalid/corrupted input');
}
}
}

View File

@@ -1,97 +1,25 @@
<?php
/**
* All settings that are uncommented are mandatory
* Others optional
*
* For all possible config options, check https://github.com/HaschekSolutions/pictshare/blob/master/rtfm/CONFIG.md
* or /rtfm/CONFIG.md in your installation
*/
//Set title for your image and mp4 hosting service
define('TITLE', 'PictShare');
// PNG level from 0 (largest file) to
// 9 (smallest file). Note that this doesn't affect
// quality, only file size and CPU
define('PNG_COMPRESSION', 6);
// JPG compression percenage from 0 (smallest file, worst quality)
// to 100 (large file, best quality)
define('JPEG_COMPRESSION', 90);
//If set, can be added to any image URL to delete the image and all versions of the image
//Must be longer than 10 characters
//Usage example:
// image: https://pictshare.net/b260e36b60.jpg
// to delete it, access https://pictshare.net/delete_YOURMASTERDELETECODE/b260e36b60.jpg
// Will render one last time, if refreshed won't be on the server anymore
define('MASTER_DELETE_CODE', false);
//if set, the IP, hostname or every device in the IP range (CIDR naming) will be allowed to delete images
//by supplying the parameter "delete"
//use multiple ips/hostnames/ranges: semicolon seperated
//examples:
//======
//ip: define('MASTER_DELETE_IP', '8.8.8.8');
//hostname: define('MASTER_DELETE_IP', 'home.example.com');
//ip range: define('MASTER_DELETE_IP', '192.168.0.0/24'); //all IPs from 192.168.0.0 to 192.168.0.255 can delete
//multiple: define('MASTER_DELETE_IP', '192.168.0.0/24;my.home.net;4.4.2.2');
define('MASTER_DELETE_IP', false);
//If set, upload form will only be shown on that location
//eg: define('UPLOAD_FORM_LOCATION', 'secret/upload'); then the upload form will only be visible
//from http://your.domain/secret/upload
define('UPLOAD_FORM_LOCATION', false);
//If set to true, the only page that will be rendered is the upload form
//if a wrong link is provided, 404 will be shown instead of the error page
//It's meant to be used to hide the fact that you're using pictshare and your site just looks like a content server
//use in combination with UPLOAD_FORM_LOCATION for maximum sneakiness
define('LOW_PROFILE', false);
//if set to a string, this string must be provided before upload.
//you can set multiple codes by;separating;them;with;semicolons
//if set to false, everybody can upload
//for API uploads, the GET Variable 'upload_code' must be provided
define('UPLOAD_CODE', false);
//if set to a string, this string must be provided in the URL to use any options (filters, resizes, etc..)
//you can set multiple codes by;separating;them;with;semicolons
//if set to false, everybody can use options on all images
//if image change code is not provided but the requested image (with options) already exists, it will render to the user just fine
define('IMAGE_CHANGE_CODE', false);
// shall we log all uploaders IP addresses?
define('LOG_UPLOADER', true);
//how many resizes may one image have?
//-1 = infinite
//0 = none
define('MAX_RESIZED_IMAGES',20);
//when the user requests a resize. Can the resized image be bigger than the original?
define('ALLOW_BLOATING', false);
//Force a specific domain for this server. If set to false, will autodetect.
//Use a specific domain for links presented to the user
//Format: https://your.domain.name/
define('FORCE_DOMAIN', false);
// MUST HAVE TAILING /
define('URL','https://dev.pictshare.net/');
//Shall errors be displayed to the user?
//For dev environments: true, in production: false
define('SHOW_ERRORS', false);
//define('JPEG_COMPRESSION', 90);
//define('FFMPEG_BINARY','');
//define('ALT_FOLDER','/ftp/pictshare');
//define('ALLOWED_SUBNET','192.168.0.0/24');
//for scalability reasons you might want to upload images to cloud providers
//remove comments to use
/* BACKBLAZE B2 */
/* You can find your info here: https://secure.backblaze.com/b2_buckets.htm */
//define('BACKBLAZE',true); //true=>use backblaze false=>don't
//define('BACKBLAZE_ID','');
//define('BACKBLAZE_KEY', '');
//define('BACKBLAZE_BUCKET_ID', '');
//define('BACKBLAZE_BUCKET_NAME', '');
//define('BACKBLAZE_AUTODOWNLOAD', true); //if true, will download images from backblaze if not found local
//define('BACKBLAZE_AUTOUPLOAD', true); //if true, will upload images to backblaze when they are uploaded to pictshare
//define('BACKBLAZE_AUTODELETE', true); //if true, will delete images from backblaze if they are deleted from pictshare
//If you have a NAS or some cifs or nfs mounted drive, you can specify this here as a folder
//if a requested hash is not found locally, its looked up on this location. This allows for mounted external spaces
//or just backups on a second drive.
//Also new hashes will be uploaded there (just the originals, not resizes)
//value should be a path **without tailing slash**!
define('ALT_FOLDER','/mnt');
//S3 settings
//
//define('S3_BUCKET','bucketname');
//define('S3_ACCESS_KEY','');
//define('S3_SECRET_KEY','');
//define('S3_ENDPOINT','http://localhost:9000'); //optional, only if you're using S3 compatible storage like Minio

View File

@@ -1,27 +1,22 @@
<?php
session_cache_limiter("public");
$expiry = 90; //days
session_cache_expire($expiry * 24 * 60);
session_start();
// basic path definitions
define('DS', DIRECTORY_SEPARATOR);
define('ROOT', dirname(__FILE__));
define('PATH',((dirname($_SERVER['PHP_SELF'])=='/'||dirname($_SERVER['PHP_SELF'])=='\\'||dirname($_SERVER['PHP_SELF'])=='/index.php'||dirname($_SERVER['PHP_SELF'])=='/backend.php')?'/':dirname($_SERVER['PHP_SELF']).'/'));
//loading default settings if exist
if(!file_exists(ROOT.DS.'inc'.DS.'config.inc.php'))
exit('Rename /inc/example.config.inc.php to /inc/config.inc.php first!');
include_once(ROOT.DS.'inc'.DS.'config.inc.php');
if(FORCE_DOMAIN)
define('DOMAINPATH',FORCE_DOMAIN);
else
define('DOMAINPATH',(($_SERVER['HTTPS'])?'https':'http').'://'.$_SERVER['HTTP_HOST']);
error_reporting(E_ALL & ~E_NOTICE);
if(SHOW_ERRORS)
ini_set('display_errors','On');
else ini_set('display_errors','Off');
//loading core and controllers
include_once(ROOT.DS.'inc'.DS.'core.php');
$url = $_GET['url'];
removeMagicQuotes();
$GLOBALS['params'] = explode('/', $_GET['url']);
callHook();
loadAllContentControllers();
//load external things if existing
if(file_exists(ROOT.'/lib/vendor/autoload.php'))
require ROOT.'/lib/vendor/autoload.php';
//send the URL to the architect. It'll know what to do
$url = $_GET['url']?$_GET['url']:ltrim($_SERVER['REQUEST_URI'],'/');
architect($url);

View File

@@ -0,0 +1,45 @@
<?php
/**
* Content controller interface for new content types
*/
interface ContentController
{
/**
* When implementing a new content controller, you must specify a constant with the name of "ctype"
* This constant will be used to distinguish static controllers (which have files on disk) from dynamic ones (which don't, like the placeholder controller)
*
* Possible values: 'static' or 'dynamic'
*/
//const ctype = 'static';
/** This method will return all file extensions that will be associated with this content type
* for example 'pdf' but it could be anything really. You just need a way later to confirm that a type is what it says it is
*
*
* @return array the extensions of files associated with this controller. eg. return array('pdf');
*/
public function getRegisteredExtensions();
/** This method will be called whenever the system has to find out if a user requested (existing) hash
* belongs to this controller.
* In here the content should be rendered or processed like resized or something.
* You can decide what it does by working with the $url array which gives you every element in the URL
* Does not need to return anything for example you can just set the header and print your data right away
*
* @param string $hash the hash (with extension eg '5saB2.pdf') of the file this controller will work with
* @param array $url contains all URL elements exploded with '/' so you can do your magic.
*/
public function handleHash($hash,$url);
/** This method will be called if the upload script detects the content of a newly uploaded file as one of the
* extensions registered at "getRegisteredExtensions".
* For Example if someone uploads a PDF and getRegisteredExtensions has registered "pdf", then this method of this
* controller will be called
*
* @param string $tmpfile is the location on disk of the temp file that was uploaded. It is your job to put it somewhere, your handleHash method will find it again
* @param array $hash (optional) if you want your upload to have a certain hash then add it here. This allows for user chosen hashes
*/
public function handleUpload($tmpfile,$hash=false);
}

View File

@@ -0,0 +1,69 @@
<?php
/**
* StorageController interface
*
* Must be implemented by all storage systems
*/
interface StorageController
{
/**
* Checks if this storage system is enabled.
* For example check if all depenencies are met
* or config vars are set
*
* @return bool
*/
function isEnabled();
/**
* Is fired whenever a hash is not found locally
* Use this to look in your storage system for the file
*
* @param string $hash is the hash of the file requested
*
* @return bool
*/
function hashExists($hash);
/**
* Returns an array of all items in this storage controller
*
* @return array
*/
function getItems();
/**
* If a file does exist in this storage system, then this method should
* get the file and put it in the default data directory
*
* The file should be placed in /data/$hash/$hash where the first $hash is obviously
* a folder that you might have to create first before putting the file in
*
* @param string $hash is the hash of the file that should be pulled from this storage system
* @param string $location is the location where the downloaded file should be placed
*
* @return bool true if successful
*/
function pullFile($hash,$location);
/**
* Whenever a new file is uploaded this method will be called
* You should then upload it or do whatever your storage system is meant to do with new files
*
* @param string $hash is the hash of the new file. The file path of this file is always getDataDir().DS.$hash.DS.$hash
*
* @return bool true if successful
*/
function pushFile($source,$hash);
/**
* If deletion of a file is requested, this method is called
*
* @param string $hash is the hash of the file. Delete this hash from your storage system
*
* @return bool true if successful
*/
function deleteFile($hash);
}

3530
js/dropzone.js Normal file

File diff suppressed because it is too large Load Diff

2
js/highlight.pack.js Normal file

File diff suppressed because one or more lines are too long

40
js/pictshare.js Normal file
View File

@@ -0,0 +1,40 @@
Dropzone.autoDiscover = false;
$(function () {
var myDropzone = new Dropzone("#dropzone");
//console.log(myDropzone.options);
if (maxUploadFileSize !== undefined)
myDropzone.options.maxFilesize = maxUploadFileSize;
myDropzone.options.timeout = 0,
myDropzone.on("sending", function(file, xhr, formData) {
if(document.getElementById("uploadcode"))
formData.append("uploadcode", document.getElementById("uploadcode").value);
});
myDropzone.on('error', function(file, response) {
alert("Error: "+response.reason);
});
myDropzone.on("success", function (file, response) {
console.log("raw response: " + response);
if (response == null || response == "null")
$("#uploadinfo").append("<div class='alert alert-danger' role='alert'><strong>Error uploading " + file.name + "</strong><br/>Reason is unknown :(</div>")
else {
var o = response;
if (o.status == 'ok')
$("#uploadinfo").append("<div class='alert alert-success' role='alert'><strong>" + file.name + "</strong> uploaded as <a target='_blank' href='/" + o.hash + "'>" + o.hash + "</a><br/>URL: <a target='_blank' href='" + o.url + "'>" + o.url + "</a> <button class='btn btn-xs' onClick='navigator.clipboard.writeText(\"" + o.url + "\");'>Copy URL</button></div>")
else if (o.status == 'err')
$("#uploadinfo").append("<div class='alert alert-danger' role='alert'><strong>Error uploading " + file.name + "</strong><br/>Reason: " + o.reason + "</div>")
console.log(o)
}
});
document.onpaste = function (event) {
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (index in items) {
var item = items[index];
if (item.kind === 'file') {
// adds the file to your dropzone instance
myDropzone.addFile(item.getAsFile())
}
}
}
})

99
js/styles/a11y-dark.css Normal file
View File

@@ -0,0 +1,99 @@
/* a11y-dark theme */
/* Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css */
/* @author: ericwbailey */
/* Comment */
.hljs-comment,
.hljs-quote {
color: #d4d0ab;
}
/* Red */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
color: #ffa07a;
}
/* Orange */
.hljs-number,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link {
color: #f5ab35;
}
/* Yellow */
.hljs-attribute {
color: #ffd700;
}
/* Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
color: #abe338;
}
/* Blue */
.hljs-title,
.hljs-section {
color: #00e0e0;
}
/* Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #dcc6e0;
}
.hljs {
display: block;
overflow-x: auto;
background: #2b2b2b;
color: #f8f8f2;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
@media screen and (-ms-high-contrast: active) {
.hljs-addition,
.hljs-attribute,
.hljs-built_in,
.hljs-builtin-name,
.hljs-bullet,
.hljs-comment,
.hljs-link,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-params,
.hljs-string,
.hljs-symbol,
.hljs-type,
.hljs-quote {
color: highlight;
}
.hljs-keyword,
.hljs-selector-tag {
font-weight: bold;
}
}

99
js/styles/a11y-light.css Normal file
View File

@@ -0,0 +1,99 @@
/* a11y-light theme */
/* Based on the Tomorrow Night Eighties theme: https://github.com/isagalaev/highlight.js/blob/master/src/styles/tomorrow-night-eighties.css */
/* @author: ericwbailey */
/* Comment */
.hljs-comment,
.hljs-quote {
color: #696969;
}
/* Red */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion {
color: #d91e18;
}
/* Orange */
.hljs-number,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link {
color: #aa5d00;
}
/* Yellow */
.hljs-attribute {
color: #aa5d00;
}
/* Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition {
color: #008000;
}
/* Blue */
.hljs-title,
.hljs-section {
color: #007faa;
}
/* Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #7928a1;
}
.hljs {
display: block;
overflow-x: auto;
background: #fefefe;
color: #545454;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
@media screen and (-ms-high-contrast: active) {
.hljs-addition,
.hljs-attribute,
.hljs-built_in,
.hljs-builtin-name,
.hljs-bullet,
.hljs-comment,
.hljs-link,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-params,
.hljs-string,
.hljs-symbol,
.hljs-type,
.hljs-quote {
color: highlight;
}
.hljs-keyword,
.hljs-selector-tag {
font-weight: bold;
}
}

108
js/styles/agate.css Normal file
View File

@@ -0,0 +1,108 @@
/*!
* Agate by Taufik Nurrohman <https://github.com/tovic>
* ----------------------------------------------------
*
* #ade5fc
* #a2fca2
* #c6b4f0
* #d36363
* #fcc28c
* #fc9b9b
* #ffa
* #fff
* #333
* #62c8f3
* #888
*
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #333;
color: white;
}
.hljs-name,
.hljs-strong {
font-weight: bold;
}
.hljs-code,
.hljs-emphasis {
font-style: italic;
}
.hljs-tag {
color: #62c8f3;
}
.hljs-variable,
.hljs-template-variable,
.hljs-selector-id,
.hljs-selector-class {
color: #ade5fc;
}
.hljs-string,
.hljs-bullet {
color: #a2fca2;
}
.hljs-type,
.hljs-title,
.hljs-section,
.hljs-attribute,
.hljs-quote,
.hljs-built_in,
.hljs-builtin-name {
color: #ffa;
}
.hljs-number,
.hljs-symbol,
.hljs-bullet {
color: #d36363;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal {
color: #fcc28c;
}
.hljs-comment,
.hljs-deletion,
.hljs-code {
color: #888;
}
.hljs-regexp,
.hljs-link {
color: #c6b4f0;
}
.hljs-meta {
color: #fc9b9b;
}
.hljs-deletion {
background-color: #fc9b9b;
color: #333;
}
.hljs-addition {
background-color: #a2fca2;
color: #333;
}
.hljs a {
color: inherit;
}
.hljs a:focus,
.hljs a:hover {
color: inherit;
text-decoration: underline;
}

89
js/styles/an-old-hope.css Normal file
View File

@@ -0,0 +1,89 @@
/*
An Old Hope Star Wars Syntax (c) Gustavo Costa <gusbemacbe@gmail.com>
Original theme - Ocean Dark Theme by https://github.com/gavsiu
Based on Jesse Leite's Atom syntax theme 'An Old Hope' https://github.com/JesseLeite/an-old-hope-syntax-atom
*/
/* Death Star Comment */
.hljs-comment,
.hljs-quote
{
color: #B6B18B;
}
/* Darth Vader */
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-regexp,
.hljs-deletion
{
color: #EB3C54;
}
/* Threepio */
.hljs-number,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params,
.hljs-meta,
.hljs-link
{
color: #E7CE56;
}
/* Luke Skywalker */
.hljs-attribute
{
color: #EE7C2B;
}
/* Obi Wan Kenobi */
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-addition
{
color: #4FB4D7;
}
/* Yoda */
.hljs-title,
.hljs-section
{
color: #78BB65;
}
/* Mace Windu */
.hljs-keyword,
.hljs-selector-tag
{
color: #B45EA4;
}
/* Millenium Falcon */
.hljs
{
display: block;
overflow-x: auto;
background: #1C1D21;
color: #c0c5ce;
padding: 0.5em;
}
.hljs-emphasis
{
font-style: italic;
}
.hljs-strong
{
font-weight: bold;
}

View File

@@ -0,0 +1,66 @@
/*
Date: 24 Fev 2015
Author: Pedro Oliveira <kanytu@gmail . com>
*/
.hljs {
color: #a9b7c6;
background: #282b2e;
display: block;
overflow-x: auto;
padding: 0.5em;
}
.hljs-number,
.hljs-literal,
.hljs-symbol,
.hljs-bullet {
color: #6897BB;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-deletion {
color: #cc7832;
}
.hljs-variable,
.hljs-template-variable,
.hljs-link {
color: #629755;
}
.hljs-comment,
.hljs-quote {
color: #808080;
}
.hljs-meta {
color: #bbb529;
}
.hljs-string,
.hljs-attribute,
.hljs-addition {
color: #6A8759;
}
.hljs-section,
.hljs-title,
.hljs-type {
color: #ffc66d;
}
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #e8bf6a;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,88 @@
/*
Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #FFFFFF;
}
.hljs,
.hljs-subst {
color: #434f54;
}
.hljs-keyword,
.hljs-attribute,
.hljs-selector-tag,
.hljs-doctag,
.hljs-name {
color: #00979D;
}
.hljs-built_in,
.hljs-literal,
.hljs-bullet,
.hljs-code,
.hljs-addition {
color: #D35400;
}
.hljs-regexp,
.hljs-symbol,
.hljs-variable,
.hljs-template-variable,
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #00979D;
}
.hljs-type,
.hljs-string,
.hljs-selector-id,
.hljs-selector-class,
.hljs-quote,
.hljs-template-tag,
.hljs-deletion {
color: #005C5F;
}
.hljs-title,
.hljs-section {
color: #880000;
font-weight: bold;
}
.hljs-comment {
color: rgba(149,165,166,.8);
}
.hljs-meta-keyword {
color: #728E00;
}
.hljs-meta {
color: #728E00;
color: #434f54;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-function {
color: #728E00;
}
.hljs-number {
color: #8A7B52;
}

73
js/styles/arta.css Normal file
View File

@@ -0,0 +1,73 @@
/*
Date: 17.V.2011
Author: pumbur <pumbur@pumbur.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #222;
}
.hljs,
.hljs-subst {
color: #aaa;
}
.hljs-section {
color: #fff;
}
.hljs-comment,
.hljs-quote,
.hljs-meta {
color: #444;
}
.hljs-string,
.hljs-symbol,
.hljs-bullet,
.hljs-regexp {
color: #ffcc33;
}
.hljs-number,
.hljs-addition {
color: #00cc66;
}
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-template-variable,
.hljs-attribute,
.hljs-link {
color: #32aaee;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #6644aa;
}
.hljs-title,
.hljs-variable,
.hljs-deletion,
.hljs-template-tag {
color: #bb1166;
}
.hljs-section,
.hljs-doctag,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

45
js/styles/ascetic.css Normal file
View File

@@ -0,0 +1,45 @@
/*
Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: white;
color: black;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-symbol,
.hljs-bullet,
.hljs-section,
.hljs-addition,
.hljs-attribute,
.hljs-link {
color: #888;
}
.hljs-comment,
.hljs-quote,
.hljs-meta,
.hljs-deletion {
color: #ccc;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-section,
.hljs-name,
.hljs-type,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

View File

@@ -0,0 +1,83 @@
/* Base16 Atelier Cave Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Cave Comment */
.hljs-comment,
.hljs-quote {
color: #7e7887;
}
/* Atelier-Cave Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-regexp,
.hljs-link,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #be4678;
}
/* Atelier-Cave Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #aa573c;
}
/* Atelier-Cave Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #2a9292;
}
/* Atelier-Cave Blue */
.hljs-title,
.hljs-section {
color: #576ddb;
}
/* Atelier-Cave Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #955ae7;
}
.hljs-deletion,
.hljs-addition {
color: #19171c;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #be4678;
}
.hljs-addition {
background-color: #2a9292;
}
.hljs {
display: block;
overflow-x: auto;
background: #19171c;
color: #8b8792;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,85 @@
/* Base16 Atelier Cave Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Cave Comment */
.hljs-comment,
.hljs-quote {
color: #655f6d;
}
/* Atelier-Cave Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #be4678;
}
/* Atelier-Cave Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #aa573c;
}
/* Atelier-Cave Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #2a9292;
}
/* Atelier-Cave Blue */
.hljs-title,
.hljs-section {
color: #576ddb;
}
/* Atelier-Cave Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #955ae7;
}
.hljs-deletion,
.hljs-addition {
color: #19171c;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #be4678;
}
.hljs-addition {
background-color: #2a9292;
}
.hljs {
display: block;
overflow-x: auto;
background: #efecf4;
color: #585260;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Dune Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Dune Comment */
.hljs-comment,
.hljs-quote {
color: #999580;
}
/* Atelier-Dune Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #d73737;
}
/* Atelier-Dune Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #b65611;
}
/* Atelier-Dune Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #60ac39;
}
/* Atelier-Dune Blue */
.hljs-title,
.hljs-section {
color: #6684e1;
}
/* Atelier-Dune Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #b854d4;
}
.hljs {
display: block;
overflow-x: auto;
background: #20201d;
color: #a6a28c;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Dune Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Dune Comment */
.hljs-comment,
.hljs-quote {
color: #7d7a68;
}
/* Atelier-Dune Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #d73737;
}
/* Atelier-Dune Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #b65611;
}
/* Atelier-Dune Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #60ac39;
}
/* Atelier-Dune Blue */
.hljs-title,
.hljs-section {
color: #6684e1;
}
/* Atelier-Dune Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #b854d4;
}
.hljs {
display: block;
overflow-x: auto;
background: #fefbec;
color: #6e6b5e;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,84 @@
/* Base16 Atelier Estuary Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Estuary Comment */
.hljs-comment,
.hljs-quote {
color: #878573;
}
/* Atelier-Estuary Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #ba6236;
}
/* Atelier-Estuary Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #ae7313;
}
/* Atelier-Estuary Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #7d9726;
}
/* Atelier-Estuary Blue */
.hljs-title,
.hljs-section {
color: #36a166;
}
/* Atelier-Estuary Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #5f9182;
}
.hljs-deletion,
.hljs-addition {
color: #22221b;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #ba6236;
}
.hljs-addition {
background-color: #7d9726;
}
.hljs {
display: block;
overflow-x: auto;
background: #22221b;
color: #929181;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,84 @@
/* Base16 Atelier Estuary Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Estuary Comment */
.hljs-comment,
.hljs-quote {
color: #6c6b5a;
}
/* Atelier-Estuary Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #ba6236;
}
/* Atelier-Estuary Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #ae7313;
}
/* Atelier-Estuary Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #7d9726;
}
/* Atelier-Estuary Blue */
.hljs-title,
.hljs-section {
color: #36a166;
}
/* Atelier-Estuary Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #5f9182;
}
.hljs-deletion,
.hljs-addition {
color: #22221b;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #ba6236;
}
.hljs-addition {
background-color: #7d9726;
}
.hljs {
display: block;
overflow-x: auto;
background: #f4f3ec;
color: #5f5e4e;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Forest Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Forest Comment */
.hljs-comment,
.hljs-quote {
color: #9c9491;
}
/* Atelier-Forest Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #f22c40;
}
/* Atelier-Forest Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #df5320;
}
/* Atelier-Forest Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #7b9726;
}
/* Atelier-Forest Blue */
.hljs-title,
.hljs-section {
color: #407ee7;
}
/* Atelier-Forest Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #6666ea;
}
.hljs {
display: block;
overflow-x: auto;
background: #1b1918;
color: #a8a19f;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Forest Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Forest Comment */
.hljs-comment,
.hljs-quote {
color: #766e6b;
}
/* Atelier-Forest Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #f22c40;
}
/* Atelier-Forest Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #df5320;
}
/* Atelier-Forest Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #7b9726;
}
/* Atelier-Forest Blue */
.hljs-title,
.hljs-section {
color: #407ee7;
}
/* Atelier-Forest Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #6666ea;
}
.hljs {
display: block;
overflow-x: auto;
background: #f1efee;
color: #68615e;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Heath Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Heath Comment */
.hljs-comment,
.hljs-quote {
color: #9e8f9e;
}
/* Atelier-Heath Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #ca402b;
}
/* Atelier-Heath Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #a65926;
}
/* Atelier-Heath Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #918b3b;
}
/* Atelier-Heath Blue */
.hljs-title,
.hljs-section {
color: #516aec;
}
/* Atelier-Heath Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #7b59c0;
}
.hljs {
display: block;
overflow-x: auto;
background: #1b181b;
color: #ab9bab;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Heath Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Heath Comment */
.hljs-comment,
.hljs-quote {
color: #776977;
}
/* Atelier-Heath Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #ca402b;
}
/* Atelier-Heath Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #a65926;
}
/* Atelier-Heath Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #918b3b;
}
/* Atelier-Heath Blue */
.hljs-title,
.hljs-section {
color: #516aec;
}
/* Atelier-Heath Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #7b59c0;
}
.hljs {
display: block;
overflow-x: auto;
background: #f7f3f7;
color: #695d69;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Lakeside Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Lakeside Comment */
.hljs-comment,
.hljs-quote {
color: #7195a8;
}
/* Atelier-Lakeside Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #d22d72;
}
/* Atelier-Lakeside Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #935c25;
}
/* Atelier-Lakeside Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #568c3b;
}
/* Atelier-Lakeside Blue */
.hljs-title,
.hljs-section {
color: #257fad;
}
/* Atelier-Lakeside Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #6b6bb8;
}
.hljs {
display: block;
overflow-x: auto;
background: #161b1d;
color: #7ea2b4;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Lakeside Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Lakeside Comment */
.hljs-comment,
.hljs-quote {
color: #5a7b8c;
}
/* Atelier-Lakeside Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #d22d72;
}
/* Atelier-Lakeside Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #935c25;
}
/* Atelier-Lakeside Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #568c3b;
}
/* Atelier-Lakeside Blue */
.hljs-title,
.hljs-section {
color: #257fad;
}
/* Atelier-Lakeside Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #6b6bb8;
}
.hljs {
display: block;
overflow-x: auto;
background: #ebf8ff;
color: #516d7b;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,84 @@
/* Base16 Atelier Plateau Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Plateau Comment */
.hljs-comment,
.hljs-quote {
color: #7e7777;
}
/* Atelier-Plateau Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #ca4949;
}
/* Atelier-Plateau Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #b45a3c;
}
/* Atelier-Plateau Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #4b8b8b;
}
/* Atelier-Plateau Blue */
.hljs-title,
.hljs-section {
color: #7272ca;
}
/* Atelier-Plateau Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #8464c4;
}
.hljs-deletion,
.hljs-addition {
color: #1b1818;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #ca4949;
}
.hljs-addition {
background-color: #4b8b8b;
}
.hljs {
display: block;
overflow-x: auto;
background: #1b1818;
color: #8a8585;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,84 @@
/* Base16 Atelier Plateau Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Plateau Comment */
.hljs-comment,
.hljs-quote {
color: #655d5d;
}
/* Atelier-Plateau Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #ca4949;
}
/* Atelier-Plateau Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #b45a3c;
}
/* Atelier-Plateau Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #4b8b8b;
}
/* Atelier-Plateau Blue */
.hljs-title,
.hljs-section {
color: #7272ca;
}
/* Atelier-Plateau Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #8464c4;
}
.hljs-deletion,
.hljs-addition {
color: #1b1818;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #ca4949;
}
.hljs-addition {
background-color: #4b8b8b;
}
.hljs {
display: block;
overflow-x: auto;
background: #f4ecec;
color: #585050;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,84 @@
/* Base16 Atelier Savanna Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Savanna Comment */
.hljs-comment,
.hljs-quote {
color: #78877d;
}
/* Atelier-Savanna Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #b16139;
}
/* Atelier-Savanna Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #9f713c;
}
/* Atelier-Savanna Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #489963;
}
/* Atelier-Savanna Blue */
.hljs-title,
.hljs-section {
color: #478c90;
}
/* Atelier-Savanna Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #55859b;
}
.hljs-deletion,
.hljs-addition {
color: #171c19;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #b16139;
}
.hljs-addition {
background-color: #489963;
}
.hljs {
display: block;
overflow-x: auto;
background: #171c19;
color: #87928a;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,84 @@
/* Base16 Atelier Savanna Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Savanna Comment */
.hljs-comment,
.hljs-quote {
color: #5f6d64;
}
/* Atelier-Savanna Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #b16139;
}
/* Atelier-Savanna Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #9f713c;
}
/* Atelier-Savanna Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #489963;
}
/* Atelier-Savanna Blue */
.hljs-title,
.hljs-section {
color: #478c90;
}
/* Atelier-Savanna Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #55859b;
}
.hljs-deletion,
.hljs-addition {
color: #171c19;
display: inline-block;
width: 100%;
}
.hljs-deletion {
background-color: #b16139;
}
.hljs-addition {
background-color: #489963;
}
.hljs {
display: block;
overflow-x: auto;
background: #ecf4ee;
color: #526057;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Seaside Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Seaside Comment */
.hljs-comment,
.hljs-quote {
color: #809980;
}
/* Atelier-Seaside Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #e6193c;
}
/* Atelier-Seaside Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #87711d;
}
/* Atelier-Seaside Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #29a329;
}
/* Atelier-Seaside Blue */
.hljs-title,
.hljs-section {
color: #3d62f5;
}
/* Atelier-Seaside Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #ad2bee;
}
.hljs {
display: block;
overflow-x: auto;
background: #131513;
color: #8ca68c;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Seaside Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Seaside Comment */
.hljs-comment,
.hljs-quote {
color: #687d68;
}
/* Atelier-Seaside Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #e6193c;
}
/* Atelier-Seaside Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #87711d;
}
/* Atelier-Seaside Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #29a329;
}
/* Atelier-Seaside Blue */
.hljs-title,
.hljs-section {
color: #3d62f5;
}
/* Atelier-Seaside Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #ad2bee;
}
.hljs {
display: block;
overflow-x: auto;
background: #f4fbf4;
color: #5e6e5e;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Sulphurpool Dark - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Sulphurpool Comment */
.hljs-comment,
.hljs-quote {
color: #898ea4;
}
/* Atelier-Sulphurpool Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #c94922;
}
/* Atelier-Sulphurpool Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #c76b29;
}
/* Atelier-Sulphurpool Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #ac9739;
}
/* Atelier-Sulphurpool Blue */
.hljs-title,
.hljs-section {
color: #3d8fd1;
}
/* Atelier-Sulphurpool Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #6679cc;
}
.hljs {
display: block;
overflow-x: auto;
background: #202746;
color: #979db4;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,69 @@
/* Base16 Atelier Sulphurpool Light - Theme */
/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) */
/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */
/* Atelier-Sulphurpool Comment */
.hljs-comment,
.hljs-quote {
color: #6b7394;
}
/* Atelier-Sulphurpool Red */
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-tag,
.hljs-name,
.hljs-regexp,
.hljs-link,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #c94922;
}
/* Atelier-Sulphurpool Orange */
.hljs-number,
.hljs-meta,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #c76b29;
}
/* Atelier-Sulphurpool Green */
.hljs-string,
.hljs-symbol,
.hljs-bullet {
color: #ac9739;
}
/* Atelier-Sulphurpool Blue */
.hljs-title,
.hljs-section {
color: #3d8fd1;
}
/* Atelier-Sulphurpool Purple */
.hljs-keyword,
.hljs-selector-tag {
color: #6679cc;
}
.hljs {
display: block;
overflow-x: auto;
background: #f5f7ff;
color: #5e6687;
padding: 0.5em;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,77 @@
/*
Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage
Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
line-height: 1.3em;
color: #abb2bf;
background: #282c34;
border-radius: 5px;
}
.hljs-keyword, .hljs-operator {
color: #F92672;
}
.hljs-pattern-match {
color: #F92672;
}
.hljs-pattern-match .hljs-constructor {
color: #61aeee;
}
.hljs-function {
color: #61aeee;
}
.hljs-function .hljs-params {
color: #A6E22E;
}
.hljs-function .hljs-params .hljs-typing {
color: #FD971F;
}
.hljs-module-access .hljs-module {
color: #7e57c2;
}
.hljs-constructor {
color: #e2b93d;
}
.hljs-constructor .hljs-string {
color: #9CCC65;
}
.hljs-comment, .hljs-quote {
color: #b18eb1;
font-style: italic;
}
.hljs-doctag, .hljs-formula {
color: #c678dd;
}
.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst {
color: #e06c75;
}
.hljs-literal {
color: #56b6c2;
}
.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string {
color: #98c379;
}
.hljs-built_in, .hljs-class .hljs-title {
color: #e6c07b;
}
.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number {
color: #d19a66;
}
.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title {
color: #61aeee;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}

View File

@@ -0,0 +1,96 @@
/*
Atom One Dark by Daniel Gamage
Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
base: #282c34
mono-1: #abb2bf
mono-2: #818896
mono-3: #5c6370
hue-1: #56b6c2
hue-2: #61aeee
hue-3: #c678dd
hue-4: #98c379
hue-5: #e06c75
hue-5-2: #be5046
hue-6: #d19a66
hue-6-2: #e6c07b
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #abb2bf;
background: #282c34;
}
.hljs-comment,
.hljs-quote {
color: #5c6370;
font-style: italic;
}
.hljs-doctag,
.hljs-keyword,
.hljs-formula {
color: #c678dd;
}
.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
color: #e06c75;
}
.hljs-literal {
color: #56b6c2;
}
.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-meta-string {
color: #98c379;
}
.hljs-built_in,
.hljs-class .hljs-title {
color: #e6c07b;
}
.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
color: #d19a66;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title {
color: #61aeee;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}

View File

@@ -0,0 +1,96 @@
/*
Atom One Light by Daniel Gamage
Original One Light Syntax theme from https://github.com/atom/one-light-syntax
base: #fafafa
mono-1: #383a42
mono-2: #686b77
mono-3: #a0a1a7
hue-1: #0184bb
hue-2: #4078f2
hue-3: #a626a4
hue-4: #50a14f
hue-5: #e45649
hue-5-2: #c91243
hue-6: #986801
hue-6-2: #c18401
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #383a42;
background: #fafafa;
}
.hljs-comment,
.hljs-quote {
color: #a0a1a7;
font-style: italic;
}
.hljs-doctag,
.hljs-keyword,
.hljs-formula {
color: #a626a4;
}
.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
color: #e45649;
}
.hljs-literal {
color: #0184bb;
}
.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-meta-string {
color: #50a14f;
}
.hljs-built_in,
.hljs-class .hljs-title {
color: #c18401;
}
.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
color: #986801;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title {
color: #4078f2;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}

64
js/styles/brown-paper.css Normal file
View File

@@ -0,0 +1,64 @@
/*
Brown Paper style from goldblog.com.ua (c) Zaripov Yura <yur4ik7@ukr.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background:#b7a68e url(./brown-papersq.png);
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal {
color:#005599;
font-weight:bold;
}
.hljs,
.hljs-subst {
color: #363c69;
}
.hljs-string,
.hljs-title,
.hljs-section,
.hljs-type,
.hljs-attribute,
.hljs-symbol,
.hljs-bullet,
.hljs-built_in,
.hljs-addition,
.hljs-variable,
.hljs-template-tag,
.hljs-template-variable,
.hljs-link,
.hljs-name {
color: #2c009f;
}
.hljs-comment,
.hljs-quote,
.hljs-meta,
.hljs-deletion {
color: #802022;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal,
.hljs-doctag,
.hljs-title,
.hljs-section,
.hljs-type,
.hljs-name,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

BIN
js/styles/brown-papersq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,60 @@
/*
codepen.io Embed Theme
Author: Justin Perry <http://github.com/ourmaninamsterdam>
Original theme - https://github.com/chriskempson/tomorrow-theme
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #222;
color: #fff;
}
.hljs-comment,
.hljs-quote {
color: #777;
}
.hljs-variable,
.hljs-template-variable,
.hljs-tag,
.hljs-regexp,
.hljs-meta,
.hljs-number,
.hljs-built_in,
.hljs-builtin-name,
.hljs-literal,
.hljs-params,
.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-deletion {
color: #ab875d;
}
.hljs-section,
.hljs-title,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-type,
.hljs-attribute {
color: #9b869b;
}
.hljs-string,
.hljs-keyword,
.hljs-selector-tag,
.hljs-addition {
color: #8f9c6c;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

View File

@@ -0,0 +1,71 @@
/*
Colorbrewer theme
Original: https://github.com/mbostock/colorbrewer-theme (c) Mike Bostock <mike@ocks.org>
Ported by Fabrício Tavares de Oliveira
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #fff;
}
.hljs,
.hljs-subst {
color: #000;
}
.hljs-string,
.hljs-meta,
.hljs-symbol,
.hljs-template-tag,
.hljs-template-variable,
.hljs-addition {
color: #756bb1;
}
.hljs-comment,
.hljs-quote {
color: #636363;
}
.hljs-number,
.hljs-regexp,
.hljs-literal,
.hljs-bullet,
.hljs-link {
color: #31a354;
}
.hljs-deletion,
.hljs-variable {
color: #88f;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-title,
.hljs-section,
.hljs-built_in,
.hljs-doctag,
.hljs-type,
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-strong {
color: #3182bd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-attribute {
color: #e6550d;
}

77
js/styles/darcula.css Normal file
View File

@@ -0,0 +1,77 @@
/*
Darcula color scheme from the JetBrains family of IDEs
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #2b2b2b;
}
.hljs {
color: #bababa;
}
.hljs-strong,
.hljs-emphasis {
color: #a8a8a2;
}
.hljs-bullet,
.hljs-quote,
.hljs-link,
.hljs-number,
.hljs-regexp,
.hljs-literal {
color: #6896ba;
}
.hljs-code,
.hljs-selector-class {
color: #a6e22e;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-section,
.hljs-attribute,
.hljs-name,
.hljs-variable {
color: #cb7832;
}
.hljs-params {
color: #b9b9b9;
}
.hljs-string {
color: #6a8759;
}
.hljs-subst,
.hljs-type,
.hljs-built_in,
.hljs-builtin-name,
.hljs-symbol,
.hljs-selector-id,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-template-tag,
.hljs-template-variable,
.hljs-addition {
color: #e0c46c;
}
.hljs-comment,
.hljs-deletion,
.hljs-meta {
color: #7f7f7f;
}

63
js/styles/dark.css Normal file
View File

@@ -0,0 +1,63 @@
/*
Dark style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #444;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal,
.hljs-section,
.hljs-link {
color: white;
}
.hljs,
.hljs-subst {
color: #ddd;
}
.hljs-string,
.hljs-title,
.hljs-name,
.hljs-type,
.hljs-attribute,
.hljs-symbol,
.hljs-bullet,
.hljs-built_in,
.hljs-addition,
.hljs-variable,
.hljs-template-tag,
.hljs-template-variable {
color: #d88;
}
.hljs-comment,
.hljs-quote,
.hljs-deletion,
.hljs-meta {
color: #777;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal,
.hljs-title,
.hljs-section,
.hljs-doctag,
.hljs-type,
.hljs-name,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

6
js/styles/darkula.css Normal file
View File

@@ -0,0 +1,6 @@
/*
Deprecated due to a typo in the name and left here for compatibility purpose only.
Please use darcula.css instead.
*/
@import url('darcula.css');

99
js/styles/default.css Normal file
View File

@@ -0,0 +1,99 @@
/*
Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #F0F0F0;
}
/* Base color: saturation 0; */
.hljs,
.hljs-subst {
color: #444;
}
.hljs-comment {
color: #888888;
}
.hljs-keyword,
.hljs-attribute,
.hljs-selector-tag,
.hljs-meta-keyword,
.hljs-doctag,
.hljs-name {
font-weight: bold;
}
/* User color: hue: 0 */
.hljs-type,
.hljs-string,
.hljs-number,
.hljs-selector-id,
.hljs-selector-class,
.hljs-quote,
.hljs-template-tag,
.hljs-deletion {
color: #880000;
}
.hljs-title,
.hljs-section {
color: #880000;
font-weight: bold;
}
.hljs-regexp,
.hljs-symbol,
.hljs-variable,
.hljs-template-variable,
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #BC6060;
}
/* Language color: hue: 90; */
.hljs-literal {
color: #78A960;
}
.hljs-built_in,
.hljs-bullet,
.hljs-code,
.hljs-addition {
color: #397300;
}
/* Meta color: hue: 200 */
.hljs-meta {
color: #1f7199;
}
.hljs-meta-string {
color: #4d99bf;
}
/* Misc effects */
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

97
js/styles/docco.css Normal file
View File

@@ -0,0 +1,97 @@
/*
Docco style used in http://jashkenas.github.com/docco/ converted by Simon Madine (@thingsinjars)
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #000;
background: #f8f8ff;
}
.hljs-comment,
.hljs-quote {
color: #408080;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal,
.hljs-subst {
color: #954121;
}
.hljs-number {
color: #40a070;
}
.hljs-string,
.hljs-doctag {
color: #219161;
}
.hljs-selector-id,
.hljs-selector-class,
.hljs-section,
.hljs-type {
color: #19469d;
}
.hljs-params {
color: #00f;
}
.hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-variable,
.hljs-template-variable {
color: #008080;
}
.hljs-regexp,
.hljs-link {
color: #b68;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

76
js/styles/dracula.css Normal file
View File

@@ -0,0 +1,76 @@
/*
Dracula Theme v1.2.0
https://github.com/zenorocha/dracula-theme
Copyright 2015, All rights reserved
Code licensed under the MIT license
http://zenorocha.mit-license.org
@author Éverton Ribeiro <nuxlli@gmail.com>
@author Zeno Rocha <hi@zenorocha.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #282a36;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal,
.hljs-section,
.hljs-link {
color: #8be9fd;
}
.hljs-function .hljs-keyword {
color: #ff79c6;
}
.hljs,
.hljs-subst {
color: #f8f8f2;
}
.hljs-string,
.hljs-title,
.hljs-name,
.hljs-type,
.hljs-attribute,
.hljs-symbol,
.hljs-bullet,
.hljs-addition,
.hljs-variable,
.hljs-template-tag,
.hljs-template-variable {
color: #f1fa8c;
}
.hljs-comment,
.hljs-quote,
.hljs-deletion,
.hljs-meta {
color: #6272a4;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal,
.hljs-title,
.hljs-section,
.hljs-doctag,
.hljs-type,
.hljs-name,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

71
js/styles/far.css Normal file
View File

@@ -0,0 +1,71 @@
/*
FAR Style (c) MajestiC <majestic2k@gmail.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #000080;
}
.hljs,
.hljs-subst {
color: #0ff;
}
.hljs-string,
.hljs-attribute,
.hljs-symbol,
.hljs-bullet,
.hljs-built_in,
.hljs-builtin-name,
.hljs-template-tag,
.hljs-template-variable,
.hljs-addition {
color: #ff0;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-section,
.hljs-type,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-variable {
color: #fff;
}
.hljs-comment,
.hljs-quote,
.hljs-doctag,
.hljs-deletion {
color: #888;
}
.hljs-number,
.hljs-regexp,
.hljs-literal,
.hljs-link {
color: #0f0;
}
.hljs-meta {
color: #008080;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-title,
.hljs-section,
.hljs-name,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

88
js/styles/foundation.css vendored Normal file
View File

@@ -0,0 +1,88 @@
/*
Description: Foundation 4 docs style for highlight.js
Author: Dan Allen <dan.j.allen@gmail.com>
Website: http://foundation.zurb.com/docs/
Version: 1.0
Date: 2013-04-02
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #eee; color: black;
}
.hljs-link,
.hljs-emphasis,
.hljs-attribute,
.hljs-addition {
color: #070;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong,
.hljs-string,
.hljs-deletion {
color: #d14;
}
.hljs-strong {
font-weight: bold;
}
.hljs-quote,
.hljs-comment {
color: #998;
font-style: italic;
}
.hljs-section,
.hljs-title {
color: #900;
}
.hljs-class .hljs-title,
.hljs-type {
color: #458;
}
.hljs-variable,
.hljs-template-variable {
color: #336699;
}
.hljs-bullet {
color: #997700;
}
.hljs-meta {
color: #3344bb;
}
.hljs-code,
.hljs-number,
.hljs-literal,
.hljs-keyword,
.hljs-selector-tag {
color: #099;
}
.hljs-regexp {
background-color: #fff0ff;
color: #880088;
}
.hljs-symbol {
color: #990073;
}
.hljs-tag,
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #007700;
}

71
js/styles/github-gist.css Normal file
View File

@@ -0,0 +1,71 @@
/**
* GitHub Gist Theme
* Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro
*/
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}

99
js/styles/github.css Normal file
View File

@@ -0,0 +1,99 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

78
js/styles/gml.css Normal file
View File

@@ -0,0 +1,78 @@
/*
GML Theme - Meseta <meseta@gmail.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: #222222;
color: #C0C0C0;
}
.hljs-keywords {
color: #FFB871;
font-weight: bold;
}
.hljs-built_in {
color: #FFB871;
}
.hljs-literal {
color: #FF8080;
}
.hljs-symbol {
color: #58E55A;
}
.hljs-comment {
color: #5B995B;
}
.hljs-string {
color: #FFFF00;
}
.hljs-number {
color: #FF8080;
}
.hljs-attribute,
.hljs-selector-tag,
.hljs-doctag,
.hljs-name,
.hljs-bullet,
.hljs-code,
.hljs-addition,
.hljs-regexp,
.hljs-variable,
.hljs-template-variable,
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-type,
.hljs-selector-id,
.hljs-selector-class,
.hljs-quote,
.hljs-template-tag,
.hljs-deletion,
.hljs-title,
.hljs-section,
.hljs-function,
.hljs-meta-keyword,
.hljs-meta,
.hljs-subst {
color: #C0C0C0;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

89
js/styles/googlecode.css Normal file
View File

@@ -0,0 +1,89 @@
/*
Google Code style (c) Aahan Krish <geekpanth3r@gmail.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
background: white;
color: black;
}
.hljs-comment,
.hljs-quote {
color: #800;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-section,
.hljs-title,
.hljs-name {
color: #008;
}
.hljs-variable,
.hljs-template-variable {
color: #660;
}
.hljs-string,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-regexp {
color: #080;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-meta,
.hljs-number,
.hljs-link {
color: #066;
}
.hljs-title,
.hljs-doctag,
.hljs-type,
.hljs-attr,
.hljs-built_in,
.hljs-builtin-name,
.hljs-params {
color: #606;
}
.hljs-attribute,
.hljs-subst {
color: #000;
}
.hljs-formula {
background-color: #eee;
font-style: italic;
}
.hljs-selector-id,
.hljs-selector-class {
color: #9B703F
}
.hljs-addition {
background-color: #baeeba;
}
.hljs-deletion {
background-color: #ffc8bd;
}
.hljs-doctag,
.hljs-strong {
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
}

101
js/styles/grayscale.css Normal file
View File

@@ -0,0 +1,101 @@
/*
grayscale style (c) MY Sun <simonmysun@gmail.com>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #fff;
}
.hljs-comment,
.hljs-quote {
color: #777;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal {
color: #777;
}
.hljs-string,
.hljs-doctag,
.hljs-formula {
color: #333;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAJ0lEQVQIW2O8e/fufwYGBgZBQUEQxcCIIfDu3Tuwivfv30NUoAsAALHpFMMLqZlPAAAAAElFTkSuQmCC) repeat;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #000;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-class .hljs-title,
.hljs-type,
.hljs-name {
color: #333;
font-weight: bold;
}
.hljs-tag {
color: #333;
}
.hljs-regexp {
color: #333;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==) repeat;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link {
color: #000;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAKElEQVQIW2NkQAO7d+/+z4gsBhJwdXVlhAvCBECKwIIwAbhKZBUwBQA6hBpm5efZsgAAAABJRU5ErkJggg==) repeat;
}
.hljs-built_in,
.hljs-builtin-name {
color: #000;
text-decoration: underline;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
color: #fff;
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==) repeat;
}
.hljs-addition {
color: #000;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAALUlEQVQYV2N89+7dfwYk8P79ewZBQUFkIQZGOiu6e/cuiptQHAPl0NtNxAQBAM97Oejj3Dg7AAAAAElFTkSuQmCC) repeat;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

Some files were not shown because too many files have changed in this diff Show More