|
|
|
|
@ -6,7 +6,7 @@ from bs4 import BeautifulSoup |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def find_start_seconds(region): |
|
|
|
|
''' Returns start second for region. ''' |
|
|
|
|
"""Returns start second for region.""" |
|
|
|
|
if len(region["Start"]) > 9: |
|
|
|
|
start_time = datetime.strptime(region["Start"], "%H:%M:%S.%f") |
|
|
|
|
elif len(region["Start"]) in [8, 9]: |
|
|
|
|
@ -17,8 +17,9 @@ def find_start_seconds(region): |
|
|
|
|
t = start_time.time() |
|
|
|
|
return (t.hour * 60 + t.minute) * 60 + t.second |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def find_lenght_seconds(region): |
|
|
|
|
''' Returns lenght of region in seconds. ''' |
|
|
|
|
"""Returns lenght of region in seconds.""" |
|
|
|
|
if len(region["Length"]) > 9: |
|
|
|
|
lenght = datetime.strptime(region["Length"], "%H:%M:%S.%f") |
|
|
|
|
elif len(region["Length"]) in [8, 9]: |
|
|
|
|
@ -28,26 +29,46 @@ def find_lenght_seconds(region): |
|
|
|
|
t = lenght.time() |
|
|
|
|
return (t.hour * 60 + t.minute) * 60 + t.second |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def colorize(soup): |
|
|
|
|
# Get colors from clips on timeline. |
|
|
|
|
colors = {} |
|
|
|
|
n_regions = len(timline.find_all("Region")) |
|
|
|
|
for region in timline.find_all("Region"): |
|
|
|
|
timeline = soup.find("Tracks") |
|
|
|
|
for region in timeline.find_all("Region"): |
|
|
|
|
try: |
|
|
|
|
colors[str(region["Ref"])] = int(region["Colour"]) |
|
|
|
|
except: |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
# Give colors to clips in clipboard |
|
|
|
|
for group in soup.find_all("Group"): |
|
|
|
|
soup = colorize_clipboard(soup, colors) |
|
|
|
|
soup = colorize_timeline(soup, colors) |
|
|
|
|
return soup |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def colorize_clipboard(soup, colors): |
|
|
|
|
"""Give colors to clips in clipboard.""" |
|
|
|
|
|
|
|
|
|
clipboard = soup.find("Clipboard") |
|
|
|
|
for group in clipboard.find_all("Group"): |
|
|
|
|
# new_group_tag = soup.new_tag('Group', {'Caption':group['Caption'], 'IsExpanded':group['IsExpanded']}) |
|
|
|
|
new_group_tag = group |
|
|
|
|
# Go over clips (nested regions). |
|
|
|
|
for clip in group.find_all("Clip"): |
|
|
|
|
# new_clip_tag = soup.new_tag('Clip', {'Name':clip['Name'], 'Start':clip['Start'], 'Length':clip['Length']}) |
|
|
|
|
new_clip_tag = clip |
|
|
|
|
for region in clip.find_all("Region"): |
|
|
|
|
new_region_tag = region |
|
|
|
|
try: |
|
|
|
|
new_region_tag["Colour"] = colors[region["Ref"]] |
|
|
|
|
except KeyError: |
|
|
|
|
new_region_tag["Colour"] = "0" |
|
|
|
|
new_clip_tag.append(new_region_tag) |
|
|
|
|
new_group_tag.append(new_clip_tag) |
|
|
|
|
|
|
|
|
|
# Go over regions. |
|
|
|
|
for region in group.find_all("Region"): |
|
|
|
|
try: |
|
|
|
|
with s: |
|
|
|
|
st.markdown(f':green[{region["Name"]}]') |
|
|
|
|
sleep(1/(n_regions)) |
|
|
|
|
except KeyError: |
|
|
|
|
pass |
|
|
|
|
if region.parent.name == "Clip": |
|
|
|
|
continue |
|
|
|
|
new_region_tag = region |
|
|
|
|
try: |
|
|
|
|
new_region_tag["Colour"] = colors[region["Ref"]] |
|
|
|
|
@ -58,38 +79,82 @@ def colorize(soup): |
|
|
|
|
|
|
|
|
|
soup.Session.Clipboard.replace_with(new_clipboard_tag) |
|
|
|
|
|
|
|
|
|
return soup |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def colorize_timeline(soup, colors): |
|
|
|
|
print(colors) |
|
|
|
|
# Give colors to clips on timeline. |
|
|
|
|
new_tracks_tag = soup.find("Tracks") |
|
|
|
|
tracks = soup.find("Tracks") |
|
|
|
|
|
|
|
|
|
for track in tracks.find_all("Track"): |
|
|
|
|
try: |
|
|
|
|
with s: |
|
|
|
|
st.markdown(f':green[{region["Name"]}]') |
|
|
|
|
sleep(1/(n_regions)) |
|
|
|
|
except KeyError: |
|
|
|
|
pass |
|
|
|
|
new_track_tag = track |
|
|
|
|
for region in track.find_all("Region"): |
|
|
|
|
new_region_tag = region |
|
|
|
|
try: |
|
|
|
|
new_region_tag["Colour"] = colors[region["Ref"]] |
|
|
|
|
except KeyError: |
|
|
|
|
print(region) |
|
|
|
|
new_region_tag["Colour"] = "0" |
|
|
|
|
new_track_tag.append(new_region_tag) |
|
|
|
|
new_tracks_tag.append(new_track_tag) |
|
|
|
|
soup.Session.Tracks.replace_with(new_tracks_tag) |
|
|
|
|
return soup |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def print_analyzing(soup): |
|
|
|
|
regions = soup.find_all("Region") |
|
|
|
|
n_regions = len(regions) |
|
|
|
|
for region in regions: |
|
|
|
|
try: |
|
|
|
|
with s0: |
|
|
|
|
st.markdown(f':green[{region["Name"]}]') |
|
|
|
|
sleep(1 / (n_regions * 2)) |
|
|
|
|
except KeyError: |
|
|
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def colorize_groups(soup): |
|
|
|
|
"""Give color to regions based on groups they are in.""" |
|
|
|
|
groups = soup.find_all("Group") |
|
|
|
|
ids = [] |
|
|
|
|
ids_groups = [] |
|
|
|
|
for group in reversed(groups): |
|
|
|
|
print(group["Caption"]) |
|
|
|
|
regions = [] |
|
|
|
|
# try: |
|
|
|
|
for region in group.find_all("Region"): |
|
|
|
|
if region["Ref"] not in ids: # Exclude if already in another group. |
|
|
|
|
regions.append(region["Ref"]) |
|
|
|
|
# except: |
|
|
|
|
# pass |
|
|
|
|
ids += regions |
|
|
|
|
ids_groups.append(regions) |
|
|
|
|
|
|
|
|
|
colors = {} |
|
|
|
|
for group in ids_groups: |
|
|
|
|
group_color = (ids_groups.index(group) * 50) % 360 |
|
|
|
|
for ref in group: |
|
|
|
|
colors[ref] = group_color |
|
|
|
|
|
|
|
|
|
soup = colorize_clipboard(soup, colors) |
|
|
|
|
soup = colorize_timeline(soup, colors) |
|
|
|
|
return soup |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_rainbow(soup): |
|
|
|
|
''' Returns a tracks tag colored like a rainbow. ''' |
|
|
|
|
"""Returns a tracks tag colored like a rainbow.""" |
|
|
|
|
|
|
|
|
|
new_tracks_tag = soup.find("Tracks") |
|
|
|
|
tracks = soup.find("Tracks") |
|
|
|
|
regions = tracks.find_all("Region") |
|
|
|
|
min_start = min([find_start_seconds(i) for i in regions]) |
|
|
|
|
max_end = max([int(find_start_seconds(i) + find_lenght_seconds(i)) for i in regions]) |
|
|
|
|
max_end = max( |
|
|
|
|
[int(find_start_seconds(i) + find_lenght_seconds(i)) for i in regions] |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
lenght = int(max_end-min_start) |
|
|
|
|
lenght = int(max_end - min_start) |
|
|
|
|
|
|
|
|
|
# Give colors to clips on timeline. |
|
|
|
|
new_tracks_tag = soup.find("Tracks") |
|
|
|
|
@ -99,102 +164,136 @@ def make_rainbow(soup): |
|
|
|
|
for region in track.find_all("Region"): |
|
|
|
|
new_region_tag = region |
|
|
|
|
try: |
|
|
|
|
middle = find_start_seconds(region) + find_lenght_seconds(region)/2 |
|
|
|
|
new_region_tag["Colour"] = int(((middle)/lenght)*360) |
|
|
|
|
middle = find_start_seconds(region) + find_lenght_seconds(region) / 2 |
|
|
|
|
new_region_tag["Colour"] = int(((middle) / lenght) * 360) |
|
|
|
|
except KeyError: |
|
|
|
|
new_region_tag["Colour"] = "0" |
|
|
|
|
new_track_tag.append(new_region_tag) |
|
|
|
|
new_tracks_tag.append(new_track_tag) |
|
|
|
|
|
|
|
|
|
return new_tracks_tag |
|
|
|
|
|
|
|
|
|
print_sleep = False |
|
|
|
|
soup.Session.Tracks.replace_with(new_tracks_tag) |
|
|
|
|
return soup |
|
|
|
|
|
|
|
|
|
st.title(":green[Colorize] your :red[Hindenburg] project") |
|
|
|
|
|
|
|
|
|
st.markdown( |
|
|
|
|
t1, t2, t3 = st.tabs(['From timeline', 'From clipboard', 'As rainbow 🌈']) |
|
|
|
|
with t1: |
|
|
|
|
st.markdown( |
|
|
|
|
""" |
|
|
|
|
1. Set colors for a few clips on your timeline, ideally at least one clip from |
|
|
|
|
each recording. |
|
|
|
|
2. Upload your Hindenburg project file (ending with *.nhsx*) below to add the same color |
|
|
|
|
to other clips originating from the same recording. |
|
|
|
|
3. Choose *Colors from timeline* to download the project file **and put it in the same folder as your original project file**. |
|
|
|
|
""" |
|
|
|
|
1. Set colors for a few clips on your timeline, ideally at least one clip from |
|
|
|
|
each recording. |
|
|
|
|
2. Upload your Hindenburg project file (ending with *.nhsx*) below to add the same color |
|
|
|
|
to other clips originating from the same recording. |
|
|
|
|
3. Download the modified file *and put it in the same folder as your original project file*. |
|
|
|
|
**No data is saved anywhere**. Made by [Lasse Edfast](https://lasseedfast.se). You need to be using Hindenburg 2.0 to use colors. |
|
|
|
|
""" |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
with st.expander(label="Unclear? See an example here.", expanded=False): |
|
|
|
|
st.write("*Put colors on clips like this...*") |
|
|
|
|
st.image("before.png") |
|
|
|
|
st.write("*...and you get a file that looks like this*") |
|
|
|
|
st.image("after.png") |
|
|
|
|
|
|
|
|
|
with st.expander(label='Unclear? See an example here.', expanded=False): |
|
|
|
|
st.write('*Put colors on clips like this...*') |
|
|
|
|
st.image('before.png') |
|
|
|
|
st.write('*...and you get a file that looks like this*') |
|
|
|
|
st.image('after.png') |
|
|
|
|
with t2: |
|
|
|
|
st.markdown(''' |
|
|
|
|
This alternative can be good if you have created clipboards for each person/interview as all clips in the same clipboard will |
|
|
|
|
be given the same color. |
|
|
|
|
If you have clips originating from the same recording in different clipboards it will be given the |
|
|
|
|
color for the last clipbord where it is included. |
|
|
|
|
Choose *Colors from clipboard* to download the project file **and put it in the same folder as your original project file**. |
|
|
|
|
''') |
|
|
|
|
|
|
|
|
|
with t3: |
|
|
|
|
st.markdown(''' |
|
|
|
|
This alternative makes your timeline into a beautiful rainbow! Lots of love but maybe not where you will start a longer project. |
|
|
|
|
Choose *Download rainbow project!* to download the project file **and put it in the same folder as your original project file**. |
|
|
|
|
''') |
|
|
|
|
st.markdown('No data is saved anywhere. Made by [Lasse Edfast](https://lasseedfast.se). You need to be using Hindenburg 2.0 to use colors.') |
|
|
|
|
# Ask for file. |
|
|
|
|
uploaded_file = st.file_uploader( |
|
|
|
|
"*Upload your project file*", label_visibility="hidden", type="nhsx", accept_multiple_files=False |
|
|
|
|
"*Upload your project file*", |
|
|
|
|
label_visibility="hidden", |
|
|
|
|
type="nhsx", |
|
|
|
|
accept_multiple_files=False, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if uploaded_file: |
|
|
|
|
# Make soup. |
|
|
|
|
stringio = StringIO(uploaded_file.getvalue().decode("utf-8")) |
|
|
|
|
soup = BeautifulSoup(stringio.read(), "xml") |
|
|
|
|
if "soup" not in st.session_state: # Make soup. |
|
|
|
|
stringio = StringIO(uploaded_file.getvalue().decode("utf-8")) |
|
|
|
|
soup = BeautifulSoup(stringio.read(), "xml") |
|
|
|
|
st.session_state["soup"] = soup |
|
|
|
|
soup = st.session_state["soup"] |
|
|
|
|
|
|
|
|
|
project_name = soup.find("AudioPool")["Path"].replace(" Files", "") |
|
|
|
|
new_clipboard_tag = soup.new_tag("Clipboard") |
|
|
|
|
|
|
|
|
|
timline = soup.find("Tracks") |
|
|
|
|
|
|
|
|
|
s0 = st.empty() |
|
|
|
|
with s0: |
|
|
|
|
if 'analyzed' not in st.session_state: |
|
|
|
|
print_analyzing(soup) |
|
|
|
|
sleep(1) |
|
|
|
|
|
|
|
|
|
st.session_state['analyzed'] = True |
|
|
|
|
st.markdown("Choose your colors:") |
|
|
|
|
sleep(0.3) |
|
|
|
|
# Area to print things. |
|
|
|
|
c1, c2 = st.columns(2) |
|
|
|
|
with c1: |
|
|
|
|
s = st.empty() |
|
|
|
|
|
|
|
|
|
if 'soup' not in st.session_state: |
|
|
|
|
soup = colorize(soup) |
|
|
|
|
st.session_state['soup'] = soup |
|
|
|
|
print_sleep = True # Sleep while with print if first run. |
|
|
|
|
else: |
|
|
|
|
soup = st.session_state['soup'] |
|
|
|
|
c1, c2, c3 = st.columns(3) |
|
|
|
|
|
|
|
|
|
# Allow the user to download file. |
|
|
|
|
|
|
|
|
|
with c1: |
|
|
|
|
with s: |
|
|
|
|
if print_sleep: |
|
|
|
|
st.markdown(":green[Exporting...]") |
|
|
|
|
sleep(0.7) |
|
|
|
|
st.download_button( |
|
|
|
|
"🎈 Download file", |
|
|
|
|
soup.encode("utf-8"), |
|
|
|
|
file_name=f"{project_name}_colors.nhsx", |
|
|
|
|
) |
|
|
|
|
if "soup1" not in st.session_state: |
|
|
|
|
soup1 = colorize(soup) |
|
|
|
|
st.session_state["soup1"] = soup1 |
|
|
|
|
soup1 = st.session_state["soup1"] |
|
|
|
|
|
|
|
|
|
# Allow the user to download file. |
|
|
|
|
st.download_button( |
|
|
|
|
"🎨 Colors from timeline", |
|
|
|
|
soup1.encode("utf-8"), |
|
|
|
|
file_name=f"{project_name}_colors.nhsx", |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
with c2: |
|
|
|
|
e = st.empty() |
|
|
|
|
with e: |
|
|
|
|
rainbow = st.button('🌈 Turn timeline into a rainbow! 🌈') |
|
|
|
|
if "soup2" not in st.session_state: |
|
|
|
|
soup2 = colorize_groups(soup) |
|
|
|
|
st.session_state["soup2"] = soup2 |
|
|
|
|
soup2 = st.session_state["soup2"] |
|
|
|
|
st.download_button( |
|
|
|
|
"🎨 Colors from clipboard", |
|
|
|
|
soup2.encode("utf-8"), |
|
|
|
|
file_name=f"{project_name}_colors.nhsx", |
|
|
|
|
) |
|
|
|
|
with c3: |
|
|
|
|
if "soup3" not in st.session_state: |
|
|
|
|
soup3 = make_rainbow(soup) |
|
|
|
|
st.session_state["soup3"] = soup3 |
|
|
|
|
else: |
|
|
|
|
soup3 = st.session_state["soup3"] |
|
|
|
|
|
|
|
|
|
s3 = st.empty() |
|
|
|
|
with s3: |
|
|
|
|
rainbow = st.button("🌈 Rainbow timeline!") |
|
|
|
|
|
|
|
|
|
if rainbow: |
|
|
|
|
for _ in range(0, 4): |
|
|
|
|
with e: |
|
|
|
|
st.markdown('🌧️') |
|
|
|
|
with s3: |
|
|
|
|
st.markdown("🌧️") |
|
|
|
|
sleep(0.4) |
|
|
|
|
with e: |
|
|
|
|
st.markdown('') |
|
|
|
|
with s3: |
|
|
|
|
st.markdown("") |
|
|
|
|
sleep(0.15) |
|
|
|
|
with e: |
|
|
|
|
st.markdown('🌦️') |
|
|
|
|
with s3: |
|
|
|
|
st.markdown("🌦️") |
|
|
|
|
sleep(1) |
|
|
|
|
with e: |
|
|
|
|
with s3: |
|
|
|
|
rainbows = [] |
|
|
|
|
for _ in range(0,10): |
|
|
|
|
rainbows.append('🌈') |
|
|
|
|
st.markdown(''.join(rainbows)) |
|
|
|
|
for _ in range(0, 10): |
|
|
|
|
rainbows.append("🌈") |
|
|
|
|
st.markdown("".join(rainbows)) |
|
|
|
|
sleep(0.09) |
|
|
|
|
new_tracks_tag = make_rainbow(soup) |
|
|
|
|
soup.Session.Tracks.replace_with(new_tracks_tag) |
|
|
|
|
with e: |
|
|
|
|
|
|
|
|
|
with s3: |
|
|
|
|
st.download_button( |
|
|
|
|
"🌈 Download rainbow project", |
|
|
|
|
soup.encode("utf-8"), |
|
|
|
|
file_name=f"{project_name}_rainbow.nhsx", |
|
|
|
|
) |
|
|
|
|
"🌈 Download rainbow project! 🌈", |
|
|
|
|
soup3.encode("utf-8"), |
|
|
|
|
file_name=f"{project_name}_rainbow.nhsx", |
|
|
|
|
) |
|
|
|
|
|