product2204 commited on
Commit
4803ae9
·
verified ·
1 Parent(s): d09be74

Upload 13 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ clip/video/circle_head_3584x2160.mov filter=lfs diff=lfs merge=lfs -text
clip/.DS_Store ADDED
Binary file (6.15 kB). View file
 
clip/.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ __pycache__
2
+ csv
3
+ failed_urls.csv
4
+ batch_emails.csv
clip/1_website_recording.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time, subprocess, csv
2
+ from threading import Timer
3
+ import pandas
4
+ from selenium import webdriver
5
+ from selenium.webdriver.chrome.service import Service
6
+
7
+ DRIVER_PATH = '/Users/moonma/Downloads/chromedriver-mac-x64/chromedriver'
8
+ LEADS_FNAME = 'csv/100_batch.csv'
9
+ PAGE_LOAD_TIME = 4
10
+ SCROLL_WAIT_TIME = 2
11
+ video_time = PAGE_LOAD_TIME + SCROLL_WAIT_TIME*3
12
+
13
+ service = Service(executable_path=DRIVER_PATH)
14
+ options = webdriver.ChromeOptions()
15
+ options.add_argument("--start-maximized")
16
+ driver = webdriver.Chrome(service=service, options=options)
17
+
18
+ df_raw = pandas.read_csv(LEADS_FNAME)
19
+ with open("csv/failed_urls.csv", 'a', newline='') as failed_url_csv:
20
+ csvwriter = csv.writer(failed_url_csv, delimiter=',')
21
+
22
+ for index, row in df_raw.iterrows():
23
+ url = row['organization_primary_domain']
24
+ if not url.startswith('http://www.'): url = 'http://www.' + url
25
+ print(f"row#{index}: {url}")
26
+
27
+ try:
28
+ driver.get(url)
29
+ except Exception:
30
+ csvwriter.writerow(row)
31
+ print(f" {url} → NOT WORKING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
32
+ continue
33
+ print(f"url split: {url.split('.')[-2]}")
34
+ video_fname = str(index) + '_' + url.split('.')[-2] + "_" + row['first_name'] + "_" + row['last_name'] + '.mov'
35
+ proc = subprocess.Popen(['screencapture', '-v', "video/1-recording/"+video_fname], stdin=subprocess.PIPE)
36
+ kill = kill = lambda process: process.kill()
37
+ video_timer = Timer(video_time, kill, [proc])
38
+
39
+ last_height = driver.execute_script("return document.body.scrollHeight")
40
+ time.sleep(PAGE_LOAD_TIME)
41
+
42
+ # Scroll to bottom
43
+ driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
44
+ time.sleep(SCROLL_WAIT_TIME)
45
+
46
+ # Scroll to top
47
+ driver.execute_script("window.scrollTo(document.body.scrollHeight, 0);")
48
+ time.sleep(SCROLL_WAIT_TIME*2)
49
+
50
+ try:
51
+ video_timer.start()
52
+ stdout, stderr = proc.communicate()
53
+ finally:
54
+ video_timer.cancel()
clip/2_slow_elongate.sh ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # video/1-recording/ is 18 characters
4
+ for FILE in video/1-recording/*; do
5
+ video_name=${FILE:18}
6
+ ffmpeg -i $FILE -filter:v "setpts=3*PTS" video/2-slowed/$video_name
7
+ done
8
+
9
+ # video/2-slowed/ is 16 characters
10
+ for FILE in video/2-slowed/*; do
11
+ video_name=${FILE:15}
12
+ ffmpeg -i $FILE -vf tpad=stop_mode=clone:stop_duration=92,scale=3584x2160,setsar=1:1 video/3-elongated/$video_name
13
+ done
clip/3_overlay.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import subprocess, os, time
2
+ import cv2
3
+
4
+ directory = 'video/3-elongated'
5
+ website_vfiles = []
6
+ for fname in os.listdir(directory):
7
+ if fname.endswith('.mov'):
8
+ fname = os.path.join(directory, fname)
9
+ website_vfiles.append(fname)
10
+ print(website_vfiles)
11
+
12
+ for i, ws in enumerate(website_vfiles):
13
+ speaker_vfile = 'video/circle_head_3584x2160.mov'
14
+ speaker = cv2.VideoCapture(speaker_vfile)
15
+ foreground_width = int(speaker.get(cv2.CAP_PROP_FRAME_WIDTH))
16
+ foreground_height = int(speaker.get (cv2.CAP_PROP_FRAME_HEIGHT))
17
+ # print(f"talking head video width and height: {foreground_width, foreground_height}") # 3584 2160
18
+
19
+ print(f"####{i}: {ws}")
20
+ start_time = time.time()
21
+ id_str = ws[len(directory)+1:-4]
22
+ overlay_noaudio_vfile = 'overlay_' + id_str + '.mov'
23
+ output_vfile = 'video/4-overlayed/' + id_str + '.mov'
24
+ # print(f" overlay_noaudio_vfile: {overlay_noaudio_vfile}")
25
+ # print(f" final_vfile: {output_vfile}")
26
+
27
+ website = cv2.VideoCapture(ws)
28
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
29
+ output_video = cv2.VideoWriter(overlay_noaudio_vfile, fourcc, 24.0, (int(website.get(3)),int(website.get(4))))
30
+
31
+ background_width = int(website.get(cv2.CAP_PROP_FRAME_WIDTH))
32
+ background_height = int (website.get(cv2.CAP_PROP_FRAME_HEIGHT))
33
+ # print(f" talking head video width and height: {background_width, background_height}") # 3584 2160
34
+
35
+ ct=0
36
+ while True:
37
+ background_success, background_frame = website.read()
38
+ foreground_success, foreground_frame = speaker.read()
39
+ if not background_success or not foreground_success: break
40
+ if ct%100 ==0: print(f" keep going ... {ct}")
41
+
42
+ foreground_frame_resized = cv2.resize(foreground_frame, (background_width, background_height))
43
+
44
+ # Convert the foreground frame to grayscale and threshold it
45
+ foreground_gray = cv2.cvtColor(foreground_frame_resized, cv2.COLOR_BGR2GRAY)
46
+ ret, mask = cv2.threshold(foreground_gray, 10, 255, cv2.THRESH_BINARY)
47
+ # Invert the mask so that the foreground is white and the background is black
48
+ mask_inv = cv2.bitwise_not(mask)
49
+ # Use the mask to extract the foreground from the foreground frame
50
+ foreground_extracted = cv2.bitwise_and(foreground_frame_resized, foreground_frame_resized, mask=mask)
51
+ # Use the inverted mask to extract the background from the background frame
52
+ background_extracted = cv2.bitwise_and(background_frame, background_frame, mask=mask_inv)
53
+ # Combine the foreground and background
54
+ output_frame = cv2.add(foreground_extracted, background_extracted)
55
+ # Write the output frame to the output video
56
+ output_video.write(output_frame)
57
+ # print(ct)
58
+ ct += 1
59
+ # print(output_frame[0][0])
60
+
61
+ website.release()
62
+ output_video.release()
63
+ speaker.release()
64
+ cv2.destroyAllWindows()
65
+ subprocess.call('ls', shell=True)
66
+
67
+ cmd = f'ffmpeg -i {overlay_noaudio_vfile} -i video/circle_head_3584x2160.mov -map 0:v:0? -map 1:a:0 {output_vfile}'
68
+ subprocess.call(cmd, shell=True)
69
+ # os.remove(overlay_noaudio_vfile)
70
+
71
+ end_time = time.time()
72
+ elapsed_time = end_time - start_time
73
+ hours, rem = divmod(elapsed_time, 3600)
74
+ minutes, seconds = divmod(rem, 60)
75
+ hours, minutes, seconds = int(hours), int(minutes), int(seconds)
76
+ print(f" this overlay took {minutes} minutes {seconds} seconds")
77
+
78
+ # ffmpeg -i overlay_3berkley_Angela_Berkley.mov -i circle_head_3584x2160.mov -map 0:v:0 -map 1:a:0 overlayed/3berkley_Angela_Berkley.mov
clip/README.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Why is this worth doing?
2
+
3
+ [Clipio](https://clipio.com/) is a cheaper option than [pitchlane](https://pitchlane.com/?gclid=CjwKCAiAtt2tBhBDEiwALZuhAA6eUbE9iTTvlpcibtNnvmvJpO-58IX8LHac_woj7nIADLqF8qS2hBoCXV8QAvD_BwE), however, both of them have the following problems:
4
+ - the video doesn't actually scroll over, it's just a stactic website screenshot with a moving cursor
5
+ - It costs a significant amount of money. If you are ready to scale, it's a good deal, but if you are testing things out, you may not want to pay for that. Clipio still costs $97/mo to generate 5000 videos.
6
+
7
+ I found the first 2 problems embarrasing for my brand.
8
+
9
+ This solution does take longer time to run, but you can get better screenrecording videos with zero dollar cost:
10
+
11
+ # High Level Steps:
12
+ ### Step 1 - Generate 10 second website recording (`website_recording.py`)
13
+ - a python script
14
+ - visit each URL with Selenium
15
+ - interact the website as pause, scroll down, pause, and scroll up for 10 seconds in total
16
+ - use an unblocking screenrecording solution, which means you can interact and record the scree at the same time
17
+ - iterate through URLs with each URL visit generates a video file
18
+
19
+ ### Step 2 - Extends 10 seconds screen recording to 2 minutes video (`slow_elongate.sh`)
20
+ - a shell script
21
+ - slow down 10 seconds into 30 seconds video, because when Selenium scrolls the page, the Python API doesn't provde a good control over the scrolling speed and it looks unnatural.
22
+ - use last frame to fill up another 90 seconds becuase your video should focus on your sales pitch, not the their website, their website is only grab the attention
23
+ - wola, you got a 2 minute video
24
+
25
+ ### Step 3 - Prepare talking head video (One time thing, `Final Cut Pro`)
26
+ - manually by any video recorder
27
+ - crop your 2 minutes talking head video into a circle
28
+ - repositioned properly
29
+ - background should be pure black for overlay mask in the next step
30
+
31
+ ### Step 4 - Overlay the talking head on the website video(`overlay.py`)
32
+ - Manual setup for the very first time
33
+ 1. resize the talking head video and the website/profile video (the automated recording videos we got earlier) to same frame size so that they can be overlayed using `cv2`
34
+ 2. inspect the video to set proper codec, fps, and frame size for the overlay output file
35
+ - Each batch
36
+ 1. mask the black background of each talking head frame into transparent
37
+ 2. merge each mased talking head frame with website frame
38
+ 3. generate overlay video without audio
39
+ 4. add audio from original talking head video into the genreated overlay video
40
+ 5. I ran 100 videos each time which takes about 8 hours form URL to ready to send videos.
41
+
42
+ ### Step 5 - Upload to Instantly or Gmails
43
+
44
+ ** you need to track the view rate of your video, so you need a video host and tracking solution**
45
+ ** only allows uploading 10 videos each time **
46
+
47
+ # Tech Challenges
48
+ 1. find an unblocking screen recorder that works with Selenium interactions
49
+ 2. sync audio back to the video after video is edited with CV2
50
+
51
+
52
+ # Final
53
+
54
+ This repo isn't actively mainteined, so if you encountered technical issues or have questions specific to your business operation, please join our [free community on skool](https://www.skool.com/ai-for-coaches-creators-2571/about). You can post your issues or attending free daily workshops to get the help you need.
clip/video/.DS_Store ADDED
Binary file (8.2 kB). View file
 
clip/video/1-recording/.DS_Store ADDED
Binary file (6.15 kB). View file
 
clip/video/2-slowed/.DS_Store ADDED
Binary file (6.15 kB). View file
 
clip/video/3-elongated/.DS_Store ADDED
Binary file (6.15 kB). View file
 
clip/video/4-overlayed/.DS_Store ADDED
Binary file (6.15 kB). View file
 
clip/video/5-broken/.DS_Store ADDED
Binary file (6.15 kB). View file
 
clip/video/circle_head_3584x2160.mov ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d9b818660ff228a9ee96af7b4e58297c36011118d4bb8740a2e6c52ad6246d7f
3
+ size 15515733