mirror of
https://github.com/KevinMidboe/zoff.git
synced 2025-10-29 09:50:24 +00:00
Moved to more partials
This commit is contained in:
18
package.json
18
package.json
@@ -11,15 +11,14 @@
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zoff-music/zoff.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/zoff-music/zoff/issues"
|
||||
},
|
||||
"author": {
|
||||
"name": "Kasper Rynning Tønnesen",
|
||||
"email": "kasper@kasperrt.no"
|
||||
},
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/zoff-music/zoff/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp-util": "~3.0.6",
|
||||
"gulp": "~3.9.0",
|
||||
@@ -28,10 +27,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/zoff-music/zoff#readme",
|
||||
"dependencies": {
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-uglifyjs": "^0.6.2",
|
||||
"gulp-util": "^3.0.8",
|
||||
"bad-words": "^1.5.1",
|
||||
"body-parser": "^1.17.1",
|
||||
"cookie-parser": "^1.4.3",
|
||||
@@ -40,7 +35,12 @@
|
||||
"express": "^4.15.2",
|
||||
"express-handlebars": "^3.0.0",
|
||||
"express-subdomain": "^1.0.5",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-uglifyjs": "^0.6.2",
|
||||
"gulp-util": "^3.0.8",
|
||||
"jimp": "^0.2.27",
|
||||
"mobile-detect": "^1.3.7",
|
||||
"mongodb": "^2.0.27",
|
||||
"mongojs": "^2.4.0",
|
||||
"node-cryptojs-aes": "^0.4.0",
|
||||
|
||||
@@ -1,322 +1,14 @@
|
||||
<div id="main-container" class="channelpage noselect cursor-default">
|
||||
<header>
|
||||
<div class="navbar-fixed">
|
||||
<nav id="nav">
|
||||
<div class="nav-wrapper">
|
||||
|
||||
<div class="brand-logo truncate zbrand">
|
||||
<a href="/" class="brand-logo brand-logo-navigate">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
|
||||
<span id="chan" class="chan clickable truncate" title="Show big URL">{{list_name}}</span>
|
||||
</div>
|
||||
|
||||
<ul class="title-container">
|
||||
<li class="song-title cursor-pointer truncate" id="song-title">
|
||||
Loading...
|
||||
</li>
|
||||
<li class="search-container hide" id="search-wrapper">
|
||||
<input id="search" class="search_input" type="text" title="Search for songs..." placeholder="Find song on YouTube..." onsubmit="null;" autocomplete="off" />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="right control-list noselect">
|
||||
<li id="search_loader" class="valign-wrapper">
|
||||
<div id="search_loader_inner">
|
||||
<div class="preloader-wrapper small search_loader_spinner">
|
||||
<div class="spinner-layer spinner-white-only">
|
||||
<div class="circle-clipper left">
|
||||
<div class="circle"></div>
|
||||
</div><div class="gap-patch">
|
||||
<div class="circle"></div>
|
||||
</div><div class="circle-clipper right">
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-btn" href="#find" id="search-btn">
|
||||
<i class="material-icons">search</i>
|
||||
<!--<span class="hover-text">Find</span>-->
|
||||
</a>
|
||||
</li>
|
||||
<!--<li>
|
||||
<a class="nav-btn prev" href="#prev">
|
||||
<i class="material-icons">skip_previous</i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-btn skip" href="#skip">
|
||||
<i class="material-icons">skip_next</i>
|
||||
<span class="hover-text">Skip</span>
|
||||
</a>
|
||||
</li>-->
|
||||
<li>
|
||||
<a class="nav-btn" href="#stir" id="shuffle">
|
||||
<i class="material-icons">shuffle</i>
|
||||
<!--<span class="hover-text">Stir</span>-->
|
||||
</a>
|
||||
</li>
|
||||
<li class="settings-hamburger" data-activates="settings-bar" id="settings">
|
||||
<!--<a class="nav-btn" href="#settings" data-activates="settings-bar" id="settings">
|
||||
<i class="material-icons">menu</i>
|
||||
</a>-->
|
||||
<div class="hamburger-sidenav">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="side-nav" id="settings-bar">
|
||||
{{> panel}}
|
||||
</ul>
|
||||
<div id="results" class="search_results hide">
|
||||
<div id="temp-results-container">
|
||||
<div id="temp-results" class="result-object">
|
||||
<div id="result" class="result">
|
||||
<img class="thumb" src="/assets/images/loading.png" alt="Thumb"/>
|
||||
|
||||
<div class="search-title truncate"></div>
|
||||
<span class="result_info"></span>
|
||||
<div class="waves-effect waves-orange btn-flat" id="add-many" title="Add several videos">
|
||||
<i class="material-icons">playlist_add</i>
|
||||
</div>
|
||||
<a href="#" target="_blank" class="waves-effect waves-orange btn-flat open-externally" title="Open on YouTube">
|
||||
<i class="material-icons">open_in_new</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="empty-results-container">
|
||||
<div id="empty-results" class="valign-wrapper">
|
||||
<span class="valign">No results found..</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div id="user_password" class="modal">
|
||||
<div class="modal-content">
|
||||
<h5>Locked Channel</h5>
|
||||
<form id="user-password-channel-form">
|
||||
<div class="input-field">
|
||||
<input id="user-pass-input" name="user-pass" type="password" autocomplete="off" />
|
||||
<label for="user-pass-input" class="noselect">Password</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat close-user-password">Close</a>
|
||||
<a href="#!" class="waves-effect waves-green btn-flat submit-user-password">Submit</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="delete_song_alert" class="modal">
|
||||
<div class="modal-content">
|
||||
<h5>Delete song</h5>
|
||||
<p>Are you sure you want to delete <span id="delete_song_title"></span>?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="waves-effect waves-red btn-flat accept-delete right red-text">Delete</a>
|
||||
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat cancel-song-delete">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="help" class="modal modal-fixed-footer">
|
||||
<div class="modal-content">
|
||||
<h4>Help</h4>
|
||||
<p>When listening on a channel, there are some different buttons you can click.</p>
|
||||
<p>If you click the <i class="material-icons">menu</i>, you'll open the settings panel. Here you can change channel settings, decide if you want the computer you're on can be remote-controlled, enable or disable local mode, and import playlists from YouTube.</p>
|
||||
<p>The <i class="material-icons">search</i>, opens up a search inputfield. If you start typing here, the site will automagically search for your input!</p>
|
||||
<p>If you click the button next to the search icon <i class="material-icons">skip_next</i>, you'll skip on a song. The one next to that one <i class="material-icons">shuffle</i>, is shuffling of the list.</p>
|
||||
<p>Clicking a song in the playlist, gives it a vote. If you're logged in, you'll have a delete button at your disposal.</p>
|
||||
<p>Also, whenever you're logged in, you'll have three tabs in the top of the playlist thats called "Playlist", "Suggested" and "Chat". The playlist obviously shows the playlist. But the suggested tab, shows 5 songs that YouTube recommends based on the current song. There might also be user recommended songs. To add any of these, just click them as you'd click a song to vote.</p>
|
||||
<p>If you want to listen to the channel without any "hickups", or being affected by other peoples votes, there is a local mode. By opening up the settings <i class="material-icons">menu</i>, and checking the local mode checkbox, you will be free of synced listening! This will also enable seeking in the current playing video, perfect for those songs you only like a part of!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="embed" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Embed</h4>
|
||||
<p>Copy the code in the textarea, and paste on your website.</p>
|
||||
<p>
|
||||
<input type="checkbox" id="autoplay" checked="checked" />
|
||||
<label for="autoplay" class="padding_right_26">Autoplay</label>
|
||||
<label for="width_embed" class="embed-label">Width</label>
|
||||
<input type="number" value="600" id="width_embed" class="settings_embed" min="1" />
|
||||
<label for="height_embed" class="padding_left_6 embed-label">Height</label>
|
||||
<input type="number" value="300" id="height_embed" class="settings_embed" min="1" />
|
||||
<label for="color_embed" class="padding_left_6 embed-label">Color</label>
|
||||
<input type="color" id="color_embed" class="settings_embed" value="#808080" />
|
||||
</p>
|
||||
<textarea id="embed-area"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
{{> channel/header}}
|
||||
<div id="channel-load" class="progress">
|
||||
<div class="indeterminate" id="channel-load-move"></div>
|
||||
</div>
|
||||
<main class="container center-align main">
|
||||
<div id="main-row" class="row">
|
||||
<div id="video-container" class="col s12 m9 video-container no-opacity click-through">
|
||||
<!--
|
||||
width: calc(100% - 261px);
|
||||
display: inline;
|
||||
-->
|
||||
<div id="fireplace_player" class="ytplayer"></div>
|
||||
<div id="player" class="ytplayer"></div>
|
||||
<div id="main_components">
|
||||
<div id="player_overlay" class="hide valign-wrapper">
|
||||
<div id="playing_on"><div id="chromecast_icon">
|
||||
<i class="material-icons">cast</i>
|
||||
</div>
|
||||
<div id="chromecast_text"></div>
|
||||
</div>
|
||||
<div id="player_overlay_text" class="valign center-align">
|
||||
Waiting for Video
|
||||
</div>
|
||||
<div id="player_overlay_controls" class="hide valign-wrapper">
|
||||
<div id="playpause-overlay" class="valign center-align">
|
||||
<i id="play-overlay" class="material-icons hide">play_arrow</i>
|
||||
<i id="pause-overlay" class="material-icons">pause</i>
|
||||
</div>
|
||||
<div id="volume-button-overlay">
|
||||
<i id="v-mute-overlay" class="material-icons">volume_off</i>
|
||||
<i id="v-low-overlay" class="material-icons">volume_mute</i>
|
||||
<i id="v-medium-overlay" class="material-icons">volume_down</i>
|
||||
<i id="v-full-overlay" class="material-icons">volume_up</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="controls" class="noselect">
|
||||
<div class="playbar-btn prev playbar hide">
|
||||
<i class="material-icons">skip_previous</i>
|
||||
</div>
|
||||
<div id="playpause" class="playbar-btn margin-playbar">
|
||||
<i id="play" class="material-icons hide">play_arrow</i>
|
||||
<i id="pause" class="material-icons">pause</i>
|
||||
</div>
|
||||
<div class="playbar-btn skip playbar">
|
||||
<i class="material-icons">skip_next</i>
|
||||
</div>
|
||||
<div id="duration"></div>
|
||||
<div id="fullscreen" class="hide-on-small-only playbar-btn">
|
||||
<i class="material-icons">fullscreen</i>
|
||||
</div>
|
||||
<button class="castButton playbar-btn" id="castButton" is="google-cast-button">
|
||||
</button>
|
||||
<div id="volume-button" class="playbar-btn">
|
||||
<i id="v-mute" class="material-icons">volume_off</i>
|
||||
<i id="v-low" class="material-icons">volume_mute</i>
|
||||
<i id="v-medium" class="material-icons">volume_down</i>
|
||||
<i id="v-full" class="material-icons">volume_up</i>
|
||||
</div>
|
||||
<div class="volume-container">
|
||||
<div id="volume"></div>
|
||||
</div>
|
||||
<div id="viewers" data-position="top"></div>
|
||||
<div id="bar"></div>
|
||||
</div>
|
||||
{{> channel/players}}
|
||||
{{> channel/tabs}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="playlist" class="col s12 m3">
|
||||
<!--<div id="top-button" title="Scroll to the top" class="rounded-bottom hide top-button-with-tabs hide-on-small-only">Top</div>
|
||||
<div id="bottom-button" title="Scroll to the bottom" class="rounded-top hide hide-on-small-only">Bottom</div>
|
||||
--><ul class="tabs playlist-tabs tabs-fixed-width" style="width:96%">
|
||||
<li class="tab col s3"><a class="playlist-tab-links playlist-link active truncate" href="#wrapper">Playlist</a></li>
|
||||
<li class="tab col s3"><a class="playlist-tab-links chat-link truncate" href="#chat">Chat<span class="new badge white hide"></span></a></li>
|
||||
</ul>
|
||||
<ul class="tabs playlist-tabs-loggedIn hide tabs-fixed-width" style="width: 96%;">
|
||||
<li class="tab col s3"><a class="playlist-tab-links playlist-link active truncate" href="#wrapper">Playlist</a></li>
|
||||
<li class="tab col s3"><a class="playlist-tab-links suggested-link truncate" href="#suggestions">Suggested<span class="new badge white hide"></span></a></li>
|
||||
<li class="tab col s3"><a class="playlist-tab-links chat-link truncate" href="#chat">Chat<span class="new badge white hide"></span></a></li>
|
||||
</ul>
|
||||
<div id="find_div" class="hide">
|
||||
<form id="find_form">
|
||||
<input type="text" name="find_value" placeholder="Find.." id="find_input" autocomplete="off" />
|
||||
<div class="num_of_found">
|
||||
<span id="num_found">0</span>/<span id="of_total_found">0</span>
|
||||
<div id="playbar">
|
||||
</div>
|
||||
<a href="#" id="close_find_form_button"><i class="material-icons">clear</i></a>
|
||||
</form>
|
||||
</div>
|
||||
<div id="wrapper" class="tabs_height">
|
||||
<div id="list-song-html">
|
||||
<div id="list-song" class="card left-align list-song playlist-element waves-effect waves-light">
|
||||
<div class="clickable vote-container" title="Vote!">
|
||||
<a class="clickable center-align votebg">
|
||||
<span class="lazy card-image cardbg list-image" style="background-image:url('/assets/images/loading.png');">
|
||||
</span>
|
||||
<span class="card-duration">
|
||||
01:00
|
||||
</span>
|
||||
</a>
|
||||
<span class="card-content">
|
||||
<span class="flow-text truncate list-title"></span>
|
||||
<span class="vote-span">
|
||||
<span class="list-votes"></span>
|
||||
<span class="highlighted vote-text"> votes</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-action center-align list-remove">
|
||||
<a href="#" class="waves-effect btn-flat clickable more_button">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</a>
|
||||
<!--<a title="Remove song" class="waves-effect btn-flat clickable hide-on-small-only delete_button hide suggested_remove">Delete</a>
|
||||
<a title="Remove song" class="waves-effect btn-flat clickable hide-on-med-and-up delete_button hide suggested_remove"><i class="material-icons">close</i></a>-->
|
||||
</div>
|
||||
<div class="mobile-delete red">DELETE</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="suggestions" class="tabs_height" style="display:none;">
|
||||
<p class="suggest-title-info">YouTube Suggests:</p>
|
||||
<div class="suggest_bar" id="suggest-song-html">
|
||||
</div>
|
||||
<p class="suggest-title-info" id="user_suggests">Users Suggests:</p>
|
||||
<div class="suggest_bar" id="user-suggest-html">
|
||||
</div>
|
||||
</div>
|
||||
<div id="chat-container" class="tabs_height" style="display:none;">
|
||||
<ul class="" id="chat-bar">
|
||||
<li id="chat-log">
|
||||
<ul class="inherit-height">
|
||||
<li class="active inherit-height">
|
||||
<!--<ul id="chat inherit-height">-->
|
||||
<div class="row inherit-height">
|
||||
<div class="col s12">
|
||||
<ul class="tabs chatTabs tabs-fixed-width">
|
||||
<li class="tab col s3 chat-tab-li"><a class="active chat-tab truncate" href="#channelchat">{{list_name}}</a></li>
|
||||
<li class="tab col s3 chat-tab-li"><a class="chat-tab" href="#all_chat">All</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="channelchat" class="col s12 inherit-height"><ul id="chatchannel" class="inherit-height"></ul></div>
|
||||
<div id="all_chat" class="col s12 inherit-height"><ul id="chatall" class="inherit-height"></ul></div>
|
||||
</div>
|
||||
<!--</ul>-->
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="chat-input" class="row">
|
||||
<form action="#" id="chatForm">
|
||||
<input id="text-chat-input" class="col s9" name="input" type="text" autocomplete="off" placeholder="Chat" maxlength="150" />
|
||||
<a href="#" id="chat_submit" class="btn col s2 white waves-effect"><i class="material-icons">send</i></a>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="playbar">
|
||||
</div>
|
||||
</main>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -1,117 +1,7 @@
|
||||
<div id="main-container">
|
||||
<header>
|
||||
<nav id="fp-nav">
|
||||
<div class="nav-wrapper">
|
||||
<a href="#" class="brand-logo">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
<div id="frontpage-viewer-counter" class="noselect" title="Divided among all channels. Hidden or not"></div>
|
||||
<!--<a href="//zoff.me" class="brand-logo brand-mobile hide-on-med-and-up">Zoff</a>-->
|
||||
<ul class="right hide-on-med-and-down">
|
||||
<li><a class="header-buttons waves-effect waves-cyan" id="offline-mode" title="Local mode" href="#">Local</a></li>
|
||||
<li><a class="header-buttons waves-effect waves-green" title="Remote control a Zoff player" href="https://remote.zoff.me">Remote</a></li>
|
||||
<li><a class="header-buttons modal-trigger waves-effect waves-orange" data-target="about">About</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="about" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>About</h4>
|
||||
<p>Zoff is a shared (free) YouTube based radio service, built upon the YouTube API. <br><br>
|
||||
Zoff is mainly a web-based service. The website uses NodeJS with Socket.IO, MongoDB and express on the backend, with JavaScript, jQuery and Materialize on the frontend.<br><br>
|
||||
The team consists of Kasper Rynning-Tønnesen and Nicolas Almagro Tonne, and the project has been worked on since late 2014.<br><br>
|
||||
|
||||
</p>
|
||||
<h4>Legal</h4>
|
||||
<p>Copyright © 2017 <br>Nicolas Almagro Tonne and Kasper Rynning-Tønnesen
|
||||
<br><br>
|
||||
Creative Commons License<br>
|
||||
Zoff is licensed under a <br><a href="http://creativecommons.org/licenses/by-nc-nd/3.0/no/">Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Norway License.</a>
|
||||
<br>
|
||||
Do not redistribute without permission from the developers.
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="donation" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Thanks!</h4>
|
||||
<p>Thanks for your donation, we love you <3
|
||||
<br><br>
|
||||
We will use the money for something awesome, just you wait and see!
|
||||
<br><br>
|
||||
We might also add your name somewhere in the code as a sign of gratitude, see if you can find it! (Might take a day or two for us to see the donation and implement it..)
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="modal-action modal-close waves-effect waves-green btn-flat">I'm awesome! (Close)</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="help" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Help</h4>
|
||||
<p>At the center of the site, you'll see a input field. This is meant to navigate to new or existing channels. If you input something here that doesn't exist, a new channel will be create at the blink of an eye! Remember to put a password on the list you've created, so no one else takes it from you! (It's on a first come, first serve basis). When you're ready to proceed, just click the listen button!</p>
|
||||
<p>Underneath the input fields, there are several tiles. These are channels that already exists, and they can be clicked! To listen to one of these channels, it is just to click the tile.</p>
|
||||
<p>If you want to listen to the channel without any "hickups", or being affected by other peoples votes, there is a local mode. By clicking the local button in the header, you will be free of synced listening!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
|
||||
<div class="section mega">
|
||||
<div id="mega-background"></div>
|
||||
<h5>Create a radio channel, collaborate and listen</h5>
|
||||
<form class="channel-finder">
|
||||
<div class="input-field">
|
||||
<p class="prefix">zoff.me/</p>
|
||||
<input
|
||||
class="room-namer autocomplete desktop-search"
|
||||
type="text"
|
||||
id="autocomplete-input"
|
||||
name="chan"
|
||||
placeholder="chill"
|
||||
title="Type channel name here to create or listen to a channel. Only alphanumerical chars. [a-zA-Z0-9]+"
|
||||
autocomplete="off"
|
||||
autofocus
|
||||
required
|
||||
pattern="[a-zA-Z0-9]+"
|
||||
spellcheck="false"
|
||||
maxlength="18"
|
||||
/>
|
||||
<button class="listen-button btn waves-effect waves-light white-text col s2">Listen</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="pitch outline">
|
||||
<div>Live & democratic playlists with YouTube Music</div>
|
||||
<div>Play everywhere — No login required</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section mobile-search">
|
||||
<form class="channel-finder-mobile row" id="base">
|
||||
<div class="input-field col s12">
|
||||
<input
|
||||
class="autocomplete mobile-search"
|
||||
type="text"
|
||||
id="searchFrontpage"
|
||||
name="chan"
|
||||
title="Type channel name here to create or listen to a channel. Only alphanumerical chars. [a-zA-Z0-9]+"
|
||||
autocomplete="off"
|
||||
required pattern="[a-zA-Z0-9]+"
|
||||
spellcheck="false"
|
||||
maxlength="18"
|
||||
data-length="18"
|
||||
/>
|
||||
<label for="searchFrontpage" class="noselect">Find or create radio channel</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{{> frontpage/header}}
|
||||
{{> frontpage/search/desktop}}
|
||||
{{> frontpage/search/mobile}}
|
||||
<div id="channel-load" class="progress">
|
||||
<div class="indeterminate" id="channel-load-move"></div>
|
||||
</div>
|
||||
@@ -131,37 +21,7 @@
|
||||
<div id="preloader" class="progress">
|
||||
<div class="indeterminate"></div>
|
||||
</div>
|
||||
<div id="channel-list-container">
|
||||
|
||||
<ul class="row" id="channels">
|
||||
<li id="chan-card" class="col s6 m4 l3">
|
||||
<div class="card sticky-action">
|
||||
<a class="chan-link">
|
||||
<div class="chan-bg card-image cardbg"></div>
|
||||
<div class="card-content">
|
||||
<i class="material-icons pin">star_rate</i>
|
||||
<p class="left-align">
|
||||
<span class="chan-name flow-text truncate"></span>
|
||||
<br>
|
||||
<span class="highlighted">Viewers: </span>
|
||||
<span class="chan-views"></span>
|
||||
<br>
|
||||
<span class="highlighted">Songs: </span>
|
||||
<span class="chan-songs"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-action noselect">
|
||||
<span class="chan-link-element waves-effect waves-orange btn-flat">Listen</span>
|
||||
</div>
|
||||
<div class="card-reveal">
|
||||
<span class="card-title grey-text text-darken-4 truncate"></span>
|
||||
<p class="description_text"></p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{{> frontpage/channels}}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -1,93 +1,12 @@
|
||||
<header>
|
||||
<nav id="fp-nav">
|
||||
<div class="nav-wrapper">
|
||||
<a href="https://zoff.me" class="brand-logo brand-logo-navigate hide-on-med-and-down">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
<div class="brand-logo truncate zbrand">
|
||||
<a href="https://zoff.me" class="hide-on-large-only brand-logo-navigate">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
</div>
|
||||
<ul class="right hide-on-med-and-down">
|
||||
<li><a class="waves-effect green" title="Remote control a Zoff player" href="https://remote.zoff.me">Remote</a></li>
|
||||
<li><a class="modal-trigger waves-effect waves-orange" data-target="about">About</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="about" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>About</h4>
|
||||
<p>Zoff is a shared (free) YouTube based radio service, built upon the YouTube API. <br><br>
|
||||
Zoff is mainly a web-based service. The website uses NodeJS with Socket.IO, MongoDB and express on the backend, with JavaScript, jQuery and Materialize on the frontend.<br><br>
|
||||
The team consists of Kasper Rynning-Tønnesen and Nicolas Almagro Tonne, and the project has been worked on since late 2014.<br><br>
|
||||
|
||||
</p>
|
||||
<h4>Legal</h4>
|
||||
<p>Copyright © 2017 <br>Nicolas Almagro Tonne and Kasper Rynning-Tønnesen
|
||||
<br><br>
|
||||
Creative Commons License<br>
|
||||
Zoff is licensed under a <br><a href="http://creativecommons.org/licenses/by-nc-nd/3.0/no/">Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Norway License.</a>
|
||||
<br>
|
||||
Do not redistribute without permission from the developers.
|
||||
<br>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="help" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Help</h4>
|
||||
<p>To remote-control a computer, just type in the ID for that computer. (This can be found in the settings panel on the computer you want to remote control. There is also a QR code for you to scan.</p>
|
||||
<p>When you've entered the ID for the computer you want to control, you'll be able to change the volume, have the controled computer vote for skipping, pause the video or play the video.</p>
|
||||
<p>The input field you used to enter the ID (if you entered it), has now changed some. If you type in something here now, the controled computer will change channel!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{> remote/header}}
|
||||
<main class="center-align container remote-container">
|
||||
<div class="section">
|
||||
<h3 id="remote-text">Remote Controller</h3>
|
||||
</div>
|
||||
<div class="section">
|
||||
<form id="remoteform" class="row">
|
||||
<div class="input-field col s12">
|
||||
<input
|
||||
class="input-field"
|
||||
type="text"
|
||||
id="search"
|
||||
name="chan"
|
||||
title="Type channel name here to create or listen to a channel. Only alphanumerical chars. [a-zA-Z0-9]+"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
maxlength="10"
|
||||
data-length="10"
|
||||
/>
|
||||
<label for="search" id="forsearch">Type ID of host to be controlled</label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="rc" id="remote-controls">
|
||||
<a id="playbutton" class="remote-button chan-link waves-effect btn green">
|
||||
<i id="remote_play" class="material-icons">play_arrow</i>
|
||||
</a>
|
||||
<a id="pausebutton" class="remote-button chan-link waves-effect btn gray">
|
||||
<i id="remote_pause" class="material-icons">pause</i>
|
||||
</a>
|
||||
<a id="skipbutton" class="remote-button chan-link waves-effect btn blue">
|
||||
<i id="remote_skip" class="material-icons">skip_next</i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="volume-elements">
|
||||
<div class="rc" id="volume-control" title="Volume"></div>
|
||||
<i class="material-icons slider-vol rc">volume_up</i>
|
||||
</div>
|
||||
|
||||
{{> remote/input}}
|
||||
{{> remote/buttons}}
|
||||
{{> remote/volume}}
|
||||
</div>
|
||||
|
||||
<div class="section about-remote">
|
||||
|
||||
28
server/public/partials/channel/chat.handlebars
Normal file
28
server/public/partials/channel/chat.handlebars
Normal file
@@ -0,0 +1,28 @@
|
||||
<div id="chat-container" class="tabs_height" style="display:none;">
|
||||
<ul class="" id="chat-bar">
|
||||
<li id="chat-log">
|
||||
<ul class="inherit-height">
|
||||
<li class="active inherit-height">
|
||||
<!--<ul id="chat inherit-height">-->
|
||||
<div class="row inherit-height">
|
||||
<div class="col s12">
|
||||
<ul class="tabs chatTabs tabs-fixed-width">
|
||||
<li class="tab col s3 chat-tab-li"><a class="active chat-tab truncate" href="#channelchat">{{list_name}}</a></li>
|
||||
<li class="tab col s3 chat-tab-li"><a class="chat-tab" href="#all_chat">All</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="channelchat" class="col s12 inherit-height"><ul id="chatchannel" class="inherit-height"></ul></div>
|
||||
<div id="all_chat" class="col s12 inherit-height"><ul id="chatall" class="inherit-height"></ul></div>
|
||||
</div>
|
||||
<!--</ul>-->
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="chat-input" class="row">
|
||||
<form action="#" id="chatForm">
|
||||
<input id="text-chat-input" class="col s9" name="input" type="text" autocomplete="off" placeholder="Chat" maxlength="150" />
|
||||
<a href="#" id="chat_submit" class="btn col s2 white waves-effect"><i class="material-icons">send</i></a>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
162
server/public/partials/channel/header.handlebars
Normal file
162
server/public/partials/channel/header.handlebars
Normal file
@@ -0,0 +1,162 @@
|
||||
<header>
|
||||
<div class="navbar-fixed">
|
||||
<nav id="nav">
|
||||
<div class="nav-wrapper">
|
||||
|
||||
<div class="brand-logo truncate zbrand">
|
||||
<a href="/" class="brand-logo brand-logo-navigate">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
|
||||
<span id="chan" class="chan clickable truncate" title="Show big URL">{{list_name}}</span>
|
||||
</div>
|
||||
|
||||
<ul class="title-container">
|
||||
<li class="song-title cursor-pointer truncate" id="song-title">
|
||||
Loading...
|
||||
</li>
|
||||
<li class="search-container hide" id="search-wrapper">
|
||||
<input id="search" class="search_input" type="text" title="Search for songs..." placeholder="Find song on YouTube..." onsubmit="null;" autocomplete="off" />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="right control-list noselect">
|
||||
<li id="search_loader" class="valign-wrapper">
|
||||
<div id="search_loader_inner">
|
||||
<div class="preloader-wrapper small search_loader_spinner">
|
||||
<div class="spinner-layer spinner-white-only">
|
||||
<div class="circle-clipper left">
|
||||
<div class="circle"></div>
|
||||
</div><div class="gap-patch">
|
||||
<div class="circle"></div>
|
||||
</div><div class="circle-clipper right">
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-btn" href="#find" id="search-btn">
|
||||
<i class="material-icons">search</i>
|
||||
<!--<span class="hover-text">Find</span>-->
|
||||
</a>
|
||||
</li>
|
||||
<!--<li>
|
||||
<a class="nav-btn prev" href="#prev">
|
||||
<i class="material-icons">skip_previous</i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="nav-btn skip" href="#skip">
|
||||
<i class="material-icons">skip_next</i>
|
||||
<span class="hover-text">Skip</span>
|
||||
</a>
|
||||
</li>-->
|
||||
<li>
|
||||
<a class="nav-btn" href="#stir" id="shuffle">
|
||||
<i class="material-icons">shuffle</i>
|
||||
<!--<span class="hover-text">Stir</span>-->
|
||||
</a>
|
||||
</li>
|
||||
<li class="settings-hamburger" data-activates="settings-bar" id="settings">
|
||||
<!--<a class="nav-btn" href="#settings" data-activates="settings-bar" id="settings">
|
||||
<i class="material-icons">menu</i>
|
||||
</a>-->
|
||||
<div class="hamburger-sidenav">
|
||||
<span></span>
|
||||
<span></span>
|
||||
<span></span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="side-nav" id="settings-bar">
|
||||
{{> channel/panel}}
|
||||
</ul>
|
||||
<div id="results" class="search_results hide">
|
||||
<div id="temp-results-container">
|
||||
<div id="temp-results" class="result-object">
|
||||
<div id="result" class="result">
|
||||
<img class="thumb" src="/assets/images/loading.png" alt="Thumb"/>
|
||||
|
||||
<div class="search-title truncate"></div>
|
||||
<span class="result_info"></span>
|
||||
<div class="waves-effect waves-orange btn-flat" id="add-many" title="Add several videos">
|
||||
<i class="material-icons">playlist_add</i>
|
||||
</div>
|
||||
<a href="#" target="_blank" class="waves-effect waves-orange btn-flat open-externally" title="Open on YouTube">
|
||||
<i class="material-icons">open_in_new</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="empty-results-container">
|
||||
<div id="empty-results" class="valign-wrapper">
|
||||
<span class="valign">No results found..</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div id="user_password" class="modal">
|
||||
<div class="modal-content">
|
||||
<h5>Locked Channel</h5>
|
||||
<form id="user-password-channel-form">
|
||||
<div class="input-field">
|
||||
<input id="user-pass-input" name="user-pass" type="password" autocomplete="off" />
|
||||
<label for="user-pass-input" class="noselect">Password</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat close-user-password">Close</a>
|
||||
<a href="#!" class="waves-effect waves-green btn-flat submit-user-password">Submit</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="delete_song_alert" class="modal">
|
||||
<div class="modal-content">
|
||||
<h5>Delete song</h5>
|
||||
<p>Are you sure you want to delete <span id="delete_song_title"></span>?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="waves-effect waves-red btn-flat accept-delete right red-text">Delete</a>
|
||||
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat cancel-song-delete">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="help" class="modal modal-fixed-footer">
|
||||
<div class="modal-content">
|
||||
<h4>Help</h4>
|
||||
<p>When listening on a channel, there are some different buttons you can click.</p>
|
||||
<p>If you click the <i class="material-icons">menu</i>, you'll open the settings panel. Here you can change channel settings, decide if you want the computer you're on can be remote-controlled, enable or disable local mode, and import playlists from YouTube.</p>
|
||||
<p>The <i class="material-icons">search</i>, opens up a search inputfield. If you start typing here, the site will automagically search for your input!</p>
|
||||
<p>If you click the button next to the search icon <i class="material-icons">skip_next</i>, you'll skip on a song. The one next to that one <i class="material-icons">shuffle</i>, is shuffling of the list.</p>
|
||||
<p>Clicking a song in the playlist, gives it a vote. If you're logged in, you'll have a delete button at your disposal.</p>
|
||||
<p>Also, whenever you're logged in, you'll have three tabs in the top of the playlist thats called "Playlist", "Suggested" and "Chat". The playlist obviously shows the playlist. But the suggested tab, shows 5 songs that YouTube recommends based on the current song. There might also be user recommended songs. To add any of these, just click them as you'd click a song to vote.</p>
|
||||
<p>If you want to listen to the channel without any "hickups", or being affected by other peoples votes, there is a local mode. By opening up the settings <i class="material-icons">menu</i>, and checking the local mode checkbox, you will be free of synced listening! This will also enable seeking in the current playing video, perfect for those songs you only like a part of!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="embed" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Embed</h4>
|
||||
<p>Copy the code in the textarea, and paste on your website.</p>
|
||||
<p>
|
||||
<input type="checkbox" id="autoplay" checked="checked" />
|
||||
<label for="autoplay" class="padding_right_26">Autoplay</label>
|
||||
<label for="width_embed" class="embed-label">Width</label>
|
||||
<input type="number" value="600" id="width_embed" class="settings_embed" min="1" />
|
||||
<label for="height_embed" class="padding_left_6 embed-label">Height</label>
|
||||
<input type="number" value="300" id="height_embed" class="settings_embed" min="1" />
|
||||
<label for="color_embed" class="padding_left_6 embed-label">Color</label>
|
||||
<input type="color" id="color_embed" class="settings_embed" value="#808080" />
|
||||
</p>
|
||||
<textarea id="embed-area"></textarea>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
57
server/public/partials/channel/players.handlebars
Normal file
57
server/public/partials/channel/players.handlebars
Normal file
@@ -0,0 +1,57 @@
|
||||
<div id="video-container" class="col s12 m9 video-container no-opacity click-through">
|
||||
<div id="fireplace_player" class="ytplayer"></div>
|
||||
<div id="player" class="ytplayer"></div>
|
||||
<div id="main_components">
|
||||
<div id="player_overlay" class="hide valign-wrapper">
|
||||
<div id="playing_on">
|
||||
<div id="chromecast_icon">
|
||||
<i class="material-icons">cast</i>
|
||||
</div>
|
||||
<div id="chromecast_text"></div>
|
||||
</div>
|
||||
<div id="player_overlay_text" class="valign center-align">
|
||||
Waiting for Video
|
||||
</div>
|
||||
<div id="player_overlay_controls" class="hide valign-wrapper">
|
||||
<div id="playpause-overlay" class="valign center-align">
|
||||
<i id="play-overlay" class="material-icons hide">play_arrow</i>
|
||||
<i id="pause-overlay" class="material-icons">pause</i>
|
||||
</div>
|
||||
<div id="volume-button-overlay">
|
||||
<i id="v-mute-overlay" class="material-icons">volume_off</i>
|
||||
<i id="v-low-overlay" class="material-icons">volume_mute</i>
|
||||
<i id="v-medium-overlay" class="material-icons">volume_down</i>
|
||||
<i id="v-full-overlay" class="material-icons">volume_up</i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="controls" class="noselect">
|
||||
<div class="playbar-btn prev playbar hide">
|
||||
<i class="material-icons">skip_previous</i>
|
||||
</div>
|
||||
<div id="playpause" class="playbar-btn margin-playbar">
|
||||
<i id="play" class="material-icons hide">play_arrow</i>
|
||||
<i id="pause" class="material-icons">pause</i>
|
||||
</div>
|
||||
<div class="playbar-btn skip playbar">
|
||||
<i class="material-icons">skip_next</i>
|
||||
</div>
|
||||
<div id="duration"></div>
|
||||
<div id="fullscreen" class="hide-on-small-only playbar-btn">
|
||||
<i class="material-icons">fullscreen</i>
|
||||
</div>
|
||||
<button class="castButton playbar-btn" id="castButton" is="google-cast-button"></button>
|
||||
<div id="volume-button" class="playbar-btn">
|
||||
<i id="v-mute" class="material-icons">volume_off</i>
|
||||
<i id="v-low" class="material-icons">volume_mute</i>
|
||||
<i id="v-medium" class="material-icons">volume_down</i>
|
||||
<i id="v-full" class="material-icons">volume_up</i>
|
||||
</div>
|
||||
<div class="volume-container">
|
||||
<div id="volume"></div>
|
||||
</div>
|
||||
<div id="viewers" data-position="top"></div>
|
||||
<div id="bar"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
30
server/public/partials/channel/playlist.handlebars
Normal file
30
server/public/partials/channel/playlist.handlebars
Normal file
@@ -0,0 +1,30 @@
|
||||
<div id="wrapper" class="tabs_height">
|
||||
<div id="list-song-html">
|
||||
<div id="list-song" class="card left-align list-song playlist-element waves-effect waves-light">
|
||||
<div class="clickable vote-container" title="Vote!">
|
||||
<a class="clickable center-align votebg">
|
||||
<span class="lazy card-image cardbg list-image" style="background-image:url('/assets/images/loading.png');">
|
||||
</span>
|
||||
<span class="card-duration">
|
||||
01:00
|
||||
</span>
|
||||
</a>
|
||||
<span class="card-content">
|
||||
<span class="flow-text truncate list-title"></span>
|
||||
<span class="vote-span">
|
||||
<span class="list-votes"></span>
|
||||
<span class="highlighted vote-text"> votes</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-action center-align list-remove">
|
||||
<a href="#" class="waves-effect btn-flat clickable more_button">
|
||||
<i class="material-icons">more_vert</i>
|
||||
</a>
|
||||
<!--<a title="Remove song" class="waves-effect btn-flat clickable hide-on-small-only delete_button hide suggested_remove">Delete</a>
|
||||
<a title="Remove song" class="waves-effect btn-flat clickable hide-on-med-and-up delete_button hide suggested_remove"><i class="material-icons">close</i></a>-->
|
||||
</div>
|
||||
<div class="mobile-delete red">DELETE</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
8
server/public/partials/channel/suggestions.handlebars
Normal file
8
server/public/partials/channel/suggestions.handlebars
Normal file
@@ -0,0 +1,8 @@
|
||||
<div id="suggestions" class="tabs_height" style="display:none;">
|
||||
<p class="suggest-title-info">YouTube Suggests:</p>
|
||||
<div class="suggest_bar" id="suggest-song-html">
|
||||
</div>
|
||||
<p class="suggest-title-info" id="user_suggests">Users Suggests:</p>
|
||||
<div class="suggest_bar" id="user-suggest-html">
|
||||
</div>
|
||||
</div>
|
||||
23
server/public/partials/channel/tabs.handlebars
Normal file
23
server/public/partials/channel/tabs.handlebars
Normal file
@@ -0,0 +1,23 @@
|
||||
<div id="playlist" class="col s12 m3">
|
||||
<ul class="tabs playlist-tabs tabs-fixed-width" style="width:96%">
|
||||
<li class="tab col s3"><a class="playlist-tab-links playlist-link active truncate" href="#wrapper">Playlist</a></li>
|
||||
<li class="tab col s3"><a class="playlist-tab-links chat-link truncate" href="#chat">Chat<span class="new badge white hide"></span></a></li>
|
||||
</ul>
|
||||
<ul class="tabs playlist-tabs-loggedIn hide tabs-fixed-width" style="width: 96%;">
|
||||
<li class="tab col s3"><a class="playlist-tab-links playlist-link active truncate" href="#wrapper">Playlist</a></li>
|
||||
<li class="tab col s3"><a class="playlist-tab-links suggested-link truncate" href="#suggestions">Suggested<span class="new badge white hide"></span></a></li>
|
||||
<li class="tab col s3"><a class="playlist-tab-links chat-link truncate" href="#chat">Chat<span class="new badge white hide"></span></a></li>
|
||||
</ul>
|
||||
<div id="find_div" class="hide">
|
||||
<form id="find_form">
|
||||
<input type="text" name="find_value" placeholder="Find.." id="find_input" autocomplete="off" />
|
||||
<div class="num_of_found">
|
||||
<span id="num_found">0</span>/<span id="of_total_found">0</span>
|
||||
</div>
|
||||
<a href="#" id="close_find_form_button"><i class="material-icons">clear</i></a>
|
||||
</form>
|
||||
</div>
|
||||
{{> channel/playlist}}
|
||||
{{> channel/suggestions}}
|
||||
{{> channel/chat}}
|
||||
</div>
|
||||
26
server/public/partials/frontpage/channel.handlebars
Normal file
26
server/public/partials/frontpage/channel.handlebars
Normal file
@@ -0,0 +1,26 @@
|
||||
<li id="chan-card" class="col s6 m4 l3">
|
||||
<div class="card sticky-action">
|
||||
<a class="chan-link">
|
||||
<div class="chan-bg card-image cardbg"></div>
|
||||
<div class="card-content">
|
||||
<i class="material-icons pin">star_rate</i>
|
||||
<p class="left-align">
|
||||
<span class="chan-name flow-text truncate"></span>
|
||||
<br>
|
||||
<span class="highlighted">Viewers: </span>
|
||||
<span class="chan-views"></span>
|
||||
<br>
|
||||
<span class="highlighted">Songs: </span>
|
||||
<span class="chan-songs"></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-action noselect">
|
||||
<span class="chan-link-element waves-effect waves-orange btn-flat">Listen</span>
|
||||
</div>
|
||||
<div class="card-reveal">
|
||||
<span class="card-title grey-text text-darken-4 truncate"></span>
|
||||
<p class="description_text"></p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
5
server/public/partials/frontpage/channels.handlebars
Normal file
5
server/public/partials/frontpage/channels.handlebars
Normal file
@@ -0,0 +1,5 @@
|
||||
<div id="channel-list-container">
|
||||
<ul class="row" id="channels">
|
||||
{{> frontpage/channel}}
|
||||
</ul>
|
||||
</div>
|
||||
64
server/public/partials/frontpage/header.handlebars
Normal file
64
server/public/partials/frontpage/header.handlebars
Normal file
@@ -0,0 +1,64 @@
|
||||
<header>
|
||||
<nav id="fp-nav">
|
||||
<div class="nav-wrapper">
|
||||
<a href="#" class="brand-logo">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
<div id="frontpage-viewer-counter" class="noselect" title="Divided among all channels. Hidden or not"></div>
|
||||
<!--<a href="//zoff.me" class="brand-logo brand-mobile hide-on-med-and-up">Zoff</a>-->
|
||||
<ul class="right hide-on-med-and-down">
|
||||
<li><a class="header-buttons waves-effect waves-cyan" id="offline-mode" title="Local mode" href="#">Local</a></li>
|
||||
<li><a class="header-buttons waves-effect waves-green" title="Remote control a Zoff player" href="https://remote.zoff.me">Remote</a></li>
|
||||
<li><a class="header-buttons modal-trigger waves-effect waves-orange" data-target="about">About</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="about" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>About</h4>
|
||||
<p>Zoff is a shared (free) YouTube based radio service, built upon the YouTube API. <br><br>
|
||||
Zoff is mainly a web-based service. The website uses NodeJS with Socket.IO, MongoDB and express on the backend, with JavaScript, jQuery and Materialize on the frontend.<br><br>
|
||||
The team consists of Kasper Rynning-Tønnesen and Nicolas Almagro Tonne, and the project has been worked on since late 2014.<br><br>
|
||||
|
||||
</p>
|
||||
<h4>Legal</h4>
|
||||
<p>Copyright © 2017 <br>Nicolas Almagro Tonne and Kasper Rynning-Tønnesen
|
||||
<br><br>
|
||||
Creative Commons License<br>
|
||||
Zoff is licensed under a <br><a href="http://creativecommons.org/licenses/by-nc-nd/3.0/no/">Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Norway License.</a>
|
||||
<br>
|
||||
Do not redistribute without permission from the developers.
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="donation" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Thanks!</h4>
|
||||
<p>Thanks for your donation, we love you <3
|
||||
<br><br>
|
||||
We will use the money for something awesome, just you wait and see!
|
||||
<br><br>
|
||||
We might also add your name somewhere in the code as a sign of gratitude, see if you can find it! (Might take a day or two for us to see the donation and implement it..)
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="modal-action modal-close waves-effect waves-green btn-flat">I'm awesome! (Close)</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="help" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Help</h4>
|
||||
<p>At the center of the site, you'll see a input field. This is meant to navigate to new or existing channels. If you input something here that doesn't exist, a new channel will be create at the blink of an eye! Remember to put a password on the list you've created, so no one else takes it from you! (It's on a first come, first serve basis). When you're ready to proceed, just click the listen button!</p>
|
||||
<p>Underneath the input fields, there are several tiles. These are channels that already exists, and they can be clicked! To listen to one of these channels, it is just to click the tile.</p>
|
||||
<p>If you want to listen to the channel without any "hickups", or being affected by other peoples votes, there is a local mode. By clicking the local button in the header, you will be free of synced listening!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</header>
|
||||
28
server/public/partials/frontpage/search/desktop.handlebars
Normal file
28
server/public/partials/frontpage/search/desktop.handlebars
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="section mega">
|
||||
<div id="mega-background"></div>
|
||||
<h5>Create a radio channel, collaborate and listen</h5>
|
||||
<form class="channel-finder">
|
||||
<div class="input-field">
|
||||
<p class="prefix">zoff.me/</p>
|
||||
<input
|
||||
class="room-namer autocomplete desktop-search"
|
||||
type="text"
|
||||
id="autocomplete-input"
|
||||
name="chan"
|
||||
placeholder="chill"
|
||||
title="Type channel name here to create or listen to a channel. Only alphanumerical chars. [a-zA-Z0-9]+"
|
||||
autocomplete="off"
|
||||
autofocus
|
||||
required
|
||||
pattern="[a-zA-Z0-9]+"
|
||||
spellcheck="false"
|
||||
maxlength="18"
|
||||
/>
|
||||
<button class="listen-button btn waves-effect waves-light white-text col s2">Listen</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="pitch outline">
|
||||
<div>Live & democratic playlists with YouTube Music</div>
|
||||
<div>Play everywhere — No login required</div>
|
||||
</div>
|
||||
</div>
|
||||
19
server/public/partials/frontpage/search/mobile.handlebars
Normal file
19
server/public/partials/frontpage/search/mobile.handlebars
Normal file
@@ -0,0 +1,19 @@
|
||||
<div class="section mobile-search">
|
||||
<form class="channel-finder-mobile row" id="base">
|
||||
<div class="input-field col s12">
|
||||
<input
|
||||
class="autocomplete mobile-search"
|
||||
type="text"
|
||||
id="searchFrontpage"
|
||||
name="chan"
|
||||
title="Type channel name here to create or listen to a channel. Only alphanumerical chars. [a-zA-Z0-9]+"
|
||||
autocomplete="off"
|
||||
required pattern="[a-zA-Z0-9]+"
|
||||
spellcheck="false"
|
||||
maxlength="18"
|
||||
data-length="18"
|
||||
/>
|
||||
<label for="searchFrontpage" class="noselect">Find or create radio channel</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
11
server/public/partials/remote/buttons.handlebars
Normal file
11
server/public/partials/remote/buttons.handlebars
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="rc" id="remote-controls">
|
||||
<a id="playbutton" class="remote-button chan-link waves-effect btn green">
|
||||
<i id="remote_play" class="material-icons">play_arrow</i>
|
||||
</a>
|
||||
<a id="pausebutton" class="remote-button chan-link waves-effect btn gray">
|
||||
<i id="remote_pause" class="material-icons">pause</i>
|
||||
</a>
|
||||
<a id="skipbutton" class="remote-button chan-link waves-effect btn blue">
|
||||
<i id="remote_skip" class="material-icons">skip_next</i>
|
||||
</a>
|
||||
</div>
|
||||
50
server/public/partials/remote/header.handlebars
Normal file
50
server/public/partials/remote/header.handlebars
Normal file
@@ -0,0 +1,50 @@
|
||||
<header>
|
||||
<nav id="fp-nav">
|
||||
<div class="nav-wrapper">
|
||||
<a href="https://zoff.me" class="brand-logo brand-logo-navigate hide-on-med-and-down">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
<div class="brand-logo truncate zbrand">
|
||||
<a href="https://zoff.me" class="hide-on-large-only brand-logo-navigate">
|
||||
<img id="zicon" src="/assets/images/z.svg" alt="zoff" title="Zoff" />
|
||||
</a>
|
||||
</div>
|
||||
<ul class="right hide-on-med-and-down">
|
||||
<li><a class="waves-effect green" title="Remote control a Zoff player" href="https://remote.zoff.me">Remote</a></li>
|
||||
<li><a class="modal-trigger waves-effect waves-orange" data-target="about">About</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div id="about" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>About</h4>
|
||||
<p>Zoff is a shared (free) YouTube based radio service, built upon the YouTube API. <br><br>
|
||||
Zoff is mainly a web-based service. The website uses NodeJS with Socket.IO, MongoDB and express on the backend, with JavaScript, jQuery and Materialize on the frontend.<br><br>
|
||||
The team consists of Kasper Rynning-Tønnesen and Nicolas Almagro Tonne, and the project has been worked on since late 2014.<br><br>
|
||||
</p>
|
||||
<h4>Legal</h4>
|
||||
<p>Copyright © 2017 <br>Nicolas Almagro Tonne and Kasper Rynning-Tønnesen
|
||||
<br><br>
|
||||
Creative Commons License<br>
|
||||
Zoff is licensed under a <br><a href="http://creativecommons.org/licenses/by-nc-nd/3.0/no/">Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Norway License.</a>
|
||||
<br>
|
||||
Do not redistribute without permission from the developers.
|
||||
<br>
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="help" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Help</h4>
|
||||
<p>To remote-control a computer, just type in the ID for that computer. (This can be found in the settings panel on the computer you want to remote control. There is also a QR code for you to scan.</p>
|
||||
<p>When you've entered the ID for the computer you want to control, you'll be able to change the volume, have the controled computer vote for skipping, pause the video or play the video.</p>
|
||||
<p>The input field you used to enter the ID (if you entered it), has now changed some. If you type in something here now, the controled computer will change channel!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class=" modal-action modal-close waves-effect waves-green btn-flat">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
16
server/public/partials/remote/input.handlebars
Normal file
16
server/public/partials/remote/input.handlebars
Normal file
@@ -0,0 +1,16 @@
|
||||
<form id="remoteform" class="row">
|
||||
<div class="input-field col s12">
|
||||
<input
|
||||
class="input-field"
|
||||
type="text"
|
||||
id="search"
|
||||
name="chan"
|
||||
title="Type channel name here to create or listen to a channel. Only alphanumerical chars. [a-zA-Z0-9]+"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
maxlength="10"
|
||||
data-length="10"
|
||||
/>
|
||||
<label for="search" id="forsearch">Type ID of host to be controlled</label>
|
||||
</div>
|
||||
</form>
|
||||
4
server/public/partials/remote/volume.handlebars
Normal file
4
server/public/partials/remote/volume.handlebars
Normal file
@@ -0,0 +1,4 @@
|
||||
<div class="volume-elements">
|
||||
<div class="rc" id="volume-control" title="Volume"></div>
|
||||
<i class="material-icons slider-vol rc">volume_up</i>
|
||||
</div>
|
||||
@@ -12,38 +12,7 @@ router.use(function(req, res, next) {
|
||||
});
|
||||
|
||||
router.route('/:channel_name').get(function(req, res, next){
|
||||
try{
|
||||
var url = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'] : req.headers.host.split(":")[0];
|
||||
var subdomain = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'].split(".") : req.headers.host.split(":")[0].split(".");
|
||||
if(url != "zoff.me" && url != "remote.zoff.me" && url != "fb.zoff.me" && url != "remote.localhost" && url != "localhost") {
|
||||
res.redirect("https://zoff.me");
|
||||
return;
|
||||
}
|
||||
if(subdomain[0] == "remote") {
|
||||
var data = {
|
||||
year: 2017,
|
||||
javascript_file: "remote.min.js"
|
||||
}
|
||||
res.render('layouts/remote', data);
|
||||
} else if(subdomain.length >= 2 && subdomain[0] == "www") {
|
||||
res.redirect("https://zoff.me");
|
||||
} else {
|
||||
if(req.params.channel_name == "_embed") {
|
||||
res.sendFile(path.join(pathThumbnails, '/public/assets/html/embed.html'));
|
||||
} else if(req.params.channel_name == "o_callback") {
|
||||
res.sendFile(path.join(pathThumbnails, '/public/assets/html/callback.html'));
|
||||
} else {
|
||||
var data = {
|
||||
list_name: capitalizeFirstLetter(req.params.channel_name),
|
||||
year: 2017,
|
||||
javascript_file: "main.min.js"
|
||||
}
|
||||
res.render('layouts/channel', data);
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
res.redirect("https://zoff.me");
|
||||
}
|
||||
channel(req, res, next);
|
||||
});
|
||||
|
||||
router.route('/api/frontpages').get(function(req, res) {
|
||||
@@ -120,46 +89,6 @@ router.route('/api/imageblob').post(function(req, res) {
|
||||
});
|
||||
});
|
||||
|
||||
/*
|
||||
*
|
||||
* TODO:
|
||||
*
|
||||
* Add custom userplaylists, only visible for those with that specific cookie
|
||||
*
|
||||
*
|
||||
router.route('/:user_name/:channel_name').get(function(req, res, next){
|
||||
var protocol = req.protocol;
|
||||
var subdomain = req.headers['x-forwarded-host'].split(".");
|
||||
|
||||
if((subdomain[0] != 'localhost' && !(subdomain.length >= 2 && subdomain[1] == 'localhost')) && protocol != "https") {
|
||||
res.redirect("https://zoff.me");
|
||||
return;
|
||||
}
|
||||
if(subdomain[0] == "remote") {
|
||||
var data = {
|
||||
year: 2017,
|
||||
javascript_file: "remote.min.js"
|
||||
}
|
||||
res.render('layouts/remote', data);
|
||||
} else if(subdomain.length >= 2 && subdomain[0] == "www") {
|
||||
res.redirect("https://zoff.me");
|
||||
} else {
|
||||
if(req.params.channel_name == "_embed") {
|
||||
res.sendFile(path.join(__dirname, '/public/assets/html/embed.html'));
|
||||
} else if(req.params.channel_name == "o_callback") {
|
||||
res.sendFile(path.join(__dirname, '/public/assets/html/callback.html'));
|
||||
} else {
|
||||
var data = {
|
||||
list_name: capitalizeFirstLetter(req.params.channel_name),
|
||||
year: 2017,
|
||||
javascript_file: "main.min.js"
|
||||
}
|
||||
res.render('layouts/channel', data);
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
router.route('/api/mail').post(function(req, res) {
|
||||
let transporter = nodemailer.createTransport(mailconfig);
|
||||
|
||||
@@ -191,35 +120,15 @@ router.route('/api/mail').post(function(req, res) {
|
||||
});
|
||||
|
||||
router.route('/').get(function(req, res, next){
|
||||
try{
|
||||
var url = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'] : req.headers.host.split(":")[0];
|
||||
var subdomain = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'].split(".") : req.headers.host.split(":")[0].split(".");
|
||||
if(url != "zoff.me" && url != "remote.zoff.me" && url != "fb.zoff.me" && url != "remote.localhost" && url != "localhost") {
|
||||
res.redirect("https://zoff.me");
|
||||
return;
|
||||
}
|
||||
if(subdomain[0] == "remote") {
|
||||
var data = {
|
||||
year: 2017,
|
||||
javascript_file: "remote.min.js"
|
||||
}
|
||||
res.render('layouts/remote', data);
|
||||
} else if(subdomain[0] == "www") {
|
||||
res.redirect("https://zoff.me");
|
||||
} else {
|
||||
var data = {
|
||||
year: 2017,
|
||||
javascript_file: "main.min.js"
|
||||
}
|
||||
res.render('layouts/frontpage', data);
|
||||
}
|
||||
} catch(e) {
|
||||
//console.log(e);
|
||||
//res.redirect("https://zoff.me");
|
||||
}
|
||||
root(req, res, next);
|
||||
});
|
||||
|
||||
|
||||
router.route('/').post(function(req, res, next){
|
||||
root(req, res, next);
|
||||
});
|
||||
|
||||
function root(req, res, next) {
|
||||
try{
|
||||
var url = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'] : req.headers.host.split(":")[0];
|
||||
var subdomain = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'].split(".") : req.headers.host.split(":")[0].split(".");
|
||||
@@ -238,7 +147,7 @@ router.route('/').post(function(req, res, next){
|
||||
} else {
|
||||
var data = {
|
||||
year: 2017,
|
||||
javascript_file: "main.min.js"
|
||||
javascript_file: "main.min.js",
|
||||
}
|
||||
res.render('layouts/frontpage', data);
|
||||
}
|
||||
@@ -246,9 +155,9 @@ router.route('/').post(function(req, res, next){
|
||||
//console.log(e);
|
||||
//res.redirect("https://zoff.me");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
router.route('/:channel_name').post(function(req, res, next){
|
||||
function channel(req, res, next) {
|
||||
try{
|
||||
var url = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'] : req.headers.host.split(":")[0];
|
||||
var subdomain = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'].split(".") : req.headers.host.split(":")[0].split(".");
|
||||
@@ -281,9 +190,7 @@ router.route('/:channel_name').post(function(req, res, next){
|
||||
} catch(e) {
|
||||
res.redirect("https://zoff.me");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function capitalizeFirstLetter(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
|
||||
Reference in New Issue
Block a user