@@ -3,30 +3,94 @@ import { tz } from 'moment-timezone';
33import { moment } from "obsidian" ;
44import { WINDOWS_TO_IANA_TIMEZONES } from './generated/windowsTimezones' ;
55
6- export function extractMeetingInfo ( e : any ) : { callUrl : string , callType : string } {
6+ import { FieldExtractionPattern } from './settings/ICSSettings' ;
77
8- // Check for Google Meet conference data
9- if ( e [ "GOOGLE-CONFERENCE" ] ) {
10- return { callUrl : e [ "GOOGLE-CONFERENCE" ] , callType : 'Google Meet' } ;
8+ export function extractFields ( e : any , patterns ?: FieldExtractionPattern [ ] ) : Record < string , string [ ] > {
9+ // If patterns not provided or empty, return empty object
10+ if ( ! patterns || patterns . length === 0 ) {
11+ return { } ;
1112 }
12- // Check if the location contains a Zoom link
13- if ( e . location && e . location . includes ( 'zoom.us' ) ) {
14- return { callUrl : e . location , callType : 'Zoom' } ;
13+
14+ const extractedFields : Record < string , string [ ] > = { } ;
15+
16+ // Sort patterns by priority (lower numbers = higher priority)
17+ const sortedPatterns = patterns . sort ( ( a , b ) => a . priority - b . priority ) ;
18+
19+ for ( const pattern of sortedPatterns ) {
20+ const matches = findPatternMatches ( e , pattern ) ;
21+ if ( matches . length > 0 ) {
22+ const fieldName = pattern . extractedFieldName ;
23+ if ( ! extractedFields [ fieldName ] ) {
24+ extractedFields [ fieldName ] = [ ] ;
25+ }
26+ extractedFields [ fieldName ] . push ( ...matches ) ;
27+ }
28+ }
29+
30+ // Deduplicate all extracted fields
31+ for ( const fieldName in extractedFields ) {
32+ extractedFields [ fieldName ] = [ ...new Set ( extractedFields [ fieldName ] ) ] ;
33+ }
34+
35+ return extractedFields ;
36+ }
37+
38+ function findPatternMatches ( e : any , pattern : FieldExtractionPattern ) : string [ ] {
39+ const matches : string [ ] = [ ] ;
40+
41+ // Special handling for Google Meet conference data
42+ if ( pattern . pattern === "GOOGLE-CONFERENCE" && e [ "GOOGLE-CONFERENCE" ] ) {
43+ matches . push ( e [ "GOOGLE-CONFERENCE" ] ) ;
44+ return matches ;
45+ }
46+
47+ // Check location field
48+ if ( e . location ) {
49+ const locationMatches = matchTextForPattern ( e . location , pattern ) ;
50+ matches . push ( ...locationMatches ) ;
1551 }
52+
53+ // Check description field
1654 if ( e . description ) {
17- const skypeMatch = e . description . match ( / h t t p s : \/ \/ j o i n .s k y p e .c o m \/ [ a - z A - Z 0 - 9 ] + / ) ;
18- if ( skypeMatch ) {
19- return { callUrl : skypeMatch [ 0 ] , callType : 'Skype' } ;
20- }
55+ const descriptionMatches = matchTextForPattern ( e . description , pattern ) ;
56+ matches . push ( ...descriptionMatches ) ;
57+ }
58+
59+ return matches ;
60+ }
61+
62+ function matchTextForPattern ( text : string , pattern : FieldExtractionPattern ) : string [ ] {
63+ const matches : string [ ] = [ ] ;
2164
22- const teamsMatch = e . description . match ( / ( h t t p s : \/ \/ t e a m s \. m i c r o s o f t \. c o m \/ l \/ m e e t u p - j o i n \/ [ ^ > ] + ) / ) ;
23- if ( teamsMatch ) {
24- return { callUrl : teamsMatch [ 0 ] , callType : 'Microsoft Teams' } ;
65+ try {
66+ if ( pattern . matchType === 'contains' ) {
67+ if ( text . includes ( pattern . pattern ) ) {
68+ // For contains match, try to extract URLs from the text
69+ const urlMatches = text . match ( / h t t p s ? : \/ \/ [ ^ \s < > " ] + / g) ;
70+ if ( urlMatches ) {
71+ matches . push ( ...urlMatches ) ;
72+ } else {
73+ // If no URLs found, return the original text
74+ matches . push ( text ) ;
75+ }
76+ }
77+ } else if ( pattern . matchType === 'regex' ) {
78+ const regex = new RegExp ( pattern . pattern , 'g' ) ; // Use global flag to find all matches
79+ let match ;
80+ while ( ( match = regex . exec ( text ) ) !== null ) {
81+ // If regex has capture groups, use the first group, otherwise use full match
82+ matches . push ( match [ 1 ] || match [ 0 ] ) ;
83+ }
2584 }
85+ } catch {
86+ // Skip invalid regex patterns
87+ console . warn ( `Invalid regex pattern: ${ pattern . pattern } ` ) ;
2688 }
27- return { callUrl : null , callType : null } ;
89+
90+ return matches ;
2891}
2992
93+
3094function applyRecurrenceDateAndTimezone ( originalDate : Date , currentDate : Date , tzid : string ) : Date {
3195 const originalMoment = tz ( originalDate , tzid ) ;
3296
0 commit comments