Module: AsciinemaWin::OutputOrganizer

Defined in:
lib/asciinema_win/output_organizer.rb

Overview

Output organization utilities

Provides structured directory organization for recordings and exports with timestamp-based naming and format-specific subdirectories.

Defined Under Namespace

Classes: Session

Constant Summary collapse

DEFAULT_BASE_DIR =

Default base directory for outputs

"asciinema_output"
FORMAT_DIRS =

Format subdirectory mapping

{
  cast: "recordings",
  html: "html",
  svg: "svg",
  txt: "text",
  text: "text",
  json: "json",
  gif: "video",
  mp4: "video",
  webm: "video",
  thumbnail: "thumbnails"
}.freeze

Class Method Summary collapse

Class Method Details

.cleanup(base_dir: DEFAULT_BASE_DIR, keep_days: 30) ⇒ Integer

Clean old files from output directory

Parameters:

  • base_dir (String) (defaults to: DEFAULT_BASE_DIR)

    Base output directory

  • keep_days (Integer) (defaults to: 30)

    Keep files newer than this many days

Returns:

  • (Integer)

    Number of files deleted



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/asciinema_win/output_organizer.rb', line 125

def cleanup(base_dir: DEFAULT_BASE_DIR, keep_days: 30)
  cutoff = Time.now - (keep_days * 24 * 60 * 60)
  deleted = 0

  Dir.glob(File.join(base_dir, "**", "*")).each do |file|
    next unless File.file?(file)
    next if File.mtime(file) > cutoff

    File.delete(file)
    deleted += 1
  end

  # Remove empty directories
  Dir.glob(File.join(base_dir, "**", "*"))
     .select { |d| File.directory?(d) }
     .sort_by { |d| -d.length }  # Deepest first
     .each do |dir|
       Dir.rmdir(dir) if Dir.empty?(dir)
     rescue Errno::ENOTEMPTY
       # Skip non-empty directories
     end

  deleted
end

.create_session(name, base_dir: DEFAULT_BASE_DIR) ⇒ Session

Create a session directory for related outputs

Parameters:

  • name (String)

    Session name

  • base_dir (String) (defaults to: DEFAULT_BASE_DIR)

    Base output directory

Returns:

  • (Session)

    Session object for organizing related files



67
68
69
70
# File 'lib/asciinema_win/output_organizer.rb', line 67

def create_session(name, base_dir: DEFAULT_BASE_DIR)
  session_id = "#{sanitize_name(name)}_#{timestamp_string}"
  Session.new(session_id, base_dir)
end

.list_sessions(base_dir: DEFAULT_BASE_DIR) ⇒ Array<String>

List all sessions in output directory

Parameters:

  • base_dir (String) (defaults to: DEFAULT_BASE_DIR)

    Base output directory

Returns:

  • (Array<String>)

    Session directory names



86
87
88
89
90
91
92
93
94
# File 'lib/asciinema_win/output_organizer.rb', line 86

def list_sessions(base_dir: DEFAULT_BASE_DIR)
  recordings_dir = File.join(base_dir, "recordings")
  return [] unless Dir.exist?(recordings_dir)

  Dir.children(recordings_dir)
     .select { |f| File.directory?(File.join(recordings_dir, f)) }
     .sort
     .reverse
end

.output_path(base_name, format:, base_dir: DEFAULT_BASE_DIR, timestamp: true, session_id: nil) ⇒ String

Get organized output path

Parameters:

  • base_name (String)

    Base name for the file

  • format (Symbol)

    Output format

  • base_dir (String) (defaults to: DEFAULT_BASE_DIR)

    Base output directory

  • timestamp (Boolean) (defaults to: true)

    Include timestamp in filename

  • session_id (String, nil) (defaults to: nil)

    Session ID for grouping related files

Returns:

  • (String)

    Full output path



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/asciinema_win/output_organizer.rb', line 37

def output_path(base_name, format:, base_dir: DEFAULT_BASE_DIR, timestamp: true, session_id: nil)
  # Ensure base directory exists
  ensure_directory(base_dir)

  # Get format-specific subdirectory
  format_dir = FORMAT_DIRS[format.to_sym] || "other"
  full_dir = File.join(base_dir, format_dir)

  # Add session subdirectory if provided
  if session_id
    full_dir = File.join(full_dir, session_id)
  end

  ensure_directory(full_dir)

  # Build filename
  filename = if timestamp
               "#{base_name}_#{timestamp_string}.#{format}"
             else
               "#{base_name}.#{format}"
             end

  File.join(full_dir, filename)
end

.recording_path(name, base_dir: DEFAULT_BASE_DIR, timestamp: true) ⇒ String

Get organized path for a recording

Parameters:

  • name (String)

    Recording name

  • base_dir (String) (defaults to: DEFAULT_BASE_DIR)

    Base output directory

  • timestamp (Boolean) (defaults to: true)

    Include timestamp

Returns:

  • (String)

    Full path to recording file



78
79
80
# File 'lib/asciinema_win/output_organizer.rb', line 78

def recording_path(name, base_dir: DEFAULT_BASE_DIR, timestamp: true)
  output_path(sanitize_name(name), format: :cast, base_dir: base_dir, timestamp: timestamp)
end

.summary(base_dir: DEFAULT_BASE_DIR) ⇒ Hash

Get summary of output directory contents

Parameters:

  • base_dir (String) (defaults to: DEFAULT_BASE_DIR)

    Base output directory

Returns:

  • (Hash)

    Summary of files by category



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/asciinema_win/output_organizer.rb', line 100

def summary(base_dir: DEFAULT_BASE_DIR)
  result = {}

  FORMAT_DIRS.values.uniq.each do |subdir|
    path = File.join(base_dir, subdir)
    next unless Dir.exist?(path)

    files = Dir.glob(File.join(path, "**", "*"))
               .select { |f| File.file?(f) }

    result[subdir] = {
      count: files.length,
      total_size: files.sum { |f| File.size(f) },
      files: files.map { |f| File.basename(f) }
    }
  end

  result
end