Skip to content

Commit

Permalink
Split "Roles" CSV column into Video and Audio role columns (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
orchetect committed Dec 30, 2022
1 parent e3906ff commit 6bfd305
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ extension CSVExportProfile {
case position
case clipName
case clipDuration
case role
case videoRoles
case audioRoles
case eventName
case projectName
case libraryName
Expand All @@ -31,7 +32,8 @@ extension CSVExportProfile.Field: ExportField {
case .position: return "Marker Position"
case .clipName: return "Clip Name"
case .clipDuration: return "Clip Duration"
case .role: return "Role & Subrole"
case .videoRoles: return "Video Role & Subrole"
case .audioRoles: return "Audio Role & Subrole"
case .eventName: return "Event Name"
case .projectName: return "Project Name"
case .libraryName: return "Library Name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ extension CSVExportProfile {
public let position: String
public let clipName: String
public let clipDuration: String
public let role: String
public let audioRoles: String
public let videoRoles: String
public let eventName: String
public let projectName: String
public let libraryName: String
Expand All @@ -34,7 +35,8 @@ extension CSVExportProfile {
position = marker.positionTimecodeString
clipName = marker.parentInfo.clipName
clipDuration = marker.parentInfo.clipDurationTimecodeString
role = marker.role
videoRoles = marker.roles.filter(\.isVideo).map { $0.stringValue }.joined(separator: ", ")
audioRoles = marker.roles.filter(\.isAudio).map { $0.stringValue }.joined(separator: ", ")
eventName = marker.parentInfo.eventName
projectName = marker.parentInfo.projectName
libraryName = marker.parentInfo.libraryName
Expand All @@ -55,7 +57,8 @@ extension CSVExportProfile {
.position: position,
.clipName: clipName,
.clipDuration: clipDuration,
.role: role,
.videoRoles: videoRoles,
.audioRoles: audioRoles,
.eventName: eventName,
.projectName: projectName,
.libraryName: libraryName,
Expand Down
42 changes: 29 additions & 13 deletions Sources/MarkersExtractor/Extractors/FCPXMLMarkerExtractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@ class FCPXMLMarkerExtractor {
let fps = getParentFPS(markerXML)
let parentDuration = (try? parentClip.fcpxDuration?.toTimecode(at: fps)) ?? .init(at: fps)
let position = calcMarkerPosition(markerXML, parentFPS: fps, parentDuration: parentDuration)
let roles = getClipRoles(parentClip).joined(separator: ", ")
let roles = getClipRoles(parentClip)

return Marker(
type: type,
name: markerXML.fcpxValue ?? "",
notes: markerXML.fcpxNote ?? "",
role: roles,
roles: roles,
position: position,
parentInfo: Marker.ParentInfo(
clipName: getClipName(parentClip),
Expand Down Expand Up @@ -200,25 +200,41 @@ class FCPXMLMarkerExtractor {
return .standard
}

private func getClipRoles(_ clip: XMLElement) -> [String] {
private func getClipRoles(_ clip: XMLElement) -> [MarkerRole] {
if let acSourceRole = clip.subElement(named: "audio-channel-source")?.fcpxRole {
return [acSourceRole].map { $0.localizedCapitalized }
return [acSourceRole].map { .audio($0.localizedCapitalized) }
}

var roles: Set<String?> = [
// gather

let audioRolesPool = [
clip.getElementAttribute("audioRole"),
clip.subElement(named: "video")?.subElement(named: "audio")?.fcpxRole, // TODO: ??
clip.subElement(named: "audio")?.fcpxRole
].compactMap { $0?.localizedCapitalized }

var videoRolesPool = [
clip.getElementAttribute("videoRole"),
clip.fcpxRole,
clip.subElement(named: "video")?.subElement(named: "audio")?.fcpxRole,
clip.subElement(named: "video")?.fcpxRole,
clip.subElement(named: "audio")?.fcpxRole,
]
clip.fcpxRole
].compactMap { $0?.localizedCapitalized }

if clip.name == "title" && roles.compactMap({ $0 }).isEmpty {
roles.insert("Titles")
if clip.name == "title" && videoRolesPool.compactMap({ $0 }).isEmpty {
videoRolesPool.append("Titles")
}

// Clean out all nil and return sorted array
return roles.compactMap { $0?.localizedCapitalized }.sorted()
// pack into enum cases

let videoRoles: [MarkerRole] = videoRolesPool
.sorted()
.map { .video($0) }

let audioRoles: [MarkerRole] = audioRolesPool
.sorted()
.map { .audio($0) }

// return

return videoRoles + audioRoles
}
}
2 changes: 1 addition & 1 deletion Sources/MarkersExtractor/Marker/Marker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public struct Marker: Equatable, Hashable {
var type: MarkerType
var name: String
var notes: String
var role: String
var roles: [MarkerRole] // TODO: is more than one role possible?
var position: Timecode

// TODO: This shouldn't be stored here. Should be refactored out to reference its parent with computed properties.
Expand Down
37 changes: 37 additions & 0 deletions Sources/MarkersExtractor/Marker/MarkerRole.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation

public enum MarkerRole: Hashable, Equatable {
case audio(String)
case video(String)
}

extension MarkerRole: CustomStringConvertible {
public var description: String {
stringValue
}

var stringValue: String {
switch self {
case .audio(let string):
return string
case .video(let string):
return string
}
}
}

extension MarkerRole {
var isAudio: Bool {
guard case .audio = self else {
return false
}
return true
}

var isVideo: Bool {
guard case .video = self else {
return false
}
return true
}
}

0 comments on commit 6bfd305

Please sign in to comment.