summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--COPYRIGHT29
-rw-r--r--HISTORY1
-rw-r--r--README1
-rwxr-xr-xbin/vdrnfofs28
-rwxr-xr-xsetup.py43
-rw-r--r--tests/__init__.py0
-rw-r--r--tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/001.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/002.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/003.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/004.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/info.vdr6
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/001.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/002.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/003.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/004.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/info.vdr6
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/001.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/002.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/003.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/004.vdr1
-rw-r--r--tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/info.vdr6
-rw-r--r--tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00001.ts1
-rw-r--r--tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00002.ts1
-rw-r--r--tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00003.ts1
-rw-r--r--tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00004.ts1
-rw-r--r--tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/info6
-rw-r--r--tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/001.vdr1
-rw-r--r--tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/002.vdr1
-rw-r--r--tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/003.vdr1
-rw-r--r--tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/004.vdr1
-rw-r--r--tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/info.vdr6
-rw-r--r--tests/syslog.py2
-rwxr-xr-xtests/test_all40
-rw-r--r--tests/test_dir.py40
-rw-r--r--tests/test_gettattr.py38
-rw-r--r--tests/test_mpg.py46
-rw-r--r--tests/test_nfo.py47
-rw-r--r--tests/test_path_to_node_mapping.py45
-rw-r--r--vdrnfofs/__init__.py0
-rw-r--r--vdrnfofs/concatenated_file_reader.py58
-rw-r--r--vdrnfofs/filesystemnodes.py136
-rw-r--r--vdrnfofs/vdr.py32
-rw-r--r--vdrnfofs/vdrnfofs.py129
44 files changed, 766 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/COPYRIGHT b/COPYRIGHT
new file mode 100644
index 0000000..7e63661
--- /dev/null
+++ b/COPYRIGHT
@@ -0,0 +1,29 @@
+Copyright 2010 Tobias Grimm <vdr@e-tobi.net> All rights reserved.
+
+Software License Agreement (BSD License)
+
+Redistribution and use of this software in source and binary forms, with or
+without modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name of the author/copyright holder nor the names of contributors may
+ be used to endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/HISTORY b/HISTORY
new file mode 100644
index 0000000..1333ed7
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1 @@
+TODO
diff --git a/README b/README
new file mode 100644
index 0000000..1333ed7
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+TODO
diff --git a/bin/vdrnfofs b/bin/vdrnfofs
new file mode 100755
index 0000000..60d176c
--- /dev/null
+++ b/bin/vdrnfofs
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+import sys
+from vdrnfofs import vdrnfofs
+
+if __name__ == '__main__':
+ vdrnfofs.main()
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..63145d2
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import os
+import re
+
+from distutils.core import setup
+from distutils.file_util import copy_file
+from distutils.command.build_py import build_py
+from distutils.command.install_data import install_data
+
+from glob import glob
+from subprocess import check_call
+
+setup (
+ name='vdrnfofs',
+ version='1.0',
+ maintainer = "Tobias Grimm",
+ maintainer_email = "vdr@e.tobi.net",
+ description = "Access VDR recordings as mpg and nfo files",
+ license = "GNU GPL v2",
+ scripts = ['bin/vdrnfofs'],
+ packages = ['vdrnfofs'],
+)
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/__init__.py
diff --git a/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/001.vdr b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/001.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/001.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/002.vdr b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/002.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/002.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/003.vdr b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/003.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/003.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/004.vdr b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/004.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/004.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/info.vdr b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/info.vdr
new file mode 100644
index 0000000..08787fc
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample1/2008-03-28.20.13.99.99.rec/info.vdr
@@ -0,0 +1,6 @@
+C S19.2E-1-1101-28112
+E 6345 1189982700 18900 4E 10
+T Movie Title
+S Movie Subtitle
+D A movie about something
+X 2 03 deu stereo
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/001.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/001.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/001.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/002.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/002.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/002.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/003.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/003.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/003.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/004.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/004.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/004.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/info.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/info.vdr
new file mode 100644
index 0000000..08787fc
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.98.rec/info.vdr
@@ -0,0 +1,6 @@
+C S19.2E-1-1101-28112
+E 6345 1189982700 18900 4E 10
+T Movie Title
+S Movie Subtitle
+D A movie about something
+X 2 03 deu stereo
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/001.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/001.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/001.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/002.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/002.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/002.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/003.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/003.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/003.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/004.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/004.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/004.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/info.vdr b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/info.vdr
new file mode 100644
index 0000000..08787fc
--- /dev/null
+++ b/tests/sample_video_dir/folder/sample2/2008-03-28.20.13.99.99.rec/info.vdr
@@ -0,0 +1,6 @@
+C S19.2E-1-1101-28112
+E 6345 1189982700 18900 4E 10
+T Movie Title
+S Movie Subtitle
+D A movie about something
+X 2 03 deu stereo
diff --git a/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00001.ts b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00001.ts
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00001.ts
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00002.ts b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00002.ts
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00002.ts
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00003.ts b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00003.ts
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00003.ts
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00004.ts b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00004.ts
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/00004.ts
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/info b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/info
new file mode 100644
index 0000000..08787fc
--- /dev/null
+++ b/tests/sample_video_dir/sample-vdr1.7/2008-03-28.20.13.99.99.rec/info
@@ -0,0 +1,6 @@
+C S19.2E-1-1101-28112
+E 6345 1189982700 18900 4E 10
+T Movie Title
+S Movie Subtitle
+D A movie about something
+X 2 03 deu stereo
diff --git a/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/001.vdr b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/001.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/001.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/002.vdr b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/002.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/002.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/003.vdr b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/003.vdr
new file mode 100644
index 0000000..6a537b5
--- /dev/null
+++ b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/003.vdr
@@ -0,0 +1 @@
+1234567890 \ No newline at end of file
diff --git a/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/004.vdr b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/004.vdr
new file mode 100644
index 0000000..c76a964
--- /dev/null
+++ b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/004.vdr
@@ -0,0 +1 @@
+abcdefghij \ No newline at end of file
diff --git a/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/info.vdr b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/info.vdr
new file mode 100644
index 0000000..08787fc
--- /dev/null
+++ b/tests/sample_video_dir/sample/2008-03-28.20.13.99.99.rec/info.vdr
@@ -0,0 +1,6 @@
+C S19.2E-1-1101-28112
+E 6345 1189982700 18900 4E 10
+T Movie Title
+S Movie Subtitle
+D A movie about something
+X 2 03 deu stereo
diff --git a/tests/syslog.py b/tests/syslog.py
new file mode 100644
index 0000000..abadaa2
--- /dev/null
+++ b/tests/syslog.py
@@ -0,0 +1,2 @@
+def syslog(*arg):
+ raise
diff --git a/tests/test_all b/tests/test_all
new file mode 100755
index 0000000..02ab99f
--- /dev/null
+++ b/tests/test_all
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import os
+import sys
+import unittest
+
+def suite():
+ suite = unittest.TestSuite()
+ for _, _, files in os.walk('.'):
+ for name in filter(is_test, files):
+ tests = unittest.defaultTestLoader.loadTestsFromName(name[:-3])
+ suite.addTests(tests)
+ return suite
+
+def is_test(filename):
+ return filename.startswith('test_') and filename.endswith('.py')
+
+if __name__ == "__main__":
+ sys.path.insert(0, '.')
+ unittest.main(defaultTest="suite")
diff --git a/tests/test_dir.py b/tests/test_dir.py
new file mode 100644
index 0000000..e7562f0
--- /dev/null
+++ b/tests/test_dir.py
@@ -0,0 +1,40 @@
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import sys
+import os
+import unittest
+import xml.etree.ElementTree
+
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+from vdrnfofs.vdrnfofs import *
+
+class TestDir(unittest.TestCase):
+ def setUp(self):
+ self.video = self.video_dir = os.path.abspath(os.path.dirname(__file__) + '/sample_video_dir')
+
+ def test_not_existing(self):
+ node = get_node(self.video, '/does_not_exist')
+ self.assertEqual(None, node)
+
+ def test_content(self):
+ node = get_node(self.video, '/')
+ self.assertEqual(5, len(node.content()))
+
diff --git a/tests/test_gettattr.py b/tests/test_gettattr.py
new file mode 100644
index 0000000..7bae140
--- /dev/null
+++ b/tests/test_gettattr.py
@@ -0,0 +1,38 @@
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import sys
+import os
+import unittest
+import stat
+
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+from vdrnfofs.vdrnfofs import *
+
+class TestPathToNodeMapping(unittest.TestCase):
+ def setUp(self):
+ self.fs = VdrNfoFs()
+ self.fs.video = self.video_dir = os.path.abspath(os.path.dirname(__file__) + '/sample_video_dir')
+
+ def test_root(self):
+ attr = self.fs.getattr('/')
+ self.assertEqual(stat.S_IFDIR | 0755, attr.st_mode)
+ self.assertEqual(2 + 5, attr.st_nlink)
diff --git a/tests/test_mpg.py b/tests/test_mpg.py
new file mode 100644
index 0000000..397b5fe
--- /dev/null
+++ b/tests/test_mpg.py
@@ -0,0 +1,46 @@
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import sys
+import os
+import unittest
+import xml.etree.ElementTree
+
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+from vdrnfofs.vdrnfofs import *
+
+class TestMpg(unittest.TestCase):
+ def setUp(self):
+ self.video = self.video_dir = os.path.abspath(os.path.dirname(__file__) + '/sample_video_dir')
+
+ def test_not_existing(self):
+ node = get_node(self.video, '/does_not_exist_2008-03-28.20.13.99.99.rec.mpg')
+ self.assertEqual(None, node)
+
+ def test_mpg(self):
+ node = get_node(self.video, '/sample_2008-03-28.20.13.99.99.rec.mpg')
+ self.assertEqual(40, node.size())
+ self.assertEqual('1234567890abcdefghij1234567890abcdefghij', node.read(0, 4096))
+
+ def test_mpg_new(self):
+ node = get_node(self.video, '/sample-vdr1.7_2008-03-28.20.13.99.99.rec.mpg')
+ self.assertEqual(40, node.size())
+ self.assertEqual('1234567890abcdefghij1234567890abcdefghij', node.read(0, 4096))
+
diff --git a/tests/test_nfo.py b/tests/test_nfo.py
new file mode 100644
index 0000000..e7107a3
--- /dev/null
+++ b/tests/test_nfo.py
@@ -0,0 +1,47 @@
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import sys
+import os
+import unittest
+import xml.etree.ElementTree
+
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+from vdrnfofs.vdrnfofs import *
+
+class TestNfo(unittest.TestCase):
+ def setUp(self):
+ self.video = self.video_dir = os.path.abspath(os.path.dirname(__file__) + '/sample_video_dir')
+
+ def test_not_existing(self):
+ node = get_node(self.video, '/does_not_exist_2008-03-28.20.13.99.99.rec.nfo')
+ self.assertEqual(None, node)
+
+ def test_nfo(self):
+ node = get_node(self.video, '/sample_2008-03-28.20.13.99.99.rec.nfo')
+ nfo = xml.etree.ElementTree.fromstring(node.read(0, 4096))
+ self.assertEqual('Movie Title', nfo.find('title').text)
+ self.assertEqual('A movie about something', nfo.find('plot').text)
+
+ def test_nfo_new(self):
+ node = get_node(self.video, '/sample-vdr1.7_2008-03-28.20.13.99.99.rec.nfo')
+ nfo = xml.etree.ElementTree.fromstring(node.read(0, 4096))
+ self.assertEqual('Movie Title', nfo.find('title').text)
+ self.assertEqual('A movie about something', nfo.find('plot').text)
diff --git a/tests/test_path_to_node_mapping.py b/tests/test_path_to_node_mapping.py
new file mode 100644
index 0000000..59f3515
--- /dev/null
+++ b/tests/test_path_to_node_mapping.py
@@ -0,0 +1,45 @@
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import sys
+import os
+import unittest
+
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+from vdrnfofs.vdrnfofs import *
+
+class TestPathToNodeMapping(unittest.TestCase):
+ def setUp(self):
+ self.video = self.video_dir = os.path.abspath(os.path.dirname(__file__) + '/sample_video_dir')
+
+ def test_root(self):
+ node = get_node(self.video, '/')
+ self.assertEqual('', node.file_system_name)
+ self.assertEqual(self.video, node.path)
+
+ def test_subdir(self):
+ node = get_node(self.video, '/folder')
+ self.assertEqual('folder', node.file_system_name)
+ self.assertEqual(self.video + '/folder', node.path)
+
+ def test_mpg(self):
+ node = get_node(self.video, '/sample_2008-03-28.20.13.99.99.rec.mpg')
+ self.assertEqual('sample_2008-03-28.20.13.99.99.rec.mpg', node.file_system_name)
+ self.assertEqual(self.video + '/sample/2008-03-28.20.13.99.99.rec', node.path)
diff --git a/vdrnfofs/__init__.py b/vdrnfofs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vdrnfofs/__init__.py
diff --git a/vdrnfofs/concatenated_file_reader.py b/vdrnfofs/concatenated_file_reader.py
new file mode 100644
index 0000000..9f05ebd
--- /dev/null
+++ b/vdrnfofs/concatenated_file_reader.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+#
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import os
+
+class ConcatenatedFileReader:
+ def __init__(self, filenames):
+ self.files = [(f, os.path.getsize(f)) for f in filenames]
+ self.current_filename = None
+ self.current_file = None
+
+ def read(self, offset, size):
+ buffer = ""
+ ptr = offset
+ while (len(buffer) < size):
+ (filename, file_offset) = self.filename_from_offset(ptr)
+ if filename:
+ if (self.current_filename != filename):
+ if self.current_file:
+ self.current_file.close()
+ self.current_filename = filename
+ self.current_file = open(filename, 'r')
+ self.current_file.seek(file_offset)
+ buffer += self.current_file.read(size - len(buffer))
+ ptr = offset + len(buffer)
+ else:
+ break
+ return buffer
+
+ def release(self):
+ if self.current_file:
+ self.current_file.close()
+
+ def filename_from_offset(self, offset):
+ for (filename, size) in self.files:
+ if offset >= size:
+ offset -= size
+ else:
+ return (filename, offset)
+ return (None, 0)
diff --git a/vdrnfofs/filesystemnodes.py b/vdrnfofs/filesystemnodes.py
new file mode 100644
index 0000000..6902d9f
--- /dev/null
+++ b/vdrnfofs/filesystemnodes.py
@@ -0,0 +1,136 @@
+# -*- coding: utf-8 -*-
+#
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import glob
+import os
+import fuse
+import stat
+
+from concatenated_file_reader import *
+from vdr import *
+
+class NodeAttributes(fuse.Stat):
+ def __init__(self):
+ self.st_mode = 0
+ self.st_ino = 0
+ self.st_dev = 0
+ self.st_nlink = 0
+ self.st_uid = 0
+ self.st_gid = 0
+ self.st_size = 0
+ self.st_atime = 0
+ self.st_mtime = 0
+ self.st_ctime = 0
+
+class MpgNode:
+ def __init__(self, path):
+ self.path = os.path.normpath(path)
+ self.mpeg_files = glob.glob(path + '/[0-9]*.vdr')
+ if not self.mpeg_files:
+ self.mpeg_files = glob.glob(path + '/[0-9]*.ts')
+ self.mpeg_files.sort()
+ self.file_system_name = os.path.basename(os.path.abspath(path + '/..')) + '_' + os.path.basename(path) + '.mpg'
+ self.reader = ConcatenatedFileReader(self.mpeg_files)
+
+ def size(self):
+ size = 0
+ for file in self.mpeg_files:
+ size += os.path.getsize(file)
+ return size
+
+ def read(self, offset, size):
+ return self.reader.read(offset, size)
+
+ def release(self):
+ return self.reader.release()
+
+ def get_stat(self):
+ attr = NodeAttributes()
+ attr.st_mode = stat.S_IFREG | 644
+ attr.st_nlink = 1
+ attr.st_size = self.size()
+ return attr
+
+
+class NfoNode:
+ def __init__(self, path):
+ self.path = os.path.normpath(path)
+ self.file_system_name = os.path.basename(os.path.abspath(path + '/..')) + '_' + os.path.basename(path) + '.nfo'
+ if os.path.exists(path + '/info.vdr'):
+ info_vdr = InfoVdr(path + '/info.vdr')
+ elif os.path.exists(path + '/info'):
+ info_vdr = InfoVdr(path + '/info')
+ else:
+ info_vdr = InfoVdr()
+ self.nfo_content = """<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<movie>
+ <title>%s</title>
+ <plot>%s</plot>
+</movie>
+""" % (info_vdr['T'], info_vdr['D'])
+
+ def size(self):
+ return len(self.nfo_content)
+
+ def read(self, offset, size):
+ return self.nfo_content[offset:offset+size]
+
+ def get_stat(self):
+ attr = NodeAttributes()
+ attr.st_mode = stat.S_IFREG | 644
+ attr.st_nlink = 1
+ attr.st_size = self.size()
+ return attr
+
+
+class DirNode:
+ def __init__(self, path):
+ self.path = os.path.normpath(path)
+ self.file_system_name = os.path.basename(path)
+ self.cache = []
+
+ def content(self):
+ if not self.cache:
+ for entry in os.listdir(self.path):
+ entry = self.path + '/' + entry
+ if self.is_sub_folder(entry):
+ self.cache.append(DirNode(entry))
+ for recording in glob.glob(entry + '/*.rec'):
+ if os.path.exists(recording + '/info.vdr') or os.path.exists(recording + '/info'):
+ self.cache.append(MpgNode(recording))
+ self.cache.append(NfoNode(recording))
+ return self.cache
+
+ def is_sub_folder(self, dir):
+ if not os.path.isdir(dir):
+ return False
+ if dir.endswith('.rec'):
+ return False
+ for entry in os.listdir(dir):
+ if not entry.endswith('.rec'):
+ return True
+ return False
+
+ def get_stat(self):
+ attr = NodeAttributes()
+ attr.st_mode = stat.S_IFDIR | 0755
+ attr.st_nlink = 2 + len(self.content())
+ return attr
diff --git a/vdrnfofs/vdr.py b/vdrnfofs/vdr.py
new file mode 100644
index 0000000..b3c2311
--- /dev/null
+++ b/vdrnfofs/vdr.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+#
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+class InfoVdr:
+ def __init__(self, filename = None):
+ self.values = {'T' : 'Unknown', 'D': 'No Description'}
+ if filename:
+ file = open(filename, 'r')
+ for line in file:
+ line = line.rstrip("\r\n")
+ self.values[line[0]] = line[2:]
+
+ def __getitem__(self, key):
+ return self.values[key] if self.values.has_key(key) else ''
diff --git a/vdrnfofs/vdrnfofs.py b/vdrnfofs/vdrnfofs.py
new file mode 100644
index 0000000..dc6deb3
--- /dev/null
+++ b/vdrnfofs/vdrnfofs.py
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+#
+# VDR-NFO-FS creates a file system for VDR recordings, which maps each
+# recording to a single mpg-file and nfo-file containing some meta data.
+#
+# Copyright (C) 2010 - 2011 by Tobias Grimm
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import os
+import stat
+import errno
+import sys
+import fuse
+import syslog
+
+from concatenated_file_reader import *
+from vdr import *
+from filesystemnodes import *
+
+fuse.fuse_python_api = (0, 2)
+
+def get_node(video, path):
+ virtual_path, virtual_file_extension = os.path.splitext(path)
+ if virtual_file_extension in ['.mpg', '.nfo']:
+ p = virtual_path.rfind('_')
+ if p > 0:
+ video_path = video + '/' + virtual_path[0:p] + '/' + virtual_path[p+1:]
+ if not os.path.isdir(video_path):
+ return None
+ elif virtual_file_extension == '.mpg':
+ return MpgNode(video_path)
+ elif virtual_file_extension == '.nfo':
+ return NfoNode(video_path)
+ else:
+ if os.path.isdir(video + '/' + path):
+ return DirNode(video + path)
+ return None
+
+class VdrNfoFsFile:
+ def __init__(self, path, flags, *mode):
+ self.path = path
+ self.node = get_node(VdrNfoFsFile.video_root, path)
+
+ def read(self, size, offset):
+ try:
+ if not self.node:
+ return -errno.ENOENT
+ return self.node.read(offset, size)
+ except:
+ syslog.syslog('VdrFuseFs: Unexpected error for read(%s)' % self.path)
+
+ def release(self, flags):
+ self.node.release()
+
+# def write(self, buf, offset):
+# return 0
+
+# def _fflush(self):
+# if 'w' in self.file.mode or 'a' in self.file.mode:
+# self.file.flush()
+
+# def fsync(self, isfsyncfile):
+
+# def flush(self):
+
+# def fgetattr(self):
+# return 0
+
+# def ftruncate(self, len):
+
+# def lock(self, cmd, owner, **kw):
+
+
+class VdrNfoFs(fuse.Fuse):
+ def __init__(self, *args, **kw):
+ fuse.Fuse.__init__(self, *args, **kw)
+ self.video = ""
+
+ def getattr(self, path):
+ try:
+ node = get_node(self.video, path)
+ if node:
+ return node.get_stat()
+ return -errno.ENOENT
+ except:
+ syslog.syslog('VdrFuseFs: Unexpected error for getattr(%s): %s' % path)
+
+ def readdir(self, path, offset):
+ try:
+ yield fuse.Direntry('.')
+ yield fuse.Direntry('..')
+ node = get_node(self.video, path)
+ if node:
+ for item in node.content():
+ yield fuse.Direntry(item.file_system_name)
+ except:
+ syslog.syslog('VdrFuseFs: Unexpected error for readdir(%s)' % path)
+
+ def main(self, *a, **kw):
+ VdrNfoFsFile.video_root = self.video
+ self.file_class = VdrNfoFsFile
+ return fuse.Fuse.main(self, *a, **kw)
+
+def main():
+ usage = "\nVDR-NFO-FS - access VDR recordings as mpg and nfo files\n"
+ usage += fuse.Fuse.fusage
+
+ version = "%prog " + fuse.__version__
+
+ fs = VdrNfoFs(version=version, usage=usage, dash_s_do='setsingle')
+ fs.parser.add_option(mountopt="video", default='', help="The video directory containing the VDR recordings")
+ fs.parse(values=fs, errex=1)
+ fs.main()
+
+if __name__ == '__main__':
+ main()