diff --git a/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs b/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs
index af0b4ef..baf4531 100644
--- a/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs
+++ b/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/Parser.cs
@@ -269,7 +269,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
         }
 
         public Expression parse() {
-            Token<string> token = _sts.get();
+            Token<string> token = _sts.Get();
             switch (token) {
                 case GroupingToken gt:
                     return parse_grouping(gt, gt.closing_value);
@@ -287,14 +287,14 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
             Debug.Assert(start.value == end.value);
             Debug.Assert("'\"".Contains(start.value));
             string r = "";
-            while (_sts.available() > 0) {
-                Token<string> t = _sts.get();
+            while (_sts.Available() > 0) {
+                Token<string> t = _sts.Get();
                 if (t.value == end.value) {
                     break;
                 }
                 r += t.value;
             }
-            _sts.commit();
+            _sts.Commit();
             return new String(r);
         }
 
@@ -303,13 +303,13 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
                 return parse_string(start, end);
             }
             IList<Expression> expressions = new List<Expression>();
-            while (_sts.available() > 0) {
-                Token<string> t = _sts.get();
+            while (_sts.Available() > 0) {
+                Token<string> t = _sts.Get();
                 if (t.value == end.value) {
-                    _sts.commit();
+                    _sts.Commit();
                     break;
                 }
-                _sts.rewind(1);
+                _sts.Rewind(1);
                 expressions.Add(parse());
             }
             return new List(expressions);
@@ -318,7 +318,7 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
         Expression parse_atom(AtomToken at) {
             int parsed_value;
             if (int.TryParse(at.value, out parsed_value)) {
-                _sts.commit();
+                _sts.Commit();
                 return new Integer(parsed_value);
             }
             if (at.value.Equals("t")) {
@@ -327,19 +327,19 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
             if (at.value.Equals("nil")) {
                 return new Boolean(false);
             }
-            _sts.commit();
+            _sts.Commit();
             return new Symbol(at.value);
         }
 
         Expression parse_operator(OperatorToken ot) {
             string v = ot.value;
-            while (_sts.available() > 0) {
-                Token<string> t = _sts.get();
+            while (_sts.Available() > 0) {
+                Token<string> t = _sts.Get();
                 if (t is OperatorToken ot_) {
                     v += ot_.value;
                     continue;
                 }
-                _sts.rewind(1);
+                _sts.Rewind(1);
                 break;
             }
             return new Symbol(v);
diff --git a/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/TokenStream.cs b/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/TokenStream.cs
index 58f5925..ec6447f 100644
--- a/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/TokenStream.cs
+++ b/Jellyfin.Plugin.SmartPlaylist/Lisp/Compiler/TokenStream.cs
@@ -24,10 +24,10 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
     class SpaceToken : Token<string> {
         private SpaceToken(string value) : base(value) {}
         private static IToken<string>? take(CharStream program) {
-            if (program.available() == 0) {
+            if (program.Available() == 0) {
                 return null;
             }
-            if (program.get() == ' ') {
+            if (program.Get() == ' ') {
                 return new SpaceToken(" ");
             }
             return null;
@@ -37,10 +37,10 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
     class GroupingToken: Token<string> {
         private GroupingToken(string value) : base(value) {}
         private static IToken<string>? take(CharStream program) {
-            if (program.available() == 0) {
+            if (program.Available() == 0) {
                 return null;
             }
-            char t = program.get();
+            char t = program.Get();
             if ("()\"'".Contains(t)) {
                 return new GroupingToken(t.ToString());
             }
@@ -61,13 +61,13 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
         private AtomToken(string value) : base(value) {}
         private static IToken<string>? take(CharStream program) {
             string value = "";
-            while (program.available() > 0) {
-                char t = program.get();
+            while (program.Available() > 0) {
+                char t = program.Get();
                 if (!"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".Contains(t)) {
                     if (value.Equals("")) {
                         return null;
                     }
-                    program.rewind(1);
+                    program.Rewind(1);
                     return new AtomToken(value);
                 }
                 value += t;
@@ -79,10 +79,10 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
     class OperatorToken : Token<string> {
         private OperatorToken(string value) : base(value) {}
         private static IToken<string>? take(CharStream program) {
-            if (program.available() == 0) {
+            if (program.Available() == 0) {
                 return null;
             }
-            return new OperatorToken(program.get().ToString());
+            return new OperatorToken(program.Get().ToString());
             //char t = program.get();
             //if ("+-*/%".Contains(t)) {
             //    return new OperatorToken(t.ToString());
@@ -108,12 +108,12 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
             IList<Token<string>> result = new List<Token<string>>();
             int prev_avail = 0;
             while (true) {
-                if (prev_avail == program.available() && prev_avail == 0) {
+                if (prev_avail == program.Available() && prev_avail == 0) {
                     break;
-                } else if (prev_avail == program.available()) {
+                } else if (prev_avail == program.Available()) {
                     throw new ApplicationException("Program is invalid");
                 }
-                prev_avail = program.available();
+                prev_avail = program.Available();
                 foreach (Type c in _classes) {
                     Token<string>? t = (Token<string>?) c.GetMethod(
                         "take",
@@ -127,10 +127,10 @@ namespace Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler {
                         new object[]{program}
                     );
                     if (t == null) {
-                        program.rewind();
+                        program.Rewind();
                         continue;
                     }
-                    program.commit();
+                    program.Commit();
                     result.Add(t);
                     break;
                 }
diff --git a/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs b/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs
index 81bb9d8..08bcdc0 100644
--- a/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs
+++ b/Jellyfin.Plugin.SmartPlaylist/Util/Stream.cs
@@ -1,47 +1,61 @@
 namespace Jellyfin.Plugin.SmartPlaylist.Util {
     public interface IStream<T> {
-        int available();
-        T get();
-        int commit();
-        int rewind();
-        int rewind(int n);
+        int Available();
+        T Get();
+        int Commit();
+        int Rewind();
+        int Rewind(int n);
+        int Consumed();
+        IStream<T> Copy();
     }
 
     public class Stream<T> : IStream<T> {
         private readonly IList<T> _items;
         private int _cursor;
-        private int _ephemeral_cursor;
+        private int _ephemeralCursor;
 
         protected Stream(IList<T> items) {
             _items = items;
             _cursor = 0;
-            _ephemeral_cursor = 0;
+            _ephemeralCursor = 0;
         }
 
-        public int available() {
-            return _items.Count - _ephemeral_cursor;
+        private Stream(IList<T> items, int cursor, int ephemeralCursor) {
+            _items = items;
+            _cursor = cursor;
+            _ephemeralCursor = ephemeralCursor;
         }
-        public T get() {
-            return _items[_ephemeral_cursor++];
+
+        public int Available() {
+            return _items.Count - _ephemeralCursor;
         }
-        public int commit() {
-            int diff = _ephemeral_cursor - _cursor;
-            _cursor = _ephemeral_cursor;
+        public T Get() {
+            return _items[_ephemeralCursor++];
+        }
+        public int Commit() {
+            int diff = Consumed();
+            _cursor = _ephemeralCursor;
             return diff;
         }
-        public int rewind() {
-            int diff = _ephemeral_cursor - _cursor;
-            _ephemeral_cursor = _cursor;
+        public int Rewind() {
+            int diff = Consumed();
+            _ephemeralCursor = _cursor;
             return diff;
         }
-        public int rewind(int n) {
-            int diff = _ephemeral_cursor - _cursor;
+        public int Rewind(int n) {
+            int diff = Consumed();
             if (diff < n) {
                 n = diff;
             }
-            _ephemeral_cursor -= n;
+            _ephemeralCursor -= n;
             return n;
         }
+        public int Consumed() {
+            return _ephemeralCursor - _cursor;
+        }
+        public IStream<T> Copy() {
+            return new Stream<T>(_items, _cursor, _ephemeralCursor);
+        }
     }
 }