summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrothedev <grothedev@gmail.com>2025-07-20 11:54:44 -0400
committergrothedev <grothedev@gmail.com>2025-07-20 11:54:44 -0400
commitb0d1f580c8883a8402a2380e896c120189250658 (patch)
tree6d4d5fe4ab2e929486bb91b89c85ba4c91371091
parent82b5ea0eb32a68394ac33a0f8767acfd6ccb77b2 (diff)
changes from laptop
-rw-r--r--ffmpeg-repl.py129
-rw-r--r--ffmpeg-suite.sh36
-rw-r--r--videdit.py286
-rw-r--r--wow3.py98
4 files changed, 549 insertions, 0 deletions
diff --git a/ffmpeg-repl.py b/ffmpeg-repl.py
new file mode 100644
index 0000000..f63b4ce
--- /dev/null
+++ b/ffmpeg-repl.py
@@ -0,0 +1,129 @@
+#!/bin/python3
+
+import readline # Add this at the top
+# ... rest of the code
+
+import sys
+
+class SimpleREPL:
+ def __init__(self):
+ self.prompt = ">> "
+ self.commands = {
+ "help": self._show_help,
+ "exit": self._exit_repl,
+ "quit": self._exit_repl, # Alias for exit
+ "echo": self._echo,
+ "stack": self._stack, #vertical or horizontal
+
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex hstack output.mp4
+
+#audio from first vid
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack[v]" -map "[v]" -map 0:a -c:a copy output.mp4
+
+#resize videos to same height
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]scale=-1:720[v0];[1:v]scale=-1:720[v1];[v0][v1]hstack[v]" -map "[v]" -map 0:a -c:a copy output.mp4
+
+#padding between vids
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]pad=iw+10:ih[v0];[v0][1:v]hstack[v]" -map "[v]" -map 0:a output.mp4
+
+#shorter duration vid
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack=shortest=1[v]" -map "[v]" -map 0:a output.mp4
+
+#mix audio from both
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack=shortest=1[v]" -map "[v]" -map 0:a output.mp4
+
+#force same dimensions
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack[v];[0:a][1:a]amix[a]" -map "[v]" -map "[a]" output.mp4
+
+#vertical stack
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]scale=640:480[v0];[1:v]scale=640:480[v1];[v0][v1]hstack[v]" -map "[v]" -map 0:a output.mp4
+
+#3 or more vids sidebyside
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex vstack output.mp4
+
+# Three videos
+ffmpeg -i video1.mp4 -i video2.mp4 -i video3.mp4 -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v]" -map "[v]" -map 0:a output.mp4
+
+# Four videos (2x2 grid)
+ffmpeg -i video1.mp4 -i video2.mp4 -i video3.mp4 -i video4.mp4 -filter_complex "[0:v][1:v]hstack[top];[2:v][3:v]hstack[bottom];[top][bottom]vstack[v]" -map "[v]" -map 0:a output.mp4
+
+ def _show_help(self, *args):
+ """Displays available commands."""
+ print("Available commands:")
+ for cmd, func in self.commands.items():
+ docstring = func.__doc__ or "No description available."
+ print(f" {cmd:<15} - {docstring.strip().splitlines()[0]}") # Show first line of docstring
+ return None # No printable result for help
+
+ def _exit_repl(self, *args):
+ """Exits the REPL."""
+ print("Exiting REPL. Goodbye!")
+ sys.exit(0)
+
+ def _echo(self, *args):
+ """Echoes the input arguments back to the user.
+ Usage: echo <arg1> <arg2> ...
+ """
+ if not args:
+ return "Echo: Nothing to echo!"
+ return "Echo: " + " ".join(args)
+
+ # --- Placeholder for your custom commands ---
+ # def _handle_my_command(self, arg1, arg2=None, *other_args):
+ # """
+ # Description of my_command.
+ # Usage: my_command <required_arg> [optional_arg] ...
+ # """
+ # # Your command logic here
+ # # Example:
+ # # self.app_state['something'] = arg1
+ # # return f"Processed {arg1} and {arg2}"
+ # pass
+
+
+ def evaluate(self, line):
+ """Evaluates a single line of input."""
+ parts = line.strip().split()
+ if not parts:
+ return None # Empty line
+
+ command_name = parts[0].lower() # Case-insensitive command matching
+ args = parts[1:]
+
+ if command_name in self.commands:
+ command_func = self.commands[command_name]
+ try:
+ return command_func(*args)
+ except TypeError as e:
+ # Catch errors related to incorrect number of arguments
+ return f"Error: Invalid arguments for '{command_name}'. Usage: {command_func.__doc__ or ''}"
+ except Exception as e:
+ return f"Error executing '{command_name}': {e}"
+ else: #todo check for partial str match
+
+ return f"Unknown command: '{command_name}'. Type 'help' for available commands."
+
+ def run(self):
+ """Runs the REPL main loop."""
+ print("Welcome to SimpleREPL! Type 'help' for commands or 'exit' to quit.")
+ while True:
+ try:
+ line = input(self.prompt)
+ if line.strip(): # Process only if line is not empty
+ result = self.evaluate(line)
+ if result is not None: # Print only if there's a result
+ print(result)
+ except EOFError: # Ctrl+D
+ print("\nExiting REPL (EOF).")
+ break
+ except KeyboardInterrupt: # Ctrl+C
+ print("\nInterrupted. Type 'exit' or 'quit' to exit.")
+ # Optionally, you might want to clear any partial input here
+ # or reset some state if an operation was interrupted.
+ except Exception as e:
+ print(f"An unexpected error occurred: {e}")
+ # Depending on severity, you might want to break or continue
+
+if __name__ == "__main__":
+ repl_app = SimpleREPL()
+ repl_app.run()
diff --git a/ffmpeg-suite.sh b/ffmpeg-suite.sh
new file mode 100644
index 0000000..c3623c2
--- /dev/null
+++ b/ffmpeg-suite.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+
+#videos side by side
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex hstack output.mp4
+
+#audio from first vid
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack[v]" -map "[v]" -map 0:a -c:a copy output.mp4
+
+#resize videos to same height
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]scale=-1:720[v0];[1:v]scale=-1:720[v1];[v0][v1]hstack[v]" -map "[v]" -map 0:a -c:a copy output.mp4
+
+#padding between vids
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]pad=iw+10:ih[v0];[v0][1:v]hstack[v]" -map "[v]" -map 0:a output.mp4
+
+#shorter duration vid
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack=shortest=1[v]" -map "[v]" -map 0:a output.mp4
+
+#mix audio from both
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack=shortest=1[v]" -map "[v]" -map 0:a output.mp4
+
+#force same dimensions
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]hstack[v];[0:a][1:a]amix[a]" -map "[v]" -map "[a]" output.mp4
+
+#vertical stack
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v]scale=640:480[v0];[1:v]scale=640:480[v1];[v0][v1]hstack[v]" -map "[v]" -map 0:a output.mp4
+
+#3 or more vids sidebyside
+ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex vstack output.mp4
+
+# Three videos
+ffmpeg -i video1.mp4 -i video2.mp4 -i video3.mp4 -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v]" -map "[v]" -map 0:a output.mp4
+
+# Four videos (2x2 grid)
+ffmpeg -i video1.mp4 -i video2.mp4 -i video3.mp4 -i video4.mp4 -filter_complex "[0:v][1:v]hstack[top];[2:v][3:v]hstack[bottom];[top][bottom]vstack[v]" -map "[v]" -map 0:a output.mp4
+
diff --git a/videdit.py b/videdit.py
new file mode 100644
index 0000000..698ce86
--- /dev/null
+++ b/videdit.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+"""
+Video Clip Extractor GUI
+A simple GUI application for extracting video clips using ffmpeg
+"""
+
+import tkinter as tk
+from tkinter import filedialog, messagebox, ttk
+import subprocess
+import os
+import threading
+from pathlib import Path
+import re
+
+class VideoClipperGUI:
+ def __init__(self, root):
+ self.root = root
+ self.root.title("Video Clip Extractor")
+ self.root.geometry("600x400")
+
+ # Variables
+ self.input_file = tk.StringVar()
+ self.start_time = tk.StringVar(value="00:00:00")
+ self.end_time = tk.StringVar(value="00:00:10")
+ self.output_dir = tk.StringVar(value=os.getcwd())
+
+ self.setup_ui()
+
+ def setup_ui(self):
+ # Main frame
+ main_frame = ttk.Frame(self.root, padding="10")
+ main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
+
+ # Configure grid weights
+ self.root.columnconfigure(0, weight=1)
+ self.root.rowconfigure(0, weight=1)
+ main_frame.columnconfigure(1, weight=1)
+
+ # Input file selection
+ ttk.Label(main_frame, text="Input Video File:").grid(row=0, column=0, sticky=tk.W, pady=5)
+
+ file_frame = ttk.Frame(main_frame)
+ file_frame.grid(row=0, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5)
+ file_frame.columnconfigure(0, weight=1)
+
+ self.file_entry = ttk.Entry(file_frame, textvariable=self.input_file, state="readonly")
+ self.file_entry.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5))
+
+ ttk.Button(file_frame, text="Browse", command=self.browse_file).grid(row=0, column=1)
+
+ # Time inputs
+ ttk.Label(main_frame, text="Start Time:").grid(row=1, column=0, sticky=tk.W, pady=5)
+ self.start_entry = ttk.Entry(main_frame, textvariable=self.start_time, width=15)
+ self.start_entry.grid(row=1, column=1, sticky=tk.W, pady=5)
+ ttk.Label(main_frame, text="(HH:MM:SS or seconds)").grid(row=1, column=2, sticky=tk.W, padx=(5, 0))
+
+ ttk.Label(main_frame, text="End Time:").grid(row=2, column=0, sticky=tk.W, pady=5)
+ self.end_entry = ttk.Entry(main_frame, textvariable=self.end_time, width=15)
+ self.end_entry.grid(row=2, column=1, sticky=tk.W, pady=5)
+ ttk.Label(main_frame, text="(HH:MM:SS or seconds)").grid(row=2, column=2, sticky=tk.W, padx=(5, 0))
+
+ # Output directory
+ ttk.Label(main_frame, text="Output Directory:").grid(row=3, column=0, sticky=tk.W, pady=5)
+
+ output_frame = ttk.Frame(main_frame)
+ output_frame.grid(row=3, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5)
+ output_frame.columnconfigure(0, weight=1)
+
+ self.output_entry = ttk.Entry(output_frame, textvariable=self.output_dir)
+ self.output_entry.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 5))
+
+ ttk.Button(output_frame, text="Browse", command=self.browse_output_dir).grid(row=0, column=1)
+
+ # Options frame
+ options_frame = ttk.LabelFrame(main_frame, text="Options", padding="5")
+ options_frame.grid(row=4, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=10)
+ options_frame.columnconfigure(1, weight=1)
+
+ # Quality/encoding options
+ ttk.Label(options_frame, text="Quality:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5))
+ self.quality_var = tk.StringVar(value="copy")
+ quality_combo = ttk.Combobox(options_frame, textvariable=self.quality_var, width=15)
+ quality_combo['values'] = ("copy (fastest)", "high", "medium", "low")
+ quality_combo.grid(row=0, column=1, sticky=tk.W)
+
+ # Extract button
+ self.extract_btn = ttk.Button(main_frame, text="Extract Clip", command=self.extract_clip)
+ self.extract_btn.grid(row=5, column=0, columnspan=3, pady=20)
+
+ # Progress bar
+ self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
+ self.progress.grid(row=6, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=5)
+
+ # Status/output text
+ text_frame = ttk.LabelFrame(main_frame, text="Output", padding="5")
+ text_frame.grid(row=7, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
+ text_frame.columnconfigure(0, weight=1)
+ text_frame.rowconfigure(0, weight=1)
+ main_frame.rowconfigure(7, weight=1)
+
+ self.output_text = tk.Text(text_frame, height=8, wrap=tk.WORD)
+ scrollbar = ttk.Scrollbar(text_frame, orient=tk.VERTICAL, command=self.output_text.yview)
+ self.output_text.configure(yscrollcommand=scrollbar.set)
+
+ self.output_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
+ scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))
+
+ # Initial message
+ self.log_message("Ready to extract video clips. Select a video file to begin.")
+
+ def browse_file(self):
+ """Open file dialog to select input video file"""
+ filetypes = [
+ ("Video files", "*.mp4 *.avi *.mkv *.mov *.wmv *.flv *.webm *.m4v"),
+ ("All files", "*.*")
+ ]
+
+ filename = filedialog.askopenfilename(
+ title="Select Video File",
+ filetypes=filetypes
+ )
+
+ if filename:
+ self.input_file.set(filename)
+ self.log_message(f"Selected input file: {os.path.basename(filename)}")
+
+ def browse_output_dir(self):
+ """Open directory dialog to select output directory"""
+ directory = filedialog.askdirectory(title="Select Output Directory")
+ if directory:
+ self.output_dir.set(directory)
+
+ def validate_time_format(self, time_str):
+ """Validate and normalize time format"""
+ time_str = time_str.strip()
+
+ # If it's just numbers, treat as seconds
+ if re.match(r'^\d+(\.\d+)?$', time_str):
+ return float(time_str)
+
+ # If it's HH:MM:SS format
+ if re.match(r'^\d{1,2}:\d{2}:\d{2}(\.\d+)?$', time_str):
+ return time_str
+
+ # If it's MM:SS format, convert to HH:MM:SS
+ if re.match(r'^\d{1,2}:\d{2}(\.\d+)?$', time_str):
+ return f"00:{time_str}"
+
+ raise ValueError(f"Invalid time format: {time_str}")
+
+ def log_message(self, message):
+ """Add message to output text widget"""
+ self.output_text.insert(tk.END, f"{message}\n")
+ self.output_text.see(tk.END)
+ self.root.update_idletasks()
+
+ def get_ffmpeg_quality_params(self):
+ """Get ffmpeg parameters based on quality setting"""
+ quality = self.quality_var.get()
+
+ if "copy" in quality:
+ return ["-c", "copy"]
+ elif "high" in quality:
+ return ["-c:v", "libx264", "-crf", "18", "-c:a", "aac", "-b:a", "192k"]
+ elif "medium" in quality:
+ return ["-c:v", "libx264", "-crf", "23", "-c:a", "aac", "-b:a", "128k"]
+ elif "low" in quality:
+ return ["-c:v", "libx264", "-crf", "28", "-c:a", "aac", "-b:a", "96k"]
+ else:
+ return ["-c", "copy"]
+
+ def extract_clip(self):
+ """Extract video clip using ffmpeg"""
+ # Validation
+ if not self.input_file.get():
+ messagebox.showerror("Error", "Please select an input video file")
+ return
+
+ if not os.path.isfile(self.input_file.get()):
+ messagebox.showerror("Error", "Input file does not exist")
+ return
+
+ try:
+ start_time = self.validate_time_format(self.start_time.get())
+ end_time = self.validate_time_format(self.end_time.get())
+ except ValueError as e:
+ messagebox.showerror("Error", str(e))
+ return
+
+ # Disable extract button and start progress
+ self.extract_btn.config(state="disabled")
+ self.progress.start()
+
+ # Run extraction in separate thread
+ thread = threading.Thread(target=self._run_extraction, args=(start_time, end_time))
+ thread.daemon = True
+ thread.start()
+
+ def _run_extraction(self, start_time, end_time):
+ """Run ffmpeg extraction in background thread"""
+ try:
+ # Generate output filename
+ input_path = Path(self.input_file.get())
+ timestamp = str(int(os.path.getctime(self.input_file.get())))
+ output_filename = f"{input_path.stem}_clip_{timestamp}{input_path.suffix}"
+ output_path = os.path.join(self.output_dir.get(), output_filename)
+
+ # Build ffmpeg command
+ cmd = ["ffmpeg", "-i", self.input_file.get()]
+
+ # Add start time
+ if isinstance(start_time, (int, float)) and start_time > 0:
+ cmd.extend(["-ss", str(start_time)])
+ elif isinstance(start_time, str) and start_time != "00:00:00":
+ cmd.extend(["-ss", start_time])
+
+ # Add duration or end time
+ if isinstance(end_time, (int, float)) and isinstance(start_time, (int, float)):
+ duration = end_time - start_time
+ cmd.extend(["-t", str(duration)])
+ elif isinstance(end_time, str):
+ cmd.extend(["-to", end_time])
+
+ # Add quality parameters
+ cmd.extend(self.get_ffmpeg_quality_params())
+
+ # Add output file
+ cmd.append(output_path)
+
+ self.log_message(f"Starting extraction...")
+ self.log_message(f"Command: {' '.join(cmd)}")
+
+ # Run ffmpeg
+ process = subprocess.run(
+ cmd,
+ capture_output=True,
+ text=True,
+ cwd=self.output_dir.get()
+ )
+
+ # Handle results
+ if process.returncode == 0:
+ self.log_message(f"✓ Successfully extracted clip to: {output_filename}")
+ self.log_message(f"Output file size: {self._get_file_size(output_path)}")
+ else:
+ self.log_message(f"✗ Error during extraction:")
+ self.log_message(process.stderr)
+
+ except Exception as e:
+ self.log_message(f"✗ Exception occurred: {str(e)}")
+
+ finally:
+ # Re-enable button and stop progress
+ self.root.after(0, self._extraction_finished)
+
+ def _extraction_finished(self):
+ """Called when extraction is finished"""
+ self.progress.stop()
+ self.extract_btn.config(state="normal")
+
+ def _get_file_size(self, filepath):
+ """Get human-readable file size"""
+ try:
+ size = os.path.getsize(filepath)
+ for unit in ['B', 'KB', 'MB', 'GB']:
+ if size < 1024.0:
+ return f"{size:.1f} {unit}"
+ size /= 1024.0
+ return f"{size:.1f} TB"
+ except:
+ return "Unknown"
+
+def main():
+ # Check if ffmpeg is available
+ try:
+ subprocess.run(["ffmpeg", "-version"], capture_output=True, check=True)
+ except (subprocess.CalledProcessError, FileNotFoundError):
+ messagebox.showerror("Error", "ffmpeg not found. Please install ffmpeg and ensure it's in your PATH.")
+ return
+
+ root = tk.Tk()
+ app = VideoClipperGUI(root)
+ root.mainloop()
+
+if __name__ == "__main__":
+ main() \ No newline at end of file
diff --git a/wow3.py b/wow3.py
new file mode 100644
index 0000000..03253b7
--- /dev/null
+++ b/wow3.py
@@ -0,0 +1,98 @@
+#!/usr/bin/python3
+
+import argparse
+import sys
+import time
+import os
+#Words Of Wisdom
+# output some random text from some given collection of files,
+# - primarily used to grab some random "words of wisdom" from my journals and writings
+
+paths=[] #the paths to scan recursively for files from which to grab text
+samplefiles=[] #the paths of the individual files from which we want to grab text
+matchpattern='' #if we want to filter the files by some text pattern that the filename must match
+time_min = -1 #threshold time. dont use files that are older
+v=False
+def attemptReadSampleFile(filepath):
+ if v: print('checking {}'.format(filepath))
+ if os.path.isfile(filepath):
+ try:
+ with open(filepath, 'rb') as f:
+ ftype = filetype.guess(filepath)
+ if v: print('filetype: {}'.format(str(ftype)))
+ if ftype is not None:
+ if ftype.extension in ['py', 'c', 'cc', 'h', 'hh', 'java', 'rst', 'css', 'html', 'htm', 'js', 'php', 'sh']: #don't want code in the sample data
+ if v: print('this file is code')
+ return None
+ if ftype.extension == 'odt' and filepath[-1] != '#': #openoffice doc and not a lock file
+ subproc = subprocess.run(['odt2txt', filepath], encoding='utf-8', stdout=subprocess.PIPE)
+ return subproc.stdout
+ if ftype.extension == 'txt':
+ return str(f.read(), encoding='utf-8')
+ else:
+ fb = f.read() #file data (bytes) to detect encoding
+ enc = str(chardet.detect(fb)['encoding'])
+ if v: print('encoding: {}'.format(enc))
+ if enc in ['ascii', 'utf-8']:
+ return str(fb, encoding=enc)
+ else:
+ return None
+ except Exception as e:
+ print(f"Error reading file {filepath}: {e}")
+ return None
+ else:
+ if v: print('not a file')
+ return None
+
+def parseArgs():
+ parser = argparse.ArgumentParser(description='output some random text from some given collection of files')
+ parser.add_argument('-v', '--verbose', action='store_true', help='verbose')
+
+ parser.add_argument('-p', '--path', type=str, required=False, help='a path to scan', action='append', default=['~/doc'])
+ parser.add_argument('-o', '--output', type=str, required=False, help='output file')
+ args = parser.parse_args()
+ return args
+
+def main():
+ args = parseArgs()
+ if args.verbose:
+ print(f"Input file: {args.input}")
+ if args.output:
+ print(f"Output file: {args.output}")
+
+ if args.path:
+ paths.append(args.path)
+
+
+ tStart = time.time()
+ for p in paths:
+ if v: print('path {}'.format(p))
+ if os.path.isdir(p):
+ for root,dirs,files in os.walk(p):
+ if v: print('walk {}: {} files, {} dirs'.format(root, len(files), len(dirs)))
+ for f in files:
+ samplefiles.append(root + '/' + f)
+ else:
+ samplefiles.append(p)
+ tEnd = time.time()
+ tDuration = tEnd - tStart
+ print('gathered {} candidate files in {} seconds, from paths {}'.format(len(samplefiles), tDuration, str(paths)))
+ #pick random file until we get an acceptable one
+ fi = random.randint(0, len(samplefiles))
+ t = attemptReadSampleFile(samplefiles[fi])
+ while t == None:
+ del samplefiles[fi]
+ fi = random.randint(0, len(samplefiles))
+ t = attemptReadSampleFile(samplefiles[fi])
+
+ mt = time.ctime(os.path.getmtime(samplefiles[fi]))
+ print('{} ;\n last modified {} :\n {}'.format(samplefiles[fi], mt, t))
+
+ lines = t.splitlines()
+ li = random.randint(0, len(t)) #line index
+ #ci = random.randint(0, len(t)) #character index
+ res = '\n'.join(lines[li: li+7])
+ print(res)
+
+if __name__ == '__main__':
+ main() \ No newline at end of file