Create 1.1-indev branch, list of updates in README
This commit is contained in:
parent
8ca4aa4327
commit
3f27bfdbdf
185
README.md
185
README.md
|
|
@ -1,7 +1,7 @@
|
|||
fore.st - Panama Red(v1)
|
||||
fore.st - Pineapple Express(v1.1-indev)
|
||||
======
|
||||
|
||||
fore.st is the server software for ourfore.st, a community based chat & video embedding site tailored to service
|
||||
fore.st is the server software for ourfore.st, a community based chat & synced video embedding site tailored to service
|
||||
the TTN community post-shutdown. The softwre is made freely available both for legal reasons
|
||||
but also as it seems as that is what is best for the community in the advant of another shutdown.
|
||||
|
||||
|
|
@ -10,20 +10,6 @@ and carries many of the same features. Modifcations to the software have been/ar
|
|||
being made to make the platform a more familiar place for TTN users. Contributions
|
||||
are welcome.
|
||||
|
||||
Current dev goals:
|
||||
- image upload button/ audio(maybe? Autoplay disabled.) & mp4/webm embed support
|
||||
- basic library features(add to lib without queueing, show videos from other channels)
|
||||
- add 3 columns to lib table: type(show,movie,video), genre(comedy,food,horror,etc...), tags(stupidbullshit, etc...), sort or search by type/genre/tags
|
||||
- improved profiles (profile pages, badges, stats)
|
||||
- forum (a la ttn discussions)
|
||||
- other custom chat commands (thunder, birdup, etc..)
|
||||
- gold(toke-ns?)
|
||||
- games?(in-browser? game servers that w/ steamid tie-in to toke-ns?)
|
||||
|
||||
Current goals for ourfore.st instance:
|
||||
- fix gdrive support(we'll probably be moving hosts at some point...)
|
||||
- continue w/ development goals and exist with the d00dz
|
||||
|
||||
## Installation
|
||||
There is currently no installation guide for the software, however since not much has
|
||||
changed in the backend, you should be fine with official [cytube docs](https://github.com/calzoneman/sync/wiki/CyTube-3.0-Installation-Guide).
|
||||
|
|
@ -32,16 +18,173 @@ changed in the backend, you should be fine with official [cytube docs](https://g
|
|||
You can reach out by bugging rainbownapkin on the ttn discord or ourfore.st, you can also send an email to ourforest(at)420blaze.it
|
||||
|
||||
## Shoutouts
|
||||
- Thanks to Simon for making TTN, we wouldn't be here if it wheren't that shit.
|
||||
- Thanks to jaredlego-aka-goops, Rongtern, n' Sassy for helping with moderation and content aggregation for ourfore.st, we'll be set fer fackin dayz lol.
|
||||
- Thanks to Simon for making TTN,
|
||||
- Thanks to our excellent mod team for chat moderation and content aggregation
|
||||
- Thanks to etchingham for being a community contact while TTN's been winding down, I think all of us see you as a pillar of the community so your support means a lot.
|
||||
- Thanks to calzoneman for making [cytube](https://github.com/calzoneman/sync), that saved our asses.
|
||||
- Thanks to the core TTN community and everyone else who's ever used it, I was only there for the last handful of years but it was an absolute fuckin' ride. You guys are the best, it isn't TTN but I hope this at least help fills the gap.
|
||||
|
||||
## License
|
||||
## Pineapple Express Indev Release Notes
|
||||
This is the first indev release for fore.st 1.1 Pineapple Express. This is the last push before the codebase is merged upstream with the newest version of cytube. Should probably get that done sooner than later. Heres a check list of the planned/completed features in this revision:
|
||||
|
||||
Original source code in this repository is provided under the MIT license
|
||||
(see the LICENSE file for the full text).
|
||||
-quick shit & bugfixes ✓
|
||||
--change markdown filters to require three symbols on each side, quickest fix for filters ✓
|
||||
--move refresh button to title bar ✓
|
||||
--delete custom embed button, replace with button under generel "add video" button ✓
|
||||
--move playlist item count and length next to buttons & compact ui ✓
|
||||
--hide playlist frame and control from users who don't have permission to view playlist (no one can see the afterparty playlist except mods, why should they have the controls cluttering things up?) ✓
|
||||
--add "mention" to userlist dropdown menu ✓
|
||||
--add "toke with" to userlist dropdown menu for shits n gigs ✓
|
||||
--unlatch sync on pause and scrub, show sync button on titlebar when sync is unlatched, this wont support classic yt at the moment. Invidious support planned ✓
|
||||
--caption support for raw video (no saving captions in channel history just yet, this will be in the next update which will involve a rework/addition to the database) ✓
|
||||
--fix bugged airdate after "queue next" ✓
|
||||
--collapsing playlist items hides pref and airtime by default. Airdate on same line as title, airtime and pref below ✓
|
||||
--collapse/expand all playlist item button ✓
|
||||
--close playlist button ✓
|
||||
--basic ui fixes/tweaks ✓
|
||||
--disabled !toke link embedding on emote alt text ✓
|
||||
--fix chatbar resizing on new message notification (might just by cytube+) ✓
|
||||
--relicense to agpl ✓
|
||||
--disable/remove unregistered channels ✓
|
||||
--rename "legacy playlist buttons" to compact, fix location. This seems like it could be usable if not better than default ✓
|
||||
--save temporary vids to channel library
|
||||
|
||||
-slide out panel (not an end user feature in and of itself, however a common UI element used for most menus, made to be quick and ezpz ✓
|
||||
--function for opening, closing ✓
|
||||
--allow switching menus on panel without having to open/close it ✓
|
||||
--pretty slide out animation ✓
|
||||
|
||||
-improved poll UI ✓
|
||||
--poll panel auto-opens when poll starts ✓
|
||||
--button slides in chatbar from left, slides back after poll done ✓
|
||||
--on click toggles poll ui on left of chat menu ✓
|
||||
--improved poll chat announcements ~Original announcement removed. May implement once server whisper implemented.
|
||||
|
||||
-improved emote ui ✓
|
||||
--slide out emote ui ✓
|
||||
--search bar ✓
|
||||
--optional alphabet sort(default) ✓
|
||||
--optional legacy emote menu available ✓
|
||||
|
||||
-cytube+ ripout ✓
|
||||
--scroll to current item button ✓
|
||||
--orientation buttons in title bar ✓
|
||||
--quick settings(icon next to emote button) ✓
|
||||
---general pref
|
||||
----theme ✓
|
||||
---playback pref ✓
|
||||
----video orientation ✓
|
||||
----toggle orientation buttons ✓
|
||||
----sync threshold (in seconds) ✓
|
||||
----youtube source (add after degoogling) ~
|
||||
---chat pref ✓
|
||||
----use legacy cytube emote menu ✓
|
||||
----blink title on chat ✓
|
||||
----chat notification sound ✓
|
||||
----chat desktop notification ✓
|
||||
|
||||
-trim/tidy default cytube commands
|
||||
--replace / with ! as defualt server-side command indicator to match tokebot and TTN commands. / will be used for future client-side commands ✓
|
||||
---me ✓
|
||||
---sp ✓
|
||||
---afk ✓
|
||||
---poll ✓
|
||||
---hpoll ✓
|
||||
---mute ✓
|
||||
---smute ✓
|
||||
---unmute ✓
|
||||
---kick ✓
|
||||
---ban ✓
|
||||
---ipban ✓
|
||||
---clear ✓
|
||||
---clean ✓
|
||||
---cleantitle ✓
|
||||
--remove/consolidate/add to commands ✓
|
||||
---say -> announce(change tokebot modflair CSS to announce CSS, make normal modflair for bot/admin rank) ✓
|
||||
---remove kickanons ✓
|
||||
---remove d (drink) ✓
|
||||
---add user specific function to clear ('!clear <username>' to clear chats by said user) ✓
|
||||
|
||||
--Merge Upstream to newest cytube commit
|
||||
|
||||
-improved server-whisper system
|
||||
--public leave/join messages
|
||||
--server-whisper target parameter for user specific whispers
|
||||
--server-whisper name
|
||||
|
||||
-getplaylistlinks outputs in fpanel
|
||||
--I mean its pretty fucking simple I dont know how you can screw this one up bud.
|
||||
--ezpzlmnsqze
|
||||
|
||||
-ui sizing overhaul
|
||||
--rip out all but the ONE TRUE layout. It's not 2014 anymore, one layout with dynamic elements will get you further than multiple static ones.
|
||||
--chat/player sized to fit canvas with navbar (remove -+ buttons on player)
|
||||
--theatre mode toggle icon on title bar (hides navbar, player/chat takes up entire screen)
|
||||
--click to drag chat/player split
|
||||
--shade player (hide and unload video, titel bar shows title and unshade icon only)
|
||||
--shade chat (hide chat box, message box, send button. chat header bar collapses, retains user count and expansion arrows. Userlist/poll open/close is independent.)
|
||||
--popout video button
|
||||
--popout chat button
|
||||
--remove legacy cytube themes. If they wheren't compatible after the emote panel, they certainly won't be now lmao
|
||||
|
||||
-decaffeinate player.js
|
||||
--Coffee script was a bad idea then, and it makes even less sense now.
|
||||
--fuck me its just javascript with worse syntax, no real debugging tools, and build times
|
||||
--literally fucking why though?(I guess it made sense before ES6 but still fuck me)
|
||||
|
||||
-degoogling
|
||||
--yt-dlp backend for serverside metadata acquisition of youtube videos w/o registered API key or google account
|
||||
--potentially leverage yt-dlp backend for other media sources
|
||||
--invidious embed support for youtube video playback
|
||||
--youtube source in user prefrences (three or four invidious instances from different countries/continents, official youtube embed, or custom invidious instance)
|
||||
|
||||
-autobump
|
||||
--sepearate bump lists, based on js/txt files at first, will be stored in db next update (may use multiple at once)
|
||||
--skip next bump/disable bumping
|
||||
--bump frequency (default: 1)
|
||||
--queue method: random from last-half, round-robin, full random
|
||||
--override next bump
|
||||
--require video be at least 4 minutes to add bump (mods can override from bump menu)
|
||||
|
||||
-merge tokebot into ourfore.st codebase, one server instead of two.
|
||||
--profile and userlist entry
|
||||
---bot specific rank
|
||||
--reset cooldown accessible from modmenu (quiet and loud, quiet by default)
|
||||
--log tokes w/ date to file. This will be switched to mariadb in the next update
|
||||
--tokefile, list of usernames with toke count. This will be switched to mariadb in the next update
|
||||
--total tokes listed on profile tooltip
|
||||
|
||||
|
||||
-mod panel
|
||||
--button on chatbar
|
||||
--mod message (sends message to all active mods)
|
||||
--new poll button
|
||||
--autobump control tab
|
||||
--tokebot control tab
|
||||
--playlist tab
|
||||
--modflair
|
||||
--open playlist below video (if closed, otherwise this does not appear)
|
||||
--open playlist below video by default
|
||||
|
||||
|
||||
-merge fore.st theme changes to fore.st dusk, consider moving some of them over to cytube.css for easier management
|
||||
|
||||
-extra shit(probs wait til next update, or hotfix)
|
||||
--short chats (acronyms, emoji, single letters/numbers/symbols) pop in over video from left starting at top left, overflow pops in below, instead of in chat box. Chats slide back up into top of vid after 2s. (optional, default on)
|
||||
--basic mod chat (save to mod channel + pm all online mods)
|
||||
--basic profile page (in side panel)
|
||||
--css variables in theme for ez customizablity
|
||||
--user themes
|
||||
--change background to other themes background or img from url(theme background by default)
|
||||
--native odysee support (no raw embed)
|
||||
|
||||
|
||||
## License
|
||||
Original fore.st code is provided under the Affero General Public License v3 in order to prevent fore.st being used in proprietary software.
|
||||
(see the LICENSE file for the full text.)
|
||||
|
||||
Cytube source code originally licensed under MIT license
|
||||
(see the LICENSE file for the full text.)
|
||||
|
||||
Bundled source code, such as third-party CSS and JavaScript libraries, are
|
||||
provided under their respective licenses.
|
||||
|
|
|
|||
7303
package-lock.json
generated
7303
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -60,7 +60,7 @@
|
|||
"babel-plugin-add-module-exports": "^1.0.4",
|
||||
"coffeescript": "^1.9.2",
|
||||
"eslint": "^7.32.0",
|
||||
"mocha": "^8.4.0",
|
||||
"mocha": "^10.0.0",
|
||||
"sinon": "^10.0.0"
|
||||
},
|
||||
"babel": {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ window.Player = class Player
|
|||
|
||||
@setMediaProperties(data)
|
||||
@paused = false
|
||||
@latched = true
|
||||
@seeklatch = false #used to lock sync latch when seeking for sync
|
||||
@lastSTime = 0
|
||||
|
||||
load: (data) ->
|
||||
@setMediaProperties(data)
|
||||
|
|
@ -19,7 +22,20 @@ window.Player = class Player
|
|||
|
||||
pause: ->
|
||||
@paused = true
|
||||
|
||||
latch: ->
|
||||
if not @latched
|
||||
@latched = true
|
||||
unlatch: ->
|
||||
if not @seeklatch
|
||||
if @latched
|
||||
$("#latchvid").show()
|
||||
@latched = false
|
||||
else
|
||||
@seeklatch = false
|
||||
latchseek: ->
|
||||
@seeklatch = true
|
||||
getLatch: (cb) ->
|
||||
cb(@latched)
|
||||
seekTo: (time) ->
|
||||
|
||||
setVolume: (volume) ->
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ window.DailymotionPlayer = class DailymotionPlayer extends Player
|
|||
@setMediaProperties(data)
|
||||
@initialVolumeSet = false
|
||||
@playbackReadyCb = null
|
||||
@latched = true
|
||||
|
||||
waitUntilDefined(window, 'DM', =>
|
||||
removeOld()
|
||||
|
|
@ -37,6 +38,8 @@ window.DailymotionPlayer = class DailymotionPlayer extends Player
|
|||
@paused = true
|
||||
if CLIENT.leader
|
||||
sendVideoUpdate()
|
||||
else
|
||||
@unlatch()
|
||||
)
|
||||
|
||||
@dm.addEventListener('playing', =>
|
||||
|
|
@ -49,6 +52,11 @@ window.DailymotionPlayer = class DailymotionPlayer extends Player
|
|||
@initialVolumeSet = true
|
||||
)
|
||||
|
||||
@dm.addEventListener('seeked', =>
|
||||
if not CLIENT.leader
|
||||
@unlatch()
|
||||
)
|
||||
|
||||
# Once the video stops, the internal state of the player
|
||||
# becomes unusable and attempting to load() will corrupt it and
|
||||
# crash the player with an error. As a short–medium term
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ TYPE_MAP =
|
|||
tc: TwitchClipPlayer
|
||||
cm: VideoJSPlayer
|
||||
|
||||
|
||||
window.loadMediaPlayer = (data) ->
|
||||
try
|
||||
if window.PLAYER
|
||||
|
|
@ -41,16 +42,20 @@ window.handleMediaUpdate = (data) ->
|
|||
PLAYER = window.PLAYER
|
||||
|
||||
#bodge for fcyp.js layout
|
||||
handleWindowResize()
|
||||
#handleWindowResize()
|
||||
|
||||
#update airdate
|
||||
dispSTimes();
|
||||
|
||||
PLAYER.lastSTime = data.currentTime;
|
||||
if not PLAYER.latched #check if the shits latched, if not stop while we're ahead.
|
||||
return
|
||||
|
||||
# Do not update if the current time is past the end of the video, unless
|
||||
# the video has length 0 (which is a special case for livestreams)
|
||||
if typeof PLAYER.mediaLength is 'number' and
|
||||
if (typeof PLAYER.mediaLength is 'number' and
|
||||
PLAYER.mediaLength > 0 and
|
||||
data.currentTime > PLAYER.mediaLength
|
||||
data.currentTime > PLAYER.mediaLength)
|
||||
return
|
||||
|
||||
# Negative currentTime indicates a lead-in for clients to load the video,
|
||||
|
|
@ -66,6 +71,7 @@ window.handleMediaUpdate = (data) ->
|
|||
|
||||
if waiting
|
||||
PLAYER.seekTo(0)
|
||||
PLAYER.latchseek()
|
||||
# YouTube player has a race condition that crashes the player if
|
||||
# play(), seek(0), and pause() are called quickly without waiting
|
||||
# for events to fire. Setting a flag variable that is checked in the
|
||||
|
|
@ -83,6 +89,7 @@ window.handleMediaUpdate = (data) ->
|
|||
|
||||
if data.paused and not PLAYER.paused
|
||||
PLAYER.seekTo(data.currentTime)
|
||||
PLAYER.latchseek()
|
||||
PLAYER.pause()
|
||||
else if PLAYER.paused and not data.paused
|
||||
PLAYER.play()
|
||||
|
|
@ -101,6 +108,7 @@ window.handleMediaUpdate = (data) ->
|
|||
if diff > accuracy
|
||||
# The player is behind the correct time
|
||||
PLAYER.seekTo(time)
|
||||
PLAYER.latchseek()
|
||||
else if diff < -accuracy
|
||||
# The player is ahead of the correct time
|
||||
# Don't seek all the way back, to account for possible buffering.
|
||||
|
|
@ -109,8 +117,10 @@ window.handleMediaUpdate = (data) ->
|
|||
if not (PLAYER instanceof DailymotionPlayer)
|
||||
time += 1
|
||||
PLAYER.seekTo(time)
|
||||
PLAYER.latchseek()
|
||||
)
|
||||
|
||||
|
||||
window.removeOld = (replace) ->
|
||||
$('#soundcloud-volume-holder').remove()
|
||||
replace ?= $('<div/>').addClass('embed-responsive-item')
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
|
|||
constructor: (data) ->
|
||||
if not (this instanceof VideoJSPlayer)
|
||||
return new VideoJSPlayer(data)
|
||||
|
||||
@load(data)
|
||||
|
||||
loadPlayer: (data) ->
|
||||
|
|
@ -97,20 +96,14 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
|
|||
).appendTo(video)
|
||||
)
|
||||
|
||||
if data.meta.textTracks
|
||||
data.meta.textTracks.forEach((track) ->
|
||||
label = track.name
|
||||
attrs =
|
||||
src: track.url
|
||||
kind: 'subtitles'
|
||||
type: track.type
|
||||
label: label
|
||||
|
||||
if track.default? and track.default
|
||||
attrs.default = ''
|
||||
|
||||
$('<track/>').attr(attrs).appendTo(video)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@player = videojs(video[0],
|
||||
# https://github.com/Dash-Industry-Forum/dash.js/issues/2184
|
||||
|
|
@ -150,6 +143,9 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
|
|||
@paused = true
|
||||
if CLIENT.leader
|
||||
sendVideoUpdate()
|
||||
else
|
||||
@unlatch()
|
||||
|
||||
)
|
||||
|
||||
@player.on('play', =>
|
||||
|
|
@ -162,6 +158,9 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
|
|||
# spinner remains.
|
||||
@player.on('seeked', =>
|
||||
$('.vjs-waiting').removeClass('vjs-waiting')
|
||||
if not CLIENT.leader #this part has nothing to do with IE and all to do with sync latching :P
|
||||
@unlatch()
|
||||
|
||||
)
|
||||
|
||||
# Workaround for Chrome-- it seems that the click bindings for
|
||||
|
|
@ -184,12 +183,27 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
|
|||
|
||||
load: (data) ->
|
||||
@setMediaProperties(data)
|
||||
@latched = true
|
||||
# Note: VideoJS does have facilities for loading new videos into the
|
||||
# existing player object, however it appears to be pretty glitchy when
|
||||
# a video can't be played (either previous or next video). It's safer
|
||||
# to just reset the entire thing.
|
||||
@destroy()
|
||||
@loadPlayer(data)
|
||||
@setTracks(data)
|
||||
|
||||
setTracks: (data) ->
|
||||
if data.meta.textTracks
|
||||
data.meta.textTracks.forEach((track) ->
|
||||
label = track.name
|
||||
$('<track>').attr(
|
||||
src: track.url
|
||||
kind: 'subtitles'
|
||||
type: track.type
|
||||
label: label
|
||||
default: true
|
||||
).prependTo("video")
|
||||
)
|
||||
|
||||
play: ->
|
||||
@paused = false
|
||||
|
|
@ -200,6 +214,9 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
|
|||
@paused = true
|
||||
if @player and @player.readyState() > 0
|
||||
@player.pause()
|
||||
if not CLIENT.leader
|
||||
@unlatch()
|
||||
|
||||
|
||||
seekTo: (time) ->
|
||||
if @player and @player.readyState() > 0
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ window.VimeoPlayer = class VimeoPlayer extends Player
|
|||
|
||||
load: (data) ->
|
||||
@setMediaProperties(data)
|
||||
@latched = true
|
||||
|
||||
waitUntilDefined(window, 'Vimeo', =>
|
||||
video = $('<iframe/>')
|
||||
|
|
@ -32,6 +33,9 @@ window.VimeoPlayer = class VimeoPlayer extends Player
|
|||
@paused = true
|
||||
if CLIENT.leader
|
||||
sendVideoUpdate()
|
||||
else
|
||||
@unlatch()
|
||||
|
||||
)
|
||||
|
||||
@vimeo.on('play', =>
|
||||
|
|
@ -40,6 +44,11 @@ window.VimeoPlayer = class VimeoPlayer extends Player
|
|||
sendVideoUpdate()
|
||||
)
|
||||
|
||||
@vimeo.on('seeked', =>
|
||||
if not CLIENT.leader
|
||||
@unlatch()
|
||||
)
|
||||
|
||||
@play()
|
||||
@setVolume(VOLUME)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
var ChannelModule = require("./module");
|
||||
var Flags = require("../flags");
|
||||
var fs = require("fs");
|
||||
|
|
@ -94,8 +133,9 @@ function Channel(name) {
|
|||
}, USERCOUNT_THROTTLE);
|
||||
const self = this;
|
||||
db.channels.load(this, function (err) {
|
||||
if (err && err !== "Channel is not registered") {
|
||||
self.emit("loadFail", "Failed to load channel data from the database. Please try again later.");
|
||||
if (err /*&& err !== "Channel is not registered"*/) {
|
||||
//self.emit("channelNotRegistered");
|
||||
self.emit("loadFail", "Channel not found.");
|
||||
self.setFlag(Flags.C_ERROR);
|
||||
} else {
|
||||
self.initModules();
|
||||
|
|
@ -147,7 +187,6 @@ Channel.prototype.initModules = function () {
|
|||
"./permissions" : "permissions",
|
||||
"./emotes" : "emotes",
|
||||
"./chat" : "chat",
|
||||
"./drink" : "drink",
|
||||
"./filters" : "filters",
|
||||
"./customization" : "customization",
|
||||
"./opts" : "options",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
var Config = require("../config");
|
||||
var XSS = require("../xss");
|
||||
var ChannelModule = require("./module");
|
||||
|
|
@ -36,18 +75,16 @@ function ChatModule(_channel) {
|
|||
this.supportsDirtyCheck = true;
|
||||
|
||||
/* Default commands */
|
||||
this.registerCommand("/me", this.handleCmdMe.bind(this));
|
||||
this.registerCommand("/sp", this.handleCmdSp.bind(this));
|
||||
this.registerCommand("/say", this.handleCmdSay.bind(this));
|
||||
this.registerCommand("/rcv", this.handleCmdSay.bind(this));
|
||||
this.registerCommand("/shout", this.handleCmdSay.bind(this));
|
||||
this.registerCommand("/clear", this.handleCmdClear.bind(this));
|
||||
this.registerCommand("/a", this.handleCmdAdminflair.bind(this));
|
||||
this.registerCommand("/afk", this.handleCmdAfk.bind(this));
|
||||
this.registerCommand("/mute", this.handleCmdMute.bind(this));
|
||||
this.registerCommand("/smute", this.handleCmdSMute.bind(this));
|
||||
this.registerCommand("/unmute", this.handleCmdUnmute.bind(this));
|
||||
this.registerCommand("/unsmute", this.handleCmdUnmute.bind(this));
|
||||
this.registerCommand("!me", this.handleCmdMe.bind(this));
|
||||
this.registerCommand("!sp", this.handleCmdSp.bind(this));
|
||||
this.registerCommand("!announce", this.handleCmdSay.bind(this));
|
||||
this.registerCommand("!clear", this.handleCmdClear.bind(this));
|
||||
this.registerCommand("!a", this.handleCmdAdminflair.bind(this));
|
||||
this.registerCommand("!afk", this.handleCmdAfk.bind(this));
|
||||
this.registerCommand("!mute", this.handleCmdMute.bind(this));
|
||||
this.registerCommand("!smute", this.handleCmdSMute.bind(this));
|
||||
this.registerCommand("!unmute", this.handleCmdUnmute.bind(this));
|
||||
this.registerCommand("!unsmute", this.handleCmdUnmute.bind(this));
|
||||
}
|
||||
|
||||
ChatModule.prototype = Object.create(ChannelModule.prototype);
|
||||
|
|
@ -320,7 +357,8 @@ ChatModule.prototype.processChatMsg = function (user, data) {
|
|||
msgobj.meta.addClass = "greentext";
|
||||
}
|
||||
|
||||
if (data.msg.indexOf("/") === 0) {
|
||||
//if (data.msg.indexOf("/") === 0) {Legacy from cytube '/' commands
|
||||
if (data.msg.indexOf("!") === 0) {
|
||||
var space = data.msg.indexOf(" ");
|
||||
var cmd;
|
||||
if (space < 0) {
|
||||
|
|
@ -455,7 +493,8 @@ ChatModule.prototype.sendMessage = function (msgobj) {
|
|||
};
|
||||
|
||||
ChatModule.prototype.registerCommand = function (cmd, cb) {
|
||||
cmd = cmd.replace(/^\//, "");
|
||||
//cmd = cmd.replace(/^\//, ""); Legacy from cytube '/' commands
|
||||
cmd = cmd.replace(/^!/, "");
|
||||
this.commandHandlers[cmd] = cb;
|
||||
};
|
||||
|
||||
|
|
@ -495,11 +534,43 @@ ChatModule.prototype.handleCmdClear = function (user, _msg, _meta) {
|
|||
return;
|
||||
}
|
||||
|
||||
var target = _msg.toLowerCase().split(" ")[1];
|
||||
var tdisp = undefined;
|
||||
var nhit = false;
|
||||
|
||||
|
||||
|
||||
if(target != null){
|
||||
for(var i = 0; i < this.channel.users.length; i++){
|
||||
if(nhit = (target === this.channel.users[i].getLowerName())){
|
||||
tdisp = this.channel.users[i].getName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
target = nhit ? target : undefined;
|
||||
}
|
||||
|
||||
|
||||
this.dirty = true;
|
||||
this.buffer = [];
|
||||
this.channel.broadcastAll("clearchat", { clearedBy: user.getName() });
|
||||
this.sendModMessage(user.getName() + " cleared chat.", -1);
|
||||
this.channel.logger.log("[mod] " + user.getName() + " used /clear");
|
||||
|
||||
|
||||
this.channel.broadcastAll("clearchat", { clearedBy: user.getName(), target: tdisp });
|
||||
|
||||
if(target == null){
|
||||
this.buffer = [];
|
||||
this.sendModMessage(user.getName() + " cleared chat.", -1);
|
||||
this.channel.logger.log("[mod] " + user.getName() + " used !clear");
|
||||
}else{
|
||||
for(var x = 0; x < this.buffer.length; x++){
|
||||
if(this.buffer[x].username.toLowerCase() == target){
|
||||
//this.buffer.msg = '';
|
||||
this.buffer.splice(x,1);
|
||||
x--;
|
||||
}
|
||||
}
|
||||
this.sendModMessage(user.getName() + " cleared chats from " + tdisp + ".", -1);
|
||||
this.channel.logger.log("[mod] " + user.getName() + " cleared chats from " + tdisp + ".");
|
||||
}
|
||||
};
|
||||
|
||||
ChatModule.prototype.handleCmdAdminflair = function (user, msg, meta) {
|
||||
|
|
@ -510,7 +581,7 @@ ChatModule.prototype.handleCmdAdminflair = function (user, msg, meta) {
|
|||
args.shift();
|
||||
|
||||
var superadminflair = {
|
||||
labelclass: "label-danger",
|
||||
labelclass: "label-admin",
|
||||
icon: "glyphicon-globe"
|
||||
};
|
||||
|
||||
|
|
@ -547,7 +618,7 @@ ChatModule.prototype.handleCmdMute = function (user, msg, _meta) {
|
|||
var name = args.shift();
|
||||
if (typeof name !== "string") {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: "/mute requires a target name"
|
||||
msg: "!mute requires a target name"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -564,7 +635,7 @@ ChatModule.prototype.handleCmdMute = function (user, msg, _meta) {
|
|||
|
||||
if (!target) {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: "/mute target " + name + " not present in channel."
|
||||
msg: "!mute target " + name + " not present in channel."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -572,7 +643,7 @@ ChatModule.prototype.handleCmdMute = function (user, msg, _meta) {
|
|||
if (target.account.effectiveRank >= user.account.effectiveRank
|
||||
|| target.account.globalRank > user.account.globalRank) {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: "/mute failed - " + target.getName() + " has equal or higher rank " +
|
||||
msg: "!mute failed - " + target.getName() + " has equal or higher rank " +
|
||||
"than you."
|
||||
});
|
||||
return;
|
||||
|
|
@ -597,7 +668,7 @@ ChatModule.prototype.handleCmdSMute = function (user, msg, _meta) {
|
|||
var name = args.shift();
|
||||
if (typeof name !== "string") {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: "/smute requires a target name"
|
||||
msg: "!smute requires a target name"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -614,7 +685,7 @@ ChatModule.prototype.handleCmdSMute = function (user, msg, _meta) {
|
|||
|
||||
if (!target) {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: "/smute target " + name + " not present in channel."
|
||||
msg: "!smute target " + name + " not present in channel."
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -622,7 +693,7 @@ ChatModule.prototype.handleCmdSMute = function (user, msg, _meta) {
|
|||
if (target.account.effectiveRank >= user.account.effectiveRank
|
||||
|| target.account.globalRank > user.account.globalRank) {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: "/smute failed - " + target.getName() + " has equal or higher rank " +
|
||||
msg: "!smute failed - " + target.getName() + " has equal or higher rank " +
|
||||
"than you."
|
||||
});
|
||||
return;
|
||||
|
|
@ -648,7 +719,7 @@ ChatModule.prototype.handleCmdUnmute = function (user, msg, _meta) {
|
|||
var name = args.shift();
|
||||
if (typeof name !== "string") {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: "/unmute requires a target name"
|
||||
msg: "!unmute requires a target name"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +0,0 @@
|
|||
// TODO: figure out what to do with this module
|
||||
// it serves a very niche use case and is only a core module because of
|
||||
// legacy reasons (early channels requested it before I had criteria
|
||||
// around what to include in core)
|
||||
var ChannelModule = require("./module");
|
||||
|
||||
function DrinkModule(_channel) {
|
||||
ChannelModule.apply(this, arguments);
|
||||
this.drinks = 0;
|
||||
}
|
||||
|
||||
DrinkModule.prototype = Object.create(ChannelModule.prototype);
|
||||
|
||||
DrinkModule.prototype.onUserPostJoin = function (user) {
|
||||
user.socket.emit("drinkCount", this.drinks);
|
||||
};
|
||||
|
||||
DrinkModule.prototype.onUserPreChat = function (user, data, cb) {
|
||||
var msg = data.msg;
|
||||
var perms = this.channel.modules.permissions;
|
||||
if (msg.match(/^\/d-?[0-9]*/) && perms.canCallDrink(user)) {
|
||||
msg = msg.substring(2);
|
||||
var m = msg.match(/^(-?[0-9]+)/);
|
||||
var count;
|
||||
if (m) {
|
||||
count = parseInt(m[1]);
|
||||
if (isNaN(count) || count < -10000 || count > 10000) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg = msg.replace(m[1], "").trim();
|
||||
if (msg || count > 0) {
|
||||
msg += " drink! (x" + count + ")";
|
||||
} else {
|
||||
this.drinks += count;
|
||||
this.channel.broadcastAll("drinkCount", this.drinks);
|
||||
return cb(null, ChannelModule.DENY);
|
||||
}
|
||||
} else {
|
||||
msg = msg.trim() + " drink!";
|
||||
count = 1;
|
||||
}
|
||||
|
||||
this.drinks += count;
|
||||
this.channel.broadcastAll("drinkCount", this.drinks);
|
||||
data.msg = msg;
|
||||
data.meta.addClass = "drink";
|
||||
data.meta.forceShowName = true;
|
||||
cb(null, ChannelModule.PASSTHROUGH);
|
||||
} else {
|
||||
cb(null, ChannelModule.PASSTHROUGH);
|
||||
}
|
||||
};
|
||||
|
||||
DrinkModule.prototype.onMediaChange = function () {
|
||||
this.drinks = 0;
|
||||
this.channel.broadcastAll("drinkCount", 0);
|
||||
};
|
||||
|
||||
module.exports = DrinkModule;
|
||||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
var ChannelModule = require("./module");
|
||||
var db = require("../database");
|
||||
var Flags = require("../flags");
|
||||
|
|
@ -19,11 +58,10 @@ function KickBanModule(_channel) {
|
|||
ChannelModule.apply(this, arguments);
|
||||
|
||||
if (this.channel.modules.chat) {
|
||||
this.channel.modules.chat.registerCommand("/kick", this.handleCmdKick.bind(this));
|
||||
this.channel.modules.chat.registerCommand("/kickanons", this.handleCmdKickAnons.bind(this));
|
||||
this.channel.modules.chat.registerCommand("/ban", this.handleCmdBan.bind(this));
|
||||
this.channel.modules.chat.registerCommand("/ipban", this.handleCmdIPBan.bind(this));
|
||||
this.channel.modules.chat.registerCommand("/banip", this.handleCmdIPBan.bind(this));
|
||||
this.channel.modules.chat.registerCommand("!kick", this.handleCmdKick.bind(this));
|
||||
this.channel.modules.chat.registerCommand("!ban", this.handleCmdBan.bind(this));
|
||||
this.channel.modules.chat.registerCommand("!ipban", this.handleCmdIPBan.bind(this));
|
||||
this.channel.modules.chat.registerCommand("!banip", this.handleCmdIPBan.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,25 +233,6 @@ KickBanModule.prototype.handleCmdKick = function (user, msg, _meta) {
|
|||
}
|
||||
};
|
||||
|
||||
KickBanModule.prototype.handleCmdKickAnons = function (user, _msg, _meta) {
|
||||
if (!this.channel.modules.permissions.canKick(user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var users = Array.prototype.slice.call(this.channel.users);
|
||||
users.forEach(function (u) {
|
||||
if (!u.is(Flags.U_LOGGED_IN)) {
|
||||
u.kick("anonymous user");
|
||||
}
|
||||
});
|
||||
|
||||
this.channel.logger.log("[mod] " + user.getName() + " kicked anonymous users.");
|
||||
if (this.channel.modules.chat) {
|
||||
this.channel.modules.chat.sendModMessage(user.getName() + " kicked anonymous " +
|
||||
"users");
|
||||
}
|
||||
};
|
||||
|
||||
/* /ban - name bans */
|
||||
KickBanModule.prototype.handleCmdBan = function (user, msg, _meta) {
|
||||
var args = msg.split(" ");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
var ChannelModule = require("./module"); var ULList = require("../ullist");
|
||||
var AsyncQueue = require("../asyncqueue");
|
||||
var Media = require("../media");
|
||||
|
|
@ -9,6 +48,7 @@ var db = require("../database");
|
|||
var CustomEmbedFilter = require("../customembed").filter;
|
||||
var XSS = require("../xss");
|
||||
import { Counter } from 'prom-client';
|
||||
import { validateTextTracks as tvalidate } from '../custom-media';
|
||||
|
||||
const LOGGER = require('@calzoneman/jsli')('playlist');
|
||||
|
||||
|
|
@ -27,7 +67,8 @@ const TYPE_QUEUE = {
|
|||
pos: "string",
|
||||
title: "string,boolean,optional",
|
||||
duration: "number,optional",
|
||||
temp: "boolean,optional"
|
||||
temp: "boolean,optional",
|
||||
subtitle: "string"
|
||||
};
|
||||
|
||||
const TYPE_SET_TEMP = {
|
||||
|
|
@ -105,8 +146,8 @@ function PlaylistModule(_channel) {
|
|||
this._refreshing = false;
|
||||
|
||||
if (this.channel.modules.chat) {
|
||||
this.channel.modules.chat.registerCommand("/clean", this.handleClean.bind(this));
|
||||
this.channel.modules.chat.registerCommand("/cleantitle", this.handleClean.bind(this));
|
||||
this.channel.modules.chat.registerCommand("!clean", this.handleClean.bind(this));
|
||||
this.channel.modules.chat.registerCommand("!cleantitle", this.handleClean.bind(this));
|
||||
}
|
||||
|
||||
this.supportsDirtyCheck = true;
|
||||
|
|
@ -408,6 +449,11 @@ PlaylistModule.prototype.handleQueue = function (user, data) {
|
|||
data.title = false;
|
||||
}
|
||||
|
||||
|
||||
if (!data.subtitle){
|
||||
data.subtitle = false;
|
||||
}
|
||||
|
||||
var link = util.formatLink(id, type, null);
|
||||
var perms = this.channel.modules.permissions;
|
||||
|
||||
|
|
@ -491,6 +537,7 @@ PlaylistModule.prototype.handleQueue = function (user, data) {
|
|||
type: data.type,
|
||||
pos: data.pos,
|
||||
title: data.title,
|
||||
subtitle: data.subtitle,
|
||||
link: link,
|
||||
temp: temp,
|
||||
shouldAddToLibrary: !temp,
|
||||
|
|
@ -1051,16 +1098,52 @@ PlaylistModule.prototype._addItem = function (media, data, user, cb) {
|
|||
media.setTitle(data.title);
|
||||
}
|
||||
|
||||
|
||||
console.log("pre media subload");
|
||||
console.log(data);
|
||||
if (data.subtitle && (media.type === "cu" || media.type === "fi")) {
|
||||
|
||||
|
||||
var ttracks = [{
|
||||
"url": data.subtitle,
|
||||
"contentType": "text/vtt",
|
||||
"name": "English Subs",
|
||||
"default": true
|
||||
}];
|
||||
|
||||
|
||||
console.log(Config.get('http.root-domain'));
|
||||
try {
|
||||
tvalidate(ttracks);
|
||||
} catch (error) {
|
||||
user.socket.emit("errorMsg", {
|
||||
msg: `Invalid text track error:` + error
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
media.meta.textTracks = ttracks;
|
||||
|
||||
}
|
||||
|
||||
var success = function () {
|
||||
var tempST = 0;
|
||||
//var packet = {
|
||||
// item: item.pack(),
|
||||
// after: item.prev ? item.prev.uid : "prepend"
|
||||
//};
|
||||
|
||||
self.meta.count++;
|
||||
|
||||
self.items.forEach(function (item){//iterate items
|
||||
self.items.find(item.uid).media.startTime = tempST;//current item start time = tempST
|
||||
tempST += item.media.seconds;
|
||||
});
|
||||
|
||||
|
||||
/*self.meta.count++;
|
||||
media.startTime = self.meta.rawTime;
|
||||
self.meta.rawTime += media.seconds;
|
||||
self.meta.time = util.formatTime(self.meta.rawTime);
|
||||
self.meta.time = util.formatTime(self.meta.rawTime);*/ //old buggy shit
|
||||
|
||||
var sTemp = [[],[]];
|
||||
|
||||
|
|
@ -1297,8 +1380,8 @@ PlaylistModule.prototype.handleClean = function (user, msg, _meta) {
|
|||
var cmd = args.shift();
|
||||
if (args.length === 0) {
|
||||
return user.socket.emit("errorMsg", {
|
||||
msg: "No target given for " + cmd + ". Usage: /clean <username> or " +
|
||||
"/cleantitle <title>"
|
||||
msg: "No target given for " + cmd + ". Usage: !clean <username> or " +
|
||||
"!cleantitle <title>"
|
||||
});
|
||||
}
|
||||
var target;
|
||||
|
|
@ -1315,9 +1398,9 @@ PlaylistModule.prototype.handleClean = function (user, msg, _meta) {
|
|||
" with target regex: " + target);
|
||||
|
||||
var cleanfn;
|
||||
if (cmd === "/clean") {
|
||||
if (cmd === "!clean") {
|
||||
cleanfn = function (item) { return target.test(item.queueby); };
|
||||
} else if (cmd === "/cleantitle") {
|
||||
} else if (cmd === "!cleantitle") {
|
||||
cleanfn = function (item) { return target.exec(item.media.title) !== null; };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ function PollModule(_channel) {
|
|||
this.roomViewHidden = this.channel.uniqueName + ROOM_VIEW_HIDDEN;
|
||||
this.roomNoViewHidden = this.channel.uniqueName + ROOM_NO_VIEW_HIDDEN;
|
||||
if (this.channel.modules.chat) {
|
||||
this.channel.modules.chat.registerCommand("poll", this.handlePollCmd.bind(this, false));
|
||||
this.channel.modules.chat.registerCommand("hpoll", this.handlePollCmd.bind(this, true));
|
||||
this.channel.modules.chat.registerCommand("!poll", this.handlePollCmd.bind(this, false));
|
||||
this.channel.modules.chat.registerCommand("!hpoll", this.handlePollCmd.bind(this, true));
|
||||
}
|
||||
this.supportsDirtyCheck = true;
|
||||
}
|
||||
|
|
@ -254,7 +254,8 @@ PollModule.prototype.handlePollCmd = function (obscured, user, msg, _meta) {
|
|||
// Ensure any existing poll is closed
|
||||
this.handleClosePoll(user);
|
||||
|
||||
msg = msg.replace(/^\/h?poll/, "");
|
||||
msg = msg.replace(/^!h?poll/, "");
|
||||
//msg = msg.replace(/^\/h?poll/, "");
|
||||
|
||||
var args = msg.split(",");
|
||||
var title = args.shift();
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ function validateSources(sources, data) {
|
|||
}
|
||||
}
|
||||
|
||||
function validateTextTracks(textTracks) {
|
||||
export function validateTextTracks(textTracks) {
|
||||
if (typeof textTracks === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
13
src/user.js
13
src/user.js
|
|
@ -102,10 +102,15 @@ User.prototype.handleJoinChannel = function handleJoinChannel(data) {
|
|||
|
||||
if (!chan.is(Flags.C_READY)) {
|
||||
chan.once("loadFail", reason => {
|
||||
this.socket.emit("errorMsg", {
|
||||
msg: reason,
|
||||
alert: true
|
||||
});
|
||||
|
||||
if(reason == "Channel not found."){
|
||||
this.socket.emit("channelNotFound");
|
||||
}else{
|
||||
this.socket.emit("errorMsg", {
|
||||
msg: reason,
|
||||
alert: true
|
||||
});
|
||||
}
|
||||
this.kick(`Channel could not be loaded: ${reason}`);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,44 @@
|
|||
extends layout.pug
|
||||
|
||||
block content
|
||||
//
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
//
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
.col-md-8.col-md-offset-2
|
||||
.aboutText
|
||||
h1 Welcome to ourfore.st!
|
||||
|
|
@ -19,4 +57,4 @@ block content
|
|||
| No spamming submit channel or chat
|
||||
p.
|
||||
Comments? Questions? Feature requests? DMCA Notices? <a href="mailto:ourforest@420blaze.it">Email us!</a>
|
||||
h4 fore.st version: Panama Red (v1)
|
||||
h4 fore.st version: Pineapple Express (v1.1-INDEV)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
//
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
//
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
doctype html
|
||||
html(lang="en")
|
||||
head
|
||||
|
|
@ -27,17 +66,22 @@ html(lang="en")
|
|||
#motd
|
||||
.clear
|
||||
#announcements.row
|
||||
#drinkbarwrap.row
|
||||
#drinkbar.col-lg-12.col-md-12
|
||||
h1#drinkcount
|
||||
#main.row
|
||||
#videowrap.col-lg-7.col-md-7
|
||||
p#videowrap-header
|
||||
span#resize-video-larger.glyphicon.glyphicon-plus.pointer(title="Make the video larger")
|
||||
span#resize-video-smaller.glyphicon.glyphicon-minus.pointer(title="Make the video smaller")
|
||||
span#mediarefresh.playercont.glyphicon.glyphicon-retweet.pointer(title="Reload the video player")
|
||||
span#flipx-video.playercont.glyphicon.glyphicon-resize-horizontal.pointer(title="Flip Player Horizontally",onclick='javascript:$("#ytapiplayer").toggleClass("mirx")')
|
||||
span#flipy-video.playercont.glyphicon.glyphicon-resize-vertical.pointer(title="Flip Player Vertically",onclick='javascript:$("#ytapiplayer").toggleClass("miry")')
|
||||
span#showplaylist.playercont.glyphicon.glyphicon-list.pointer(style="display: none;", title="Show playlist")
|
||||
span#resize-video-larger.playercont.glyphicon.glyphicon-plus.pointer(title="Make the video larger")
|
||||
span#resize-video-smaller.playercont.glyphicon.glyphicon-minus.pointer(title="Make the video smaller")
|
||||
span#latchvid.label.label-default.pull-right.pointer(style="display: none;") Sync
|
||||
span#currenttitle Nothing Playing
|
||||
.embed-responsive.embed-responsive-16by9
|
||||
#ytapiplayer.embed-responsive-item
|
||||
div#subliminaltoke
|
||||
img(src="/img/tokeleaf.png")
|
||||
h3 Take a <a onclick="chatsmack('!toke')">Toke!</a>
|
||||
#chatwrap.col-lg-5.col-md-5
|
||||
#chatheader
|
||||
span#modflair.label.label-default.pull-right.pointer Name Color
|
||||
|
|
@ -46,9 +90,16 @@ html(lang="en")
|
|||
i#userlisttoggle.glyphicon.glyphicon-chevron-down.pull-left.pointer(title="Show/Hide Userlist")
|
||||
#chatmain
|
||||
#userlist
|
||||
#fpaneldiv.fpanel(style="display: none;")
|
||||
#fptitlediv.fptitlebar.fpanel
|
||||
p#fptitle.fptitlebar.fpanel null
|
||||
p#closefpanel.fptitlebar.fpanel.glyphicon.glyphicon-remove.pointer(onclick="javascript:closeFPanel()", title="Close null panel.")
|
||||
#fpcontdiv.fpcont.fpanel
|
||||
#messagebuffer.linewrap
|
||||
#chatbar(style="display: flex;")
|
||||
button#emotelistbtn.btn.btn-sm.btn-default(title="emotes") ;)
|
||||
button#pollopenbtn.btn.btn-sm.btn-default.glyphicon.glyphicon-ok.chatbtn(onclick="javascript:panelbtn(fpoll)",style="display: none;", title="Poll")
|
||||
button#prefopenbtn.btn.btn-sm.btn-default.glyphicon.glyphicon-cog.chatbtn(onclick="javascript:panelbtn(fpset)",title="Quick Settings")
|
||||
button#emoteopenbtn.btn.btn-sm.btn-default.chatbtn(onclick="javascript:panelbtn(fpemote)",title="Emotes") ;)
|
||||
form(action="javascript:void(0)" style="display: flex; flex-grow: 1;")
|
||||
input#chatline.form-control(type="text", maxlength="320", style="display: none")
|
||||
#guestlogin.input-group
|
||||
|
|
@ -57,32 +108,37 @@ html(lang="en")
|
|||
button#chatsend.btn.btn-sm.btn-default Send
|
||||
#rightcontrols.col-lg-7.col-md-7
|
||||
#plcontrol.btn-group
|
||||
button#showsearch.btn.btn-sm.btn-default(title="Search for a video", data-toggle="collapse", data-target="#searchcontrol")
|
||||
span.glyphicon.glyphicon-search
|
||||
button#showmediaurl.btn.btn-sm.btn-default(title="Add video from URL", data-toggle="collapse", data-target="#addfromurl")
|
||||
span.glyphicon.glyphicon-plus
|
||||
button#showcustomembed.btn.btn-sm.btn-default(title="Embed a custom frame", data-toggle="collapse", data-target="#customembed")
|
||||
span.glyphicon.glyphicon-th-large
|
||||
button#showsearch.btn.btn-sm.btn-default(title="Channel History + Video Search", data-toggle="collapse", data-target="#searchcontrol")
|
||||
span.glyphicon.glyphicon-search
|
||||
button#showplaylistmanager.btn.btn-sm.btn-default(title="Manage playlists", data-toggle="collapse", data-target="#playlistmanager")
|
||||
span.glyphicon.glyphicon-list
|
||||
button#clearplaylist.btn.btn-sm.btn-default(title="Clear the playlist")
|
||||
span.glyphicon.glyphicon-trash
|
||||
button#shuffleplaylist.btn.btn-sm.btn-default(title="Shuffle the playlist")
|
||||
span.glyphicon.glyphicon-sort
|
||||
button#qlockbtn.btn.btn-sm.btn-danger(title="Playlist locked")
|
||||
span.glyphicon.glyphicon-lock
|
||||
#videocontrols.btn-group.pull-right
|
||||
button#mediarefresh.btn.btn-sm.btn-default(title="Reload the video player")
|
||||
span.glyphicon.glyphicon-retweet
|
||||
button#fullscreenbtn.btn.btn-sm.btn-default(title="Make the video player fullscreen")
|
||||
span.glyphicon.glyphicon-fullscreen
|
||||
button#scrollitm.btn.btn-sm.btn-default(title="Scroll to Current Item",onclick="javascript:scrollQueue()")
|
||||
span.glyphicon.glyphicon-hand-right
|
||||
button#getplaylist.btn.btn-sm.btn-default(title="Retrieve playlist links")
|
||||
span.glyphicon.glyphicon-link
|
||||
button#voteskip.btn.btn-sm.btn-default(title="Voteskip")
|
||||
span.glyphicon.glyphicon-step-forward
|
||||
button#shuffleplaylist.btn.btn-sm.btn-default(title="Shuffle the playlist")
|
||||
span.glyphicon.glyphicon-sort
|
||||
button#clearplaylist.btn.btn-sm.btn-default(title="Clear the playlist")
|
||||
span.glyphicon.glyphicon-trash
|
||||
button#qlockbtn.btn.btn-sm.btn-danger(title="Playlist locked")
|
||||
span.glyphicon.glyphicon-lock
|
||||
#playlistauxcont
|
||||
span#hideplaylist.glyphicon.glyphicon-remove.pointer(title="Close Playlist")
|
||||
span#blindItems.glyphicon.glyphicon-resize-small.pointer(title="Collapse All Items")
|
||||
#plmeta
|
||||
span#plcount 0 items
|
||||
br
|
||||
span#pllength 00:00:00
|
||||
//#videocontrols.btn-group.pull-right
|
||||
//button#fullscreenbtn.btn.btn-sm.btn-default(title="Make the video player fullscreen")This makes no sense, all supported players already have a full screen button. Not a fan of the placement of this anywho
|
||||
//span.glyphicon.glyphicon-fullscreen
|
||||
//button#voteskip.btn.btn-sm.btn-default(title="Voteskip") I don't like the way this is implemented, I think a poll based voteskip feature would be better, though I think it'd be better to not do a full rip-out
|
||||
//span.glyphicon.glyphicon-step-forward
|
||||
//this is being removed in favor of better UI
|
||||
#leftcontrols.col-lg-5.col-md-5
|
||||
button#newpollbtn.btn.btn-sm.btn-default New Poll
|
||||
|
||||
#playlistrow.row
|
||||
#rightpane.col-lg-7.col-md-7
|
||||
#rightpane-inner.row
|
||||
|
|
@ -107,6 +163,9 @@ html(lang="en")
|
|||
button#queue_next.btn.btn-default Queue next
|
||||
span.input-group-btn
|
||||
button#queue_end.btn.btn-default Queue last
|
||||
span.input-group-btn#showcustomembed
|
||||
button#showcustomembed.btn.btn-default(title="Embed a custom frame", data-toggle="collapse", data-target="#customembed")
|
||||
span.glyphicon.glyphicon-th-large
|
||||
.checkbox
|
||||
label
|
||||
input.add-temp(type="checkbox")
|
||||
|
|
@ -139,12 +198,8 @@ html(lang="en")
|
|||
| Add as temporary
|
||||
ul#userpl_list.videolist
|
||||
#queuefail.col-lg-12.col-md-12
|
||||
.vertical-spacer
|
||||
.col-lg-12.col-md-12
|
||||
ul#queue.videolist
|
||||
#plmeta
|
||||
span#plcount 0 items
|
||||
span#pllength 00:00:00
|
||||
#leftpane.col-lg-5.col-md-5
|
||||
#leftpane-inner.row
|
||||
#pollwrap.col-lg-12.col-md-12
|
||||
|
|
@ -238,6 +293,7 @@ html(lang="en")
|
|||
include footer
|
||||
+footer()
|
||||
script(id="socketio-js", src=sioSource)
|
||||
script(src="/js/fpanel.js")
|
||||
script(src="/js/data.js")
|
||||
script(src="/js/fembed.js")
|
||||
script(src="/js/fchat.js")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,43 @@
|
|||
//
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
//
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
mixin lcheckbox(id, label)
|
||||
.form-group
|
||||
label.control-label.col-sm-4(for=id)= label
|
||||
|
|
|
|||
|
|
@ -1,6 +1,44 @@
|
|||
extends layout.pug
|
||||
|
||||
block content
|
||||
//
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
//
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
.col-lg-9.col-md-9
|
||||
h3 Public Channels
|
||||
table.table.table-bordered.table-striped
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@ mixin us-general
|
|||
.col-sm-8
|
||||
select#us-theme.form-control
|
||||
option(value="/css/themes/fore.st.css") fore.st
|
||||
option(value="/css/themes/light.css") Light
|
||||
option(value="/css/themes/bootstrap-theme.min.css") Bootstrap
|
||||
option(value="/css/themes/slate.css") Slate
|
||||
option(value="/css/themes/cyborg.css") Cyborg
|
||||
option(value="/css/themes/modern.css") Modern
|
||||
//
|
||||
option(value="/css/themes/light.css") Light
|
||||
option(value="/css/themes/slate.css") Slate
|
||||
option(value="/css/themes/bootstrap-theme.min.css") Bootstrap
|
||||
option(value="/css/themes/cyborg.css") Cyborg
|
||||
option(value="/css/themes/modern.css") Modern
|
||||
.col-sm-4
|
||||
.col-sm-8
|
||||
p.text-danger Changing layouts may require refreshing to take effect.
|
||||
|
|
@ -67,7 +68,8 @@ mixin us-playback
|
|||
p.text-info Setting <code>wmode=transparent</code> allows objects to be displayed above the video player, but may cause performance issues on some systems.
|
||||
+rcheckbox("us-hidevideo", "Remove the video player")
|
||||
+rcheckbox("us-playlistbuttons", "Hide playlist buttons by default")
|
||||
+rcheckbox("us-oldbtns", "Old style playlist buttons")
|
||||
+rcheckbox("us-oldbtns", "Compact playlist buttons")
|
||||
+rcheckbox("us-video-orientation", "Show video orientation buttons above player")
|
||||
.form-group
|
||||
label.control-label.col-sm-4(for="#us-default-quality") Quality Preference
|
||||
.col-sm-8
|
||||
|
|
@ -91,6 +93,7 @@ mixin us-chat
|
|||
+rcheckbox("us-chat-timestamp", "Show timestamps in chat")
|
||||
+rcheckbox("us-sort-rank", "Sort userlist by rank")
|
||||
+rcheckbox("us-sort-afk", "Sort AFKers to bottom")
|
||||
+rcheckbox("us-legacy-emote", "Use legacy Cytube emote menu")
|
||||
.col-sm-4
|
||||
.col-sm-8
|
||||
p.text-info The following 3 options apply to how and when you will be notified if a new chat message is received while CyTube is not the active window.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,41 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
.container-fluid {
|
||||
padding-left: 15px;
|
||||
|
|
@ -153,11 +191,15 @@
|
|||
border-radius: 0;
|
||||
}
|
||||
|
||||
#rightcontrols{
|
||||
background-color: #111111C0;
|
||||
}
|
||||
|
||||
#plmeta {
|
||||
border-radius: 4px;
|
||||
border-top: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border: none;
|
||||
float: right;
|
||||
padding-right: 1em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.videolist {
|
||||
|
|
@ -212,10 +254,128 @@ li.ui-sortable-helper, li.ui-sortable-placeholder + li.queue_entry {
|
|||
}
|
||||
|
||||
.qe_time {
|
||||
float: right;
|
||||
float: left;
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
||||
.qe_sTime, .qe_pref{
|
||||
float: right;
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
||||
#playlistauxcont {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#addformurl-title-val{
|
||||
width: auto;
|
||||
}
|
||||
.fptitlebar{
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: inherit !important;
|
||||
color: #c8c8c8;
|
||||
vertical-align: top;
|
||||
margin: 0px;
|
||||
}
|
||||
#fpcontdiv{
|
||||
}
|
||||
#subliminaltoke{
|
||||
background-color: #111111C0;
|
||||
position: absolute;
|
||||
left: calc(50% - 12em);
|
||||
top: calc(50% - 13em);
|
||||
text-align: center;
|
||||
padding: 2em 2em 1em 2em;
|
||||
border: 1px solid #949494;
|
||||
display: none;
|
||||
}
|
||||
#subliminaltoke img{
|
||||
max-height: 20em;
|
||||
}
|
||||
.emotecontdiv{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(7em,auto));
|
||||
overflow-x: hidden;
|
||||
column-gap: 0.5em;
|
||||
row-gap: 0.5em;
|
||||
margin: 3.1em 0.5em 0 0.5em;
|
||||
}
|
||||
.emotediv{
|
||||
width: 100%;
|
||||
border: 1px solid #949494;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
#emspan{
|
||||
display: flex;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.emotediv img{
|
||||
width: 100%;
|
||||
}
|
||||
.emotediv p{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.chatbtn{
|
||||
border-right: 1px solid #949494 !important;
|
||||
position: inherit !important;
|
||||
}
|
||||
#polltitle, #endpollbtn{
|
||||
margin-top: 5px;
|
||||
margin-bottom: 20px;
|
||||
display: inline-block;
|
||||
}
|
||||
#emotecont{
|
||||
display: flex;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
background-color: #1119;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
#esearchbar{
|
||||
border-right: 1px solid #949494;
|
||||
background-color: #0000 !important;
|
||||
}
|
||||
#anumspan{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0em 0.5em 0 0.5em;
|
||||
height: 100%;
|
||||
}
|
||||
#emotealphabox{
|
||||
}
|
||||
label[for="emotealphabox"]{
|
||||
}
|
||||
#fptitlediv{
|
||||
width: 100%;
|
||||
}
|
||||
#closefpanel{
|
||||
float: right;
|
||||
top: auto;
|
||||
}
|
||||
#fpaneldiv{
|
||||
float: left;
|
||||
height: 1em;
|
||||
width: 70%;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
#guestlogin{
|
||||
flex-grow: 1;
|
||||
}
|
||||
#hideplaylist {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.qe_clear {
|
||||
clear: both;
|
||||
}
|
||||
|
|
@ -236,7 +396,9 @@ li.ui-sortable-helper, li.ui-sortable-placeholder + li.queue_entry {
|
|||
#csstext, #jstext {
|
||||
font-family: Monospace;
|
||||
}
|
||||
|
||||
.fpcont{
|
||||
overflow: scroll;
|
||||
}
|
||||
#optedit, #permedit, #filteredit, #motdedit, #cssedit, #jsedit,
|
||||
#banlist, #loginhistory, #channelranks, #chanlog {
|
||||
display: none;
|
||||
|
|
@ -258,6 +420,8 @@ li.ui-sortable-helper, li.ui-sortable-placeholder + li.queue_entry {
|
|||
background-color: rgba(129, 20, 21, 0.1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.server-msg-reconnect {
|
||||
border: 1px solid #009900;
|
||||
line-height: 2;
|
||||
|
|
@ -436,7 +600,7 @@ li.ui-sortable-helper, li.ui-sortable-placeholder + li.queue_entry {
|
|||
}
|
||||
|
||||
.qfalert {
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 0px;
|
||||
padding-left: 0!important;
|
||||
padding-right: 0!important;
|
||||
}
|
||||
|
|
@ -692,10 +856,24 @@ input#logout[type="submit"]:hover {
|
|||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#resize-video-larger, #resize-video-smaller {
|
||||
.playercont {
|
||||
float: right;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.mirx{
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
.miry{
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
.mirx.miry{
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
#fpsetdiv p{
|
||||
font-weight: 700;
|
||||
display: inline;
|
||||
}
|
||||
body.hd #resize-video-larger, body.hd #resize-video-smaller {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*//
|
||||
|
||||
@import url("//fonts.googleapis.com/css?family=Droid+Sans:400,700");
|
||||
/*!
|
||||
/*! * bootswatch v3.3.1+1 * Homepage: http://bootswatch.com * Copyright 2012-2014 Thomas Park * Licensed under MIT * Based on Bootstrap */
|
||||
|
|
@ -49,6 +88,14 @@ sub,sup{
|
|||
position:relative;
|
||||
vertical-align:baseline
|
||||
}
|
||||
.label-admin, .label.label-admin{
|
||||
background-color: #cc0000;
|
||||
color: #000;
|
||||
text-shadow: #000 0 0 10px;
|
||||
box-shadow: #cc0000 0 0 10px;
|
||||
margin-right: 0.3em;
|
||||
}
|
||||
|
||||
sup{
|
||||
top:-.5em
|
||||
}
|
||||
|
|
@ -1201,7 +1248,7 @@ pre code{
|
|||
}
|
||||
.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{
|
||||
position:relative;
|
||||
min-height:1px;
|
||||
min-height:0px;
|
||||
padding-left:0px;
|
||||
padding-right:0px
|
||||
}
|
||||
|
|
@ -2027,7 +2074,7 @@ output{
|
|||
-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;
|
||||
transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s
|
||||
}
|
||||
.form-control:focus{
|
||||
.form-control:focus, #esearchbar:focus{
|
||||
border-color:#339933;
|
||||
outline:0;
|
||||
-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(51,153,51,.6);
|
||||
|
|
@ -2505,6 +2552,32 @@ select[multiple].form-group-lg .form-control,select[multiple].input-lg,textarea.
|
|||
line-height:1.5;
|
||||
border-radius:0px
|
||||
}
|
||||
.btn-ln{
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
border-radius: 0px
|
||||
}
|
||||
.qs-form{
|
||||
flex-grow: 1;
|
||||
color:#888;
|
||||
background-color:#fff;
|
||||
background-image:none;
|
||||
border:1px solid #282828;
|
||||
border-radius:0px;
|
||||
box-shadow:inset 0 1px 1px rgba(0,0,0,.075);
|
||||
transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s
|
||||
}
|
||||
.qs-form:focus{
|
||||
border-color:#339933;
|
||||
outline:0;
|
||||
-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(51,153,51,.6);
|
||||
box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(51,153,51,.6)
|
||||
}
|
||||
input.qs-form[type="text"], input.qs-form[type="password"], input.qs-form[type="email"], textarea.qs-form {
|
||||
background-color: #111111C0 !important;
|
||||
color: #c8c8c8;
|
||||
}
|
||||
.btn-group-xs>.btn,.btn-xs{
|
||||
padding:1px 5px;
|
||||
font-size:12px;
|
||||
|
|
@ -3839,7 +3912,7 @@ a.badge:focus,a.badge:hover{
|
|||
}
|
||||
.alert{
|
||||
padding:15px;
|
||||
margin-bottom:20px;
|
||||
margin-bottom:0px;
|
||||
border:1px solid transparent;
|
||||
border-radius:0px
|
||||
}
|
||||
|
|
@ -5399,10 +5472,6 @@ a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{
|
|||
#drinkcount {
|
||||
background-color: #000000;
|
||||
color: #ffffff;
|
||||
}
|
||||
#plmeta {
|
||||
border: 1px solid #949494;
|
||||
border-radius: 0px;
|
||||
}
|
||||
#userlist, #messagebuffer {
|
||||
border: 1px solid #949494;
|
||||
|
|
@ -5423,19 +5492,41 @@ a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{
|
|||
.queue_entry.queue_active {
|
||||
background-color: #333333;
|
||||
}
|
||||
#newmessages-indicator-bghack {
|
||||
background: rgb(32, 32, 32);
|
||||
background: rgba(32, 32, 32, 0.9);
|
||||
#newmessages-indicator {
|
||||
color:#339933;
|
||||
text-shadow: #ded 0 0 1px;
|
||||
text-decoration:none;
|
||||
}
|
||||
#chatheader, #userlist, #messagebuffer, #videowrap-header, .embed-responsive, #rightpane, #mainrow{
|
||||
background-color: #111111C0;
|
||||
.emotediv:hover{
|
||||
color: #ded;
|
||||
text-shadow: #339933 0 0 10px;
|
||||
box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(51,153,51,.6);
|
||||
border-color:#339933;
|
||||
}
|
||||
#newmessages-indicator:focus, #newmessages-indicator:hover {
|
||||
color:#ded;
|
||||
text-shadow: #339933 0 0 10px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.qe_sTime{
|
||||
float: right;
|
||||
font-family: Monospace;
|
||||
#emotelistbtm, #chatsend, #motdwrap, #chatline, #rightcontrols, #chatheader, #userlist, #messagebuffer, #videowrap-header, .embed-responsive, #rightpane, #mainrow{
|
||||
background-color: #111111C0;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
.aboutText{
|
||||
|
||||
#fpaneldiv{
|
||||
border: 1px #949494 solid;
|
||||
background-color: #1119;
|
||||
backdrop-filter: blur(12px);
|
||||
border-left: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#fptitlediv{
|
||||
border-bottom: 1px #949494 solid;
|
||||
}
|
||||
|
||||
.aboutText{
|
||||
background-color: #111111C0;
|
||||
padding: 10px;
|
||||
border: 1px solid #949494;
|
||||
|
|
@ -5487,7 +5578,7 @@ a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{
|
|||
text-shadow: none;
|
||||
}
|
||||
|
||||
#botmsg{
|
||||
.shout{
|
||||
text-align: center;
|
||||
color: #FFFFFF;
|
||||
text-shadow:
|
||||
|
|
@ -5507,10 +5598,6 @@ a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover{
|
|||
border-right: 1px solid #949494;
|
||||
}
|
||||
|
||||
#emotelistbtn{
|
||||
border-right: 1px solid #949494;
|
||||
}
|
||||
|
||||
#chatsend{
|
||||
border-left: 1px solid #949494;
|
||||
}
|
||||
|
|
|
|||
5519
www/css/themes/fore.st.dusk.css
Normal file
5519
www/css/themes/fore.st.dusk.css
Normal file
File diff suppressed because it is too large
Load diff
3678
www/cyp/fcyp.js
3678
www/cyp/fcyp.js
File diff suppressed because it is too large
Load diff
3668
www/cyp/fcyp.old
3668
www/cyp/fcyp.old
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
248
www/cyp/main.css
248
www/cyp/main.css
|
|
@ -1,248 +0,0 @@
|
|||
/* ----- Smoothing default CyTube CSS (works without JS) ----- */
|
||||
|
||||
|
||||
/* -- body -- */
|
||||
|
||||
body {overflow-x:hidden}
|
||||
|
||||
/* -- buttons -- */
|
||||
|
||||
.btn {text-shadow:none}
|
||||
|
||||
/* -- modal windows -- */
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.modal-dialog {max-width:950px !important; margin-top:10px}
|
||||
}
|
||||
|
||||
/* -- brand -- */
|
||||
|
||||
.navbar-brand {cursor:default}
|
||||
|
||||
/* -- MOTD -- */
|
||||
|
||||
#motdwrap {padding:10px; border-color:white; box-shadow:none}
|
||||
#togglemotd {margin-top:-5px}
|
||||
|
||||
/* -- superadmin icon -- */
|
||||
|
||||
.glyphicon-globe {margin-right:3px}
|
||||
|
||||
/* -- playlist row panes -- */
|
||||
|
||||
#rightpane, #leftpane {margin-top:5px !important; margin-bottom:5px !important}
|
||||
|
||||
/* -- left pane wells -- */
|
||||
|
||||
#leftpane .well {margin-bottom:5px}
|
||||
|
||||
/* -- queue titles -- */
|
||||
|
||||
.qe_title {margin-left:4px}
|
||||
|
||||
/* -- footer -- */
|
||||
|
||||
#footer {padding-bottom:5px; height:auto}
|
||||
|
||||
|
||||
/* ----- Patching CSS after loading JS (comments only here, actual patches in the JS) ----- */
|
||||
|
||||
|
||||
/*
|
||||
#mainpage {padding-top:52px}
|
||||
#motdrow, #announcements, #main, #playlistrow {border:solid 2px transparent; margin-bottom:5px}
|
||||
#main > div, #playlistrow > div {
|
||||
padding-left:5px; padding-right:5px; margin-top:5px; margin-bottom:5px;
|
||||
}
|
||||
#motdwrap {margin:5px -10px}
|
||||
#announcements .alert {margin:0px -10px 5px}
|
||||
#drinkcount {margin:0px}
|
||||
*/
|
||||
|
||||
|
||||
/* ----- CyTube Plus created elements CSS ----- */
|
||||
|
||||
|
||||
/* -- channel avatar -- */
|
||||
|
||||
#chanavatar {margin-right:10px}
|
||||
|
||||
/* -- azuki row (user top logo) -- */
|
||||
|
||||
#azukirow {
|
||||
padding-left:5px; padding-right:5px; border-left:solid 2px transparent; border-right:solid 2px transparent;
|
||||
background:transparent; background-repeat:no-repeat !important; background-position:center center !important;
|
||||
margin:0px -8px; min-height:5px;
|
||||
}
|
||||
|
||||
/* -- MOTD elements -- */
|
||||
|
||||
#motdlogo {margin-bottom:8px}
|
||||
#motdtabswrap {margin-top:8px}
|
||||
.motdtabs-btn {margin-right:5px}
|
||||
#motdtabscontent {padding:10px 5px}
|
||||
|
||||
/* -- rules button and panel -- */
|
||||
|
||||
#rulesbtnwrap {text-align:center}
|
||||
#rules-btn {margin-top:10px; margin-bottom:5px}
|
||||
#rulespanel-outer {width:100%; padding:0px}
|
||||
#rulespanel {
|
||||
max-width:700px; margin:0 auto; margin-top:0px; padding:4px; border:solid 2px white; text-align:left;
|
||||
border-radius:8px; -moz-border-radius:8px; -webkit-border-radius:8px;
|
||||
}
|
||||
|
||||
/* -- attention bar -- */
|
||||
|
||||
#attbarrow-outer {padding:0px 5px}
|
||||
#attbar {height:22px; background-color:white}
|
||||
|
||||
/* -- full-sized title row -- */
|
||||
|
||||
#titlerow {
|
||||
background-color:white;
|
||||
background-image:linear-gradient(to right, #cccccc, #cccccc);
|
||||
background-position:0px center;
|
||||
background-size:0% 100%; background-repeat:no-repeat;
|
||||
margin:-5px -8px 5px;
|
||||
border-radius:4px;
|
||||
}
|
||||
#titlerow-outer {
|
||||
padding:3px 5px; text-align:center; font-size:16pt; color:black;
|
||||
text-shadow: 0px 0px 10px #666666, 0px 0px 10px #666666;
|
||||
}
|
||||
#titlerow #currenttitle {border:none; background:transparent}
|
||||
|
||||
/* -- media info bar -- */
|
||||
|
||||
#mediainfo {
|
||||
background:transparent; margin-bottom:0px; border-width: 1px 1px 0px; border-style:solid solid none;
|
||||
border-color:#CCC #CCC -moz-use-text-color; border-radius:5px 5px 0px 0px;
|
||||
}
|
||||
|
||||
/* -- player alert (if hidden video after loading) -- */
|
||||
|
||||
#ytapiplayer .alert {text-align:left; margin:0px -15px}
|
||||
|
||||
/* -- player covering layer -- */
|
||||
|
||||
#coverpl {
|
||||
position:absolute; left:5px; top:0px; background-color:white;
|
||||
background-repeat:no-repeat; background-position:center center;
|
||||
}
|
||||
|
||||
/* -- sounds and admin panels GUI layers -- */
|
||||
|
||||
#sounds-dropdown, #chatfunc-dropdown {
|
||||
position:absolute; top:22px; display:block; z-index:10000; padding:5px;
|
||||
overflow:auto; margin-right:5px;
|
||||
}
|
||||
#muteall-btn, #spamclear-btn, #antiafk-btn {width:100%}
|
||||
|
||||
/* -- chat controls buttons group -- */
|
||||
|
||||
#chatcontrols {margin-top:4px}
|
||||
|
||||
/* -- chat elements -- */
|
||||
|
||||
.squavatar {width:24px; height:24px; margin-right:3px; border:solid 6px; vertical-align:middle; display:inline-block}
|
||||
.avatar {margin-right:3px}
|
||||
.server-whisper + .squavatar {display:none}
|
||||
.globalmod {margin-right:2px}
|
||||
.embedimg {max-width:200px; max-height:300px}
|
||||
.embedvid {max-width:200px; max-height:300px; border:0px; vertical-align:middle}
|
||||
|
||||
/* -- main fonts and emotes GUI layer -- */
|
||||
|
||||
#chatpanel {margin-top:0px; margin-bottom:0px}
|
||||
#fontspanel, #emotespanel {
|
||||
text-align:center; max-width:700px; margin:0px auto 5px auto; border:solid 2px white; border-radius:6px
|
||||
}
|
||||
.fluidpanel {max-width:1200px !important}
|
||||
|
||||
/* -- fonts panel -- */
|
||||
|
||||
#fontsbtnwrap {margin-top:5px; margin-bottom:5px}
|
||||
#unibtnwrap {margin:5px 45px 2px}
|
||||
@media (max-width:767px) {
|
||||
#unibtnwrap {margin:5px 25px 2px}
|
||||
}
|
||||
#fontsbtnwrap .btn, #unibtnwrap .btn {margin:0px 3px 3px 3px}
|
||||
|
||||
/* -- emotes panel -- */
|
||||
|
||||
#emotespanel img {margin:5px; max-height:35px; cursor:pointer}
|
||||
#emotesbtnwrap {text-align:center; margin:5px}
|
||||
#emotespanel .alert {text-align:left; margin:5px -10px}
|
||||
|
||||
/* -- advanced playlist controls -- */
|
||||
|
||||
#advplcontrols {width:100%; padding-top:10px}
|
||||
#advplcontrols button {width:25%}
|
||||
|
||||
/* -- database and galleries buttons gruoup -- */
|
||||
|
||||
#leftpanecontrols {margin-right:5px}
|
||||
|
||||
/* -- layout configuration box toggling button -- */
|
||||
|
||||
#layout-btn {margin-left:5px}
|
||||
|
||||
/* -- various configuration box elements -- */
|
||||
|
||||
#configbtnwrap, #modewrap, #themewrap, #funcbtnwrap, #cleardbwrap, #gallery-well, #hidewrap, #embedwrap {
|
||||
text-align:center;
|
||||
}
|
||||
.conf-cap {padding-top:9px}
|
||||
#mode-sel, #theme-sel, #gal-sel {width:80%; margin:0px auto}
|
||||
.theme-header {text-align:center; font-size:9pt; font-style:italic}
|
||||
#embed-help {cursor:pointer; margin-left:7px}
|
||||
|
||||
/* -- channel database -- */
|
||||
|
||||
.db-cat {overflow:auto; max-height:400px}
|
||||
.db-break {width:100%}
|
||||
.db-title {margin-left:4px}
|
||||
.db-link {margin-left:5px}
|
||||
#previewFrame {margin:0 auto; display:block}
|
||||
|
||||
/* -- channel galleries -- */
|
||||
|
||||
#galleryFrame {margin-bottom:10px}
|
||||
#gal-sel {margin-bottom:20px}
|
||||
|
||||
/* -- custom footer -- */
|
||||
|
||||
#leftfooter {font-size:10pt}
|
||||
div[id="leftfooter"] {text-align:center; margin-bottom:5px}
|
||||
#rightfooter {float:right; margin:0px 0px 15px 15px}
|
||||
|
||||
|
||||
/* ----- Additional JS classes ----- */
|
||||
|
||||
|
||||
.relative {position:relative}
|
||||
|
||||
.covered {visibility:hidden; opacity:0}
|
||||
|
||||
.dist {background-color:gold; color:red; font-size:12pt; font-family:times new roman; padding:3px}
|
||||
|
||||
.mX {
|
||||
-webkit-transform:scaleX(-1); -moz-transform:scaleX(-1); transform:scaleX(-1);
|
||||
-ms-transform:scaleX(-1); -o-transform:scaleX(-1);
|
||||
}
|
||||
|
||||
.mY {
|
||||
-webkit-transform:scaleY(-1); -moz-transform:scaleY(-1); transform:scaleY(-1);
|
||||
-ms-transform:scaleY(-1); -o-transform:scaleY(-1);
|
||||
}
|
||||
|
||||
.rotate {
|
||||
-webkit-transform:rotate(180deg); -moz-transform:rotate(180deg); transform:rotate(180deg);
|
||||
-ms-transform:rotate(180deg); -o-transform:rotate(180deg);
|
||||
}
|
||||
|
||||
.vertical {
|
||||
-webkit-transform:rotate(270deg); -moz-transform:rotate(270deg); transform:rotate(270deg);
|
||||
-ms-transform:rotate(270deg); -o-transform:rotate(270deg);
|
||||
}
|
||||
BIN
www/img/frst.jpg
BIN
www/img/frst.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 MiB After Width: | Height: | Size: 5.2 MiB |
BIN
www/img/tokeleaf.png
Normal file
BIN
www/img/tokeleaf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
var chosenServer = IO_SERVERS[0]; // Is the array even necessary for the ACP?
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
Callbacks = {
|
||||
/* fired when socket connection completes */
|
||||
connect: function() {
|
||||
|
|
@ -173,22 +212,17 @@ Callbacks = {
|
|||
}, time));
|
||||
},
|
||||
|
||||
channelNotRegistered: function() {
|
||||
var div = $("<div/>").addClass("alert alert-info")
|
||||
channelNotFound: function() {
|
||||
$("#motdwrap").hide();
|
||||
$("#chatline").prop("placeholder","Channel not found!");
|
||||
var div = $("<div/>").addClass("alert alert-danger")
|
||||
.appendTo($("<div/>").addClass("col-md-12").appendTo($("#announcements")));
|
||||
|
||||
$("<button/>").addClass("close pull-right")
|
||||
.appendTo(div)
|
||||
.click(function () {
|
||||
div.parent().remove();
|
||||
})
|
||||
.html("×");
|
||||
$("<h4/>").appendTo(div).text("Unregistered channel");
|
||||
$("<h4/>").appendTo(div).text("Channel not found!");
|
||||
$("<p/>").appendTo(div)
|
||||
.html("This channel is not registered to a CyTube account. You can still " +
|
||||
"use it, but some features will not be available. To register a " +
|
||||
"channel to your account, visit your <a href='/account/channels'>" +
|
||||
"channels</a> page.");
|
||||
.html("Go watch one of the channels that actually exists <a href='/'>here</a>.");
|
||||
|
||||
$("#ytapiplayer").append('<embed type="text/html" src="https://vid.puffyan.us/embed/HS-xJLNROqE?Autoplay=1&loop=1">')//KSSSSSSSSSSSSSSSSSSSSSSSH
|
||||
},
|
||||
|
||||
setMotd: function(motd) {
|
||||
|
|
@ -515,9 +549,16 @@ Callbacks = {
|
|||
}
|
||||
},
|
||||
|
||||
clearchat: function() {
|
||||
$("#messagebuffer").html("");
|
||||
LASTCHAT.name = "";
|
||||
clearchat: function(data) {
|
||||
console.log(data);
|
||||
|
||||
if(data.target == null){
|
||||
$("#messagebuffer").html("");
|
||||
}else{
|
||||
$(".chat-msg-" + data.target).html("");
|
||||
}
|
||||
|
||||
LASTCHAT.name = (data.target == null || data.target == LASTCHAT.name.toLowerCase()) ? "" : LASTCHAT.name;
|
||||
},
|
||||
|
||||
userlist: function(data) {
|
||||
|
|
@ -820,6 +861,10 @@ Callbacks = {
|
|||
}
|
||||
|
||||
function loadNext() {
|
||||
if(PLAYER){
|
||||
PLAYER.latch();
|
||||
}
|
||||
$("#latchvid").hide();
|
||||
if (!PLAYER || data.type !== PLAYER.mediaType) {
|
||||
loadMediaPlayer(data);
|
||||
} else {
|
||||
|
|
@ -932,72 +977,21 @@ Callbacks = {
|
|||
|
||||
/* REGION Polls */
|
||||
newPoll: function(data) {
|
||||
Callbacks.closePoll();
|
||||
var pollMsg = $("<div/>").addClass("poll-notify")
|
||||
.html(data.initiator + " opened a poll: \"" + data.title + "\"")
|
||||
.appendTo($("#messagebuffer"));
|
||||
scrollChat();
|
||||
//lnewPoll(data);
|
||||
fpoll.data = data;
|
||||
panelbtn(fpoll)
|
||||
$("#pollopenbtn").show("blinds");
|
||||
|
||||
var poll = $("<div/>").addClass("well active").prependTo($("#pollwrap"));
|
||||
$("<button/>").addClass("close pull-right").html("×")
|
||||
.appendTo(poll)
|
||||
.click(function() { poll.remove(); });
|
||||
if(hasPermission("pollctl")) {
|
||||
$("<button/>").addClass("btn btn-danger btn-sm pull-right").text("End Poll")
|
||||
.appendTo(poll)
|
||||
.click(function() {
|
||||
socket.emit("closePoll")
|
||||
});
|
||||
}
|
||||
|
||||
$("<h3/>").html(data.title).appendTo(poll);
|
||||
for(var i = 0; i < data.options.length; i++) {
|
||||
(function(i) {
|
||||
var callback = function () {
|
||||
socket.emit("vote", {
|
||||
option: i
|
||||
});
|
||||
poll.find(".option button").each(function() {
|
||||
$(this).removeClass("active");
|
||||
$(this).parent().removeClass("option-selected");
|
||||
});
|
||||
$(this).addClass("active");
|
||||
$(this).parent().addClass("option-selected");
|
||||
}
|
||||
$("<button/>").addClass("btn btn-default btn-sm").text(data.counts[i])
|
||||
.prependTo($("<div/>").addClass("option").html(data.options[i])
|
||||
.appendTo(poll))
|
||||
.click(callback);
|
||||
})(i);
|
||||
|
||||
}
|
||||
$("<span/>").addClass("label label-default pull-right").data('timestamp',data.timestamp).appendTo(poll)
|
||||
.attr('title', 'Poll opened by ' + data.initiator).data('initiator',data.initiator)
|
||||
.text(new Date(data.timestamp).toTimeString().split(" ")[0]);
|
||||
|
||||
poll.find(".btn").attr("disabled", !hasPermission("pollvote"));
|
||||
},
|
||||
|
||||
updatePoll: function(data) {
|
||||
var poll = $("#pollwrap .active");
|
||||
var i = 0;
|
||||
poll.find(".option button").each(function() {
|
||||
$(this).html(data.counts[i]);
|
||||
i++;
|
||||
});
|
||||
fpoll.updatePoll(data);
|
||||
},
|
||||
|
||||
closePoll: function() {
|
||||
if($("#pollwrap .active").length != 0) {
|
||||
var poll = $("#pollwrap .active");
|
||||
poll.removeClass("active").addClass("muted");
|
||||
poll.find(".option button").each(function() {
|
||||
$(this).attr("disabled", true);
|
||||
});
|
||||
poll.find(".btn-danger").each(function() {
|
||||
$(this).remove()
|
||||
});
|
||||
}
|
||||
//lclosePoll();
|
||||
fpoll.closePoll();
|
||||
|
||||
},
|
||||
|
||||
listPlaylists: function(data) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
var CL_VERSION = 3.0;
|
||||
var GS_VERSION = 1.7; // Google Drive Userscript
|
||||
|
||||
|
|
@ -121,7 +160,6 @@ var USEROPTS = {
|
|||
blink_title : getOrDefault("blink_title", "onlyping"),
|
||||
sync_accuracy : getOrDefault("sync_accuracy", 2),
|
||||
wmode_transparent : getOrDefault("wmode_transparent", true),
|
||||
chatbtn : getOrDefault("chatbtn", false),
|
||||
altsocket : getOrDefault("altsocket", false),
|
||||
qbtn_hide : getOrDefault("qbtn_hide", false),
|
||||
qbtn_idontlikechange : getOrDefault("qbtn_idontlikechange", false),
|
||||
|
|
@ -130,6 +168,7 @@ var USEROPTS = {
|
|||
ignore_channeljs : getOrDefault("ignore_channeljs", false),
|
||||
sort_rank : getOrDefault("sort_rank", true),
|
||||
sort_afk : getOrDefault("sort_afk", false),
|
||||
legacy_emote : getOrDefault("legacy_emote", false),
|
||||
default_quality : getOrDefault("default_quality", "auto"),
|
||||
boop : getOrDefault("boop", "never"),
|
||||
show_shadowchat : getOrDefault("show_shadowchat", false),
|
||||
|
|
@ -138,7 +177,8 @@ var USEROPTS = {
|
|||
strip_image : getOrDefault("strip_image", false),
|
||||
chat_tab_method : getOrDefault("chat_tab_method", "Cycle options"),
|
||||
notifications : getOrDefault("notifications", "never"),
|
||||
show_ip_in_tooltip : getOrDefault("show_ip_in_tooltip", true)
|
||||
show_ip_in_tooltip : getOrDefault("show_ip_in_tooltip", true),
|
||||
show_orientation : getOrDefault("show_orientation", "true")
|
||||
};
|
||||
|
||||
/* Backwards compatibility check */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,19 @@
|
|||
//var colorList = ["#ff2e2e", "#5f5cff", "#4de024", "#f4861f", "##b88e8e", "#8f8eb8", "#8eb1b8", "#8eb897", "#abb88e"];
|
||||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
*/
|
||||
|
||||
var colorList = ["userlist_color0", "userlist_color1", "userlist_color2", "userlist_color3", "userlist_color4", "userlist_color5", "userlist_color6"];
|
||||
|
||||
var usrColors = ([[],[]]);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
*/
|
||||
|
||||
img_ext = ['jpg', 'jpg:large', 'jpeg', 'png', 'tiff', 'gif'];
|
||||
vid_ext = ['webm', 'gifv', 'mp4'];
|
||||
proto = ['http', 'https'];
|
||||
|
|
@ -36,7 +52,7 @@ function checkEmbed(word, isEmote){
|
|||
let usersplit = word.split(stripd,2);//split word by stripd, array of before and after name
|
||||
|
||||
return usersplit[0] + '<span id="' + getColor(stripd) + '" onclick="chatpaste(\'' + stripd + '\')">' + stripd + '</span>' + usersplit[1];//decorate name
|
||||
}else if(tstripd.charAt(0) === '!'){//if !toke command(same logic as above)
|
||||
}else if(tstripd.charAt(0) === '!' && !isEmote){//if !toke command(same logic as above)
|
||||
let tokesplit = word.split(tstripd,2);
|
||||
return tokesplit[0] + '<a id="toke" onclick="chatsmack(\'' + tstripd + '\')">' + tstripd + '</a>' + tokesplit[1];
|
||||
}else{
|
||||
|
|
|
|||
307
www/js/fpanel.js
Normal file
307
www/js/fpanel.js
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
*/
|
||||
|
||||
//---Global Variables---
|
||||
CURRENTFPANEL = null;
|
||||
|
||||
//---Global Functions---
|
||||
function closeFPanel(cb){//close and null out fpanel, cb function to call when panel is closed
|
||||
$("#fpaneldiv").hide("slide", 250,function(){
|
||||
$("#fpcontdiv").empty();
|
||||
$("#fptitle").html("null Panel");
|
||||
$("#closefpanel").prop("title", "Close null panel.");
|
||||
CURRENTFPANEL = null;
|
||||
if(typeof cb === 'function'){
|
||||
cb();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sizeFPDiv(){//set inner div height to fix overflow
|
||||
$("#fpcontdiv").outerHeight($("#fpaneldiv").height() - $("#fptitlediv").outerHeight());
|
||||
}
|
||||
|
||||
function panelbtn(panel){
|
||||
if($("#fpaneldiv").is(":visible")){//if panel is visible
|
||||
difClose = CURRENTFPANEL != panel;//set difclose to if CURRENTPANEL is the same one attatched to the button we're clicking
|
||||
closeFPanel(function(){//closem panel
|
||||
if(difClose){//if
|
||||
panel.popMenu(panel.data);//pop da panel
|
||||
}
|
||||
});
|
||||
}else{//else
|
||||
panel.popMenu(panel.data);//pop that bitch son
|
||||
}
|
||||
}
|
||||
|
||||
//---base panel---
|
||||
function fpmenu(title, elm, data, ocall){//fpmenu constructor
|
||||
this.title = title;//title of menu
|
||||
this.elm = elm;//elements to insert (good for simple menus)
|
||||
this.data = data;//menu data (not used for all menus)
|
||||
this.ocall = function ocall(){};//function to call upon menu opening (used for more advanced menus)
|
||||
}
|
||||
|
||||
fpmenu.prototype.popMenu = function(idata){//POP goes the weasal!
|
||||
this.data = idata//set data
|
||||
$("#fpcontdiv").empty();//empty content div
|
||||
$("#fptitle").html(this.title + " Panel");//set panel tittle
|
||||
$("#closefpanel").prop("title", "Close " + this.title + " panel.");//set close button hover text
|
||||
$("#fpcontdiv").append(this.elm);//append element array
|
||||
this.ocall(this.data);//run open function
|
||||
CURRENTFPANEL = this;
|
||||
$("#fpaneldiv").show("slide", 250, function() {sizeFPDiv()});//show panel and correct size once open
|
||||
}
|
||||
|
||||
//---fpanel poll---
|
||||
var fpoll = new fpmenu("Poll");//create new panel fpoll
|
||||
|
||||
fpoll.elm = [//fpoll element array
|
||||
$("<h3>").prop("id","polltitle").html("Null Poll Title")//poll title
|
||||
]
|
||||
|
||||
fpoll.ocall = function(data){//fpoll open call function
|
||||
$("#polltitle").html("Poll: " + data.title);//set poll title
|
||||
if(hasPermission("pollctl")) {//if ur allowed to fuck wit da poll
|
||||
$("<button/>").addClass("btn btn-danger btn-sm pull-right").text("End Poll")//add end poll button
|
||||
.prop("id","endpollbtn")//set id
|
||||
.appendTo("#fpcontdiv")//append
|
||||
.click(function() {//click event
|
||||
socket.emit("closePoll")//endem poll
|
||||
});
|
||||
}
|
||||
|
||||
for(var i = 0; i < data.options.length; i++) {//fer all the options in the poll
|
||||
(function(i) {
|
||||
var callback = function () {//create callback function
|
||||
socket.emit("vote", {//send vote
|
||||
option: i//use current option
|
||||
});
|
||||
$("#fpcontdiv").find(".option button").each(function() {//find currently selected button
|
||||
$(this).removeClass("active");//unselect it
|
||||
$(this).parent().removeClass("option-selected");
|
||||
});
|
||||
$(this).addClass("active");//set current option as actively selected
|
||||
$(this).parent().addClass("option-selected");
|
||||
}
|
||||
$("<button/>").addClass("btn btn-default btn-sm").text(data.options[i])//add button
|
||||
.prependTo($("<div/>").addClass("option").html('<p style="display: inline;">' + data.counts[i] + "</p>")//set cont labels
|
||||
.appendTo("#fpcontdiv"))//append them to div
|
||||
.click(callback);//add click event to callback function
|
||||
})(i);
|
||||
}
|
||||
}
|
||||
|
||||
fpoll.updatePoll = function(data){//updatem poll
|
||||
var poll = $("#pollwrap .active");
|
||||
var i = 0;
|
||||
$("#fpcontdiv").find(".option p").each(function() {//for every option
|
||||
$(this).html(data.counts[i]);//correct count labels
|
||||
i++;//increment counter
|
||||
});
|
||||
}
|
||||
|
||||
fpoll.closePoll = function(data){//close poll
|
||||
tmpttl = $("#polltitle").html();//grab poll title
|
||||
$("#polltitle").html(tmpttl + " (Poll Closed)");//add closed label
|
||||
$("#pollopenbtn").hide("blinds");//hide poll button
|
||||
|
||||
$("#fpcontdiv").find(".option button").each(function() {//disable poll buttons
|
||||
$(this).prop("disabled", true);
|
||||
});
|
||||
|
||||
$("#fpcontdiv").find(".btn-danger").each(function() {//remove end poll button
|
||||
$(this).remove()
|
||||
});
|
||||
}
|
||||
|
||||
//---emote panel---
|
||||
var fpemote = new fpmenu("Emote");//create fpemote new fpanel obj
|
||||
|
||||
fpemote.isAlpha = true;//isAlpha to true because this emote panel is a fucking chad
|
||||
|
||||
fpemote.ocall = function(data){//fpemote open function
|
||||
let symask = /["!#$%&'()*+,-./:;<=>?@[\]^_`{|}~]/g;//symbol mask
|
||||
|
||||
$("<form>").prop("action","javascript:void(0)").prop("id","emotecont").append([//top inputs
|
||||
$("<input>").prop("placeholder","Search Emotes").prop("type","text").prop("id", "esearchbar").addClass("form-control").keyup(function(ev){//emote search bar
|
||||
fpemote.searchEmote($("#esearchbar").val());//search for emotes when key as users finger lifts up
|
||||
}),
|
||||
$("<span>").prop("id","anumspan").append([//alphanumspan
|
||||
$("<input>").prop("id","emotealphabox").prop("type", "checkbox").prop("checked", fpemote.isAlpha).click(function(){//alphanum sort checkbox
|
||||
fpemote.alphaPop($("#emotealphabox").prop("checked"));//pop alphanum sort
|
||||
}),
|
||||
$("<label>").prop("for", "emotealphabox").addClass("glyphicon glyphicon-sort-by-alphabet")//alphanum sort label
|
||||
])
|
||||
]).appendTo("#fpcontdiv");//add search bar, adding this in elm causes strange behavior
|
||||
|
||||
$("<div>").addClass("emotecontdiv").appendTo("#fpcontdiv");//add emote container div, creating this in elm causes obnoxious behaviour
|
||||
|
||||
fpemote.alpha = window.CHANNEL.emotes.slice(0);//create second emote array
|
||||
fpemote.alpha.sort((a, b) => a.name.replace(symask, '').toLowerCase().localeCompare(b.name.replace(symask, '').toLowerCase()));//sort it by alphabetical
|
||||
|
||||
|
||||
earray = fpemote.isAlpha ? fpemote.alpha : window.CHANNEL.emotes//use the alphanum sorted array if alphanum sort is enabled
|
||||
|
||||
earray.forEach(function(value){//for every emote
|
||||
fpemote.popEmote(value);//poulate emotes
|
||||
});
|
||||
}
|
||||
|
||||
fpemote.popEmote = function(emote){
|
||||
$("<div>").addClass("emotediv").append([//add new div for every emote
|
||||
$("<span>").prop("id","emspan").append($("<img>").prop("src", emote.image)),//insert emote thumbnails
|
||||
$("<p>").html(emote.name),//insert emote name labels
|
||||
]).click(function(){//find current emote and add onclick function
|
||||
chatpaste(emote.name);//paste emote name
|
||||
closeFPanel();//close fpanel
|
||||
}).appendTo(".emotecontdiv");//append to emote container div
|
||||
}
|
||||
|
||||
fpemote.searchEmote = function(sstring){
|
||||
i = 0;
|
||||
$(".emotecontdiv").empty();
|
||||
earray = fpemote.isAlpha ? fpemote.alpha : window.CHANNEL.emotes
|
||||
earray.forEach(function(value){
|
||||
if(value.name.toLowerCase().includes(sstring.toLowerCase()) || (sstring == null || sstring == "")){
|
||||
i++;
|
||||
fpemote.popEmote(value);
|
||||
}
|
||||
});
|
||||
|
||||
if(i <= 2){
|
||||
$(".emotecontdiv").prop("style", "grid-template-columns: auto");
|
||||
}else{
|
||||
$(".emotecontdiv").prop("style", "");
|
||||
}
|
||||
}
|
||||
|
||||
fpemote.alphaPop = function(setalpha){
|
||||
$(".emotecontdiv").empty();
|
||||
if(setalpha == null){
|
||||
fpemote.isAlpha = !fpemote.isAlpha;
|
||||
}else{
|
||||
fpemote.isAlpha = setalpha
|
||||
}
|
||||
earray = fpemote.isAlpha ? fpemote.alpha : window.CHANNEL.emotes
|
||||
if($("#esearchbar").val() != ""){
|
||||
fpemote.searchEmote($("#esearchbar").val());
|
||||
}else{
|
||||
earray.forEach(function(value){//for every emote
|
||||
fpemote.popEmote(value);//poulate emotes
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//---Quick Settings Panel---
|
||||
var fpset = new fpmenu("Quick Settings");
|
||||
|
||||
fpset.ocall = function(){
|
||||
$("#fpcontdiv").append(spanel = $("<div>").prop("id","fpsetdiv"));
|
||||
|
||||
spanel.append([
|
||||
$("<h4>").html("General Preferences"),
|
||||
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-theme").html("Theme: "),
|
||||
$("<select>").prop("id","qs-theme").addClass("qs-form").change(function() {
|
||||
USEROPTS.theme = $("#qs-theme").val();
|
||||
processOpts();
|
||||
}),
|
||||
),
|
||||
|
||||
$("<h4>").html("Playback Preferences"),
|
||||
|
||||
$("<p>").html("Video Orientation: "),
|
||||
$("<span>").prop("id","flipx-video").addClass("qsbtn glyphicon glyphicon-resize-horizontal pointer").prop("title", "Flip Player Horizontally").attr("onclick",'javascript:$("#ytapiplayer").toggleClass("mirx")'),
|
||||
$("<span>").prop("id","flipy-video").addClass("qsbtn glyphicon glyphicon-resize-vertical pointer").prop("title", "Flip Player Vertically").attr("onclick",'javascript:$("#ytapiplayer").toggleClass("miry")'),
|
||||
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-orient-buttons").html("Video Orientation Buttons on Titlebar: "),
|
||||
$("<input>").prop("id","qs-orient-buttons").prop("type","checkbox").addClass("qs-form").change(function() {
|
||||
USEROPTS.show_orientation = $("#qs-orient-buttons").prop("checked");
|
||||
processOpts();
|
||||
}),
|
||||
),
|
||||
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-sync-threshold").html("Sync Threshold(seconds): "),
|
||||
$("<input>").prop("id","qs-sync-threshold").prop("type","text").addClass("qs-form"),
|
||||
$("<button/>").addClass("btn btn-primary btn-ln").text("Save").prop("type","button").prop("id","qs-sync-threshold-save").click(function() {
|
||||
|
||||
USEROPTS.sync_accuracy = parseFloat($("#qs-sync-threshold").val()) || 2;
|
||||
processOpts();
|
||||
}),
|
||||
),
|
||||
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-yt-source").html("Youtube Source: "),
|
||||
$("<select>").prop("id","qs-yt-source").addClass("qs-form"),
|
||||
),
|
||||
|
||||
|
||||
$("<h4>").html("Chat Preferences"),
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-legacy-emote").html("Use legacy cytube emote menu: "),
|
||||
$("<input>").prop("id","qs-legacy-emote").prop("type","checkbox").addClass("qs-form").change(function() {
|
||||
USEROPTS.legacy_emote = $("#qs-legacy-emote").prop("checked");
|
||||
processOpts();
|
||||
}),
|
||||
),
|
||||
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-blink-title").html("Blink page title on new messages: "),
|
||||
$("<select>").prop("id","qs-blink-title").addClass("qs-form").change(function() {
|
||||
USEROPTS.blink_title = $("#qs-blink-title").val();
|
||||
processOpts();
|
||||
}),
|
||||
),
|
||||
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-boop").html("Beep on new message: "),
|
||||
$("<select>").prop("id","qs-boop").addClass("qs-form").change(function() {
|
||||
USEROPTS.boop = $("#qs-boop").val();
|
||||
processOpts();
|
||||
}),
|
||||
),
|
||||
|
||||
$("<form>").append(
|
||||
$("<label>").prop("for","qs-notifications").html("Browser Notification on new message: "),
|
||||
$("<select>").prop("id","qs-notifications").addClass("qs-form").change(function() {
|
||||
USEROPTS.notifications = $("#qs-notifications").val();
|
||||
processOpts();
|
||||
}),
|
||||
),
|
||||
|
||||
|
||||
])
|
||||
fpset.loadSettings();
|
||||
}
|
||||
|
||||
fpset.loadSettings = function(){
|
||||
$("#us-theme").children().clone().appendTo($("#qs-theme"));
|
||||
$("#qs-theme").val(USEROPTS.theme);
|
||||
$("#qs-orient-buttons").prop("checked", USEROPTS.show_orientation);
|
||||
$("#qs-sync-threshold").val(USEROPTS.sync_accuracy);
|
||||
$("#qs-legacy-emote").prop("checked", USEROPTS.legacy_emote);
|
||||
$("#us-blink-title").children().clone().appendTo($("#qs-blink-title"));
|
||||
$("#qs-blink-title").val(USEROPTS.blink_title);
|
||||
$("#us-ping-sound").children().clone().appendTo($("#qs-boop"));
|
||||
$("#qs-boop").val(USEROPTS.boop);
|
||||
$("#us-notifications").children().clone().appendTo($("#qs-notifications"));
|
||||
$("#qs-notifications").val(USEROPTS.notifications);
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
*/
|
||||
|
||||
var startTimes = [[],[]]//UID's, StartTimes
|
||||
var activeItem = 0;//active UID;
|
||||
var rptime = 0;//reference playlist time
|
||||
|
|
@ -14,12 +30,14 @@ function dispSTimes(){//update sTimes
|
|||
for(var i = 0; i < startTimes[0].length; i++){//for every item startTime
|
||||
var rdif = startTimes[1][i] - rptime;
|
||||
st.setTime(rltime + (rdif * 1000));
|
||||
ltimeString = "airdate: " + st.toLocaleTimeString() + " " + st.toLocaleDateString() + "</br>";
|
||||
ptimeString = "(pref time) " + formatTime(startTimes[1][i]);// create ptimeString
|
||||
ltimeString = "airdate: " + st.toLocaleTimeString() + " " + st.toLocaleDateString();
|
||||
//ptimeString = '<span id="prefTime"> (pref time) ' + formatTime(startTimes[1][i] + '</span>');// create ptimeString
|
||||
ptimeString = '(pref time) ' + formatTime(startTimes[1][i]);// create ptimeString
|
||||
|
||||
if(document.getElementsByClassName("pluid-" + startTimes[0][i])[0] != null || document.getElementsByClassName("pluid-" + startTimes[0][i])[0] != undefined){//if current item isnt null or undefined
|
||||
if($(".pluid-" + startTimes[0][i]) != null || $(".pluid-" + startTimes[0][i]) != undefined){//if current item isnt null or undefined
|
||||
|
||||
document.getElementsByClassName("pluid-" + startTimes[0][i])[0].getElementsByClassName("qe_sTime")[0].innerHTML = ltimeString + ptimeString;// set current item qe_sTime innerHTML to ptimeString
|
||||
$(".pluid-" + startTimes[0][i]).children(".qe_sTime").text(ltimeString);// set current item qe_sTime innerHTML to ptimeString
|
||||
$(".pluid-" + startTimes[0][i]).children(".qe_pref").text(ptimeString);// set current item qe_sTime innerHTML to ptimeString
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -36,3 +54,39 @@ function calcRefs(){
|
|||
PLAYER.getTime(function(seek){ctime = seek});
|
||||
rltime = ld.getTime() - (ctime * 1000);
|
||||
}
|
||||
|
||||
function expandItem(itm){
|
||||
itm.find(".btn-group").show("blind");
|
||||
itm.find(".qe_time").show("blind");
|
||||
itm.find(".qe_pref").show("blind");
|
||||
}
|
||||
|
||||
function collapseItem(itm){
|
||||
itm.find(".btn-group").hide("blind");
|
||||
itm.find(".qe_time").hide("blind");
|
||||
itm.find(".qe_pref").hide("blind");
|
||||
}
|
||||
|
||||
function toggleItem(itm){
|
||||
itm.find(".btn-group").toggle("blind");
|
||||
itm.find(".qe_time").toggle("blind");
|
||||
itm.find(".qe_pref").toggle("blind");
|
||||
}
|
||||
|
||||
function collapseItems(){
|
||||
$.each($("#queue").find("li"), function(i,el){
|
||||
collapseItem($(el));
|
||||
})
|
||||
}
|
||||
|
||||
function expandItems(){
|
||||
$.each($("#queue").find("li"), function(i,el){
|
||||
expandItem($(el));
|
||||
})
|
||||
}
|
||||
|
||||
function toggleItems(){
|
||||
$.each($("#queue").find("li"), function(i,el){
|
||||
toggleItem($(el));
|
||||
})
|
||||
}
|
||||
|
|
|
|||
105
www/js/player.js
105
www/js/player.js
|
|
@ -10,6 +10,9 @@
|
|||
}
|
||||
this.setMediaProperties(data);
|
||||
this.paused = false;
|
||||
this.latched = true;
|
||||
this.seeklatch = false;
|
||||
this.lastSTime = 0;
|
||||
}
|
||||
|
||||
Player.prototype.load = function(data) {
|
||||
|
|
@ -30,6 +33,31 @@
|
|||
return this.paused = true;
|
||||
};
|
||||
|
||||
Player.prototype.latch = function() {
|
||||
if (!this.latched) {
|
||||
return this.latched = true;
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.unlatch = function() {
|
||||
if (!this.seeklatch) {
|
||||
if (this.latched) {
|
||||
$("#latchvid").show();
|
||||
}
|
||||
return this.latched = false;
|
||||
} else {
|
||||
return this.seeklatch = false;
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.latchseek = function() {
|
||||
return this.seeklatch = true;
|
||||
};
|
||||
|
||||
Player.prototype.getLatch = function(cb) {
|
||||
return cb(this.latched);
|
||||
};
|
||||
|
||||
Player.prototype.seekTo = function(time) {};
|
||||
|
||||
Player.prototype.setVolume = function(volume) {};
|
||||
|
|
@ -64,6 +92,7 @@
|
|||
|
||||
VimeoPlayer.prototype.load = function(data) {
|
||||
this.setMediaProperties(data);
|
||||
this.latched = true;
|
||||
return waitUntilDefined(window, 'Vimeo', (function(_this) {
|
||||
return function() {
|
||||
var video;
|
||||
|
|
@ -88,6 +117,8 @@
|
|||
_this.paused = true;
|
||||
if (CLIENT.leader) {
|
||||
return sendVideoUpdate();
|
||||
} else {
|
||||
return _this.unlatch();
|
||||
}
|
||||
});
|
||||
_this.vimeo.on('play', function() {
|
||||
|
|
@ -96,6 +127,11 @@
|
|||
return sendVideoUpdate();
|
||||
}
|
||||
});
|
||||
_this.vimeo.on('seeked', function() {
|
||||
if (!CLIENT.leader) {
|
||||
return _this.unlatch();
|
||||
}
|
||||
});
|
||||
_this.play();
|
||||
return _this.setVolume(VOLUME);
|
||||
};
|
||||
|
|
@ -294,6 +330,7 @@
|
|||
this.setMediaProperties(data);
|
||||
this.initialVolumeSet = false;
|
||||
this.playbackReadyCb = null;
|
||||
this.latched = true;
|
||||
waitUntilDefined(window, 'DM', (function(_this) {
|
||||
return function() {
|
||||
var params, quality;
|
||||
|
|
@ -324,6 +361,8 @@
|
|||
_this.paused = true;
|
||||
if (CLIENT.leader) {
|
||||
return sendVideoUpdate();
|
||||
} else {
|
||||
return _this.unlatch();
|
||||
}
|
||||
});
|
||||
_this.dm.addEventListener('playing', function() {
|
||||
|
|
@ -336,6 +375,11 @@
|
|||
return _this.initialVolumeSet = true;
|
||||
}
|
||||
});
|
||||
_this.dm.addEventListener('seeked', function() {
|
||||
if (!CLIENT.leader) {
|
||||
return _this.unlatch();
|
||||
}
|
||||
});
|
||||
_this.dm.addEventListener('video_end', function() {
|
||||
return _this.dmReady = false;
|
||||
});
|
||||
|
|
@ -557,22 +601,6 @@
|
|||
}).appendTo(video);
|
||||
});
|
||||
}
|
||||
if (data.meta.textTracks) {
|
||||
data.meta.textTracks.forEach(function(track) {
|
||||
var label;
|
||||
label = track.name;
|
||||
attrs = {
|
||||
src: track.url,
|
||||
kind: 'subtitles',
|
||||
type: track.type,
|
||||
label: label
|
||||
};
|
||||
if ((track["default"] != null) && track["default"]) {
|
||||
attrs["default"] = '';
|
||||
}
|
||||
return $('<track/>').attr(attrs).appendTo(video);
|
||||
});
|
||||
}
|
||||
_this.player = videojs(video[0], {
|
||||
autoplay: _this.sources[0].type !== 'application/dash+xml',
|
||||
controls: true,
|
||||
|
|
@ -614,6 +642,8 @@
|
|||
_this.paused = true;
|
||||
if (CLIENT.leader) {
|
||||
return sendVideoUpdate();
|
||||
} else {
|
||||
return _this.unlatch();
|
||||
}
|
||||
});
|
||||
_this.player.on('play', function() {
|
||||
|
|
@ -623,7 +653,10 @@
|
|||
}
|
||||
});
|
||||
_this.player.on('seeked', function() {
|
||||
return $('.vjs-waiting').removeClass('vjs-waiting');
|
||||
$('.vjs-waiting').removeClass('vjs-waiting');
|
||||
if (!CLIENT.leader) {
|
||||
return _this.unlatch();
|
||||
}
|
||||
});
|
||||
return setTimeout(function() {
|
||||
return $('#ytapiplayer .vjs-subtitles-button .vjs-menu-item').each(function(i, elem) {
|
||||
|
|
@ -646,8 +679,26 @@
|
|||
|
||||
VideoJSPlayer.prototype.load = function(data) {
|
||||
this.setMediaProperties(data);
|
||||
this.latched = true;
|
||||
this.destroy();
|
||||
return this.loadPlayer(data);
|
||||
this.loadPlayer(data);
|
||||
return this.setTracks(data);
|
||||
};
|
||||
|
||||
VideoJSPlayer.prototype.setTracks = function(data) {
|
||||
if (data.meta.textTracks) {
|
||||
return data.meta.textTracks.forEach(function(track) {
|
||||
var label;
|
||||
label = track.name;
|
||||
return $('<track>').attr({
|
||||
src: track.url,
|
||||
kind: 'subtitles',
|
||||
type: track.type,
|
||||
label: label,
|
||||
"default": true
|
||||
}).prependTo("video");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
VideoJSPlayer.prototype.play = function() {
|
||||
|
|
@ -660,7 +711,10 @@
|
|||
VideoJSPlayer.prototype.pause = function() {
|
||||
this.paused = true;
|
||||
if (this.player && this.player.readyState() > 0) {
|
||||
return this.player.pause();
|
||||
this.player.pause();
|
||||
if (!CLIENT.leader) {
|
||||
return this.unlatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1624,8 +1678,11 @@
|
|||
window.handleMediaUpdate = function(data) {
|
||||
var PLAYER, waiting;
|
||||
PLAYER = window.PLAYER;
|
||||
handleWindowResize();
|
||||
dispSTimes();
|
||||
PLAYER.lastSTime = data.currentTime;
|
||||
if (!PLAYER.latched) {
|
||||
return;
|
||||
}
|
||||
if (typeof PLAYER.mediaLength === 'number' && PLAYER.mediaLength > 0 && data.currentTime > PLAYER.mediaLength) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -1639,6 +1696,7 @@
|
|||
}
|
||||
if (waiting) {
|
||||
PLAYER.seekTo(0);
|
||||
PLAYER.latchseek();
|
||||
if (PLAYER instanceof YouTubePlayer) {
|
||||
PLAYER.pauseSeekRaceCondition = true;
|
||||
} else {
|
||||
|
|
@ -1653,6 +1711,7 @@
|
|||
}
|
||||
if (data.paused && !PLAYER.paused) {
|
||||
PLAYER.seekTo(data.currentTime);
|
||||
PLAYER.latchseek();
|
||||
PLAYER.pause();
|
||||
} else if (PLAYER.paused && !data.paused) {
|
||||
PLAYER.play();
|
||||
|
|
@ -1666,12 +1725,14 @@
|
|||
accuracy = Math.max(accuracy, 5);
|
||||
}
|
||||
if (diff > accuracy) {
|
||||
return PLAYER.seekTo(time);
|
||||
PLAYER.seekTo(time);
|
||||
return PLAYER.latchseek();
|
||||
} else if (diff < -accuracy) {
|
||||
if (!(PLAYER instanceof DailymotionPlayer)) {
|
||||
time += 1;
|
||||
}
|
||||
return PLAYER.seekTo(time);
|
||||
PLAYER.seekTo(time);
|
||||
return PLAYER.latchseek();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
CyTube.tabCompleteMethods = {};
|
||||
|
||||
// Bash-style completion
|
||||
|
|
|
|||
|
|
@ -1,3 +1,42 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
var c = document.cookie.split(";").map(function (s) {
|
||||
return s.trim();
|
||||
|
|
|
|||
125
www/js/ui.js
125
www/js/ui.js
|
|
@ -1,3 +1,41 @@
|
|||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
/* window focus/blur */
|
||||
CyTube.ui.onPageFocus = function () {
|
||||
FOCUSED = true;
|
||||
|
|
@ -16,7 +54,7 @@ $(".modal").focus(CyTube.ui.onPageFocus);
|
|||
|
||||
$("#togglemotd").click(function () {
|
||||
var hidden = $("#motdwrap")[0].style.display === "none";
|
||||
$("#motdwrap").toggle();
|
||||
$("#motdwrap").toggle("blind");
|
||||
if (hidden) {
|
||||
$("#togglemotd").find(".glyphicon-plus")
|
||||
.removeClass("glyphicon-plus")
|
||||
|
|
@ -37,13 +75,13 @@ $("#modflair").click(function () {
|
|||
m.removeClass("label-success");
|
||||
if (SUPERADMIN) {
|
||||
USEROPTS.adminhat = true;
|
||||
m.addClass("label-danger");
|
||||
m.addClass("label-admin");
|
||||
} else {
|
||||
m.addClass("label-default");
|
||||
}
|
||||
} else if (m.hasClass("label-danger")) {
|
||||
} else if (m.hasClass("label-admin")) {
|
||||
USEROPTS.adminhat = false;
|
||||
m.removeClass("label-danger")
|
||||
m.removeClass("label-admin")
|
||||
.addClass("label-default");
|
||||
} else {
|
||||
USEROPTS.modhat = true;
|
||||
|
|
@ -183,7 +221,7 @@ function callChat(){
|
|||
if(msg.trim()) {
|
||||
var meta = {};
|
||||
if (USEROPTS.adminhat && CLIENT.rank >= 255) {
|
||||
msg = "/a " + msg;
|
||||
msg = "!a " + msg;
|
||||
} else if (USEROPTS.modhat && CLIENT.rank >= Rank.Moderator) {
|
||||
meta.modflair = CLIENT.rank;
|
||||
}
|
||||
|
|
@ -329,6 +367,14 @@ $("#mediarefresh").click(function() {
|
|||
socket.emit("playerReady");
|
||||
});
|
||||
|
||||
$("#latchvid").click(function() {
|
||||
PLAYER.latch();
|
||||
PLAYER.play();
|
||||
PLAYER.latchseek()
|
||||
PLAYER.seekTo(PLAYER.lastSTime);
|
||||
$("#latchvid").hide();
|
||||
});
|
||||
|
||||
/* playlist controls */
|
||||
|
||||
$("#queue").sortable({
|
||||
|
|
@ -406,6 +452,7 @@ function queue(pos, src) {
|
|||
|
||||
var duration = undefined;
|
||||
var title = undefined;
|
||||
var subtitle = "";
|
||||
if (data.type === "fi") {
|
||||
if (data.id.match(/^http:/)) {
|
||||
Callbacks.queueFail({
|
||||
|
|
@ -436,6 +483,7 @@ function queue(pos, src) {
|
|||
// Raw files allow title overrides since the ffprobe tag data
|
||||
// is not always correct.
|
||||
title = $("#addfromurl-title-val").val();
|
||||
subtitle = $("#addfromurl-subtitle-val").val();
|
||||
}
|
||||
|
||||
if (data.id == null || data.type == null) {
|
||||
|
|
@ -451,7 +499,8 @@ function queue(pos, src) {
|
|||
duration: duration,
|
||||
title: title,
|
||||
temp: addTemp,
|
||||
link: link
|
||||
link: link,
|
||||
subtitle: subtitle
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -500,26 +549,45 @@ $("#mediaurl").keyup(function(ev) {
|
|||
} catch (error) {
|
||||
}
|
||||
|
||||
if (editTitle) {
|
||||
if (editTitle) {//Add title and subtitles fieldS
|
||||
var title = $("#addfromurl-title");
|
||||
if (title.length === 0) {
|
||||
title = $("<div/>")
|
||||
.attr("id", "addfromurl-title")
|
||||
.appendTo($("#addfromurl"));
|
||||
$("<span/>").text("Title (optional; for raw files only)")
|
||||
.appendTo(title);
|
||||
$("<input/>").addClass("form-control")
|
||||
.attr("type", "text")
|
||||
var subtitle = $("#addfromurl-subtitle");
|
||||
|
||||
if (title.length === 0) {//if there is no title set
|
||||
title = $("<div/>")//create title div
|
||||
.attr("id", "addfromurl-title")//title div attr
|
||||
.insertAfter($("#addfromurl").find(".input-group"));//insert after URL bar
|
||||
|
||||
|
||||
$("<input/>").addClass("form-control")//create title field
|
||||
.attr("type", "text")//the attributes
|
||||
.attr("id", "addfromurl-title-val")
|
||||
.attr("placeholder", "Alternate Title")
|
||||
.attr("style", "display: none; width: 100%;")
|
||||
.keydown(function (ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
queue("end", "url");
|
||||
}
|
||||
})
|
||||
.appendTo($("#addfromurl-title"));
|
||||
.appendTo($("#addfromurl-title")).show("blind");//append and show
|
||||
|
||||
$("<input/>").addClass("form-control")//create title field
|
||||
.attr("type", "text")//the attributes
|
||||
.attr("id", "addfromurl-subtitle-val")
|
||||
.attr("placeholder", "Alternate Subtitle Track")
|
||||
.attr("style", "display: none; width: 100%;")
|
||||
.keydown(function (ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
queue("end", "url");
|
||||
}
|
||||
})
|
||||
.appendTo($("#addfromurl-title")).show("blind");//append and show
|
||||
|
||||
|
||||
}
|
||||
} else {
|
||||
$("#addfromurl-title").remove();
|
||||
$("#addfromurl-title").hide("blind");
|
||||
$("#addfromurl-title").remove();//otherwise remove
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -539,6 +607,27 @@ $("#voteskip").click(function() {
|
|||
$("#voteskip").attr("disabled", true);
|
||||
});
|
||||
|
||||
$("#blindItems").click(function(){
|
||||
$("#blindItems").toggleClass("glyphicon-resize-small");
|
||||
$("#blindItems").toggleClass("glyphicon-resize-full");
|
||||
$("#blindItems").prop("title",
|
||||
($("#blindItems").prop("title") == "Collapse All Items") ? "Expand All Items" : "Collapse All Items"
|
||||
)
|
||||
toggleItems();
|
||||
});
|
||||
|
||||
$("#hideplaylist").click(function(){
|
||||
$("#rightcontrols").hide("blind");
|
||||
$("#playlistrow").hide("blind");
|
||||
$("#showplaylist").show("");
|
||||
});
|
||||
|
||||
$("#showplaylist").click(function(){
|
||||
$("#rightcontrols").show("blind");
|
||||
$("#playlistrow").show("blind");
|
||||
$("#showplaylist").hide("");
|
||||
});
|
||||
|
||||
$("#getplaylist").click(function() {
|
||||
var callback = function(data) {
|
||||
var idx = socket.listeners("errorMsg").indexOf(errCallback);
|
||||
|
|
@ -912,6 +1001,7 @@ EMOTELISTMODAL.find(".emotelist-alphabetical").change(function () {
|
|||
});
|
||||
EMOTELISTMODAL.find(".emotelist-alphabetical").prop("checked", USEROPTS.emotelist_sort);
|
||||
|
||||
|
||||
$("#fullscreenbtn").click(function () {
|
||||
var elem = document.querySelector("#videowrap .embed-responsive");
|
||||
// this shit is why frontend web development sucks
|
||||
|
|
@ -962,4 +1052,3 @@ $("#resize-video-smaller").click(function () {
|
|||
console.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
268
www/js/util.js
268
www/js/util.js
|
|
@ -1,4 +1,42 @@
|
|||
function makeAlert(title, text, klass, textOnly) {
|
||||
/*
|
||||
fore.st is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
fore.st is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with fore.st. If not, see < http://www.gnu.org/licenses/ >.
|
||||
(C) 2022- by rainbownapkin, <ourforest@420blaze.it>
|
||||
|
||||
Original cytube license:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2022 Calvin Montgomery
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
function makeAlert(title, text, klass, textOnly) {
|
||||
if(!klass) {
|
||||
klass = "alert-info";
|
||||
}
|
||||
|
|
@ -211,6 +249,60 @@ function addUserDropdown(entry) {
|
|||
|
||||
var btngroup = $("<div/>").addClass("btn-group-vertical").appendTo(menu);
|
||||
|
||||
/* give/remove leader (moderator+ only) */
|
||||
if (hasPermission("leaderctl")) {
|
||||
var ldr = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.appendTo(btngroup);
|
||||
if(leader) {
|
||||
ldr.text("Remove Leader");
|
||||
ldr.click(function () {
|
||||
socket.emit("assignLeader", {
|
||||
name: ""
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ldr.text("Give Leader");
|
||||
ldr.click(function () {
|
||||
socket.emit("assignLeader", {
|
||||
name: name
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* pm button */
|
||||
if (name !== CLIENT.name) {
|
||||
var pm = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Private Message")
|
||||
.appendTo(btngroup)
|
||||
.click(function () {
|
||||
initPm(name).find(".panel-heading").click();
|
||||
menu.hide();
|
||||
});
|
||||
}
|
||||
|
||||
/* mention button */
|
||||
var pm = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Mention")
|
||||
.appendTo(btngroup)
|
||||
.click(function () {
|
||||
chatpaste(name);
|
||||
menu.hide();
|
||||
});
|
||||
|
||||
/* toke invide button */
|
||||
var pm = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Toke" + (name !== CLIENT.name ? " With" : ""))
|
||||
.appendTo(btngroup)
|
||||
.click(function () {
|
||||
if (name !== CLIENT.name) {
|
||||
chatsmack(" !toke up " + name);
|
||||
}else{
|
||||
chatsmack(" !toke up fuckers");
|
||||
}
|
||||
menu.hide();
|
||||
});
|
||||
|
||||
/* ignore button */
|
||||
if (name !== CLIENT.name) {
|
||||
var ignore = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
|
|
@ -236,55 +328,6 @@ function addUserDropdown(entry) {
|
|||
}
|
||||
}
|
||||
|
||||
/* pm button */
|
||||
if (name !== CLIENT.name) {
|
||||
var pm = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Private Message")
|
||||
.appendTo(btngroup)
|
||||
.click(function () {
|
||||
initPm(name).find(".panel-heading").click();
|
||||
menu.hide();
|
||||
});
|
||||
}
|
||||
|
||||
/* give/remove leader (moderator+ only) */
|
||||
if (hasPermission("leaderctl")) {
|
||||
var ldr = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
.appendTo(btngroup);
|
||||
if(leader) {
|
||||
ldr.text("Remove Leader");
|
||||
ldr.click(function () {
|
||||
socket.emit("assignLeader", {
|
||||
name: ""
|
||||
});
|
||||
});
|
||||
} else {
|
||||
ldr.text("Give Leader");
|
||||
ldr.click(function () {
|
||||
socket.emit("assignLeader", {
|
||||
name: name
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* kick button */
|
||||
if(hasPermission("kick")) {
|
||||
$("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Kick")
|
||||
.click(function () {
|
||||
var reason = prompt("Enter kick reason (optional)");
|
||||
if (reason === null) {
|
||||
return;
|
||||
}
|
||||
socket.emit("chatMsg", {
|
||||
msg: "/kick " + name + " " + reason,
|
||||
meta: {}
|
||||
});
|
||||
})
|
||||
.appendTo(btngroup);
|
||||
}
|
||||
|
||||
/* mute buttons */
|
||||
if (hasPermission("mute")) {
|
||||
var mute = $("<button/>").addClass("btn btn-xs btn-default")
|
||||
|
|
@ -322,6 +365,23 @@ function addUserDropdown(entry) {
|
|||
}
|
||||
}
|
||||
|
||||
/* kick button */
|
||||
if(hasPermission("kick")) {
|
||||
$("<button/>").addClass("btn btn-xs btn-default")
|
||||
.text("Kick")
|
||||
.click(function () {
|
||||
var reason = prompt("Enter kick reason (optional)");
|
||||
if (reason === null) {
|
||||
return;
|
||||
}
|
||||
socket.emit("chatMsg", {
|
||||
msg: "/kick " + name + " " + reason,
|
||||
meta: {}
|
||||
});
|
||||
})
|
||||
.appendTo(btngroup);
|
||||
}
|
||||
|
||||
/* ban buttons */
|
||||
if(hasPermission("ban")) {
|
||||
$("<button/>").addClass("btn btn-xs btn-default")
|
||||
|
|
@ -466,7 +526,6 @@ function scrollQueue() {
|
|||
function makeQueueEntry(item, addbtns) {
|
||||
var video = item.media;
|
||||
var li = $("<li/>");
|
||||
console.log(item);
|
||||
li.addClass("queue_entry");
|
||||
li.addClass("pluid-" + item.uid);
|
||||
li.data("uid", item.uid);
|
||||
|
|
@ -482,11 +541,12 @@ function makeQueueEntry(item, addbtns) {
|
|||
.text(video.title)
|
||||
.attr("href", formatURL(video))
|
||||
.attr("target", "_blank");
|
||||
var sTime = $("<span/>").addClass("qe_sTime").appendTo(li);
|
||||
$("<br/>").appendTo(li);
|
||||
var pref = $("<span/>").addClass("qe_pref").appendTo(li);
|
||||
pref.text(" \n");
|
||||
var time = $("<span/>").addClass("qe_time").appendTo(li);
|
||||
time.text("airtime: " + video.duration);
|
||||
$("<br/>").appendTo(li);
|
||||
var sTime = $("<span/>").addClass("qe_sTime").appendTo(li);
|
||||
sTime.text(" \n");
|
||||
//dispSTimes();
|
||||
var clear = $("<div/>").addClass("qe_clear").appendTo(li);
|
||||
if(item.temp) {
|
||||
|
|
@ -522,6 +582,8 @@ function makeSearchEntry(video) {
|
|||
function addQueueButtons(li) {
|
||||
li.find(".btn-group").remove();
|
||||
var menu = $("<div/>").addClass("btn-group").appendTo(li);
|
||||
var atime = li.find(".qe_time");
|
||||
var ptime = li.find(".qe_pref");
|
||||
// Play
|
||||
if(hasPermission("playlistjump")) {
|
||||
$("<button/>").addClass("btn btn-xs btn-default qbtn-play")
|
||||
|
|
@ -573,8 +635,6 @@ function addQueueButtons(li) {
|
|||
|
||||
// I DON'T LIKE CHANGE
|
||||
if(USEROPTS.qbtn_idontlikechange) {
|
||||
menu.addClass("pull-left");
|
||||
menu.detach().prependTo(li);
|
||||
menu.find(".btn").each(function() {
|
||||
// Clear icon
|
||||
var icon = $(this).find(".glyphicon");
|
||||
|
|
@ -584,17 +644,24 @@ function addQueueButtons(li) {
|
|||
menu.find(".qbtn-play").addClass("btn-success");
|
||||
menu.find(".qbtn-delete").addClass("btn-danger");
|
||||
}
|
||||
else if(menu.find(".btn").length != 0) {
|
||||
if(menu.find(".btn").length != 0) {
|
||||
li.unbind("contextmenu");
|
||||
li.contextmenu(function(ev) {
|
||||
// Allow shift+click to open context menu
|
||||
// (Chrome workaround, works by default on Firefox)
|
||||
if (ev.shiftKey) return true;
|
||||
ev.preventDefault();
|
||||
if(menu.css("display") == "none")
|
||||
menu.show("blind");
|
||||
else
|
||||
menu.hide("blind");
|
||||
if(menu.css("display") == "none"){
|
||||
//menu.show("blind");
|
||||
//atime.show("blind");
|
||||
//ptime.show("blind");
|
||||
expandItem(li);
|
||||
}else{
|
||||
//menu.hide("blind");
|
||||
//atime.hide("blind");
|
||||
//ptime.hide("blind");
|
||||
collapseItem(li);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
|
@ -646,15 +713,16 @@ function showUserOptions() {
|
|||
$("#us-hidevideo").prop("checked", USEROPTS.hidevid);
|
||||
$("#us-playlistbuttons").prop("checked", USEROPTS.qbtn_hide);
|
||||
$("#us-oldbtns").prop("checked", USEROPTS.qbtn_idontlikechange);
|
||||
$("#us-video-orientation").prop("checked", USEROPTS.show_orientation);
|
||||
$("#us-default-quality").val(USEROPTS.default_quality || "auto");
|
||||
|
||||
$("#us-chat-timestamp").prop("checked", USEROPTS.show_timestamps);
|
||||
$("#us-sort-rank").prop("checked", USEROPTS.sort_rank);
|
||||
$("#us-sort-afk").prop("checked", USEROPTS.sort_afk);
|
||||
$("#us-legacy-emote").prop("checked", USEROPTS.legacy_emote);
|
||||
$("#us-blink-title").val(USEROPTS.blink_title);
|
||||
$("#us-ping-sound").val(USEROPTS.boop);
|
||||
$("#us-notifications").val(USEROPTS.notifications);
|
||||
$("#us-sendbtn").prop("checked", USEROPTS.chatbtn);
|
||||
$("#us-no-emotes").prop("checked", USEROPTS.no_emotes);
|
||||
$("#us-strip-image").prop("checked", USEROPTS.strip_image);
|
||||
$("#us-chat-tab-method").val(USEROPTS.chat_tab_method);
|
||||
|
|
@ -683,15 +751,16 @@ function saveUserOptions() {
|
|||
USEROPTS.hidevid = $("#us-hidevideo").prop("checked");
|
||||
USEROPTS.qbtn_hide = $("#us-playlistbuttons").prop("checked");
|
||||
USEROPTS.qbtn_idontlikechange = $("#us-oldbtns").prop("checked");
|
||||
USEROPTS.show_orientation = $("#us-video-orientation").prop("checked");
|
||||
USEROPTS.default_quality = $("#us-default-quality").val();
|
||||
|
||||
USEROPTS.show_timestamps = $("#us-chat-timestamp").prop("checked");
|
||||
USEROPTS.sort_rank = $("#us-sort-rank").prop("checked");
|
||||
USEROPTS.sort_afk = $("#us-sort-afk").prop("checked");
|
||||
USEROPTS.legacy_emote = $("#us-legacy-emote").prop("checked");
|
||||
USEROPTS.blink_title = $("#us-blink-title").val();
|
||||
USEROPTS.boop = $("#us-ping-sound").val();
|
||||
USEROPTS.notifications = $("#us-notifications").val();
|
||||
USEROPTS.chatbtn = $("#us-sendbtn").prop("checked");
|
||||
USEROPTS.no_emotes = $("#us-no-emotes").prop("checked");
|
||||
USEROPTS.strip_image = $("#us-strip-image").prop("checked");
|
||||
USEROPTS.chat_tab_method = $("#us-chat-tab-method").val();
|
||||
|
|
@ -700,7 +769,10 @@ function saveUserOptions() {
|
|||
USEROPTS.modhat = $("#us-modflair").prop("checked");
|
||||
USEROPTS.show_shadowchat = $("#us-shadowchat").prop("checked");
|
||||
}
|
||||
processOpts();
|
||||
}
|
||||
|
||||
function processOpts(){
|
||||
storeOpts();
|
||||
applyOpts();
|
||||
}
|
||||
|
|
@ -727,7 +799,7 @@ function applyOpts() {
|
|||
fixWeirdButtonAlignmentIssue();
|
||||
}
|
||||
|
||||
switch (USEROPTS.layout) {
|
||||
/*switch (USEROPTS.layout) {
|
||||
case "synchtube-fluid":
|
||||
fluidLayout();
|
||||
case "synchtube":
|
||||
|
|
@ -740,8 +812,20 @@ function applyOpts() {
|
|||
hdLayout();
|
||||
break;
|
||||
default:
|
||||
compactLayout();
|
||||
fluidLayout();
|
||||
//compactLayout();Actual fucking cancer layout. Even for 2014. What the actual shit, this was a barely acceptable layout in 05'
|
||||
break;
|
||||
}*/
|
||||
fluidLayout();//Temporary measure until the other layouts are removed for good.
|
||||
|
||||
$("#emoteopenbtn").attr("onclick", (USEROPTS.legacy_emote ? "javascript:EMOTELISTMODAL.modal()" : "javascript:panelbtn(fpemote)"));
|
||||
|
||||
if(USEROPTS.show_orientation){
|
||||
$("#flipx-video").show();
|
||||
$("#flipy-video").show();
|
||||
}else{
|
||||
$("#flipx-video").hide();
|
||||
$("#flipy-video").hide();
|
||||
}
|
||||
|
||||
if(USEROPTS.hidevid) {
|
||||
|
|
@ -1014,6 +1098,8 @@ function handlePermissionChange() {
|
|||
setVisible("#chatline", CLIENT.rank >= 0);
|
||||
setVisible("#queue", hasPermission("seeplaylist"));
|
||||
setVisible("#plmeta", hasPermission("seeplaylist"));
|
||||
setVisible("#rightcontrols", hasPermission("seeplaylist"));
|
||||
setVisible("#playlistrow", hasPermission("seeplaylist"));
|
||||
$("#getplaylist").attr("disabled", !hasPermission("seeplaylist"));
|
||||
|
||||
setVisible("#showplaylistmanager", hasPermission("seeplaylist"));
|
||||
|
|
@ -1134,6 +1220,11 @@ function addLibraryButtons(li, item, source) {
|
|||
var id = item.id;
|
||||
var type = item.type;
|
||||
|
||||
//item.subtitle = (!subtitle) ? item.subtitle : "";
|
||||
if(item.subtitle == null || item.subtitle != undefined){
|
||||
item.subtitle = "";
|
||||
}
|
||||
|
||||
if(hasPermission("playlistadd")) {
|
||||
if(hasPermission("playlistnext")) {
|
||||
$("<button/>").addClass("btn btn-xs btn-default")
|
||||
|
|
@ -1143,6 +1234,7 @@ function addLibraryButtons(li, item, source) {
|
|||
id: id,
|
||||
pos: "next",
|
||||
type: type,
|
||||
subtitle: item.subtitle,
|
||||
temp: $(".add-temp").prop("checked")
|
||||
});
|
||||
})
|
||||
|
|
@ -1155,6 +1247,7 @@ function addLibraryButtons(li, item, source) {
|
|||
id: id,
|
||||
pos: "end",
|
||||
type: type,
|
||||
subtitle: item.subtitle,
|
||||
temp: $(".add-temp").prop("checked")
|
||||
});
|
||||
})
|
||||
|
|
@ -1530,10 +1623,10 @@ function formatChatMessage(data, last) {
|
|||
addClassToNameAndTimestamp: data.msgclass
|
||||
};
|
||||
}
|
||||
//break if toke command
|
||||
if(data.msg.charAt() === '!'){
|
||||
//break if toke command [DEPRICATED] No longer in use as chozobot is no longer used
|
||||
/*if(data.msg.charAt() === '!'){
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
// Phase 1: Determine whether to show the username or not
|
||||
var skip = data.username === last.name;
|
||||
if(data.meta.addClass === "server-whisper")
|
||||
|
|
@ -1549,15 +1642,9 @@ function formatChatMessage(data, last) {
|
|||
|
||||
last.name = data.username;
|
||||
var div = $("<div/>");
|
||||
/* drink is a special case because the entire container gets the class, not
|
||||
just the message */
|
||||
if (data.meta.addClass === "drink") {
|
||||
div.addClass("drink");
|
||||
data.meta.addClass = "";
|
||||
}
|
||||
|
||||
// Add timestamps (unless disabled)
|
||||
if (USEROPTS.show_timestamps && data.meta.modflair != 4) {
|
||||
if (USEROPTS.show_timestamps && data.meta.addClass != "shout") {
|
||||
var time = $("<span/>").addClass("timestamp").appendTo(div);
|
||||
var timestamp = new Date(data.time).toTimeString().split(" ")[0];
|
||||
time.text("["+timestamp+"] ");
|
||||
|
|
@ -1571,9 +1658,18 @@ function formatChatMessage(data, last) {
|
|||
if (!skip) {
|
||||
name.appendTo(div);
|
||||
}
|
||||
assignColors(data.username);
|
||||
if(!data.meta.addClass === "shout"){
|
||||
assignColors(data.username);
|
||||
}
|
||||
console.log(data.meta.addClass);
|
||||
if (data.meta.superadminflair) {
|
||||
$("<strong/>").addClass("username").attr('onclick',"chatpaste('" + data.username + "')").text(data.username + "> ").appendTo(name);
|
||||
|
||||
$("<strong/>").addClass("username").attr('onclick',"chatpaste('" + data.username + "')").text(data.username +
|
||||
(data.meta.addClass === "shout" ? '' : ">")
|
||||
).appendTo(name);
|
||||
if(data.meta.addClass === "shout"){
|
||||
$("<br>").appendTo(name);
|
||||
}
|
||||
name.addClass("label")
|
||||
.addClass(data.meta.superadminflair.labelclass);
|
||||
$("<span/>").addClass(data.meta.superadminflair.icon)
|
||||
|
|
@ -1581,12 +1677,16 @@ function formatChatMessage(data, last) {
|
|||
.css("margin-right", "3px")
|
||||
.prependTo(name);
|
||||
}else if (data.meta.modflair) {
|
||||
if(data.meta.modflair === 4){
|
||||
if(data.meta.addClass === "shout"){
|
||||
console.log('asdasd');
|
||||
$("<strong/>").addClass("username").attr('onclick',"chatpaste('" + data.username + "')").text(data.username + "\n").appendTo(name);
|
||||
}else{
|
||||
$("<strong/>").addClass("username").attr('onclick',"chatpaste('" + data.username + "')").text(data.username + "> ").appendTo(name);
|
||||
}
|
||||
name.addClass(getNameColor(data.meta.modflair));
|
||||
}else if(data.meta.addClass === "shout"){
|
||||
console.log('asdasd');
|
||||
$("<strong/>").addClass("username").attr('onclick',"chatpaste('" + data.username + "')").text(data.username + "\n").appendTo(name);
|
||||
}else{
|
||||
$("<strong/>").addClass("username").attr('onclick',"chatpaste('" + data.username + "')").attr('id',getColor(data.username)).text(data.username + "> ").appendTo(name);
|
||||
}
|
||||
|
|
@ -1627,8 +1727,10 @@ function addChatMessage(data) {
|
|||
// a message, it highlights messages from that user
|
||||
var safeUsername = data.username.replace(/[^\w-]/g, '\\$');
|
||||
div.addClass("chat-msg-" + safeUsername);
|
||||
if(data.meta.modflair === 4){
|
||||
div.attr("id", "botmsg");
|
||||
console.log(data.meta.modflair);
|
||||
if(data.meta.addClass === "shout"){//legacy tokebot junk
|
||||
div.addClass("shout");
|
||||
|
||||
}
|
||||
div.appendTo(msgBuf);
|
||||
div.mouseover(function() {
|
||||
|
|
@ -1648,7 +1750,7 @@ function addChatMessage(data) {
|
|||
var newMessageDiv = $("#newmessages-indicator");
|
||||
if (!newMessageDiv.length) {
|
||||
newMessageDiv = $("<div/>").attr("id", "newmessages-indicator")
|
||||
.insertBefore($("#chatline"));
|
||||
.insertBefore($("#chatbar"));
|
||||
var bgHack = $("<span/>").attr("id", "newmessages-indicator-bghack")
|
||||
.appendTo(newMessageDiv);
|
||||
|
||||
|
|
@ -1926,6 +2028,7 @@ function handleWindowResize() {
|
|||
$("#chatheader").outerHeight();
|
||||
$("#messagebuffer").outerHeight(h);
|
||||
$("#userlist").outerHeight(h);
|
||||
$("#sidepanel").outerHeight(h);
|
||||
return;
|
||||
} else {
|
||||
handleVideoResize();
|
||||
|
|
@ -1946,7 +2049,8 @@ function handleVideoResize() {
|
|||
var height = responsiveFrame.outerHeight() - $("#chatline").outerHeight() - 2;
|
||||
$("#messagebuffer").height(height);
|
||||
$("#userlist").height(height);
|
||||
|
||||
$("#fpaneldiv").height(height);
|
||||
sizeFPDiv();
|
||||
$("#ytapiplayer").attr("height", VHEIGHT = responsiveFrame.outerHeight());
|
||||
$("#ytapiplayer").attr("width", VWIDTH = responsiveFrame.outerWidth());
|
||||
};
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ function setupAudioTracks(player, tech) {
|
|||
'use strict';
|
||||
|
||||
exports.__esModule = true;
|
||||
exports['default'] = setupTextTracks;
|
||||
//exports['default'] = setupTextTracks;
|
||||
|
||||
var _dashjs = (typeof window !== "undefined" ? window['dashjs'] : typeof global !== "undefined" ? global['dashjs'] : null);
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ function attachDashTextTracksToVideojs(player, tech, tracks) {
|
|||
}
|
||||
|
||||
// Update dash when videojs's selected text track changes.
|
||||
player.textTracks().on('change', updateActiveDashTextTrack);
|
||||
//player.textTracks().on('change', updateActiveDashTextTrack);
|
||||
|
||||
// Cleanup event listeners whenever we start loading a new source
|
||||
player.one('loadstart', function () {
|
||||
|
|
@ -445,7 +445,7 @@ var Html5DashJS = function () {
|
|||
_setupAudioTracks2['default'].call(null, this.player, tech);
|
||||
|
||||
// Setup text tracks
|
||||
_setupTextTracks2['default'].call(null, this.player, tech, options);
|
||||
//_setupTextTracks2['default'].call(null, this.player, tech, options);
|
||||
|
||||
// Attach the source with any protection data
|
||||
this.mediaPlayer_.setProtectionData(this.keySystemOptions_);
|
||||
|
|
|
|||
Loading…
Reference in a new issue