scratch

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 120  →  ?path2? @ 121
File deleted
/gallery.php
File deleted
/gallery.html
/draw.html
@@ -45,7 +45,7 @@
<li><a href="text.html">Text</a></li>
<li class="active"><a href="#">Draw</a></li>
<li><a href="link.html">Link</a></li>
<li><a href="gallery.html">Gallery</a></li>
<li><a href="view.html">View</a></li>
</ul>
<div id="main-panel" class="panel panel-default">
/file.html
@@ -43,7 +43,7 @@
<li><a href="text.html">Text</a></li>
<li><a href="draw.html">Draw</a></li>
<li><a href="link.html">Link</a></li>
<li><a href="gallery.html">Gallery</a></li>
<li><a href="view.html">View</a></li>
</ul>
<div id="main-panel" class="panel panel-default">
/index.html
@@ -44,22 +44,15 @@
<li><a href="text.html">Text</a></li>
<li><a href="draw.html">Draw</a></li>
<li><a href="link.html">Link</a></li>
<li><a href="gallery.html">Gallery</a></li>
<li><a href="view.html">View</a></li>
</ul>
<div class="row">
<h2>About</h2>
<p><strong>scratch copy</strong> is a platform for small-sized asset sharing developed by <a href="http://grimore.org">Wizardry and Steamworks</a> and published under the <a href="https://creativecommons.org/publicdomain/zero/1.0/">Creative Commons CC 1.0 Universal (CC0 1.0)</a> license. The sharing platform covers images, text snippets, movie clips and any sort of media that can be conveniently shared by generating short, public and obfuscated URLs that are easily accessible.</p>
<!-- <p><a class="btn btn-default" href="#" role="button">View details &raquo;</a></p> -->
</div>
<div class="row" ng-app="scratch" ng-controller="scratch-control">
<!-- <h2>Configuration</h2>
<p>The <strong>scratch copy</strong> platform can be configured for each usage case. This section is meant to hint to the users what configuration is currently active and specifies the configured lmits and allowances.</p>
<h3>Allowed Files</h3>
<p>The file extensions <span ng-repeat="extension in extensions" id="box">{{extension}}, </span> are currently accepted for uploading.</p>
<h3>Upload Limits</h3>
<p>The current upload limit is set to {{uploadlimit}}MiB.</p> -->
<h2>Configuration</h2>
<div class="panel panel-default">
<!-- Default panel contents -->
/link.html
@@ -43,7 +43,7 @@
<li><a href="text.html">Text</a></li>
<li><a href="draw.html">Draw</a></li>
<li class="active"><a href="#">Link</a></li>
<li><a href="gallery.html">Gallery</a></li>
<li><a href="view.html">View</a></li>
</ul>
<div id="main-panel" class="panel panel-default">
/text.html
@@ -45,7 +45,7 @@
<li class="active"><a href="#">Text</a></li>
<li><a href="draw.html">Draw</a></li>
<li><a href="link.html">Link</a></li>
<li><a href="gallery.html">Gallery</a></li>
<li><a href="view.html">View</a></li>
</ul>
<div id="main-panel" class="panel panel-default">
/view.html
@@ -0,0 +1,258 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="quick asset upload">
<meta name="author" content="Wizardry and Steamworks">
<link rel="icon" href="favicon.ico">
 
<title>scratch</title>
 
<!-- Bootstrap core CSS -->
<link href="bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- blueimp gallery -->
<link rel="stylesheet" href="bower_components/blueimp-gallery/css/blueimp-gallery.min.css">
<!-- Swiper -->
<link rel="stylesheet" href="bower_components/swiper/dist/css/swiper.min.css">
 
<!-- Site-wide style CCS -->
<link href="css/style.css" rel="stylesheet">
<!-- Local style -->
<link href="css/gallery/style.css" rel="stylesheet">
</head>
 
<body>
 
<!-- Main component for a primary marketing message or call to action -->
<div class="paralax-background"></div>
<div class="jumbotron">
<h1>scratch copy</h1>
<p class="quote">the asset sharer</p>
</div>
 
<div class="container">
<ul class="nav nav-tabs">
<li><a href="index.html">Home</a></li>
<li><a href="file.html">File</a></li>
<li><a href="text.html">Text</a></li>
<li><a href="draw.html">Draw</a></li>
<li><a href="link.html">Link</a></li>
<li class="active"><a href="#">View</a></li>
</ul>
<div id="main-panel" class="panel panel-default">
<div class="panel-body">
<div class="input-group">
<input id="URL" type="text" class="form-control" readonly>
<span class="input-group-btn">
<button id="copy-url" class="btn btn-default" type="button" data-clipboard-target="#URL" data-toggle="tooltip" data-placement="auto" title="Copy to clipboard."><i class="glyphicon glyphicon-paperclip"></i></button>
</span>
<span class="input-group-btn">
<button id="btn-facebook" class="btn btn-default" type="button" disabled><i class="fa fa-facebook"></i></button>
</span>
</div>
<!-- The Gallery as inline carousel, can be positioned anywhere on the page -->
<div id="blueimp-gallery-carousel" class="blueimp-gallery blueimp-gallery-carousel">
<div class="slides"></div>
<h3 class="title"></h3>
<a class="prev">‹</a>
<a class="next">›</a>
<a class="play-pause"></a>
<!-- <ol class="indicator"></ol> -->
</div>
<div class="swiper-container">
<div id="links" class="swiper-wrapper">
</div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
</div>
</div>
</div> <!-- /container -->
<div id="footer">
<div class="container">
<p class="text-muted credit text-center">Copyright <i class="glyphicon glyphicon-copyright-mark"></i> 2017 <a href="http://grimore.org">Wizardry and Steamworks</a>.</p>
</div>
</div>
 
<!-- jQuery -->
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<!-- BootStrap -->
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<!-- Bootstrap Validator -->
<script src="bower_components/bootstrap-validator/dist/validator.min.js"></script>
<!-- blueimp-gallery -->
<script src="bower_components/blueimp-gallery/js/blueimp-gallery.min.js"></script>
<!-- Clipboard -->
<script src="bower_components/clipboard/dist/clipboard.min.js"></script>
<!-- YAML -->
<script src="bower_components/yaml.js/dist/yaml.min.js"></script>
<!-- Swiper -->
<script src="bower_components/swiper/dist/js/swiper.min.js"></script>
<!-- Wizardry and Steamworks -->
<script src="bower_components/was/dist/was.min.js"></script>
<script>
$(document).ready(() => {
// Extend gallery for HTML.
blueimp.Gallery.prototype.textFactory = function (obj, callback) {
var $element = $('<div>')
.addClass('text-content')
.attr('title', obj.title);
$.get(obj.href, {
timestamp: window.performance.now()
}).done(function (result) {
$element.html(result);
callback({
type: 'load',
target: $element[0]
});
})
.fail(function () {
callback({
type: 'error',
target: $element[0]
});
});
return $element[0];
};
$.getJSON('gallery.php', {
timestamp: window.performance.now()
}).then((data) => {
// Create slides.
var indexPage = 0;
data.chunk(50).forEach((page) => {
document.getElementById('links')
.insertAdjacentHTML(
'beforeend',
'<div id="swiper-slide-' + indexPage + '" class="swiper-slide"></div>'
);
page.forEach((link) => {
// Generic icon for text / html items.
switch(link.type) {
case 'text/plain':
link.preview ='img/text.png';
break;
}
document.getElementById('swiper-slide-' + indexPage)
.insertAdjacentHTML(
'beforeend',
'<a href="' +
link.url +
'" type="' +
link.type +
'"><img src="' +
link.preview +
'" width="60" height="40"></a>'
);
});
++indexPage;
});
// Initialize gallery.
document.getElementById('links').onclick = function (event) {
event = event || window.event;
var target = event.target || event.srcElement,
link = target.src ? target.parentNode : target,
options = {
index: link,
event: event,
carousel: true,
container: '#blueimp-gallery-carousel',
stretchImages: true,
startSlideshow: false,
onslideend: function(index, slide) {
// Set the URL.
$('#URL').val(
location.protocol
.concat("//")
.concat(window.location.hostname)
.concat("/").concat(data[index].url)
);
// Check if OpenGraph should be enabled.
switch(data[index].opengraph) {
case true:
// Enable the facebook button.
$('#btn-facebook')
.prop("disabled", false);
break;
default:
// Disable the facebook button.
$('#btn-facebook')
.prop("disabled", true);
break;
}
// Change the URL to OpenGraph when the user clicks the button.
$('#btn-facebook').on('click', () => {
$('#URL')
.val(
location.protocol.concat("//")
.concat(window.location.hostname)
.concat("/")
.concat("og")
.concat("/")
.concat(data[index].url)
);
});
}
},
links = this.getElementsByTagName('a');
blueimp.Gallery(links, options);
};
new Swiper ('.swiper-container', {
// Optional parameters
direction: 'horizontal',
// Creates duplicate element IDs if set to true.
loop: false,
// If we need pagination
//pagination: '.swiper-pagination',
// Navigation arrows
nextButton: '.swiper-button-next',
prevButton: '.swiper-button-prev',
// And if we need scrollbar
//scrollbar: '.swiper-scrollbar',
});
// Enable the Clipboard button.
new Clipboard('#copy-url');
});
});
</script>
<!-- Jumbotron parallax effect -->
<script>
var jumboHeight = $('.jumbotron').outerHeight();
function parallax(){
var scrolled = $(window).scrollTop();
$('.paralax-background').css('height', (jumboHeight-scrolled) + 'px');
}
 
$(window).scroll(function(e){
parallax();
});
</script>
</body>
</html>
/view.php
@@ -0,0 +1,131 @@
<?php
 
###########################################################################
## Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 ##
###########################################################################
 
require_once('php/pseudocrypt.php');
require_once('php/functions.php');
require_once('vendor/autoload.php');
require_once('vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/FFMpeg.php');
 
### Load configuration.
$config = spyc_load_file('config.yaml');
 
### Open MIME.
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (!$finfo) {
http_response_code(500);
die('Internal server error.');
}
 
echo json_encode(
array_values(
array_filter(
array_map(
function ($file) use ($config, $finfo) {
#### Get the file hash.
$fileHash = array_shift(explode('.', $file));
#### Build the user path.
$userPath = join(
DIRECTORY_SEPARATOR,
array(
$config['STORE_FOLDER'],
$file
)
);
#### If the extension is not allowed then skip this file.
$fileExtension = pathinfo($userPath, PATHINFO_EXTENSION);
if (!isset($fileExtension) ||
!in_array(strtoupper($fileExtension),
array_map('strtoupper', $config['ALLOWED_FILE_EXTENSIONS'])))
return null;
#### Hook for various file extensions.
$opengraph = FALSE;
switch (strtoupper($fileExtension)) {
case "MP4":
### Generate a hash for the preview image.
$previewHash = strtolower(
PseudoCrypt::hash(
preg_replace(
'/\D/',
'',
hash(
'sha512',
$fileHash
)
),
$config['ASSET_HASH_SIZE']
)
);
### Build the user path.
$previewFile = join(
DIRECTORY_SEPARATOR,
array(
$config['STORE_FOLDER'],
$previewHash
)
);
### Do not re-create the thumbnail if it already exists.
if (file_exists($previewFile.'.'.'jpg')) {
break;
}
### Extract thumbnail.
$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open($userPath);
$frame = $video->frame(
FFMpeg\Coordinate\TimeCode::fromSeconds(
$config['VIDEO_PREVIEW_IMAGE_FRAME_SECOND']
)
);
$frame->save($previewFile.'.'.'jpg');
$opengraph = TRUE;
break;
case "GIF":
$opengraph = TRUE;
case "PNG":
case "HTML":
case "HTM":
case "TGA":
case "SVG":
case "JPEG":
case "JPG":
$previewHash = $fileHash;
break;
default:
return null;
}
return array(
'url' => $fileHash,
'type' => finfo_file($finfo, $userPath),
'preview' => $previewHash,
'opengraph' => $opengraph
);
},
array_values(
array_filter(scandir($config['STORE_FOLDER']),
function ($entry) use ($config) {
return !is_dir($entry) && filesize(
join(
DIRECTORY_SEPARATOR,
array(
$config['STORE_FOLDER'],
$entry
)
)
);
}
)
)
)
)
)
);
 
finfo_close($finfo);