Commit a91ac4c7 authored by Andreas Mieke's avatar Andreas Mieke 🚂

Added /by_format/:format route, added subtype guessing by content-type and...

Added /by_format/:format route, added subtype guessing by content-type and added a HTML5 player for formats play-able in the different browsers (not final yet)
parent 67f78c24
......@@ -14,6 +14,7 @@ var config = conf('config');
/* Controllers */
var index = require('./controllers/index.js')(query, cache);
var genres = require('./controllers/genres.js')(query, cache);
var formats = require('./controllers/formats.js')(query, cache);
var yp_cgi = require('./controllers/yp-cgi.js')(query, qs);
query.connectionParameters = config.db;
......@@ -33,6 +34,7 @@ app.set('views', __dirname + '/views');
/* Routes */
app.get('/', index);
app.get('/by_genre/:genre', genres);
app.get('/by_format/:format', formats);
app.post('/cgi-bin/yp-cgi', yp_cgi);
var server = app.listen(3000, function() {
......
/* Padding for bottom navbar */
body { padding-bottom: 70px; }
\ No newline at end of file
/* Adaptations on the Xiph.org default CSS */
#content {
padding-left: 3em;
}
#navbar {
width: 150px;
}
#navbar h3 {
font-size: 0.9em;
}
#content {
margin-left: 160px;
}
h2 {
font-size: 1.5em;
}
#thepage {
width: 90%;
}
/* Top logo */
#xiphlogo {
background: transparent url('/assets/images/logo-dirxiphorg.png') no-repeat scroll top left;
}
#xiphlogo h1 a {
display: block;
text-indent: -9999px;
height: 75px;
width: 514px;
}
/* Search box */
#sidebar-search label {
display: none;
}
#search {
width: 100px;
}
/* Tag cloud */
.tag-cloud li {
display: inline;
}
.tag-cloud .context {
position: absolute;
left: -999px;
width: 990px;
}
.tag-cloud .popularity-0 { font-size: 0.7em !important; }
.tag-cloud .popularity-1 { font-size: 0.9em !important; }
.tag-cloud .popularity-2 { font-size: 1.1em !important; }
.tag-cloud .popularity-3 { font-size: 1.3em !important; }
.tag-cloud .popularity-4 { font-size: 1.4em !important; }
.tag-cloud .popularity-5 { font-size: 1.5em !important; }
.tag-cloud .popularity-2 a, .tag-cloud .popularity-3 a,
.tag-cloud .popularity-4 a, .tag-cloud .popularity-5 a {
font-weight: normal !important;
}
/* Servers list */
table.servers-list {
list-style-type: none;
margin: 0;
padding: 0;
width: 100%;
}
table.servers-list tr {
border-bottom: 1px dashed #F33;
margin-bottom: 0.3em;
min-height: 80px;
}
table.servers-list tr p {
margin: 0;
padding: 0;
}
table.servers-list tr td {
border-bottom: 1px solid #9FC0D7;
}
table.servers-list td.rank {
font-family: Palatino, Palatino Linotype, Georgia, Times New Roman, serif;
font-weight: bold;
font-style: italic;
color: #999;
font-size: 3em;
padding-right: 0.3em;
text-align: right;
vertical-align: top;
}
table.servers-list td.description {
}
table.servers-list span.name {
font-size: 1.3em;
font-weight: bold;
}
table.servers-list span.listeners {
font-variant: small-caps;
}
table.servers-list p.stream-description {
margin: 0.5em 0 0.4em;
}
table.servers-list p.stream-onair {
font-style: italic;
font-size: 0.9em;
}
table.servers-list p.stream-onair strong {
font-weight: bold;
font-style: normal;
}
table.servers-list div.stream-tags {
font-size: 0.9em;
}
table.servers-list div.stream-tags ul {
display: inline;
}
table.servers-list td.tune-in {
width: 20%;
text-align: center;
vertical-align: top;
}
table.servers-list td.tune-in a.tune-in-button {
border: 1px solid #C33;
background-color: #F33;
color: #FFF;
font-weight: bold;
padding: 0.5em;
display: block;
text-align: center;
margin: 1em 0.5em 0 0.5em;
}
table.servers-list td.tune-in a.tune-in-button:hover {
background-color: #FEE;
color: #000;
}
table.servers-list td.tune-in a.tune-in-button img {
margin-bottom: -0.3em;
}
table.servers-list td.tune-in p.format {
font-size: 0.9em;
}
table.servers-list td.tune-in p.format span.stream {
position: absolute;
left: -999px;
width: 990px;
}
.no-link {
color: #333;
text-decoration: none;
}
/* Tag list */
.inline-tags {
list-style-type: none;
padding: 0;
margin: 0;
}
.inline-tags li {
display: inline;
}
/* Pager */
.pager {
list-style-type: none;
padding: 0;
margin: 0;
}
.pager li {
display: inline;
}
.pager li a.active {
font-weight: bold;
}
var mediaElement = jQuery("#player").get(0);
var nowPlaying = jQuery("#nowplaying");
jQuery(".streamentry").html(function() {
if (mediaElement.canPlayType(jQuery(this).data("contenttype"))) {
jQuery(this).html('<button class="btn btn-default pull-right playbutton">\
<i class="glyphicon glyphicon-play"></i></button>');
}
});
jQuery(".playbutton").click(function() {
if (!mediaElement.paused) {
mediaElement.pause();
}
mediaElement.src=jQuery(this).parent().data("listenurl");
mediaElement.play();
nowPlaying.html("<strong>Now playing:</strong> " + jQuery(this).parent().data("streamname"));
});
jQuery(".stopbutton").click(function() {
if (!mediaElement.paused) {
mediaElement.pause();
mediaElement.src='';
nowPlaying.html("<strong>No playback</strong>");
}
});
\ No newline at end of file
var query, cache;
function init(q, c) {
query = q;
cache = c;
return byFormat;
}
function byFormat(req, res) {
getCachedFormatStreams(req.param("format"), function(err, result) {
if (err) {
res.send(503);
} else {
var error;
if (result.rowCount === 0) {
error = "No streams for this format.";
} else {
error = false;
}
res.render("by_xx", {
title: req.param("format"),
servers: result.rows,
error: error
});
}
});
}
function getCachedFormatStreams(format, cb) {
cache.wrap(format, function (_cb) {
getFormatStreams(format, _cb);
}, 5, cb);
}
function getFormatStreams(format, cb) {
query("SELECT id, server_name, server_type, genres, bitrate, listenurl, description, url, \
codec_sub_types, songname, listeners FROM servers WHERE $1 = ANY (codec_sub_types);", [format],
function(err, rows, result) {
cb(err, result);
});
}
module.exports = init;
\ No newline at end of file
......@@ -17,7 +17,7 @@ function byGenre(req, res) {
} else {
error = false;
}
res.render("by_genre", {
res.render("by_xx", {
title: req.param("genre"),
servers: result.rows,
error: error
......
......@@ -47,14 +47,25 @@ function ypAdd(req, res) {
function ypTouch(req, res) {
var final = parseBody(req.body);
var touch = "UPDATE servers SET lasttouch = now(), songname = $2, listeners = $3, max_listeners = $4, codec_sub_types = $5 WHERE id = $1;";
query(touch, [final.id, final.songname, final.listeners, final.max_listeners, final.codec_sub_types], function(err, row, result) {
if (err || result.rowCount === 0) {
ypRes(res, false, "Could not find database entry", null, null);
} else {
ypRes(res, true, "Scucessfully touched", null, null);
}
});
if (final.codec_sub_types) {
var touch = "UPDATE servers SET lasttouch = now(), songname = $2, listeners = $3, max_listeners = $4, codec_sub_types = $5 WHERE id = $1;";
query(touch, [final.id, final.songname, final.listeners, final.max_listeners, final.codec_sub_types], function(err, row, result) {
if (err || result.rowCount === 0) {
ypRes(res, false, "Could not find database entry", null, null);
} else {
ypRes(res, true, "Scucessfully touched", null, null);
}
});
} else {
var touch = "UPDATE servers SET lasttouch = now(), songname = $2, listeners = $3, max_listeners = $4 WHERE id = $1;";
query(touch, [final.id, final.songname, final.listeners, final.max_listeners], function(err, row, result) {
if (err || result.rowCount === 0) {
ypRes(res, false, "Could not find database entry", null, null);
} else {
ypRes(res, true, "Scucessfully touched", null, null);
}
});
}
}
function ypRemove(req, res) {
......@@ -145,6 +156,12 @@ function parseBody(body) {
}
if (body.type) {
final.server_type = body.type;
if (!body.stype) {
var buff = generateSubType(body.type);
if (buff !== null) {
final.codec_sub_types = buff.split(' ');
}
}
}
if (body.genre) {
final.genres = body.genre.split(' ');
......@@ -178,4 +195,36 @@ function parseBody(body) {
return final;
}
function generateSubType(type) {
var stype;
if (type === 'audio/opus') {
stype = 'Opus';
}
else if (type === 'audio/ogg' || type === 'application/ogg') {
stype = 'Vorbis';
}
else if (type === 'audio/mpeg' || type === 'audio/MPA' || type === 'audio/mpa-robust') {
stype = 'MP3';
}
else if (type === 'audio/aac' || type === 'audio/mp4') {
stype = 'AAC';
}
else if (type === 'audio/aacp') {
stype = 'AAC+';
}
else if (type === 'video/webm') {
stype = 'WebM';
}
else if (type === 'video/ogg') {
stype = 'Theora';
}
else if (type === 'video/nsv') {
stype = 'NSV';
}
else {
stype = null;
}
return stype;
}
module.exports = init;
\ No newline at end of file
......@@ -8,11 +8,12 @@
<link rel="icon" href="http://www.icecast.org/favicon.ico" type="image/x-icon"/>
<link rel="shortcut icon" href="http://www.icecast.org/favicon.ico" type="image/x-icon"/>
<link rel="stylesheet" href="/assets/css/bootstrap.min.css" type="text/css" />
<!--<link rel="stylesheet" href="/assets/css/bootstrap-theme.min.css" type="text/css" /> -->
<link rel="stylesheet" href="/assets/css/style-additions.css" type="text/css" />
<script src="/assets/js/jquery-2.1.1.min.js"></script>
<script src="/assets/js/bootstrap.min.js"></script>
</head>
<body>
<audio id="player" preload="auto"></audio>
<!-- <div id="xiphbar_outer">
<table id="xiphbar" border="0" cellpadding="0" cellspacing="0">
<tr>
......@@ -90,6 +91,20 @@
</div>
</div>
</div>
<nav id="playbar" class="navbar navbar-default navbar-fixed-bottom hidden-xs">
<div class="container-fluid">
<div class="row">
<div class="col-sm-11">
<p class="navbar-text" id="nowplaying"><strong>No playback</strong></p>
</div>
<div class="col-sm-1">
<button class="btn btn-default pull-right stopbutton">
<i class="glyphicon glyphicon-stop"></i>
</button>
</div>
</div>
</div>
</nav>
<!-- Oldcode -->
<!-- <div id="thepage">
<div id="navbar">
......@@ -155,5 +170,6 @@
pageTracker._trackPageview();
</script>
<!-- /GAU -->
<script src="/assets/js/player.js"></script>
</body>
</html>
\ No newline at end of file
......@@ -13,9 +13,7 @@
<small>{{ server.listeners }}&nbsp;Listeners</small></h4>
{% endif %}
</div>
<div class="col-sm-1 hidden-xs" style="padding-left: 0">
<a href="#" class="btn btn-default pull-right"><i class="glyphicon glyphicon-play"></i></a>
</div>
<div class="col-sm-1 hidden-xs streamentry" style="padding-left: 0" data-contenttype="{{ server.server_type }}" data-listenurl="{{ server.listenurl }}" data-streamname="{{ server.server_name }}"></div>
</div>
<p class="description">{{ server.description }}</p>
{% if !server.songname %} {% set server.songname = "Unknown" %} {% endif %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment