uploaded_song_datatable.rb --which is used for showing list of song in datatable.

class UploadedSongDatatable < AjaxDatatablesRails::Base
  include AjaxDatatablesRails::Extensions::Kaminari
 
  def_delegator :@view, :best_in_place
  def_delegator :@view, :link_to
  def_delegator :@view, :uploaded_song_path
  def_delegator :@view, :autocomplete_album_name_albums_path
  def_delegator :@view, :autocomplete_artist_name_artists_path
  def_delegator :@view, :autocomplete_genre_name_genres_path
  def_delegator :@view, :year_list
  def_delegator :@view, :content_tag
  def_delegator :@view, :image_tag



  def sortable_columns
    @sortable_columns ||= [
                            'UploadedSong.title',
                            'UploadedSong.artist',
                            'UploadedSong.album',
                            'UploadedSong.genre'
                          ]
  end

  def searchable_columns
    @searchable_columns ||= [
                              'UploadedSong.title',
                              'UploadedSong.artist',
                              'UploadedSong.album',
                              'UploadedSong.genre'
                            ]
  end


  private

  def data
    records.map do |record|
      [
      
       
        # best_in_place(record, , :as => :checkbox, :collection => ['<input name="mark[]" type="checkbox">'.html_safe, '<input type="checkbox" checked="true">'.html_safe]),
    nil,
       "<input type='checkbox' class='checkBoxClass' name=\"songids[]\" value='#{record.id}' >",
        best_in_place(record, :is_explicit, :as => :checkbox, :collection => ['<input type="checkbox">'.html_safe, '<input type="checkbox" checked="true">'.html_safe] , url: uploaded_song_path(record, field_to_update: 'is_explicit')),
        best_in_place(record, :title, :display_with => lambda { |v| v.blank? ? "( No title )" : v }, url: uploaded_song_path(record, field_to_update: 'title')),
        best_in_place(record, :artist, :display_with => lambda { |v| v.blank? ? "( No artist )" : v }, url: uploaded_song_path(record, field_to_update: 'artist'), html_attrs: { "data-autocomplete" => autocomplete_artist_name_artists_path, "object_id" => record.id.to_s }),
        best_in_place(record, :album, :display_with => lambda { |v| v.blank? ? "( No album )" : v }, url: uploaded_song_path(record, field_to_update: 'album'), html_attrs: { "data-autocomplete" => autocomplete_album_name_albums_path }),
        best_in_place(record, :genre, :display_with => lambda { |v| v.blank? ? "( No genre )" : v }, url: uploaded_song_path(record, field_to_update: 'genre'), html_attrs: { "data-autocomplete" => autocomplete_genre_name_genres_path }),
        best_in_place(record, :year, :as => :select, :collection => year_list, :display_with => lambda { |v| v.blank? ? "( No year )" : v }, url: uploaded_song_path(record, field_to_update: 'year')),
        best_in_place(record, :track, :display_with => lambda { |v| v.blank? ? "( No track )" : v }, url: uploaded_song_path(record, field_to_update: 'track')),
        best_in_place(record, :comment, :display_with => lambda { |v| v.blank? ? "( No comment )" : v }, url: uploaded_song_path(record, field_to_update: 'comment')),
        if record.cover_id.blank?
          link_to("No Cover", "#cover_modal", data: {song_id: record.id, toggle: "modal", multiqueue: 'false'})
        else
          link_to("#") do
            image_tag(record.cover.cover_pic.url, href: "#cover_modal", height: '50', width: '50', data: {song_id: record.id, toggle: "modal", src: record.cover.cover_pic.url, multiqueue: 'false'})
          end
        end,
        link_to(uploaded_song_path(record), method: :delete, data: { confirm: "Are you sure to delete the song ?"}) do
          content_tag :span, '', class: "glyphicon glyphicon-trash glyphicon-red"
        end
      ]
    end
  end

  def get_raw_records
    UploadedSong.all
  end
end

uploaded_song_controller.rb

require 'taglib'

class UploadedSongsController < ApplicationController

  before_action :authenticate_user!
  authorize_resource

  respond_to :json, :html, :js

  def index
    if params[:from_modal]
      sleep(10)
      flash[:notice] = "Click 'Refresh', to view recently uploaded songs."
    end
    @songs = UploadedSong.count
    respond_to do |format|
      format.html 
      format.json { render json: UploadedSongDatatable.new(view_context) }
    end
  end

  def new
    @song = UploadedSong.new
  end

  def create
    Rails.logger.debug params[:file]
    extraction_path = Pathname.new("#{Rails.root}/public")
    file_ext = File.extname(params[:file].original_filename)
    original_file_name = params[:file].original_filename
    tmp_file_base_name = File.basename(params[:file].path)
    uploaded_tmp_file = "#{extraction_path}/#{tmp_file_base_name}"
    uploaded_file = "#{extraction_path}/#{original_file_name}"

    if params[:file].content_type == "application/zip"
      Rails.logger.debug "moving #{params[:file].path} to #{extraction_path}"
      FileUtils.mv(params[:file].path, extraction_path)
      Rails.logger.debug "file moved"
      if File.rename(uploaded_tmp_file, uploaded_file)
        Resque.enqueue(ZipExtractor, uploaded_file, extraction_path.to_s, true, false)
        Rails.logger.debug "Background job started"
        head 200
      else
        File.delete(uploaded_tmp_file) if File.exist?(uploaded_tmp_file)
      end
    elsif  %w(.mp3 .ogg .mp4 .m4a).include?(file_ext)   
      FileUtils.mv(params[:file].path, extraction_path)
      if File.rename(uploaded_tmp_file, uploaded_file)
        Rails.logger.info "renaming #{tmp_file_base_name} to #{original_file_name}"
        Resque.enqueue(ZipExtractor, false, uploaded_file, false, false)
        head 200
     
      else
        File.delete(uploaded_tmp_file) if File.exist?(uploaded_tmp_file)
        head 200
      end
    else

      File.delete(params[:file].path) if File.exist?(params[:file].path)
      head 200
    end
  end

  def edit
    @song = UploadedSong.find(params[:id])
  end

  def update
    @song = UploadedSong.find(params[:id])
    @song.field_to_update = (params[:field_to_update])
    if @song.update_attributes(uploaded_song_params)
      Resque.enqueue(ZipExtractor, @song.id, false, false, @song.field_to_update)
    end
    respond_with_bip @song
  end

  def destroy
    @song = UploadedSong.find(params[:id])
    @song.destroy!
    unless @song.cover_id.blank?
      cover = Cover.find(@song.cover_id)
      cover.destroy!
    end
    if session[:ids] == nil
      respond_to do |format|
        format.html { redirect_to uploaded_songs_url, notice: 'Song was successfully destroyed.' }
        format.json { head :no_content }
      end
    else
      session[:ids].delete(@song.id)
      respond_to do |format|
        format.html { redirect_to uploaded_songs_url, notice: 'Song was successfully destroyed.' }
        format.json { head :no_content }
      end
    end
  end

  private

  def uploaded_song_params
    params.require(:uploaded_song).permit(:title, :artist, :album, :year, :track, :genre, :comment, :song_name, :attachment, :is_explicit)
  end

  def set_session_for_ids
    if session[:ids] == nil
      session[:ids] = Array.new
    end
  end

  def update_music_metadata?(song)
    TagLib::FileRef.open(song.attachment_url) do |fileref|
      unless fileref.null?
        tag = fileref.tag # true is for writing.
        tag.title = song.title
        tag.artist = song.artist
        tag.album = song.album
        tag.year = song.year.to_i
        tag.track = song.track.to_i
        tag.genre = song.genre
        tag.comment = song.comment
        if fileref.save
          return true
        else
          return false
        end
      end
    end
  end

  def update_song_name?(song)
    file_handle = File.open(song.song_path)
    dir_location = File.dirname(song.song_path)
    file_ext = File.extname(song.song_path)
    song_name = song.song_name + file_ext
    song_path = dir_location + "/#{song_name}"
    attachment = File.rename_file(file_handle, song_path)
    if song.update_attributes({attachment: attachment, song_name: song_name, song_path: song_path})
      return true
    else
      return false
    end

  end
end

uploaded_song.rb

require 'file_size_validator'
class UploadedSong < ActiveRecord::Base
  belongs_to :cover
  mount_uploader :attachment, AttachmentUploader
  skip_callback :commit, :after, :remove_attachment!, if: Proc.new{ |s| s.file_keep == true }
  validates :attachment, :file_size => { less_than: 200.megabytes }
  attr_accessor :file_keep, :field_to_update
end

zip_extractor.rb

require 'taglib'
require 'zip'

class ZipExtractor
  @queue = :songs_queue

  def self.perform path_to_zip, destination_path, delete = false, field_to_update
    if !path_to_zip.blank? and delete and !destination_path.blank? and !field_to_update
      unzip(path_to_zip, destination_path)

      Dir.glob("#{destination_path}" + '/*') do |music_file|
        base_file_name =  File.basename(music_file)
        next if base_file_name.casecmp("__macosx") == 0
        process_song(music_file)
      end
    end
   
    if !path_to_zip and !delete and !destination_path.blank? and !field_to_update
      process_song(destination_path)
    end
   
    if !path_to_zip.blank? and !delete and !destination_path and !field_to_update.blank?
      log("processing song details update")
      song = UploadedSong.find(path_to_zip)
      song_details = nil
      TagLib::FileRef.open(song.attachment_url) do |fileref|
        unless fileref.null?
          tag = fileref.tag
          case field_to_update.to_s
          when "title"
            tag.title = song.title
          when "artist"
            tag.artist = song.artist
          when "album"
            tag.album = song.album
          when "year"
            tag.year = song.year.to_i
          when "track"
            tag.track = song.track.to_i
          when "genre"
            tag.genre = song.genre
          when "comment"
            tag.comment = song.comment
          else
            log 'No parameters for "field_to_update".'
          end
          unless fileref.save
            TagLib::FileRef.open(song.attachment_url) do |fileref|
              unless fileref.null?
                tag = fileref.tag
                song_details =  {
                  title: tag.title,
                  artist: tag.artist,
                  album: tag.album,
                  year: tag.year,
                  track: tag.track,
                  genre: tag.genre,
                  comment: tag.comment,
                  is_explicit: false
                }
              end
            end
            if song_details[:title].downcase.include? 'explicit'
              song_details[:is_explicit] = true
            end
            song.update_attributes(song_details)
          end
        end
      end
    end
  end

  def self.process_song(destination_path)
    if %w(.mp3 .ogg .mp4 .m4a).include? File.extname(destination_path)
      if %w(.ogg .mp4 .m4a).include? File.extname(destination_path)
        destination_path = convert_video_to_audio(destination_path)
      end
      if %w(.mp3).include? File.extname(destination_path)
        process_mp3(destination_path)
      else
        delete_file(destination_path)
      end
    else
      delete_file(destination_path)
    end
  end

  def self.process_mp3(destination_path)
    song_details = extract_metadata(destination_path)
    rename_file = File.dirname(destination_path) + "/1-----" + File.basename(destination_path)
    extension = File.extname(destination_path)
    cover_file_name = nil

    rename = File.rename(destination_path, rename_file)
    if rename == 0
      transcoded_movie, cover_file_name = transcode_file(rename_file, destination_path)
      
      if transcoded_movie.valid?
        delete_file(rename_file)
        song_details[:attachment] = File.open(destination_path) if File.exist?(destination_path)
        # cover = nil
        p song_details[:attachment]
        unless cover_file_name.nil?
          cover = Cover.new({name: File.basename(cover_file_name), cover_pic: File.open(cover_file_name)}) if File.exist?(cover_file_name)
        end
        song = UploadedSong.new(song_details)
   
        if !cover.blank?
          if cover.save
            delete_file(cover_file_name)
            song.cover_id = cover.id
            if song.save
              delete_file(destination_path)
            end
          end
        else
          p 9999999999999999999999999999999999999999999999999999
          p song.valid?
          p song.save
          p song.errors.any?
          p song.errors.full_messages
          p 9999999999999999999999999999999999999999999999999999
          if song.save!
            delete_file(destination_path)
          end
        end
      else
        delete_file(destination_path)
        delete_file(rename_file)
      end
    else
      delete_file(destination_path)
    end
  end

  def self.convert_video_to_audio(destination_path)
    log "Found video file. Converting video to audio."
    movie = FFMPEG::Movie.new(destination_path)
    if movie.valid?
      file_name_with_no_ext = File.basename(destination_path, "#{File.extname(destination_path)}")
      out_file = "#{File.dirname(destination_path)}/#{file_name_with_no_ext}.mp3"
      out_movie = movie.transcode(out_file)
      if out_movie.valid?
        delete_file(destination_path)
        destination_path = out_file
      end
    end
    return destination_path
  end

  def self.extract_metadata(destination_path)
    log("extracting metadata from media file")
    song_details = nil
    TagLib::FileRef.open(destination_path) do |fileref|
      unless fileref.null?
        tag = fileref.tag
        song_details =
        {
          title: tag.title.blank? ? 'Single' : tag.title,
          artist: tag.artist.blank? ? 'Single' : tag.artist,
          album: tag.album.blank? ? 'Single' : tag.album,
          year: tag.year.blank? ? '' : tag.year,
          track: tag.track.blank? ? '' : tag.track,
          genre: tag.genre.blank? ? '' : tag.genre,
          comment: tag.comment.blank? ? '' : tag.comment,
          is_explicit: false
        }
        if song_details[:title].downcase.include? 'explicit'
          song_details[:is_explicit] = true
        end
        if tag.title.blank?
          tag.title = "Single"
          fileref.save
        elsif tag.artist.blank?
          tag.artist = "Single"
          fileref.save
        elsif tag.album.blank?
          tag.album = "Single"
          fileref.save
        end
      end
    end
    return song_details
  end

  def self.transcode_file(rename_file, destination_path)
    movie = FFMPEG::Movie.new(rename_file)
    cover_file_name = nil
    transcoded_movie = nil
    p movie.valid?
    if movie.valid?
      log "ffmpeg validates file #{rename_file}"
      if movie.video_stream == nil
        options = {audio_codec: "libmp3lame", audio_bitrate: 320, audio_sample_rate: 44100, audio_channels: 2}
      else
        log "removing video stream from file and extracting cover"
        cover_file_name = extract_image_from_file(rename_file)
        # "-vn" flag is used to remove video_stream from mp3 file
        options = {audio_codec: "libmp3lame", audio_bitrate: 320, audio_sample_rate: 44100, audio_channels: 2, custom: "-vn"}
      end
      transcoded_movie = movie.transcode(destination_path, options)
    else
      log "Unable to process media file."
      delete_file(rename_file)
    end
    return transcoded_movie, cover_file_name
  end

  def self.extract_image_from_file(rename_file)
    cover_file_name = nil
    cover_path = "#{Rails.root}/public/covers/"
    TagLib::MPEG::File.open(rename_file) do |fileref|
      cover_tag = fileref.id3v2_tag
      cover_img = cover_tag.frame_list('APIC').first
      unless cover_img.blank?
        ext = cover_img.mime_type.rpartition('/')[2]
        o = [('a'..'i'), ('A'..'Z')].map { |i| i.to_a }.flatten
        rand_string = (1..18).map { o[rand(o.length)] }.join
        cover_file_name = "#{cover_path}#{File.basename(rename_file).chomp('.mp3').gsub('1-----','')}-#{rand_string}.#{ext}"
        File.open(cover_file_name, "wb") { |f| f.write cover_img.picture }
        log "cover extracted from media file."
      end
    end
    return cover_file_name
  end

  def self.delete_file(filename)
    File.delete(filename) if File.exist?(filename)
  end

  def self.log(message)
    Rails.logger.debug "\n*********** #{message} ***************"
  end

  def self.unzip(path_to_zip, destination_path)
    log "unzipping #{path_to_zip} \nto #{destination_path}"
    Zip::File.open(path_to_zip) do |zip_file|
      # log "zip file is #{zip_file}"
      zip_file.each do |f|
        f_path=File.join(destination_path, f.name)
        FileUtils.mkdir_p(File.dirname(f_path))
        a = zip_file.extract(f, f_path) unless File.exist?(f_path)
        # log "file extraction complete"
        # log a
      end
      log "after zip file loop"
    end
    # log "removing original zip file"
    FileUtils.rm(path_to_zip)
    # log "removed zip file from #{path_to_zip}"
  end
end

in above means zip_extractor.rb I checked song.valid? it gives me false in rails 6 and error is cover must exist and I have checked cover is nil but in rails 4 it gives true and also checked in this version also cover is nil but song saved in database in rails but not in rails 6. anyone have proper reason why it behave like this answer fast otherwise mailto: [email protected]

0

There are 0 best solutions below