
Recherche avancée
Médias (3)
-
GetID3 - Bloc informations de fichiers
9 avril 2013, par
Mis à jour : Mai 2013
Langue : français
Type : Image
-
GetID3 - Boutons supplémentaires
9 avril 2013, par
Mis à jour : Avril 2013
Langue : français
Type : Image
-
Collections - Formulaire de création rapide
19 février 2013, par
Mis à jour : Février 2013
Langue : français
Type : Image
Autres articles (99)
-
MediaSPIP 0.1 Beta version
25 avril 2011, parMediaSPIP 0.1 beta is the first version of MediaSPIP proclaimed as "usable".
The zip file provided here only contains the sources of MediaSPIP in its standalone version.
To get a working installation, you must manually install all-software dependencies on the server.
If you want to use this archive for an installation in "farm mode", you will also need to proceed to other manual (...) -
Multilang : améliorer l’interface pour les blocs multilingues
18 février 2011, parMultilang est un plugin supplémentaire qui n’est pas activé par défaut lors de l’initialisation de MediaSPIP.
Après son activation, une préconfiguration est mise en place automatiquement par MediaSPIP init permettant à la nouvelle fonctionnalité d’être automatiquement opérationnelle. Il n’est donc pas obligatoire de passer par une étape de configuration pour cela. -
L’agrémenter visuellement
10 avril 2011MediaSPIP est basé sur un système de thèmes et de squelettes. Les squelettes définissent le placement des informations dans la page, définissant un usage spécifique de la plateforme, et les thèmes l’habillage graphique général.
Chacun peut proposer un nouveau thème graphique ou un squelette et le mettre à disposition de la communauté.
Sur d’autres sites (12879)
-
How to encode video with ffmpeg for playback on Android ?
3 janvier 2012, par SeanI've got a c++ library that is encoding video in realtime from webcams to mp4 files (H264). The settings i've got are as follows :
codecContex->profile=FF_PROFILE_H264_BASELINE; //Baseline
codecContex->gop_size=250;
codecContex->max_b_frames=0;
codecContex->max_qdiff=4;
codecContex->me_method=libffmpeg::ME_HEX;
codecContex->me_range=16;
codecContex->qmin=10;
codecContex->qmax=51;
codecContex->qcompress=0.6;
codecContex->keyint_min=10;
codecContex->trellis=0;
codecContex->level=13; //Level 1.3
codecContex->weighted_p_pred = 2;
codecContex->flags2|=CODEC_FLAG2_WPRED+CODEC_FLAG2_8X8DCT;This creates MP4 files that play on iOS devices and on Windows Phone 7 devices but not on Android devices. I've read that Android only supports movies encoded with the baseline profile. These settings should produce a baseline movie but when I look at the generated MP4 file with MediaInfo it says it's AVC(High@L1.3). This might be why it's not working but I can't seem to get it to generate something with AVC(Baseline@L1.3)...
If I remove the last line :
codecContex->flags2|=CODEC_FLAG2_WPRED+CODEC_FLAG2_8X8DCT;
Then MediaInfo reports the file as being "AVC(Main@L1.3)" instead - but those flags are part of the Baseline profile !
-
How do I get videos to upload using ruby on rails carrierwave-video ?
9 juillet 2016, par EricUpdated as of July 9, 2016
I tried to follow the instructions on the github website for the video uploader process using carrierwave-video gem but get an error that says the file or directory mmpeg -i doesn’t exist.
The upload path for images functions correctly, just not the video one.
I have added all of the following code necessary to help solve the error and minified as much as i possibly could.
Video uploader code using carrierwave
class VideoUploader < CarrierWave::Uploader::Base
include CarrierWave::Video
storage :file
version :mp4 do
process :encode_video => [:mp4, resolution: "100x100"]
end
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
endHere is the movie controller code that handles uploading of videos
class MoviesController < ApplicationController
include MoviesHelper
def index
mode "index"
end
def show
mode "show"
end
def new
mode "new"
end
def edit
mode "edit"
end
def create
mode "create"
end
def update
mode "update"
end
def destroy
mode "destroy"
end
def review
mode "review"
end
def approve
mode "approve"
end
def deny
mode "deny"
end
endHere is the model data for the movie that goes with it
class Movie < ActiveRecord::Base
attr_accessible :created_on, :description, :maintenance, :reviewed, :subplaylist_id, :title, :user_id, :video, :remote_video_url
belongs_to :user
belongs_to :subplaylist
mount_uploader :video, VideoUploader
endHere is where the movie is supposed to be displayed but it is not working
<% provide(:title, "Movie: Where movies are made!") %>
<% provide(:keywords, "movies, video") %>
<% provide(:description, "This is the place where users showcase their wonderful video talent.") %>
<p><%= notice %></p>
<h1 class="pageheader"><%= @movie.title %></h1>
<br />
<p class="pagetext"><%= video_tag(@movie.video_url.to_s, controls: true, class: "imagebox") %></p>
<p class="pagetext"><%= @movie.description %></p>
<p class="pagetext">Created on: <%= @movie.created_on.strftime("%B-%d-%Y") %></p>
<p class="pagetext">Owner: <%= getType(@movie.user) %><%= link_to @movie.user.vname, user_path(@movie.user) %></p>
<br />
<p class="pagetext"><%= link_to 'Back', mainplaylist_subplaylist_path(@subplaylist.mainplaylist, @movie.subplaylist) %></p>Here is where the movie new action is
<% provide(:title, "Movie: Create new movies here!") %>
<% provide(:description, "New movies are uploaded only to the site when the movie gets approved.") %>
<h1 class="pagetextheader">New movie</h1>
<%= render 'form' %>
<p class="pagetext"><%= link_to 'Back', mainplaylist_subplaylist_path(@subplaylist.mainplaylist, @subplaylist) %></p>Here is where the movies forum parameters are
<%= form_for([@subplaylist, @movie], :html=>{:multipart => true}) do |f| %>
<% if @movie.errors.any? %>
<div>
<h2><%= pluralize(@movie.errors.count, "error") %> prohibited this movie from being saved:</h2>
<ul>
<% @movie.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<br />
<div class="pagetext">
<%= f.label :title %><br />
<%= f.text_field :title %>
</div>
<div class="pagetext">
<%= f.file_field :video %>
</div>
<div class="pagetext">
<%= f.label :remote_video_url, "or video URL" %><br />
<%= f.text_field :remote_video_url %>
</div>
<div class="pagetext">
<%= f.label :description %><br />
<%= f.text_area :description %>
</div>
<div class="pagetext">
<%= f.submit %>
</div>
<br />
<% end %>Here is the movies helper code
module MoviesHelper
def mode(type)
code = auto_logout
if(code == true)
sign_out
redirect_to root_path
else
#Check if Maintenance is turned_on
allmode = Maintenancemode.find_by_id(1)
moviemode = Maintenancemode.find_by_id(19)
mode_turned_on = (allmode.maintenance_on || moviemode.maintenance_on)
#Determine if any maintenance is on
if(mode_turned_on)
#Determine if we are a regular user
regularUser = (!current_user || !current_user.admin?)
if(regularUser)
#Determine which maintenance mode is on
if(allmode.maintenance_on)
redirect_to maintenance_path
else
redirect_to movies_maintenance_path
end
else
switch type
end
else
switch type
end
end
end
private
def getType(user)
if(user.admin)
value = "$"
else
typeFound = Usertype.find_by_user_id(user.id)
if(typeFound)
type = typeFound.privilege
if(type == "Reviewer")
value = "^"
elsif(type == "Banned")
value = "!"
else
value = "~"
end
else
value = "~"
end
end
return value
end
def movieApproved
movieFound = Movie.find_by_id(params[:movie_id])
if(movieFound)
movieFound.reviewed = true
pouch = Pouch.find_by_user_id(movieFound.user_id)
pointsForMovie = 10
pouch.amount += pointsForMovie
@pouch = pouch
@pouch.save
@movie = movieFound
@movie.save
# MovieMailer.movie_approved(@movie, pointsForMovie).deliver
redirect_to movies_review_path
else
render "public/404"
end
end
def movieDenied
movieFound = Movie.find_by_id(params[:movie_id])
if(movieFound)
#Retrieve the user who owns this pet first
#userEmail = petFound.user.email
#Send mail to user with link to edit the pet they sent
@movie = movieFound
MovieMailer.movie_denied(@movie).deliver
redirect_to movies_review_path
else
render "public/404"
end
end
def createMovie(subplaylistFound)
newMovie = subplaylistFound.movies.new
@subplaylist = subplaylistFound
@movie = newMovie
end
def saveMovie(subplaylistFound, logged_in)
newMovie = subplaylistFound.movies.new(params[:movie])
newMovie.user_id = logged_in.id
currentTime = Time.now
newMovie.created_on = currentTime
@movie = newMovie
if(@movie.save)
@subplaylist = subplaylistFound
# MovieMailer.review_movie(@movie).deliver
flash[:success] = "#{@movie.title} is currently being reviewed please check back later."
redirect_to subplaylist_movie_path(@subplaylist, @movie)
else
render "new"
end
end
def switch(type)
if(type == "index") #Admin only
logged_in = current_user
if(logged_in)
if(logged_in.admin)
allMovies = Movies.order("created_on desc").page(params[:page]).per(10)
@movies = allMovies
else
redirect_to root_path
end
else
redirect_to root_path
end
elsif(type == "show")
movieFound = Movie.find_by_id(params[:id])
if(movieFound)
subplaylistFound = Subplaylist.find_by_id(params[:subplaylist_id])
if(subplaylistFound)
if(movieFound.reviewed)
@subplaylist = subplaylistFound
@movie = movieFound
else
logged_in = current_user
if(logged_in)
userMatch = ((logged_in.id == movieFound.user_id) || logged_in.admin)
if(userMatch)
@subplaylist = subplaylistFound
@movie = movieFound
else
redirect_to root_path
end
else
redirect_to root_path
end
end
else
redirect_to root_path
end
else
render "public/404"
end
elsif(type == "new")
logged_in = current_user
if(logged_in)
subplaylistFound = Subplaylist.find_by_id(params[:subplaylist_id])
if(subplaylistFound)
if(subplaylistFound.collab_mode)
createMovie(subplaylistFound)
else
userMatch = (logged_in.id == subplaylistFound.user_id)
if(userMatch)
createMovie(subplaylistFound)
else
redirect_to root_path
end
end
else
render "public/404"
end
else
redirect_to root_path
end
elsif(type == "create")
logged_in = current_user
if(logged_in)
subplaylistFound = Subplaylist.find_by_id(params[:subplaylist_id])
if(subplaylistFound)
if(subplaylistFound.collab_mode)
saveMovie(subplaylistFound, logged_in)
else
userMatch = (logged_in.id == subplaylistFound.user_id)
if(userMatch)
saveMovie(subplaylistFound, logged_in)
else
redirect_to root_path
end
end
else
render "public/404"
end
else
redirect_to root_path
end
elsif(type == "edit")
logged_in = current_user
if(logged_in)
movieFound = Movie.find_by_id(params[:id])
if(movieFound)
userMatch = (logged_in.id == movieFound.user_id)
if(userMatch)
subplaylistFound = Subplaylist.find_by_id(movieFound.subplaylist_id)
if(subplaylistFound)
@subplaylist = subplaylistFound
@movie = movieFound
else
render "public/404"
end
else
redirect_to root_path
end
else
render "public/404"
end
else
redirect_to root_path
end
elsif(type == "update")
logged_in = current_user
if(logged_in)
movieFound = Movie.find_by_id(params[:id])
if(movieFound)
userMatch = (logged_in.id == movieFound.user_id)
if(userMatch)
subplaylistFound = Subplaylist.find_by_id(movieFound.subplaylist_id)
if(subplaylistFound)
@movie = movieFound
if(@movie.update_attributes(params[:movie]))
@subplaylist = subplaylistFound
flash[:success] = 'Movie was successfully updated.'
redirect_to subplaylist_movie_path(@subplaylist, @movie)
else
render "edit"
end
else
render "public/404"
end
else
redirect_to root_path
end
else
render "public/404"
end
else
redirect_to root_path
end
elsif(type == "destroy")
logged_in = current_user
if(logged_in)
movieFound = Movie.find_by_id(params[:id]) #Need to move this below the admin section to protect it
if(movieFound)
if(logged_in.admin)
subplaylistFound = Subplaylist.find_by_id(movieFound.subplaylist_id)
if(subplaylistFound)
@movie = movieFound
@subplaylist = subplaylistFound
@movie.destroy
redirect_to mainplaylist_subplaylist_path(@subplaylist.mainplaylist, @subplaylist)
else
render "public/404"
end
else
redirect_to root_path
end
else
render "public/404"
end
else
redirect_to root_path
end
elsif(type == "review") #Admin
logged_in = current_user
if(logged_in)
if(logged_in.admin)
allMovies = Movie.all
moviesToReview = allMovies.select{|movie| !movie.reviewed}
@movies = Kaminari.paginate_array(moviesToReview).page(params[:page]).per(10)
else
typeFound = Usertype.find_by_user_id(logged_in.id)
if(typeFound.privilege == "Reviewer")
allMovies = Movie.all
moviesToReview = allMovies.select{|movie| !movie.reviewed}
@movies = Kaminari.paginate_array(moviesToReview).page(params[:page]).per(10)
else
redirect_to root_path
end
end
else
redirect_to root_path
end
elsif(type == "approve") #Admin
logged_in = current_user
if(logged_in)
if(logged_in.admin)
movieApproved
else
typeFound = Usertype.find_by_user_id(logged_in.id)
if(typeFound.privilege == "Reviewer")
movieApproved
else
redirect_to root_path
end
end
else
redirect_to root_path
end
elsif(type == "deny") #Admin
logged_in = current_user
if(logged_in)
if(logged_in.admin)
movieDenied
else
typeFound = Usertype.find_by_user_id(logged_in.id)
if(typeFound.privilege == "Reviewer")
movieDenied
else
redirect_to root_path
end
end
else
redirect_to root_path
end
end
end
endHere is the subplaylists show code
<% provide(:title, "Subplaylist: The place where users videos gets uploaded to!") %>
<% provide(:keywords, "user, video, uploaded") %>
<% provide(:description, "Allows the categorization of various videos that the user submitted successfully.") %>
<p><%= notice %></p>
<h1 class="pageheader"><%= @subplaylist.title %></h1>
<br />
<p class="pagetext"><%= @subplaylist.description %></p>
<br />
<div class="pagebox"><%= paginate @movies %></div>
<br />
<div class="pagetext">
<% @movies.each_with_index do |movie, index| %>
<div class="container">
<div class="inner">
<div class="inner"><%= link_to movie.title, subplaylist_movie_path(@subplaylist, movie) %></div>
<% if current_user && (current_user.id == movie.user_id || current_user.admin? )%>
<div class="inner"><%= button_to 'Edit', edit_subplaylist_movie_path(@subplaylist, movie), method: :get %></div>
<div class="inner"><%= button_to 'Destroy', [@subplaylist, movie], method: :delete, data: { confirm: 'Are you sure?' } %></div>
<% end %>
<p><%= video_tag movie.video_url(:thumb).to_s, controls: true %></p>
</div>
<br />
<p>Created on: <%= movie.created_on.strftime("%B-%d-%Y") %></p>
<p>Owner: <%= getType(movie.user) %><%= link_to movie.user.vname, user_path(movie.user) %></p>
</div>
<% if ((index + 1) % 3) == 0 %>
<br />
<br />
<% end %>
<% end %>
</div>
<br />
<% if current_user %>
<p class="pagetext"><%= link_to "New Movie", new_subplaylist_movie_path(@subplaylist) %></p>
<br />
<% end %>
<p class="pagetext"><%= link_to 'Back', user_mainplaylist_path(@mainplaylist.user.vname, @subplaylist.mainplaylist.title) %></p>Here is the subplaylists model
class Subplaylist < ActiveRecord::Base
attr_accessible :title, :description, :collab_mode
belongs_to :user
belongs_to :mainplaylist
has_many :movies, :foreign_key => "subplaylist_id", :dependent => :destroy
VALID_NAME = /\A[A-Za-z][A-Za-z1-9][A-Za-z1-9 ]+\z/
validates :title, presence: true, format: {with: VALID_NAME}
validates :description, presence: true
endHere is the subplaylists controller code
class SubplaylistsController < ApplicationController
include SubplaylistsHelper
def index
mode "index"
end
def show
mode "show"
end
def new
mode "new"
end
def edit
mode "edit"
end
def create
mode "create"
end
def update
mode "update"
end
def destroy
mode "destroy"
end
endHere is the subplaylist helper code
module SubplaylistsHelper
def mode(type)
code = auto_logout
if(code == true)
sign_out
redirect_to root_path
else
#Check if Maintenance is turned_on
allmode = Maintenancemode.find_by_id(1)
subplaylistmode = Maintenancemode.find_by_id(18)
mode_turned_on = (allmode.maintenance_on || subplaylistmode.maintenance_on)
#Determine if any maintenance is on
if(mode_turned_on)
#Determine if we are a regular user
regularUser = (!current_user || !current_user.admin?)
if(regularUser)
#Determine which maintenance mode is on
if(allmode.maintenance_on)
redirect_to maintenance_path
else
redirect_to subplaylists_maintenance_path
end
else
switch type
end
else
switch type
end
end
end
private
def getType(user)
if(user.admin)
value = "$"
else
typeFound = Usertype.find_by_user_id(user.id)
if(typeFound)
type = typeFound.privilege
if(type == "Reviewer")
value = "^"
elsif(type == "Banned")
value = "!"
else
value = "~"
end
else
value = "~"
end
end
return value
end
def switch(type)
if(type == "show")
subplaylistFound = Subplaylist.find_by_id(params[:id])
if(subplaylistFound)
mainplaylistFound = Mainplaylist.find_by_title(params[:mainplaylist_id])
if(mainplaylistFound)
playlistMatch = (subplaylistFound.mainplaylist_id == mainplaylistFound.id)
if(playlistMatch)
@mainplaylist = mainplaylistFound
@subplaylist = subplaylistFound
subplaylistMovies = @subplaylist.movies.all
reviewedMovies = subplaylistMovies
if(subplaylistMovies.count > 0)
reviewedMovies = subplaylistMovies.select{|movie| movie.reviewed}
end
@movies = Kaminari.paginate_array(reviewedMovies).page(params[:page]).per(10)
else
redirect_to root_path
end
else
render "public/404"
end
else
redirect_to root_path
end
elsif(type == "destroy")
logged_in = current_user
if(logged_in)
subplaylistFound = Subplaylist.find_by_id(params[:id]) #Need to move this below the admin section to protect it
if(subplaylistFound)
if(logged_in.admin)
mainplaylistFound = Mainplaylist.find_by_id(subplaylistFound.mainplaylist_id)
if(mainplaylistFound)
@subplaylist = subplaylistFound
@mainplaylist = mainplaylistFound
@subplaylist.destroy
redirect_to mainplaylist_subplaylists_path(@mainplaylist)
else
render "public/404"
end
else
redirect_to root_path
end
else
render "public/404"
end
else
redirect_to root_path
end
end
end
endHere is the User model
class User < ActiveRecord::Base
attr_accessible :email, :first_name, :last_name, :login_id, :vname, :password, :password_confirmation, :avatar
has_secure_password
mount_uploader :avatar, AvatarUploader
before_save { |user| user.email = user.email.downcase }
before_save { |user| user.first_name = user.first_name.humanize }
#key
has_one :sessionkey, :foreign_key => "user_id", :dependent => :destroy
has_one :usertype, :foreign_key => "user_id", :dependent => :destroy
#Video section
has_many :mainplaylists, :foreign_key => "user_id", :dependent => :destroy
has_many :subplaylists, :foreign_key => "user_id", :dependent => :destroy
has_many :movies, :foreign_key => "user_id", :dependent => :destroy
#validates :first_name, presence: true
VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
VALID_NAME_REGEX = /\A[a-z][a-z][a-z]+\z/i
VALID_VNAME_REGEX = /\A[A-Za-z][A-Za-z][A-Za-z][A-Za-z0-9 ]+([-][A-Za-z0-9 ]+)?\z/
VALID_PASSWORD_REGEX = /\A[A-Za-z0-9!][A-Za-z0-9!][A-Za-z0-9!][A-Za-z0-9!][A-Za-z0-9!][A-Za-z0-9!]+\z/
validates :first_name, presence: true, format: { with: VALID_NAME_REGEX}
validates :last_name, presence: true, format: { with: VALID_NAME_REGEX}
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX}
validates :login_id, presence: true, format: { with: VALID_VNAME_REGEX}, uniqueness: { case_sensitive: false}
validates :vname, presence: true, format: { with: VALID_VNAME_REGEX}, uniqueness: { case_sensitive: false}
validates :password, length: {minimum: 6}#, format: { with: VALID_PASSWORD_REGEX}
validates :password_confirmation, presence: true #, format: { with: VALID_PASSWORD_REGEX}
def to_param
vname
end
endHere is the sessionkey model
class Sessionkey < ActiveRecord::Base
belongs_to :user
endHere is the usertype model
class Usertype < ActiveRecord::Base
attr_accessible :privilege, :user_id #Only priviledge will be changeable
belongs_to :user
endError message
No such file or directory - ffmpeg -i /home/eric/Projects/Local/Lduelingpets/Trial/public/uploads/tmp/1466811951-3149-2702/mp4_TrialMovies.mp4
-
Discord 24/7 video stream self-bot crashes after a couple hours
21 juillet 2023, par angeloI've implemented this library to make a self-bot that streams videos from a local folder in a loop 24/7 (don't ask me why). I set up an ubuntu vps to run the bot and it works perfectly fine the first 2-3 hours, after that it gets more and more laggy until the server crashes.
pd : It's basically my first time using javascript and stole most of the code from this repo so don't bully me.


Here's the code :


import { Client, TextChannel, CustomStatus, ActivityOptions } from "discord.js-selfbot-v13";
import { command, streamLivestreamVideo, VoiceUdp, setStreamOpts, streamOpts } from "@dank074/discord-video-stream";
import config from "./config.json";
import fs from 'fs';
import path from 'path';

const client = new Client();

client.patchVoiceEvents(); //this is necessary to register event handlers

setStreamOpts(
 config.streamOpts.width,
 config.streamOpts.height,
 config.streamOpts.fps,
 config.streamOpts.bitrateKbps,
 config.streamOpts.hardware_acc
)

const prefix = '$';

const moviesFolder = config.movieFolder || './movies';

const movieFiles = fs.readdirSync(moviesFolder);
let movies = movieFiles.map(file => {
 const fileName = path.parse(file).name;
 // replace space with _
 return { name: fileName.replace(/ /g, ''), path: path.join(moviesFolder, file) };
});
let originalMovList = [...movies];
let movList = movies;
let shouldStop = false;

// print out all movies
console.log(`Available movies:\n${movies.map(m => m.name).join('\n')}`);

const status_idle = () => {
 return new CustomStatus()
 .setState('摸鱼进行中')
 .setEmoji('🐟')
}

const status_watch = (name) => {
 return new CustomStatus()
 .setState(`Playing ${name}...`)
 .setEmoji('📽')
}

// ready event
client.on("ready", () => {
 if (client.user) {
 console.log(`--- ${client.user.tag} is ready ---`);
 client.user.setActivity(status_idle() as ActivityOptions)
 }
});

let streamStatus = {
 joined: false,
 joinsucc: false,
 playing: false,
 channelInfo: {
 guildId: '',
 channelId: '',
 cmdChannelId: ''
 },
 starttime: "00:00:00",
 timemark: '',
}

client.on('voiceStateUpdate', (oldState, newState) => {
 // when exit channel
 if (oldState.member?.user.id == client.user?.id) {
 if (oldState.channelId && !newState.channelId) {
 streamStatus.joined = false;
 streamStatus.joinsucc = false;
 streamStatus.playing = false;
 streamStatus.channelInfo = {
 guildId: '',
 channelId: '',
 cmdChannelId: streamStatus.channelInfo.cmdChannelId
 }
 client.user?.setActivity(status_idle() as ActivityOptions)
 }
 }
 // when join channel success
 if (newState.member?.user.id == client.user?.id) {
 if (newState.channelId && !oldState.channelId) {
 streamStatus.joined = true;
 if (newState.guild.id == streamStatus.channelInfo.guildId && newState.channelId == streamStatus.channelInfo.channelId) {
 streamStatus.joinsucc = true;
 }
 }
 }
})

client.on('messageCreate', async (message) => {
 if (message.author.bot) return; // ignore bots
 if (message.author.id == client.user?.id) return; // ignore self
 if (!config.commandChannels.includes(message.channel.id)) return; // ignore non-command channels
 if (!message.content.startsWith(prefix)) return; // ignore non-commands

 const args = message.content.slice(prefix.length).trim().split(/ +/); // split command and arguments
 if (args.length == 0) return;

 const user_cmd = args.shift()!.toLowerCase();

 if (config.commandChannels.includes(message.channel.id)) {
 switch (user_cmd) {
 case 'play':
 playCommand(args, message);
 break;
 case 'stop':
 stopCommand(message);
 break;
 case 'playtime':
 playtimeCommand(message);
 break;
 case 'pause':
 pauseCommand(message);
 break;
 case 'resume':
 resumeCommand(message);
 break;
 case 'list':
 listCommand(message);
 break;
 case 'status':
 statusCommand(message);
 break;
 case 'refresh':
 refreshCommand(message);
 break;
 case 'help':
 helpCommand(message);
 break;
 case 'playall':
 playAllCommand(args, message);
 break;
 case 'stream':
 streamCommand(args, message);
 break;
 case 'shuffle':
 shuffleCommand();
 break;
 case 'skip':
 //skip cmd
 break;
 default:
 message.reply('Invalid command');
 }
 }
});

client.login("TOKEN_HERE");

let lastPrint = "";

async function playAllCommand(args, message) {
 if (streamStatus.joined) {
 message.reply("Already joined");
 return;
 }

 // args = [guildId]/[channelId]
 if (args.length === 0) {
 message.reply("Missing voice channel");
 return;
 }

 // process args
 const [guildId, channelId] = args.shift()!.split("/");
 if (!guildId || !channelId) {
 message.reply("Invalid voice channel");
 return;
 }

 await client.joinVoice(guildId, channelId);
 streamStatus.joined = true;
 streamStatus.playing = false;
 streamStatus.starttime = "00:00:00";
 streamStatus.channelInfo = {
 guildId: guildId,
 channelId: channelId,
 cmdChannelId: message.channel.id,
 };

 const streamUdpConn = await client.createStream();

 streamUdpConn.voiceConnection.setSpeaking(true);
 streamUdpConn.voiceConnection.setVideoStatus(true);

 playAllVideos(streamUdpConn); // Start playing videos

 // Keep the stream open

 streamStatus.joined = false;
 streamStatus.joinsucc = false;
 streamStatus.playing = false;
 lastPrint = "";
 streamStatus.channelInfo = {
 guildId: "",
 channelId: "",
 cmdChannelId: "",
 };
}

async function playAllVideos(udpConn: VoiceUdp) {

 console.log("Started playing video");

 udpConn.voiceConnection.setSpeaking(true);
 udpConn.voiceConnection.setVideoStatus(true);

 try {
 let index = 0;

 while (true) {
 if (shouldStop) {
 break; // For the stop command
 }

 if (index >= movies.length) {
 // Reset the loop
 index = 0;
 }

 const movie = movList[index];

 if (!movie) {
 console.log("Movie not found");
 index++;
 continue;
 }

 let options = {};
 options["-ss"] = "00:00:00";

 console.log(`Playing ${movie.name}...`);

 try {
 let videoStream = streamLivestreamVideo(movie.path, udpConn);
 command?.on('progress', (msg) => {
 // print timemark if it passed 10 second sionce last print, becareful when it pass 0
 if (streamStatus.timemark) {
 if (lastPrint != "") {
 let last = lastPrint.split(':');
 let now = msg.timemark.split(':');
 // turn to seconds
 let s = parseInt(now[2]) + parseInt(now[1]) * 60 + parseInt(now[0]) * 3600;
 let l = parseInt(last[2]) + parseInt(last[1]) * 60 + parseInt(last[0]) * 3600;
 if (s - l >= 10) {
 console.log(`Timemark: ${msg.timemark}`);
 lastPrint = msg.timemark;
 }
 } else {
 console.log(`Timemark: ${msg.timemark}`);
 lastPrint = msg.timemark;
 }
 }
 streamStatus.timemark = msg.timemark;
 });
 const res = await videoStream;
 console.log("Finished playing video " + res);
 } catch (e) {
 console.log(e);
 }

 index++; // Pasar a la siguiente película
 }
 } finally {
 udpConn.voiceConnection.setSpeaking(false);
 udpConn.voiceConnection.setVideoStatus(false);
 }

 command?.kill("SIGINT");
 // send message to channel, not reply
 (client.channels.cache.get(streamStatus.channelInfo.cmdChannelId) as TextChannel).send('Finished playing video, timemark is ' + streamStatus.timemark);
 client.leaveVoice();
 client.user?.setActivity(status_idle() as ActivityOptions)
 streamStatus.joined = false;
 streamStatus.joinsucc = false;
 streamStatus.playing = false;
 lastPrint = ""
 streamStatus.channelInfo = {
 guildId: '',
 channelId: '',
 cmdChannelId: ''
 };
}

function shuffleArray(array) {
 for (let i = array.length - 1; i > 0; i--) {
 const j = Math.floor(Math.random() * (i + 1));
 [array[i], array[j]] = [array[j], array[i]];
 }
}

function shuffleCommand() {
 shuffleArray(movList);
}

async function playCommand(args, message) {
 if (streamStatus.joined) {
 message.reply('Already joined');
 return;
 }

 // args = [guildId]/[channelId]
 if (args.length == 0) {
 message.reply('Missing voice channel');
 return;
 }

 // process args
 const [guildId, channelId] = args.shift()!.split('/');
 if (!guildId || !channelId) {
 message.reply('Invalid voice channel');
 return;
 }

 // get movie name and find movie file
 let moviename = args.shift()
 let movie = movies.find(m => m.name == moviename);

 if (!movie) {
 message.reply('Movie not found');
 return;
 }

 // get start time from args "hh:mm:ss"
 let startTime = args.shift();
 let options = {}
 // check if start time is valid
 if (startTime) {
 let time = startTime.split(':');
 if (time.length != 3) {
 message.reply('Invalid start time');
 return;
 }
 let h = parseInt(time[0]);
 let m = parseInt(time[1]);
 let s = parseInt(time[2]);
 if (isNaN(h) || isNaN(m) || isNaN(s)) {
 message.reply('Invalid start time');
 return;
 }
 startTime = `${h}:${m}:${s}`;
 options['-ss'] = startTime;
 console.log("Start time: " + startTime);
 }

 await client.joinVoice(guildId, channelId);
 streamStatus.joined = true;
 streamStatus.playing = false;
 streamStatus.starttime = startTime ? startTime : "00:00:00";
 streamStatus.channelInfo = {
 guildId: guildId,
 channelId: channelId,
 cmdChannelId: message.channel.id
 }
 const streamUdpConn = await client.createStream();
 playVideo(movie.path, streamUdpConn, options);
 message.reply('Playing ' + (startTime ? ` from ${startTime} ` : '') + moviename + '...');
 client.user?.setActivity(status_watch(moviename) as ActivityOptions);
}

function stopCommand(message) {
 client.leaveVoice()
 streamStatus.joined = false;
 streamStatus.joinsucc = false;
 streamStatus.playing = false;
 streamStatus.channelInfo = {
 guildId: '',
 channelId: '',
 cmdChannelId: streamStatus.channelInfo.cmdChannelId
 }
 // use sigquit??
 command?.kill("SIGINT");
 // msg
 message.reply('Stopped playing');
 shouldStop = true;
 movList = [...originalMovList];
}

function playtimeCommand(message) {
 // streamStatus.starttime + streamStatus.timemark
 // starttime is hh:mm:ss, timemark is hh:mm:ss.000
 let start = streamStatus.starttime.split(':');
 let mark = streamStatus.timemark.split(':');
 let h = parseInt(start[0]) + parseInt(mark[0]);
 let m = parseInt(start[1]) + parseInt(mark[1]);
 let s = parseInt(start[2]) + parseInt(mark[2]);
 if (s >= 60) {
 m += 1;
 s -= 60;
 }
 if (m >= 60) {
 h += 1;
 m -= 60;
 }
 message.reply(`Play time: ${h}:${m}:${s}`);
}

function pauseCommand(message) {
 if (!streamStatus.playing) {
 command?.kill("SIGSTOP");
 message.reply('Paused');
 streamStatus.playing = false;
 } else {
 message.reply('Not playing');
 }
}

function resumeCommand(message) {
 if (!streamStatus.playing) {
 command?.kill("SIGCONT");
 message.reply('Resumed');
 streamStatus.playing = true;
 } else {
 message.reply('Not playing');
 }
}

function listCommand(message) {
 message.reply(`Available movies:\n${movies.map(m => m.name).join('\n')}`);
}

function statusCommand(message) {
 message.reply(`Joined: ${streamStatus.joined}\nJoin success: ${streamStatus.joinsucc}\nPlaying: ${streamStatus.playing}\nChannel: ${streamStatus.channelInfo.guildId}/${streamStatus.channelInfo.channelId}\nTimemark: ${streamStatus.timemark}\nStart time: ${streamStatus.starttime}`);
}

function refreshCommand(message) {
 // refresh movie list
 const movieFiles = fs.readdirSync(moviesFolder);
 movies = movieFiles.map(file => {
 const fileName = path.parse(file).name;
 // replace space with _
 return { name: fileName.replace(/ /g, ''), path: path.join(moviesFolder, file) };
 });
 message.reply('Movie list refreshed ' + movies.length + ' movies found.\n' + movies.map(m => m.name).join('\n'));
}

function helpCommand(message) {
 // reply all commands here
 message.reply('Available commands:\nplay [guildId]/[channelId] [movie] [start time]\nstop\nlist\nstatus\nrefresh\nplaytime\npause\nresume\nhelp');
}

async function playVideo(video: string, udpConn: VoiceUdp, options: any) {
 console.log("Started playing video");

 udpConn.voiceConnection.setSpeaking(true);
 udpConn.voiceConnection.setVideoStatus(true);
 try {
 let videoStream = streamLivestreamVideo(video, udpConn);
 command?.on('progress', (msg) => {
 // print timemark if it passed 10 second sionce last print, becareful when it pass 0
 if (streamStatus.timemark) {
 if (lastPrint != "") {
 let last = lastPrint.split(':');
 let now = msg.timemark.split(':');
 // turn to seconds
 let s = parseInt(now[2]) + parseInt(now[1]) * 60 + parseInt(now[0]) * 3600;
 let l = parseInt(last[2]) + parseInt(last[1]) * 60 + parseInt(last[0]) * 3600;
 if (s - l >= 10) {
 console.log(`Timemark: ${msg.timemark}`);
 lastPrint = msg.timemark;
 }
 } else {
 console.log(`Timemark: ${msg.timemark}`);
 lastPrint = msg.timemark;
 }
 }
 streamStatus.timemark = msg.timemark;
 });
 const res = await videoStream;
 console.log("Finished playing video " + res);
 } catch (e) {
 console.log(e);
 } finally {
 udpConn.voiceConnection.setSpeaking(false);
 udpConn.voiceConnection.setVideoStatus(false);
 }
 command?.kill("SIGINT");
 // send message to channel, not reply
 (client.channels.cache.get(streamStatus.channelInfo.cmdChannelId) as TextChannel).send('Finished playing video, timemark is ' + streamStatus.timemark);
 client.leaveVoice();
 client.user?.setActivity(status_idle() as ActivityOptions)
 streamStatus.joined = false;
 streamStatus.joinsucc = false;
 streamStatus.playing = false;
 lastPrint = ""
 streamStatus.channelInfo = {
 guildId: '',
 channelId: '',
 cmdChannelId: ''
 }
}

async function streamCommand(args, message) {

 if (streamStatus.joined) {
 message.reply('Already joined');
 return;
 }

 // args = [guildId]/[channelId]
 if (args.length == 0) {
 message.reply('Missing voice channel');
 return;
 }

 // process args
 const [guildId, channelId] = args.shift()!.split('/');
 if (!guildId || !channelId) {
 message.reply('Invalid voice channel');
 return;
 }

 let url = args.shift()
 let options = {}

 await client.joinVoice(guildId, channelId);
 streamStatus.joined = true;
 streamStatus.playing = false;
 //streamStatus.starttime = startTime ? startTime : "00:00:00";
 streamStatus.channelInfo = {
 guildId: guildId,
 channelId: channelId,
 cmdChannelId: message.channel.id
 }
 const streamUdpConn = await client.createStream();
 playStream(url, streamUdpConn, options);
 message.reply('Playing url');
 client.user?.setActivity(status_watch('livestream') as ActivityOptions);
}

async function playStream(video: string, udpConn: VoiceUdp, options: any) {
 console.log("Started playing video");

 udpConn.voiceConnection.setSpeaking(true);
 udpConn.voiceConnection.setVideoStatus(true);

 try {
 console.log("Trying to stream url");
 const res = await streamLivestreamVideo(video, udpConn);
 console.log("Finished streaming url");
 } catch (e) {
 console.log(e);
 } finally {
 udpConn.voiceConnection.setSpeaking(false);
 udpConn.voiceConnection.setVideoStatus(false);
 }

 command?.kill("SIGINT");
 client.leaveVoice();
 client.user?.setActivity(status_idle() as ActivityOptions)
 streamStatus.joined = false;
 streamStatus.joinsucc = false;
 streamStatus.playing = false;
 streamStatus.channelInfo = {
 guildId: '',
 channelId: '',
 cmdChannelId: ''
 }

}

// run server if enabled in config
if (config.server.enabled) {
 // run server.js
 require('./server');
}




I've tried running the code with the nocache package, setting up a cron job to clean the cache every 5 minutes, unifying functions in the code, but nothigns works.
I think that the problem has to do with certain process that never really ends after one video finishes playing, probably ffmpeg. I don't know whether is my code, my vps or the library the problem.


I wanted the bot to stay in the voice channel streaming my videos 24/7 (no interruptions), I don't know how to prevent it from getting laggy after a while.


This is the config.json file just in case you wanna test the code and can't find it


{
 "token": "DCTOKEN",
 "videoChannels": ["ID", "OTHERID"],
 "commandChannels": ["ID", "OTHERID"],
 "adminIds": ["ID"],
 "movieFolder": "./movies/",
 "previewCache": "/tmp/preview-cache",
 "streamOpts": {
 "width": 1280,
 "height": 720,
 "fps": 30,
 "bitrateKbps": 3000,
 "hardware_acc": true
 },
 "server": {
 "enabled": false,
 "port": 8080
 }
}