diff --git a/src/main.rs b/src/main.rs
index 7c87c49..1a3123d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,6 +21,18 @@ fn main() {
     let argv =
         clap::App::new("srtune")
             .version(env!("CARGO_PKG_VERSION"))
+            .about("Modify a .srt file to match a video. Input and output can be a file or stream, \
+            so you pipe multiple invocations to create more complex operations. However, a single \
+            invocation should suffice in most cases.\n\
+            Times can be specified in any format: \
+            seconds (400, 14.52), hours:minutes:seconds (14:00, 15:51.12, 1:30:00). Decimal point \
+            can be period or comma; Times copied directly from the .srt file will also work.\n\
+            When a command allows both time and index as a value, index must be prefixed with '@'.\
+            The tool should be used iteratively, adjusting the invocation until the generated \
+            subtitle file meets expectations. As such, times and indices accepted by its parameters \
+            are, by default, the ones seen in the output file. Prefix a time or index with '^' \
+            to use the original value from the input instead (i.e. original index 14 is '^@14')
+            ")
             .arg(clap::Arg::with_name("input")
                      .value_name("INFILE")
                      .help("Input file, leave out for stdin"),
@@ -31,44 +43,43 @@ fn main() {
                      .value_name("OUTFILE")
                      .help("Output file, defaults to stdout"),
             )
-            .arg(clap::Arg::with_name("fromtime")
+            .arg(clap::Arg::with_name("from")
                      .short("f")
                      .long("from-time")
                      .value_name("TIME")
-                     .help("Time of the first affected entry, defaults to 0. Use seconds, M:S or \
-                     H:M:S, decimals are supported. Uses the original times before any shifts or \
-                     scaling."),
-            )
-            .arg(clap::Arg::with_name("fromindex")
-                     .short("F")
-                     .long("from-index")
-                     .value_name("INDEX")
-                     .help("Time of the first affected entry, defaults to 0. Use seconds, M:S or \
-                     H:M:S, decimals are supported. Uses the original times before any shifts or \
-                     scaling."),
+                     .help("Time of the first affected entry, or its index. Defaults to 0/^@0."),
             )
             .arg(clap::Arg::with_name("move")
                      .short("m")
                      .long("move")
                      .value_name("TIME")
                      .help("Move subtitles in time. Use seconds, M:S or H:M:S, decimals and minus \
-                     are supported."),
+                     are supported. Starts at the point specified by '--from'"),
+            )
+            .arg(clap::Arg::with_name("automove")
+                     .short("M")
+                     .long("automove")
+                     .value_name("SUBTIME=VIDEOTIME")
+                     .multiple(true)
+                     .help("Move subtitles following a given time or index to match video times. \
+                     This automatically sets '--from' if not given explicitly."),
             )
             .arg(clap::Arg::with_name("scale")
                      .short("s")
                      .long("scale")
                      .value_name("RATIO")
                      .help("Scale subtitle times and durations to compensate for bitrate \
-                     differences. 1 means identity, 1.1 makes all times 10% longer. If a start \
-                     time was given, the scaling is relative to this point, otherwise to the first \
-                     subtitle in the file. Has no effect if '--autoscale' is used."),
+                     differences. 1 means identity, 1.1 makes all times 10% longer. Scaling is \
+                     relative to the first emitted subtitle with positive time (after shifting). \
+                     Has no effect if '--autoscale' is used."),
             )
             .arg(clap::Arg::with_name("autoscale")
                      .short("S")
                      .long("autoscale")
                      .value_name("SUBTIME=VIDEOTIME")
                      .help("Calculate scaling based on a perceived difference. The scaling is \
-                     related to the first subtitle, so ensure it is aligned properly with '--move'."),
+                     related to the first emitted subtitle, so ensure it is aligned properly \
+                     with '--move'."),
             )
             .arg(clap::Arg::with_name("durscale")
                      .short("d")
@@ -117,18 +128,27 @@ fn main() {
     }
     builder.init();
 
-    let from_time = match argv.value_of("fromtime") {
-        Some(s) => {
-            SubDuration::try_from(s).expect("Bad --from-time format").as_instant()
-        }
-        None => SubInstant(0f32)
-    };
-
-    let from_index = match argv.value_of("fromindex") {
-        Some(s) => {
-            s.parse().expect("Bad --from-index format")
+    let from = match argv.value_of("from") {
+        Some(mut s) => {
+            if s.starts_with('^') {
+                s = &s[1..];
+                if s.starts_with('@') {
+                    let index = &s[1..].parse().expect("Bad --from format");
+                    FromTag::ByIndexOrig(*index)
+                } else {
+                    // this is always the orig time
+                    FromTag::ByTime(SubDuration::try_from(s).expect("Bad --from format").as_instant())
+                }
+            } else {
+                if s.starts_with('@') {
+                    let index = &s[1..].parse().expect("Bad --from format");
+                    FromTag::ByIndex(*index)
+                } else{
+                    FromTag::ByTime(SubDuration::try_from(s).expect("Bad --from format").as_instant())
+                }
+            }
         }
-        None => 0u32
+        None => FromTag::ByIndex(0)
     };
 
     let shift = match argv.value_of("move") {
@@ -159,6 +179,9 @@ fn main() {
                 panic!("Bad --autoscale format, should be SUBTIME=VIDEOTIME")
             }
             let (first, second) = (halves[0], halves[1]);
+            if first.starts_with('^') {
+                panic!("'--autoscale' always uses original times");
+            }
             let subtime = SubDuration::try_from(first).expect("Bad --autoscale format").as_instant();
             let vidtime = SubDuration::try_from(second).expect("Bad --autoscale format").as_instant();
 
@@ -167,6 +190,40 @@ fn main() {
         None => None
     };
 
+    let mut automove = Vec::<AutoMoveTag>::new();
+    match argv.values_of("automove") {
+        Some(ss) => {
+            for s in ss {
+                let halves: Vec<&str> = s.split("=").collect();
+                if halves.len() != 2 {
+                    panic!("Bad --automove format, should be SUBTIME=VIDEOTIME")
+                }
+                let (mut first, second) = (halves[0], halves[1]);
+                let vidtime = SubDuration::try_from(second).expect("Bad --automove format").as_instant();
+
+                if first.starts_with('^') {
+                    first = &first[1..];
+                    if s.starts_with('@') {
+                        let index = &first[1..].parse().expect("Bad --automove format");
+                        automove.push(AutoMoveTag::ByIndexOrig(*index, vidtime));
+                    } else {
+                        let subtime = SubDuration::try_from(first).expect("Bad --automove format").as_instant();
+                        automove.push(AutoMoveTag::ByTimeOrig(subtime, vidtime));
+                    }
+                } else {
+                    if s.starts_with('@') {
+                        let index = &first[1..].parse().expect("Bad --automove format");
+                        automove.push(AutoMoveTag::ByIndex(*index, vidtime));
+                    } else{
+                        let subtime = SubDuration::try_from(first).expect("Bad --automove format").as_instant();
+                        automove.push(AutoMoveTag::ByTime(subtime, vidtime));
+                    }
+                }
+            }
+        }
+        None => (/* no automoves */)
+    }
+
     let inf = argv.value_of("input");
     let outf = argv.value_of("output");
     let stdin = io::stdin();
@@ -205,8 +262,8 @@ fn main() {
         durscale,
         scale,
         shift,
-        from_index,
-        from_time,
+        from,
+        automove,
     });
 }
 
@@ -217,8 +274,30 @@ struct TransformOpts {
     durscale: f32,
     scale: f32,
     shift: SubDuration,
-    from_index: u32,
-    from_time: SubInstant,
+    automove: Vec<AutoMoveTag>,
+    from: FromTag,
+}
+
+#[derive(Debug)]
+enum AutoMoveTag {
+    ByTime(SubInstant, SubInstant),
+    ByTimeOrig(SubInstant, SubInstant),
+    ByIndex(u32, SubInstant),
+    ByIndexOrig(u32, SubInstant),
+    ByIndexRelative(u32, SubDuration),
+}
+
+#[derive(Debug)]
+enum FromTag {
+    ByTime(SubInstant),
+    ByIndex(u32),
+    ByIndexOrig(u32)
+}
+
+#[derive(Debug,Default,Clone,Copy)]
+struct IterState {
+    start_time : Option<SubInstant>,
+    renumber_i : u32,
 }
 
 fn transform_subtitles<'a>(lines : &mut Box<dyn Iterator<Item=Result<String, io::Error>> + 'a>,
@@ -226,9 +305,7 @@ fn transform_subtitles<'a>(lines : &mut Box<dyn Iterator<Item=Result<String, io:
                        mut opts : TransformOpts) {
     debug!("Opts: {:#?}", opts);
 
-    let mut start_time = SubInstant(0f32);
-    let mut first_found = false;
-    let mut renumber_i: u32 = 0;
+    let mut istate = IterState::default();
 
     let mut linebuf = vec![];
     while let Some(Ok(x)) = lines.next() {
@@ -242,19 +319,21 @@ fn transform_subtitles<'a>(lines : &mut Box<dyn Iterator<Item=Result<String, io:
             continue;
         }
 
+        let istate_backup = istate;
+
         // 236
         // 00:18:01,755 --> 00:18:03,774
         // (掃除機の音)
         // う~ん…。
         match u32::from_str(x) {
-            Ok(num) => {
+            Ok(num_orig) => {
                 // println!("Entry {}", num);
                 let datesrow = lines.next().unwrap().unwrap();
                 if datesrow.contains(" --> ") {
                     let mut halves = datesrow.split(" --> ");
                     let (first, second) = (halves.next().unwrap(), halves.next().unwrap());
-                    let start = SubInstant::try_from(first).unwrap();
-                    let end = SubInstant::try_from(second).unwrap();
+                    let sub_start = SubInstant::try_from(first).unwrap();
+                    let sub_end = SubInstant::try_from(second).unwrap();
 
                     linebuf.clear();
                     while let Some(Ok(x)) = lines.next() {
@@ -264,32 +343,45 @@ fn transform_subtitles<'a>(lines : &mut Box<dyn Iterator<Item=Result<String, io:
                         linebuf.push(x);
                     }
 
+                    let num_new = if opts.renumber {
+                        istate.renumber_i += 1;
+                        istate.renumber_i
+                    } else {
+                        num_orig
+                    };
+
+                    // advance numbering only for the really emitted entries
+
+
                     let mut subtitle = Subtitle {
-                        num,
-                        start,
-                        dur: SubDuration(end.0 - start.0),
+                        num : num_new,
+                        start: sub_start,
+                        dur: sub_end - sub_start,
                         text: linebuf.join("\n"),
                     };
 
-                    if start >= opts.from_time && num >= opts.from_index {
-                        if !first_found {
-                            debug!("Scaling anchored at {} (#{}), editing starts", start, num);
+                    if match opts.from {
+                        FromTag::ByTime(ins) => ins <= sub_start,
+                        FromTag::ByIndex(idx) => idx <= num_new,
+                        FromTag::ByIndexOrig(idx) => idx <= num_orig,
+                    } {
+                        if istate.start_time.is_none() {
+                            debug!("Scaling anchored at {} (#{}), editing starts", sub_start, num_orig);
                             debug!("Shifting by: {}", opts.shift);
 
-                            start_time = start;
-                            first_found = true;
+                            istate.start_time = Some(sub_start);
 
                             if let Some((mut subt, mut vidt)) = opts.autoscale {
                                 debug!("Autoscale: VT {} -> ST {}", vidt, subt);
-                                subt -= start_time;
-                                vidt -= start_time + opts.shift;
+                                subt -= sub_start;
+                                vidt -= sub_start + opts.shift;
                                 if subt.0 <= 0f32 {
                                     panic!("Error in autoscale, start time is negative or zero.");
                                 }
                                 if vidt.0 <= 0f32 {
                                     panic!("Error in autoscale, end time is negative or zero.");
                                 }
-                                debug!("  relative to #{}, after \"move\": VT {} -> ST {}", num, vidt, subt);
+                                debug!("  relative to #{}, after \"move\": VT {} -> ST {}", num_orig, vidt, subt);
                                 opts.scale = vidt.0 / subt.0;
                                 debug!("Resolved scale as {}", opts.scale);
                             }
@@ -299,24 +391,76 @@ fn transform_subtitles<'a>(lines : &mut Box<dyn Iterator<Item=Result<String, io:
                         }
 
                         if opts.scale != 1f32 {
-                            subtitle.start = subtitle.start.scale(start_time, opts.scale);
+                            subtitle.start = subtitle.start.scale(istate.start_time.unwrap(), opts.scale);
                         }
 
                         subtitle.dur *= opts.durscale;
                         subtitle.start += opts.shift;
+
+                        for amove in opts.automove.iter_mut() {
+                            match amove {
+                                AutoMoveTag::ByIndex(idx, ref vidt) => {
+                                    if num_new >= *idx {
+                                        debug!("Move by new index starts, reached {}", idx);
+                                        let vidt = *vidt;
+                                        let dif = vidt - subtitle.start;
+                                        subtitle.start = vidt;
+                                        std::mem::replace(amove, AutoMoveTag::ByIndexRelative(num_new, dif));
+                                    } else if *vidt < subtitle.start && *idx > num_new {
+//                                        istate = istate_backup;
+                                        warn!("Skip overlapped #{} (by index)", num_orig);
+                                        continue;
+                                    }
+                                }
+                                AutoMoveTag::ByIndexOrig(idx, ref vidt) => {
+                                    if num_orig >= *idx {
+                                        debug!("Move by orig index starts, reached {}", idx);
+                                        let vidt = *vidt;
+                                        let dif = vidt - subtitle.start;
+                                        subtitle.start = vidt;
+                                        std::mem::replace(amove, AutoMoveTag::ByIndexRelative(num_new, dif));
+                                    } else if *vidt < sub_start && *idx > num_orig {
+//                                        istate = istate_backup;
+                                        warn!("Skip overlapped #{} (by orig index)", num_orig);
+                                        continue;
+                                    }
+                                }
+                                AutoMoveTag::ByTime(ref subt, ref vidt) => {
+                                    if subtitle.start >= *vidt {
+                                        // TODO verify
+                                        subtitle.start += *vidt - *subt;
+                                    } else if *vidt < subtitle.start && *subt > subtitle.start {
+//                                        istate = istate_backup;
+                                        warn!("Skip overlapped #{} (by time)", num_orig);
+                                        continue;
+                                    }
+                                }
+                                AutoMoveTag::ByTimeOrig(ref subt, ref vidt) => {
+                                    if sub_start >= *subt {
+                                        // TODO verify
+                                        subtitle.start += *vidt - *subt;
+                                    } else if *vidt < subtitle.start && *subt > sub_start {
+//                                        istate = istate_backup;
+                                        warn!("Skip overlapped #{} (by orig time)", num_orig);
+                                        continue;
+                                    }
+                                },
+                                // this is used internally
+                                AutoMoveTag::ByIndexRelative(ref idx, ref dif) => {
+                                    if num_new >= *idx {
+                                        subtitle.start += *dif;
+                                    }
+                                },
+                            }
+                        }
                     }
 
                     if subtitle.start.0 < 0f32 {
                         warn!("Discarding negative time entry #{} @ {:.3}s", subtitle.num, subtitle.start.0);
+                        istate = istate_backup;
                         continue;
                     }
 
-                    // advance numbering only for the really emitted entries
-                    if opts.renumber {
-                        renumber_i += 1;
-                        subtitle.num = renumber_i;
-                    }
-
                     outfile.write(subtitle.to_string().as_bytes()).expect("failed to write");
                 }
             }
@@ -373,6 +517,14 @@ impl Sub<SubDuration> for SubInstant {
     }
 }
 
+impl Sub<SubInstant> for SubInstant {
+    type Output = SubDuration;
+
+    fn sub(self, rhs: SubInstant) -> Self::Output {
+        SubDuration(self.0 - rhs.0)
+    }
+}
+
 impl Mul<f32> for SubDuration {
     type Output = SubDuration;