4 Commitit 4d72c98c35 ... d4d0cb9568

Tekijä SHA1 Viesti Päivämäärä
  Gildas Chabot d4d0cb9568 Automatically remove \r from file list 4 vuotta sitten
  Gildas Chabot be9c16ecce Add MediaInfo to movies and generate action 4 vuotta sitten
  Gildas Chabot 7364d447e1 Add MovieFile and Subtitle file to Movies, fix Movie update 4 vuotta sitten
  Gildas Chabot 7db1a5c09e Serve files 4 vuotta sitten
6 muutettua tiedostoa jossa 142 lisäystä ja 15 poistoa
  1. 50 0
      ffmpeg/ffmpeg.go
  2. 5 0
      files.go
  3. 34 1
      movies.go
  4. 43 12
      pages/pages.go
  5. 1 1
      templates/files.html
  6. 9 1
      templates/movie.html

+ 50 - 0
ffmpeg/ffmpeg.go

@@ -0,0 +1,50 @@
1
+package ffmpeg
2
+
3
+import (
4
+	"fmt"
5
+	"os/exec"
6
+	"strings"
7
+)
8
+
9
+const (
10
+	inputFileIdentifier = "INPUT_VIDEO_FILE"
11
+)
12
+
13
+var (
14
+	Debug = true
15
+)
16
+
17
+func MediaInfo(path string) (string, error) {
18
+	out, err := execCommand(
19
+		fmt.Sprintf("-i %s", inputFileIdentifier),
20
+		path)
21
+	if err.Error() == "exit status 1" && strings.HasSuffix(out, "At least one output file must be specified") {
22
+		err = nil
23
+	}
24
+	return out, err
25
+}
26
+
27
+func execCommand(cmdStr, path string) (string, error) {
28
+	cmdSplit := strings.Split(cmdStr, " ")
29
+	for i, s := range cmdSplit {
30
+		if s == inputFileIdentifier {
31
+			cmdSplit[i] = path
32
+		}
33
+	}
34
+
35
+	cmd := exec.Command("ffmpeg", cmdSplit...)
36
+
37
+	if Debug {
38
+		fmt.Println("Executing:", cmd)
39
+	}
40
+	out, err := cmd.CombinedOutput()
41
+	if err != nil {
42
+		fmt.Printf("Error: %#v\n", err.Error())
43
+		return strings.TrimSuffix(string(out), "\n"), err
44
+	}
45
+	if Debug {
46
+		fmt.Printf("Output: %s\n", string(out))
47
+	}
48
+
49
+	return strings.TrimSuffix(string(out), "\n"), err
50
+}

+ 5 - 0
files.go

@@ -2,6 +2,7 @@ package movies
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"net/http"
5 6
 	"os"
6 7
 	"path/filepath"
7 8
 	"strings"
@@ -61,3 +62,7 @@ func stringContainsAll(path string, split []string) bool {
61 62
 	}
62 63
 	return true
63 64
 }
65
+
66
+func (fs *FileSource) Serve(w http.ResponseWriter, r *http.Request, file string) {
67
+	http.ServeFile(w, r, file)
68
+}

+ 34 - 1
movies.go

@@ -2,8 +2,11 @@ package movies
2 2
 
3 3
 import (
4 4
 	"encoding/json"
5
+	"fmt"
5 6
 	"strconv"
6 7
 	"strings"
8
+
9
+	"gogs.gildas.ch/gildas/movies/ffmpeg"
7 10
 )
8 11
 
9 12
 type Movie struct {
@@ -16,7 +19,10 @@ type Movie struct {
16 19
 	Year     string
17 20
 	Runtime  string
18 21
 
19
-	Files []string
22
+	Files     []string
23
+	MovieFile string
24
+	MediaInfo string
25
+	Subtitles string
20 26
 
21 27
 	OMDB OMDBMovie
22 28
 }
@@ -59,6 +65,19 @@ type OMDBRating struct {
59 65
 }
60 66
 
61 67
 func Unmarshal(b []byte) (*Movie, error) {
68
+	var m Movie
69
+	if err := json.Unmarshal(b, &m); err != nil {
70
+		return nil, err
71
+	}
72
+
73
+	if err := m.FillFromOMDB(); err != nil {
74
+		return nil, err
75
+	}
76
+
77
+	return &m, nil
78
+}
79
+
80
+func UnmarshalFromOMDB(b []byte) (*Movie, error) {
62 81
 	var omdb OMDBMovie
63 82
 	if err := json.Unmarshal(b, &omdb); err != nil {
64 83
 		return nil, err
@@ -112,3 +131,17 @@ func (m *Movie) FillFromOMDB() error {
112 131
 
113 132
 	return nil
114 133
 }
134
+
135
+func (m *Movie) GenerateMediaInfo() error {
136
+	if m.MovieFile == "" {
137
+		return fmt.Errorf("no movie file set")
138
+	}
139
+
140
+	mediaInfo, err := ffmpeg.MediaInfo(m.MovieFile)
141
+	if err != nil {
142
+		return fmt.Errorf("error generating media info from %q: %w", m.MovieFile, err)
143
+	}
144
+
145
+	m.MediaInfo = mediaInfo
146
+	return nil
147
+}

+ 43 - 12
pages/pages.go

@@ -18,6 +18,7 @@ func Router(c *movies.Collection) http.HandlerFunc {
18 18
 	movieHandler := Movie(c)
19 19
 	listHandler := List(c)
20 20
 	filesHandler := Files(c)
21
+	fileHandler := File(c, "/files/")
21 22
 
22 23
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
23 24
 		path := r.URL.Path
@@ -25,9 +26,6 @@ func Router(c *movies.Collection) http.HandlerFunc {
25 26
 		case path == "/":
26 27
 			homeHandler(w, r)
27 28
 			return
28
-		case path == "/files":
29
-			filesHandler(w, r)
30
-			return
31 29
 		case path == "/style.css":
32 30
 			http.ServeFile(w, r, "templates/style.css")
33 31
 			return
@@ -37,6 +35,12 @@ func Router(c *movies.Collection) http.HandlerFunc {
37 35
 		case strings.HasPrefix(path, "/tt"):
38 36
 			movieHandler(w, r)
39 37
 			return
38
+		case path == "/files":
39
+			filesHandler(w, r)
40
+			return
41
+		case strings.HasPrefix(path, "/files/"):
42
+			fileHandler(w, r)
43
+			return
40 44
 		}
41 45
 	})
42 46
 }
@@ -53,7 +57,7 @@ func Home(c *movies.Collection) http.HandlerFunc {
53 57
 
54 58
 		if r.Method == "POST" {
55 59
 			if r.FormValue("omdb_json") != "" {
56
-				m, err := movies.Unmarshal([]byte(r.FormValue("omdb_json")))
60
+				m, err := movies.UnmarshalFromOMDB([]byte(r.FormValue("omdb_json")))
57 61
 				if err != nil {
58 62
 					w.WriteHeader(http.StatusBadRequest)
59 63
 					errs = append(errs, err)
@@ -79,12 +83,14 @@ func Home(c *movies.Collection) http.HandlerFunc {
79 83
 			}
80 84
 		}
81 85
 
82
-		t.Execute(w, map[string]interface{}{
86
+		if err := t.Execute(w, map[string]interface{}{
83 87
 			"Collection": c,
84 88
 			"IMDBID":     r.URL.Query().Get("imdb_id"),
85 89
 			"OMDBString": omdbString,
86 90
 			"Errors":     errs,
87
-		})
91
+		}); err != nil {
92
+			fmt.Println(err)
93
+		}
88 94
 	})
89 95
 }
90 96
 
@@ -121,14 +127,25 @@ func Movie(c *movies.Collection) http.HandlerFunc {
121 127
 					errs = append(errs, fmt.Errorf("you cannot change the imdb id."))
122 128
 				} else {
123 129
 					m = updated
130
+					fmt.Println("Update with", m)
124 131
 					c.Update(updated)
125 132
 				}
126 133
 			}
127 134
 
128 135
 			if files := r.FormValue("files"); files != "" {
136
+				files = strings.ReplaceAll(files, "\r", "")
129 137
 				m.Files = strings.Split(files, "\n")
138
+				fmt.Println("Update with", m)
130 139
 				c.Update(m)
131 140
 			}
141
+
142
+			if r.FormValue("generate_mediainfo") != "" {
143
+				if err := m.GenerateMediaInfo(); err != nil {
144
+					errs = append(errs, err)
145
+				} else {
146
+					c.Update(m)
147
+				}
148
+			}
132 149
 		}
133 150
 
134 151
 		fileQuery := r.URL.Query().Get("file_query")
@@ -142,14 +159,16 @@ func Movie(c *movies.Collection) http.HandlerFunc {
142 159
 			errs = append(errs, err)
143 160
 		}
144 161
 
145
-		t.Execute(w, map[string]interface{}{
162
+		if err := t.Execute(w, map[string]interface{}{
146 163
 			"Movie":       m,
147 164
 			"MovieJSON":   string(b),
148 165
 			"Files":       strings.Join(m.Files, "\n"),
149 166
 			"FileQuery":   fileQuery,
150 167
 			"FileResults": fileResults,
151 168
 			"Errors":      errs,
152
-		})
169
+		}); err != nil {
170
+			fmt.Println(err)
171
+		}
153 172
 	})
154 173
 }
155 174
 
@@ -200,7 +219,7 @@ func List(c *movies.Collection) http.HandlerFunc {
200 219
 			}
201 220
 		}
202 221
 
203
-		t.Execute(w, map[string]interface{}{
222
+		if err := t.Execute(w, map[string]interface{}{
204 223
 			"List": l,
205 224
 			"Description": template.HTML(
206 225
 				blackfriday.Run(
@@ -209,7 +228,9 @@ func List(c *movies.Collection) http.HandlerFunc {
209 228
 			"Movies":   ms,
210 229
 			"ListJSON": string(b),
211 230
 			"Errors":   errs,
212
-		})
231
+		}); err != nil {
232
+			fmt.Println(err)
233
+		}
213 234
 	})
214 235
 }
215 236
 
@@ -238,9 +259,19 @@ func Files(c *movies.Collection) http.HandlerFunc {
238 259
 			}
239 260
 		}
240 261
 
241
-		t.Execute(w, map[string]interface{}{
262
+		if err := t.Execute(w, map[string]interface{}{
242 263
 			"Files":  c.AllFiles(),
243 264
 			"Errors": errs,
244
-		})
265
+		}); err != nil {
266
+			fmt.Println(err)
267
+		}
268
+	})
269
+}
270
+
271
+func File(c *movies.Collection, prefix string) http.HandlerFunc {
272
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
273
+		file := "/" + strings.TrimPrefix(r.URL.Path, prefix)
274
+
275
+		c.Files.Serve(w, r, file)
245 276
 	})
246 277
 }

+ 1 - 1
templates/files.html

@@ -18,7 +18,7 @@
18 18
 
19 19
         <ul class="file-list">
20 20
             {{ range $f := .Files }}
21
-            <li>{{ $f }}</li>
21
+            <li><a href="/files/{{ $f }}">{{ $f }}</a></li>
22 22
             {{ end }}
23 23
         </ul>
24 24
     </body>

+ 9 - 1
templates/movie.html

@@ -18,12 +18,20 @@
18 18
             <div>{{ .Movie.Director }}</div>
19 19
         </div>
20 20
 
21
+        <p>Movie file: <a href="/files/{{ .Movie.MovieFile }}">{{ .Movie.MovieFile }}</a></p>
22
+
23
+        <pre>{{ .Movie.MediaInfo }}</pre>
24
+
21 25
         <ul class="file-list">
22 26
             {{ range $f := .Movie.Files }}
23
-            <li>{{ $f }}</li>
27
+            <li><a href="/files/{{ $f }}">{{ $f }}</a></li>
24 28
             {{ end }}
25 29
         </ul>
26 30
 
31
+        <div>
32
+            <form method="post"><input type="submit" name="generate_mediainfo" value="Generate MediaInfo" /></form>
33
+        </div>
34
+
27 35
         <div>
28 36
             <form method="post">
29 37
                 <p>Update file list: <input type="submit" /><br />