diff --git a/app.py b/app.py index 22f22d9..c0f3a38 100644 --- a/app.py +++ b/app.py @@ -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() + c1, c2, c3 = st.columns(3) - 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'] - - # 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", + )