this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

track sync

+344 -47
+10
src/core/types.odin
··· 13 13 album_id: Album_Id, 14 14 } 15 15 16 + delete_track :: proc(track: Track, allocator := context.allocator) { 17 + delete(string(track.id)) 18 + delete(string(track.album_id)) 19 + delete(track.title) 20 + 21 + if mb_id, ok := track.mb_id.?; ok { 22 + delete(mb_id) 23 + } 24 + } 25 + 16 26 Artist :: struct { 17 27 id: Artist_Id, 18 28 name: string,
+1
src/db/migrations/01-init.sql
··· 25 25 mb_id TEXT, 26 26 album_id TEXT NOT NULL, 27 27 28 + UNIQUE(title, track_number, album_id) 28 29 FOREIGN KEY(album_id) REFERENCES album(id) ON DELETE CASCADE 29 30 ); 30 31
+34
src/db/repo/album.odin
··· 252 252 253 253 return albums[0], true 254 254 } 255 + 256 + 257 + get_or_create_album :: proc( 258 + db: ^sqlite.Connection, 259 + album: types.Album, 260 + allocator := context.allocator, 261 + ) -> ( 262 + res: types.Album_Id, 263 + ok: bool, 264 + ) { 265 + new_album_id, new_album_err := new_album(db, album) 266 + 267 + if (new_album_err == .None || new_album_err == .UniqueConstraint) == false { 268 + return "", false 269 + } 270 + 271 + fmt.printfln("Album Err %v", new_album_err) 272 + 273 + if (new_album_err == .UniqueConstraint) { 274 + fmt.printfln("Sync, album unique constraint") 275 + existing_album, existing_album_ok := get_album_by_title(db, album.title) 276 + 277 + assert(existing_album_ok) 278 + 279 + defer types.delete_album(existing_album) 280 + 281 + fmt.printfln("Existing Album %v", existing_album) 282 + 283 + delete(string(new_album_id)) 284 + new_album_id = types.Album_Id(strings.clone(string(existing_album.id))) 285 + } 286 + 287 + return new_album_id, true 288 + }
+37
src/db/repo/artist.odin
··· 198 198 199 199 return artist, true 200 200 } 201 + 202 + 203 + get_or_create_artist :: proc( 204 + db: ^sqlite.Connection, 205 + artist: types.Artist, 206 + allocator := context.allocator, 207 + ) -> ( 208 + res: types.Artist_Id, 209 + ok: bool, 210 + ) { 211 + 212 + new_artist_id, new_artist_err := new_artist(db, artist) 213 + 214 + if (new_artist_err == .None || new_artist_err == .UniqueConstraint) == false { 215 + return "", false 216 + } 217 + 218 + fmt.printfln("New artist |%v| with id |%v|", artist.name, new_artist_id) 219 + 220 + if (new_artist_err == .UniqueConstraint) { 221 + 222 + fmt.printfln("Sync, artist unique constraint") 223 + existing_artist, existing_artist_ok := get_artist_by_name(db, artist.name) 224 + 225 + assert(existing_artist_ok) 226 + 227 + defer types.delete_artist(existing_artist) 228 + 229 + fmt.printfln("Existing artist %v", existing_artist) 230 + 231 + delete(string(new_artist_id)) 232 + new_artist_id = types.Artist_Id(strings.clone(string(existing_artist.id))) 233 + } 234 + 235 + return new_artist_id, true 236 + 237 + }
+242
src/db/repo/track.odin
··· 1 + package repo 2 + 3 + import db_pkg "../" 4 + import sqlite "../../../vendor/sqlite" 5 + import sa "../../../vendor/sqlite/addons" 6 + import types "../../core" 7 + import "core:c" 8 + import "core:fmt" 9 + import "core:strings" 10 + 11 + 12 + new_track :: proc( 13 + db: ^sqlite.Connection, 14 + track: types.Track, 15 + allocator := context.allocator, 16 + ) -> ( 17 + new_id: types.Track_Id, 18 + err: db_pkg.DatabaseErrors, 19 + ) { 20 + 21 + fmt.printfln("New Track: %#v", track) 22 + ok: bool 23 + 24 + id := db_pkg.gen_id("track", allocator) 25 + new_id = types.Track_Id(id) 26 + 27 + c_id := strings.clone_to_cstring(id, allocator) 28 + c_title := strings.clone_to_cstring(track.title, allocator) 29 + c_album_id := strings.clone_to_cstring(string(track.album_id), allocator) 30 + 31 + defer { 32 + delete(c_id, allocator) 33 + delete(c_title, allocator) 34 + delete(c_album_id, allocator) 35 + } 36 + 37 + query: cstring = "INSERT INTO track (id, title, album_id, track_number, mb_id) VALUES (?, ?, ?, ?, ?)" 38 + 39 + stmt: ^sqlite.Statement 40 + 41 + fmt.println("before prepare") 42 + 43 + if rc := sqlite.prepare_v2(db, query, c.int(len(query)), &stmt, nil); rc != .Ok { 44 + fmt.eprintfln("prepare error %v", rc) 45 + return new_id, .UnknownError 46 + } 47 + defer sqlite.finalize(stmt) 48 + 49 + fmt.println("after prepare") 50 + 51 + if rc := sqlite.bind_text( 52 + stmt, 53 + param_idx = 1, 54 + param_value = c_id, 55 + param_len = c.int(len(id)), 56 + free = {behaviour = .Static}, 57 + ); rc != .Ok { 58 + fmt.eprintfln("failed to bind value to TrackId. result code: {}", rc) 59 + return new_id, .UnknownError 60 + } 61 + 62 + if rc := sqlite.bind_text( 63 + stmt, 64 + param_idx = 2, 65 + param_value = c_title, 66 + param_len = c.int(len(track.title)), 67 + free = {behaviour = .Static}, 68 + ); rc != .Ok { 69 + fmt.eprintfln("failed to bind value to track title. result code: {}", rc) 70 + return new_id, .UnknownError 71 + } 72 + 73 + if rc := sqlite.bind_text( 74 + stmt, 75 + param_idx = 3, 76 + param_value = c_album_id, 77 + param_len = c.int(len(track.album_id)), 78 + free = {behaviour = .Static}, 79 + ); rc != .Ok { 80 + fmt.eprintfln("failed to bind value to track album id. result code: {}", rc) 81 + return new_id, .UnknownError 82 + } 83 + 84 + 85 + if rc := sqlite.bind_int(stmt, param_idx = 4, param_value = i32(track.track_number)); 86 + rc != .Ok { 87 + fmt.eprintfln("failed to bind value to track album id. result code: {}", rc) 88 + return new_id, .UnknownError 89 + } 90 + 91 + 92 + c_mb_id: cstring 93 + defer delete(c_mb_id, allocator) 94 + 95 + if mb_id, ok := track.mb_id.?; ok { 96 + c_mb_id = strings.clone_to_cstring(mb_id, allocator) 97 + fmt.printfln("%s %s", mb_id, c_mb_id) 98 + 99 + if rc := sqlite.bind_text( 100 + stmt, 101 + param_idx = 5, 102 + param_value = c_mb_id, 103 + param_len = c.int(len(mb_id)), 104 + free = {behaviour = .Static}, 105 + ); rc != .Ok { 106 + fmt.eprintfln("failed to bind value to mb_id. result code: {}", rc) 107 + return new_id, .UnknownError 108 + } 109 + } 110 + 111 + 112 + fmt.printfln("prepared sql: {}\n", sqlite.expanded_sql(stmt)) 113 + 114 + rc := sqlite.step(stmt) 115 + fmt.printfln("Step RC: %v", rc) 116 + if (rc == .Constraint) { 117 + return new_id, .UniqueConstraint 118 + } 119 + if (rc != .Done) { 120 + return new_id, .UnknownError 121 + } 122 + 123 + return new_id, .None 124 + } 125 + 126 + get_track_by_title :: proc( 127 + db: ^sqlite.Connection, 128 + title: string, 129 + album_id: Maybe(types.Album_Id), 130 + allocator := context.allocator, 131 + ) -> ( 132 + res: types.Track, 133 + ok: bool, 134 + ) { 135 + query_with_album: cstring = "SELECT * FROM track WHERE title = ? AND album_id = ? LIMIT 1" 136 + query_without_album: cstring = "SELECT * FROM track WHERE title = ? LIMIT 1" 137 + query := query_without_album 138 + use_album_filter := false 139 + album_id_value := "" 140 + 141 + if v, has_album := album_id.?; has_album { 142 + query = query_with_album 143 + use_album_filter = true 144 + album_id_value = string(v) 145 + } 146 + 147 + stmt: ^sqlite.Statement 148 + 149 + if rc := sqlite.prepare_v2(db, query, c.int(len(query)), &stmt, nil); rc != .Ok { 150 + fmt.eprintfln("failed to prepare statement. result code: {}", rc) 151 + return res, false 152 + } 153 + 154 + defer sqlite.finalize(stmt) 155 + 156 + c_title := strings.clone_to_cstring(title, allocator) 157 + defer delete(c_title) 158 + 159 + if rc := sqlite.bind_text( 160 + stmt, 161 + param_idx = 1, 162 + param_value = c_title, 163 + param_len = c.int(len(title)), 164 + free = {behaviour = .Static}, 165 + ); rc != .Ok { 166 + fmt.eprintfln("failed to bind value to track title. result code: {}", rc) 167 + return res, false 168 + } 169 + 170 + c_album_id: cstring 171 + defer delete(c_album_id) 172 + 173 + if use_album_filter { 174 + c_album_id = strings.clone_to_cstring(album_id_value, allocator) 175 + 176 + if rc := sqlite.bind_text( 177 + stmt, 178 + param_idx = 2, 179 + param_value = c_album_id, 180 + param_len = c.int(len(album_id_value)), 181 + free = {behaviour = .Static}, 182 + ); rc != .Ok { 183 + fmt.eprintfln("failed to bind value to album_id. result code: {}", rc) 184 + return res, false 185 + } 186 + } 187 + 188 + fmt.printfln("prepared sql: {}\n", sqlite.expanded_sql(stmt)) 189 + 190 + if sqlite.step(stmt) != .Row { 191 + return res, false 192 + } 193 + 194 + track := types.Track { 195 + id = types.Track_Id(strings.clone_from(sqlite.column_text(stmt, 0))), 196 + title = strings.clone_from(sqlite.column_text(stmt, 1)), 197 + track_number = u8(sqlite.column_int(stmt, 2)), 198 + album_id = types.Album_Id(strings.clone_from(sqlite.column_text(stmt, 4))), 199 + } 200 + 201 + if mb_id_ptr := sqlite.column_text(stmt, 3); mb_id_ptr != nil { 202 + track.mb_id = strings.clone_from(mb_id_ptr) 203 + } 204 + 205 + return track, true 206 + } 207 + 208 + 209 + get_or_create_track :: proc( 210 + db: ^sqlite.Connection, 211 + track: types.Track, 212 + allocator := context.allocator, 213 + ) -> ( 214 + res: types.Track_Id, 215 + ok: bool, 216 + ) { 217 + 218 + new_track_id, new_track_err := new_track(db, track) 219 + 220 + fmt.printfln("track Err %v", new_track_err) 221 + 222 + if (new_track_err == .None || new_track_err == .UniqueConstraint) == false { 223 + return "", false 224 + } 225 + 226 + 227 + if (new_track_err == .UniqueConstraint) { 228 + fmt.printfln("Sync, track unique constraint") 229 + existing_track, existing_track_ok := get_track_by_title(db, track.title, track.album_id) 230 + 231 + assert(existing_track_ok) 232 + 233 + defer types.delete_track(existing_track) 234 + 235 + fmt.printfln("Existing track %v", existing_track) 236 + 237 + delete(string(new_track_id)) 238 + new_track_id = types.Track_Id(strings.clone(string(existing_track.id))) 239 + } 240 + 241 + return new_track_id, true 242 + }
+20 -47
src/library/sync.odin
··· 96 96 mb_id = flac.mb_artist_id, 97 97 } 98 98 99 + 99 100 fmt.printfln("Flac Comment %#v, artist %#v album %#v", flac, artist, album) 100 101 101 - new_album_id, album_err := db.new_album(db_conn, album) 102 - is_new_album := true 102 + new_album_id, new_album_ok := db.get_or_create_album(db_conn, album) 103 103 defer delete(string(new_album_id)) 104 - 105 - assert(album_err == .None || album_err == .UniqueConstraint) 106 - 107 - fmt.printfln("\n\nAlbum Err %v", album_err) 108 - 109 - if (album_err == .UniqueConstraint) { 110 - is_new_album = false 111 - fmt.printfln("Sync, album unique constraint") 112 - existing_album, existing_album_ok := db.get_album_by_title(db_conn, album.title) 113 - 114 - assert(existing_album_ok) 115 - 116 - defer types.delete_album(existing_album) 117 - 118 - fmt.printfln("Existing Album %v", existing_album) 119 - 120 - delete(string(new_album_id)) 121 - new_album_id = types.Album_Id(strings.clone(string(existing_album.id))) 122 - } 123 - 104 + assert(new_album_ok) 124 105 125 106 fmt.printfln("New album |%v| with id |%v|", album.title, new_album_id) 126 107 127 - new_artist_id, artist_err := db.new_artist(db_conn, artist) 128 - 129 - is_new_artist := true 130 - 108 + new_artist_id, new_artist_ok := db.get_or_create_artist(db_conn, artist) 131 109 defer delete(string(new_artist_id)) 132 - assert(artist_err == .None || artist_err == .UniqueConstraint) 110 + assert(new_artist_ok) 133 111 134 - fmt.printfln("New artist |%v| with id |%v|", artist.name, new_artist_id) 135 112 136 - if (artist_err == .UniqueConstraint) { 137 - is_new_artist = false 138 - 139 - fmt.printfln("Sync, artist unique constraint") 140 - existing_artist, existing_artist_ok := db.get_artist_by_name(db_conn, artist.name) 141 - 142 - assert(existing_artist_ok) 143 - 144 - defer types.delete_artist(existing_artist) 145 - 146 - fmt.printfln("Existing artist %v", existing_artist) 147 - 148 - delete(string(new_artist_id)) 149 - new_artist_id = types.Artist_Id(strings.clone(string(existing_artist.id))) 150 - } 151 - 152 - 153 - if (flac.album_artist == artist.name && (is_new_artist || is_new_album)) { 113 + if (flac.album_artist == artist.name) { 154 114 artist_album := types.ArtistAlbum { 155 115 album_id = new_album_id, 156 116 artist_id = new_artist_id, 157 117 } 158 118 159 119 artist_album_err := db.new_artist_album(db_conn, artist_album) 160 - assert(artist_err == .None || artist_err == .UniqueConstraint) 120 + assert(artist_album_err == .None || artist_album_err == .UniqueConstraint) 121 + } 161 122 123 + 124 + track := types.Track { 125 + id = "", 126 + title = flac.title, 127 + track_number = flac.track_number, 128 + album_id = new_album_id, 162 129 } 130 + 131 + 132 + new_track_id, new_track_ok := db.get_or_create_track(db_conn, track) 133 + defer delete(string(new_track_id)) 134 + assert(new_track_ok) 135 + 163 136 } 164 137 }