From e97598fc7e03f5ba98e7383eba5c8c2eedad21f8 Mon Sep 17 00:00:00 2001 From: Maxim Tretyakov Date: Mon, 20 Dec 2021 13:41:06 +0500 Subject: [PATCH] Correct show vertical video --- .../api/v1/admin/videos_controller.rb | 3 ++- app/models/photo.rb | 4 ++-- app/views/photos/show.slim | 8 ++++++++ config/locales/ru.yml | 2 ++ lib/formatters/duration.rb | 12 ++++++++---- scripts/upload_video.rb | 10 +++++++--- .../api/v1/admin/videos_controller_spec.rb | 6 ++++-- spec/lib/formatters/duration_spec.rb | 16 ++++++++++++++++ spec/models/photo_spec.rb | 1 + 9 files changed, 50 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/v1/admin/videos_controller.rb b/app/controllers/api/v1/admin/videos_controller.rb index f8fe209c..bce85dd9 100644 --- a/app/controllers/api/v1/admin/videos_controller.rb +++ b/app/controllers/api/v1/admin/videos_controller.rb @@ -37,7 +37,7 @@ def video_params :name, :rubric_id, :content_type, :original_filename, :original_timestamp, :width, :height, :md5, :sha256, :preview_md5, :preview_sha256, :video_preview_md5, :video_preview_sha256, :size, :preview_size, :video_preview_size, - :tz, lat_long: [], exif: %i[make model] + :tz, :duration, lat_long: [], exif: %i[make model] ) end @@ -45,6 +45,7 @@ def normalized_video_params video_params.tap do |par| par[:preview_size] = par[:preview_size].to_i par[:video_preview_size] = par[:video_preview_size].to_i + par[:duration] = par[:duration].to_f if par[:duration].present? end end diff --git a/app/models/photo.rb b/app/models/photo.rb index 8a4cd7b0..bdfbaa40 100644 --- a/app/models/photo.rb +++ b/app/models/photo.rb @@ -23,7 +23,7 @@ class Photo < ApplicationRecord optional: true store_accessor :props, - :rotated, :effects, :external_info, + :rotated, :effects, :external_info, :duration, :preview_filename, :preview_size, :preview_md5, :preview_sha256, :video_preview_filename, :video_preview_size, :video_preview_md5, :video_preview_sha256 @@ -43,7 +43,7 @@ class Photo < ApplicationRecord presence: true, numericality: {only_integer: true, greater_than: 0}, if: :video? validates :preview_md5, :video_preview_md5, presence: true, length: {is: 32}, if: :video? validates :preview_sha256, :video_preview_sha256, presence: true, length: {is: 64}, if: :video? - validates :preview_filename, :preview_size, :preview_md5, :preview_sha256, + validates :duration, :preview_filename, :preview_size, :preview_md5, :preview_sha256, :video_preview_filename, :video_preview_size, :video_preview_md5, :video_preview_sha256, absence: true, unless: :video? diff --git a/app/views/photos/show.slim b/app/views/photos/show.slim index 5275af74..61e1b296 100644 --- a/app/views/photos/show.slim +++ b/app/views/photos/show.slim @@ -104,6 +104,14 @@ = t('.camera') td = "#{current.exif['make']} #{current.exif['model']}" + + - if current.duration.present? + tr + th + = t('.duration') + td + = Formatters::Duration.new(current.duration, include_seconds: true).call + tr th = t('.created_at') diff --git a/config/locales/ru.yml b/config/locales/ru.yml index e54068d8..243a124a 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -201,6 +201,7 @@ ru: camera: Камера created_at: Загружено download: Скачать + duration: Длительность edit: Редактировать original_filename: Имя файла original_timestamp: Дата съёмки @@ -243,6 +244,7 @@ ru: days: '%{days}дн.' hours: '%{hours}ч.' minutes: '%{minutes}мин.' + seconds: '%{seconds}сек.' views: pagination: first: Первая страница diff --git a/lib/formatters/duration.rb b/lib/formatters/duration.rb index aa312804..f88e4341 100644 --- a/lib/formatters/duration.rb +++ b/lib/formatters/duration.rb @@ -2,8 +2,9 @@ module Formatters class Duration - def initialize(value_seconds) + def initialize(value_seconds, include_seconds: false) @minutes = (value_seconds / 60.0).round + @seconds = (value_seconds % 60).round if include_seconds end def call @@ -15,19 +16,22 @@ def call hours = (minutes / 60).floor minutes -= hours * 60 - format_duration_text days, hours, minutes + formatted = format_duration_text(days, hours, minutes, @seconds) + + formatted.empty? ? '0' : formatted.join(' ') end private - def format_duration_text(days, hours, minutes) + def format_duration_text(days, hours, minutes, seconds) result = [] result << I18n.t('tracks.duration.days', days: days) if days.positive? result << I18n.t('tracks.duration.hours', hours: hours) if hours.positive? result << I18n.t('tracks.duration.minutes', minutes: minutes.to_s.rjust(2, '0')) if minutes.positive? + result << I18n.t('tracks.duration.seconds', seconds: @seconds.to_s.rjust(2, '0')) if seconds&.positive? - result.empty? ? '0' : result.join(' ') + result end end end diff --git a/scripts/upload_video.rb b/scripts/upload_video.rb index 6173be4b..6d65ac70 100755 --- a/scripts/upload_video.rb +++ b/scripts/upload_video.rb @@ -79,19 +79,22 @@ def request_body private - def upload_request_body(general, video) # rubocop:disable Metrics/AbcSize + def upload_request_body(general, video) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity name = File.basename(filename) lat_long = general.dig(:extra, :xyz) || general.dig(:extra, :location) make = general.dig(:extra, :com_android_manufacturer) model = general.dig(:extra, :com_android_model) + dimensions = [video.fetch(:Width).to_i, video.fetch(:Height).to_i] + dimensions.reverse! if [90, 270].include?(video[:Rotation].to_i) + { name: File.basename(name, '.*'), original_filename: name, original_timestamp: parse_timestamp(general[:Tagged_Date] || general[:Encoded_Date]), - width: video.fetch(:Width).to_i, - height: video.fetch(:Height).to_i, + width: dimensions.first, + height: dimensions.last, content_type: CONTENT_TYPES_BY_EXT.fetch(general.fetch(:FileExtension)), lat_long: lat_long ? lat_long.gsub(/[^0-9.]/, ' ').to_s.strip.split.map(&:to_f) : nil, md5: md5(filename), @@ -103,6 +106,7 @@ def upload_request_body(general, video) # rubocop:disable Metrics/AbcSize video_preview_md5: md5(video_preview_file.path), video_preview_sha256: sha256(video_preview_file.path), video_preview_size: video_preview_file.size, + duration: video.fetch(:Duration).to_f, tz: @timezone, exif: make && model ? {make: make, model: model} : nil } diff --git a/spec/controllers/api/v1/admin/videos_controller_spec.rb b/spec/controllers/api/v1/admin/videos_controller_spec.rb index da137693..10eb6e5e 100644 --- a/spec/controllers/api/v1/admin/videos_controller_spec.rb +++ b/spec/controllers/api/v1/admin/videos_controller_spec.rb @@ -34,7 +34,8 @@ exif: {'make' => 'Sony', 'model' => 'Test'}, width: 1_024, height: 768, - tz: 'Europe/Moscow' + tz: 'Europe/Moscow', + duration: '120.55' } end @@ -58,7 +59,8 @@ storage_filename: String, video_preview_filename: String, lat_long: ActiveRecord::Point.new(10.5, 11.65), - original_timestamp: Time.zone.local(2021, 11, 4, 7, 12, 43) + original_timestamp: Time.zone.local(2021, 11, 4, 7, 12, 43), + duration: 120.55 ) ) diff --git a/spec/lib/formatters/duration_spec.rb b/spec/lib/formatters/duration_spec.rb index a9be2bd1..0a752df5 100644 --- a/spec/lib/formatters/duration_spec.rb +++ b/spec/lib/formatters/duration_spec.rb @@ -50,4 +50,20 @@ it { is_expected.to eq('1дн.') } end + + context 'when seconds' do + subject { described_class.new(duration, include_seconds: true).call } + + let(:duration) { 125.seconds } + + it { is_expected.to eq('02мин. 05сек.') } + end + + context 'when mode with seconds but value without seconds' do + subject { described_class.new(duration, include_seconds: true).call } + + let(:duration) { 120.seconds } + + it { is_expected.to eq('02мин.') } + end end diff --git a/spec/models/photo_spec.rb b/spec/models/photo_spec.rb index a4cc6685..0b718e30 100644 --- a/spec/models/photo_spec.rb +++ b/spec/models/photo_spec.rb @@ -58,6 +58,7 @@ it { is_expected.to validate_absence_of(:video_preview_size) } it { is_expected.to validate_absence_of(:video_preview_md5) } it { is_expected.to validate_absence_of(:video_preview_sha256) } + it { is_expected.to validate_absence_of(:duration) } end describe 'video validations' do