preset.go
⎇
Raw
1package repository
2
3import (
4 "database/sql"
5 "fmt"
6
7 "vidarchive/internal/models"
8)
9
10type PresetRepository struct {
11 db *sql.DB
12}
13
14func NewPresetRepository(db *sql.DB) *PresetRepository {
15 return &PresetRepository{db: db}
16}
17
18func insertPreset(tx *sql.Tx, p *models.Preset) error {
19 result, err := tx.Exec(
20 `INSERT INTO presets (name, description, is_default, format_mode, format, quality, custom_format, extract_audio, audio_format, embed_subs, sub_langs, embed_thumbnail, embed_metadata, write_info_json, write_comments, comment_sort, max_comments, comment_extractor_args, custom_flags)
21 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
22 p.Name, p.Description, boolToInt(p.IsDefault), p.FormatMode, p.Format, p.Quality, p.CustomFormat,
23 boolToInt(p.ExtractAudio), p.AudioFormat, boolToInt(p.EmbedSubs), p.SubLangs,
24 boolToInt(p.EmbedThumbnail), boolToInt(p.EmbedMetadata), boolToInt(p.WriteInfoJSON),
25 boolToInt(p.WriteComments), p.CommentSort, p.MaxComments, p.CommentExtractorArgs,
26 p.CustomFlags,
27 )
28 if err != nil {
29 return err
30 }
31 id, err := result.LastInsertId()
32 if err != nil {
33 return fmt.Errorf("preset last insert id: %w", err)
34 }
35 p.ID = id
36 return nil
37}
38
39func updatePreset(tx *sql.Tx, p *models.Preset) error {
40 _, err := tx.Exec(
41 `UPDATE presets SET name=?, description=?, is_default=?, format_mode=?, format=?, quality=?, custom_format=?, extract_audio=?, audio_format=?, embed_subs=?, sub_langs=?, embed_thumbnail=?, embed_metadata=?, write_info_json=?, write_comments=?, comment_sort=?, max_comments=?, comment_extractor_args=?, custom_flags=?
42 WHERE id=?`,
43 p.Name, p.Description, boolToInt(p.IsDefault), p.FormatMode, p.Format, p.Quality, p.CustomFormat,
44 boolToInt(p.ExtractAudio), p.AudioFormat, boolToInt(p.EmbedSubs), p.SubLangs,
45 boolToInt(p.EmbedThumbnail), boolToInt(p.EmbedMetadata), boolToInt(p.WriteInfoJSON),
46 boolToInt(p.WriteComments), p.CommentSort, p.MaxComments, p.CommentExtractorArgs,
47 p.CustomFlags, p.ID,
48 )
49 return err
50}
51
52func clearDefault(tx *sql.Tx) error {
53 _, err := tx.Exec(`UPDATE presets SET is_default = 0`)
54 return err
55}
56
57// Save persists p, inserting it when it has no id yet and updating it otherwise.
58// When p is the new default it first clears the previous default, doing all of it
59// within a single transaction so a mid-sequence failure can't leave the library
60// with no default set. Create and Update both route through here, so the
61// exclusive-default invariant can't be bypassed.
62func (r *PresetRepository) Save(p *models.Preset) error {
63 tx, err := r.db.Begin()
64 if err != nil {
65 return err
66 }
67 defer tx.Rollback()
68
69 if p.IsDefault {
70 if err := clearDefault(tx); err != nil {
71 return err
72 }
73 }
74 if p.ID == 0 {
75 err = insertPreset(tx, p)
76 } else {
77 err = updatePreset(tx, p)
78 }
79 if err != nil {
80 return err
81 }
82 return tx.Commit()
83}
84
85func (r *PresetRepository) GetByID(id int64) (*models.Preset, error) {
86 row := r.db.QueryRow(
87 `SELECT id, name, description, is_default, format_mode, format, quality, custom_format, extract_audio, audio_format, embed_subs, sub_langs, embed_thumbnail, embed_metadata, write_info_json, write_comments, comment_sort, max_comments, comment_extractor_args, custom_flags, created_at
88 FROM presets WHERE id = ?`, id,
89 )
90 return scanPreset(row)
91}
92
93func (r *PresetRepository) GetAll() ([]*models.Preset, error) {
94 rows, err := r.db.Query(
95 `SELECT id, name, description, is_default, format_mode, format, quality, custom_format, extract_audio, audio_format, embed_subs, sub_langs, embed_thumbnail, embed_metadata, write_info_json, write_comments, comment_sort, max_comments, comment_extractor_args, custom_flags, created_at
96 FROM presets ORDER BY name`,
97 )
98 if err != nil {
99 return nil, err
100 }
101 defer rows.Close()
102
103 var presets []*models.Preset
104 for rows.Next() {
105 p, err := scanPreset(rows)
106 if err != nil {
107 return nil, err
108 }
109 presets = append(presets, p)
110 }
111 return presets, rows.Err()
112}
113
114func (r *PresetRepository) GetDefault() (*models.Preset, error) {
115 row := r.db.QueryRow(
116 `SELECT id, name, description, is_default, format_mode, format, quality, custom_format, extract_audio, audio_format, embed_subs, sub_langs, embed_thumbnail, embed_metadata, write_info_json, write_comments, comment_sort, max_comments, comment_extractor_args, custom_flags, created_at
117 FROM presets WHERE is_default = 1 LIMIT 1`,
118 )
119 return scanPreset(row)
120}
121
122func (r *PresetRepository) Delete(id int64) error {
123 _, err := r.db.Exec(`DELETE FROM presets WHERE id = ?`, id)
124 return err
125}
126
127func scanPreset(row interface{ Scan(...interface{}) error }) (*models.Preset, error) {
128 var p models.Preset
129 var isDefault, extractAudio, embedSubs, embedThumbnail, embedMetadata, writeInfoJSON, writeComments, maxComments int
130 var description, formatMode, format, quality, customFormat, audioFormat, subLangs, commentSort, commentExtractorArgs, customFlags sql.NullString
131 err := row.Scan(
132 &p.ID, &p.Name, &description, &isDefault, &formatMode, &format, &quality, &customFormat,
133 &extractAudio, &audioFormat, &embedSubs, &subLangs,
134 &embedThumbnail, &embedMetadata, &writeInfoJSON,
135 &writeComments, &commentSort, &maxComments, &commentExtractorArgs,
136 &customFlags, &p.CreatedAt,
137 )
138 if err != nil {
139 return nil, err
140 }
141 p.Description = description.String
142 p.FormatMode = formatMode.String
143 p.Format = format.String
144 p.Quality = quality.String
145 p.CustomFormat = customFormat.String
146 p.AudioFormat = audioFormat.String
147 p.SubLangs = subLangs.String
148 p.CustomFlags = customFlags.String
149 p.CommentSort = commentSort.String
150 p.CommentExtractorArgs = commentExtractorArgs.String
151 p.MaxComments = maxComments
152 p.IsDefault = isDefault == 1
153 p.ExtractAudio = extractAudio == 1
154 p.EmbedSubs = embedSubs == 1
155 p.EmbedThumbnail = embedThumbnail == 1
156 p.EmbedMetadata = embedMetadata == 1
157 p.WriteInfoJSON = writeInfoJSON == 1
158 p.WriteComments = writeComments == 1
159 return &p, nil
160}
161
162func boolToInt(b bool) int {
163 if b {
164 return 1
165 }
166 return 0
167}
168