From 51f561ec940d63beb3eca2d5ec98b43d12392f3b Mon Sep 17 00:00:00 2001 From: Brandt Lareau Date: Tue, 16 Apr 2024 14:48:33 -0700 Subject: [PATCH] Improved the GUI and system checks that handle uploading video data commit-id:00ffc232 --- app/assets/stylesheets/bg_process.scss | 8 --- app/components/movie_title_table_component.rb | 2 +- app/controllers/application_controller.rb | 17 ++++-- app/listeners/upload_progress_listener.rb | 18 ++++--- app/models/movie.rb | 12 +++-- app/models/video.rb | 4 -- app/services/find_existing_disks_service.rb | 39 +++++++++++--- app/tool_box/shell.rb | 10 +++- app/views/layouts/_bg_progress.erb | 52 +++++++++++++++++++ app/views/layouts/application.erb | 48 ++++------------- app/workers/load_disk_worker.rb | 11 +--- app/workers/rip_worker.rb | 5 +- app/workers/upload_worker.rb | 14 +++++ 13 files changed, 154 insertions(+), 86 deletions(-) create mode 100644 app/views/layouts/_bg_progress.erb create mode 100644 app/workers/upload_worker.rb diff --git a/app/assets/stylesheets/bg_process.scss b/app/assets/stylesheets/bg_process.scss index 20f25e8e..761f9609 100644 --- a/app/assets/stylesheets/bg_process.scss +++ b/app/assets/stylesheets/bg_process.scss @@ -1,10 +1,3 @@ -.bg-processes { - position: fixed; - right: 0; - top: 0; - z-index: 4; -} - .bg-process { --bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85); --bs-toast-border-color: var(--bs-border-color-translucent); @@ -31,7 +24,6 @@ margin: 2em; max-width: 100%; pointer-events: auto; - width: var(--bs-toast-max-width); .header { display: flex; diff --git a/app/components/movie_title_table_component.rb b/app/components/movie_title_table_component.rb index 71390aee..7cb901ff 100644 --- a/app/components/movie_title_table_component.rb +++ b/app/components/movie_title_table_component.rb @@ -3,7 +3,7 @@ class MovieTitleTableComponent < ViewComponent::Base extend Dry::Initializer - option :disks, Types::Array.of(Types.Instance(Disk)) + option :disks, Types::Coercible::Array.of(Types.Instance(Disk)) option :movie, Types.Instance(Movie) def dom_id diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index becae409..93f2022c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,10 +3,11 @@ class ApplicationController < ActionController::Base include Rescuer - before_action :plex_config - before_action :movie_db_config - before_action :mkv_config + before_action :continue_upload before_action :load_disk_worker + before_action :mkv_config + before_action :movie_db_config + before_action :plex_config helper_method :free_disk_space, :total_disk_space def current_user @@ -27,6 +28,16 @@ def load_disk_worker LoadDiskWorker.perform_async end + def continue_upload + return if UploadWorker.job.pending? + + Movie.find_each do |movie| + next unless movie.tmp_plex_path_exists? + + UploadWorker.perform_async(disk_title: movie.disk_title) + end + end + private def stats diff --git a/app/listeners/upload_progress_listener.rb b/app/listeners/upload_progress_listener.rb index 65341564..b912cb76 100644 --- a/app/listeners/upload_progress_listener.rb +++ b/app/listeners/upload_progress_listener.rb @@ -26,12 +26,18 @@ def update_component cable_ready.broadcast end - def component - ProgressBarComponent.new \ - model: DiskTitle, - completed: percentage, - status: :info, - message: title + def component # rubocop:disable Metrics/MethodLength + progress_bar = render( + ProgressBarComponent.new( + model: Video, + completed: percentage, + status: :info, + message: title + ), layout: false + ) + component = ProcessComponent.new(worker: UploadWorker) + component.with_body { progress_bar } + component end def percentage diff --git a/app/models/movie.rb b/app/models/movie.rb index d5dfb6fe..fea38631 100644 --- a/app/models/movie.rb +++ b/app/models/movie.rb @@ -49,12 +49,12 @@ def plex_path @plex_path ||= Pathname.new("#{Config::Plex.newest.settings_movie_path}/#{plex_named_path}") end - def tmp_plex_path - @tmp_plex_path ||= Rails.root.join("tmp/movies/#{plex_named_path}") + def tmp_plex_dir + @tmp_plex_dir ||= Rails.root.join("tmp/movies/#{plex_name}") end - def plex_named_path - "#{plex_name}/#{plex_name}.mkv" + def tmp_plex_path + @tmp_plex_path ||= "#{tmp_plex_dir}/#{plex_name}.mkv" end def plex_name @@ -66,4 +66,8 @@ def update_maxlength(max) config.maxlength = nil end + + def tmp_plex_path_exists? + File.exist?(tmp_plex_path) + end end diff --git a/app/models/video.rb b/app/models/video.rb index 6fefc18f..13cb7dae 100644 --- a/app/models/video.rb +++ b/app/models/video.rb @@ -69,8 +69,4 @@ def ratings def release_or_air_date release_date || episode_first_air_date end - - def tmp_plex_path_exists? - File.exist?(tmp_plex_path) - end end diff --git a/app/services/find_existing_disks_service.rb b/app/services/find_existing_disks_service.rb index 38f4f4e8..7fc1408d 100644 --- a/app/services/find_existing_disks_service.rb +++ b/app/services/find_existing_disks_service.rb @@ -1,23 +1,46 @@ # frozen_string_literal: true class FindExistingDisksService - MOUNT_LINE = %r{\A(?\S+)\son\s(?:/Volumes/|)(?\S+)} + MOUNT_LINE = %r{\A(?\S+)\son\s(?:/Volumes/|)(?.*)\s[(]} + Device = Struct.new(:name, :disk_name) do + def rdisk_name + disk_name.gsub('/dev/', '/dev/r') + end + end + class << self delegate :call, to: :new end # example line: # /dev/disk4 on /Volumes/PLANET51 (udf, local, nodev, nosuid, read-only, noowners) - def call - mounts = `mount` - disks = [] - mounts.each_line do |line| + def call # rubocop:disable Metrics/MethodLength + index = 0 + devices.reduce(Disk.all) do |disks, device| + if index.zero? + disks.where( + name: device.name, + disk_name: [device.disk_name, device.rdisk_name] + ) + else + disks.or( + Disk.where( + name: device.name, + disk_name: [device.disk_name, device.rdisk_name] + ) + ) + end.tap { index += 1 } + end + end + + private + + def devices + @devices ||= `mount`.each_line.filter_map do |line| next unless line.start_with?('/dev/') match = line.match(MOUNT_LINE) - rdisk_name = match[:disk_name].gsub('/dev/', '/dev/r') - disks << Disk.find_by(name: match[:name], disk_name: [match[:disk_name], rdisk_name]) + Device.new(match[:name], match[:disk_name]) end - disks.compact end end diff --git a/app/tool_box/shell.rb b/app/tool_box/shell.rb index 3b8d49c2..f9a1fa8d 100755 --- a/app/tool_box/shell.rb +++ b/app/tool_box/shell.rb @@ -3,7 +3,15 @@ module Shell class Error < StandardError; end - Standard = Struct.new(:stdout_str, :stderr_str, :status, keyword_init: true) + Standard = Struct.new(:stdout_str, :stderr_str, :status, keyword_init: true) do + include MkvParser + + delegate :success?, to: :status + + def parsed_mkv + @parsed_mkv ||= parse_mkv_string(stdout_str) + end + end def capture3(*cmd) Rails.logger.debug { "command: #{cmd.join(', ')}" } diff --git a/app/views/layouts/_bg_progress.erb b/app/views/layouts/_bg_progress.erb new file mode 100644 index 00000000..fa790479 --- /dev/null +++ b/app/views/layouts/_bg_progress.erb @@ -0,0 +1,52 @@ +
+ <%= render ProcessComponent.new worker: ScanPlexWorker do |c| %> + <%= c.with_body do %> + <% if ScanPlexWorker.job.pending? %> + <%= + render( + ProgressBarComponent.new( + model: Movie, + completed: (ScanPlexWorker.job.worker.completed.zero? ? 20 : ScanPlexWorker.job.worker.completed), + status: :success, + message: 'scanning plex for movies', + show_percentage: false + ) + ) + %> + <% else %> + Done! you have a total of <%= pluralize(Video.count, 'video') %> on plex. + <% end %> + <% end %> + <% end %> + + <%= render ProcessComponent.new worker: LoadDiskWorker do |c| %> + <%= c.with_body do %> + <% if LoadDiskWorker.job.pending? %> + Loading the disk info + <% elsif (disks = FindExistingDisksService.call).any? %> + <%= disks.map(&:name).join(', ') %> is ready to be ripped. + <% else %> + No disks found + <% end %> + <% end %> + <% end %> + <%= render ProcessComponent.new worker: UploadWorker do |c| %> + <%= c.with_body do %> + <% if UploadWorker.job.pending? %> + + <%= + render( + ProgressBarComponent.new( + model: DiskTitle, + show_percentage: false, + status: :info, + message: 'upload in progress' + ) + ) + %> + <% else %> + Nothing is being uploaded to <%= Config::Plex.newest.settings_ftp_host %> + <% end %> + <% end %> + <% end %> +
diff --git a/app/views/layouts/application.erb b/app/views/layouts/application.erb index 6e4511e8..46bd4d49 100644 --- a/app/views/layouts/application.erb +++ b/app/views/layouts/application.erb @@ -6,49 +6,21 @@ <%= render 'layouts/head' %> -
- <%= render ProcessComponent.new worker: ScanPlexWorker do |c| %> - <%= c.with_body do %> - <% if ScanPlexWorker.job.pending? %> - <%= - render( - ProgressBarComponent.new( - model: Movie, - completed: (ScanPlexWorker.job.worker.completed.zero? ? 20 : ScanPlexWorker.job.worker.completed), - status: :success, - message: 'scanning plex for movies', - show_percentage: false - ) - ) - %> - <% else %> - Done! you have a total of <%= pluralize(Video.count, 'video') %> on plex. - <% end %> - <% end %> - <% end %> - <%= render ProcessComponent.new worker: LoadDiskWorker do |c| %> - <%= c.with_body do %> - <% if LoadDiskWorker.job.pending? %> - Loading the disk info - <% elsif (disks = FindExistingDisksService.call).any? %> - <%= disks.map(&:name).join(', ') %> is ready to be ripped. - <% else %> - No disks found - <% end %> - <% end %> - <% end %> -
- <%= render ToastComponent.new do |c| %> - <%= c.body do %> - testing - <% end %> - <% end %> <%= render 'layouts/header' %> -
<%= yield %>
+
+
+
+ <%= render 'layouts/bg_progress' %> +
+
+ <%= yield %> +
+
+
diff --git a/app/workers/load_disk_worker.rb b/app/workers/load_disk_worker.rb index 4cdc301c..3f91b0f1 100644 --- a/app/workers/load_disk_worker.rb +++ b/app/workers/load_disk_worker.rb @@ -2,19 +2,10 @@ class LoadDiskWorker < ApplicationWorker def perform - cable_ready[DiskTitleChannel.channel_name].morph \ - selector: "##{component.dom_id}", - html: render(component, layout: false) - cable_ready[DiskTitleChannel.channel_name].reload if existing_disks.nil? + cable_ready[DiskTitleChannel.channel_name].reload if existing_disks.nil? && disks.present? cable_ready.broadcast end - def component - component = ProcessComponent.new(worker: ScanPlexWorker) - component.with_body { disks.map(&:name).join(', ') } - component - end - def disks @disks ||= existing_disks || CreateDisksService.call end diff --git a/app/workers/rip_worker.rb b/app/workers/rip_worker.rb index f446ea34..d05fdf7c 100644 --- a/app/workers/rip_worker.rb +++ b/app/workers/rip_worker.rb @@ -22,9 +22,8 @@ def create_mkv(disk_title) end def upload_mkv(disk_title) - @progress_listener = UploadProgressListener.new(file_size: disk_title.size) - Ftp::UploadMkvService.call disk_title:, - progress_listener: + sleep 1 while UploadWorker.job.pending? + UploadWorker.perform_async(disk_title) end def disk_titles diff --git a/app/workers/upload_worker.rb b/app/workers/upload_worker.rb new file mode 100644 index 00000000..fd6eb33b --- /dev/null +++ b/app/workers/upload_worker.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class UploadWorker < ApplicationWorker + option :disk_title, Types.Instance(DiskTitle) + + def perform + progress_listener = UploadProgressListener.new( + title: "Uploading #{disk_title.video.title}", + file_size: disk_title.size + ) + Ftp::UploadMkvService.call disk_title:, + progress_listener: + end +end