Daniel@0: /* Part of DML (Digital Music Laboratory) Daniel@0: Copyright 2014-2015 Samer Abdallah, University of London Daniel@0: Daniel@0: This program is free software; you can redistribute it and/or Daniel@0: modify it under the terms of the GNU General Public License Daniel@0: as published by the Free Software Foundation; either version 2 Daniel@0: of the License, or (at your option) any later version. Daniel@0: Daniel@0: This program is distributed in the hope that it will be useful, Daniel@0: but WITHOUT ANY WARRANTY; without even the implied warranty of Daniel@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Daniel@0: GNU General Public License for more details. Daniel@0: Daniel@0: You should have received a copy of the GNU General Public Daniel@0: License along with this library; if not, write to the Free Software Daniel@0: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Daniel@0: */ Daniel@0: Daniel@0: :- module(ilm_p2r, []). Daniel@0: Daniel@0: /** Access to ILM database Daniel@0: */ Daniel@0: Daniel@0: Daniel@0: :- use_module(library(odbc)). Daniel@0: :- use_module(library(musicbrainz)). Daniel@0: :- use_module(library(semweb/rdf_db)). Daniel@0: :- use_module(library(termutils)). Daniel@0: :- use_module(library(odbcutils)). Daniel@0: :- use_module(library(rdfutils)). Daniel@0: :- use_module(library(dcg_core)). Daniel@0: :- use_module(library(dcg/basics)). Daniel@0: :- use_module(entailment(p2r)). Daniel@0: :- use_module(cliopatria(hooks)). Daniel@0: Daniel@0: :- set_prolog_flag(double_quotes,string). Daniel@0: Daniel@0: :- rdf_register_prefix(ilm,'http://dml.org/ilm/'). Daniel@0: Daniel@0: :- setting( ilm_genres,list(atom), Daniel@0: ['Classical','Jazz','Latin','Blues','Folk','Electronic','Reggae','Rock & Roll'], Daniel@0: "List of ILM genre names to import"). Daniel@0: Daniel@0: :- public import/0. Daniel@0: import :- with_odbc(ilm, assert_all(ilm_p2r)). Daniel@0: Daniel@0: :- rdf_meta map(+,r,+,o). Daniel@0: Daniel@0: % ---------------------------- utilities ----------------------------- Daniel@0: Daniel@0: %% genre_list_member(-Genre:uri, +GenreList:atom) is nondet. Daniel@0: genre_list_member(Genre,Atom) :- Daniel@0: parse_list_member(';',Atom,GenreName), Daniel@0: number_string(GenreId,GenreName), Daniel@0: uripattern:pattern_uri(ilm:genre/num(5,GenreId),Genre). Daniel@0: Daniel@0: %% parse_list_member(+Sep:text,+Text:text,-Item:string) is nondet. Daniel@0: parse_list_member(Sep,Atom,Item) :- Daniel@0: split_string(Atom,Sep,'',Items), Daniel@0: member(Item,Items). Daniel@0: % ---------------------- getting stuff out of database --------------------- Daniel@0: Daniel@0: genre_album(Genre,AlbumId) :- Daniel@0: qsql(ilm,"select distinct album_id from assets where genre_id=~d and track_no!=0",[Genre],row(AlbumId)). Daniel@0: Daniel@0: album_facet(AlbumId,Prop-Val) :- entity_facet(album,AlbumId,Prop,Val). Daniel@0: Daniel@0: genre_track(Genre,AlbumId-TrackNo) :- Daniel@0: qsql(ilm,"select album_id, track_no from assets where genre_id=~d and track_no!=0",[Genre],row(AlbumId,TrackNo)). Daniel@0: Daniel@0: track_facet(AlbumId-TrackNo,Prop-Val) :- entity_facet(track,AlbumId-TrackNo,Prop,Val). Daniel@0: Daniel@0: query_columns(album, Daniel@0: [ album_title, product_artist, product_classifications, product_genre, Daniel@0: product_release_year, product_label, product_upc ]). Daniel@0: query_columns(track, Daniel@0: [ assets_online, artist_name, comment, genre_id, release_year, song_title, Daniel@0: track_classifications, track_duration, track_isrc]). Daniel@0: Daniel@0: entity_facet(Type,Id,Prop,Val) :- Daniel@0: query_columns(Type,Cols), Daniel@0: pairs_keys_values(Pairs,Cols,Vals), Daniel@0: Row =.. [row|Vals], Daniel@0: phrase(entity_query(Type,Id,Cols),Codes,[]), Daniel@0: qsql(ilm,'~s',[Codes],Row), Daniel@0: member(Prop-Val,Pairs), Daniel@0: Val\='$null$', Daniel@0: Val\=''. Daniel@0: Daniel@0: entity_query(album,AlbumId,Cols) --> Daniel@0: "select ", Daniel@0: seqmap_with_sep(",",atom,Cols), Daniel@0: " from assets where album_id=", number(AlbumId). Daniel@0: Daniel@0: entity_query(track,AlbumId-TrackNo,Cols) --> Daniel@0: "select ", Daniel@0: seqmap_with_sep(",",atom,Cols), Daniel@0: " from assets where album_id=", number(AlbumId), Daniel@0: " and track_no=", number(TrackNo). Daniel@0: Daniel@0: include_genre(GenreId,Genre) :- Daniel@0: setting(ilm_genres,Genres), Daniel@0: member(Genre,Genres), Daniel@0: qsql(ilm,"select ID from classifications where name='~s'",[Genre],row(GenreId)). Daniel@0: Daniel@0: Daniel@0: % -------------------- mapping to rdf ---------------------------------- Daniel@0: Daniel@0: Daniel@0: rdf(ilm:genre/num(5,GenreID),rdf:type,mo:'Genre'), Daniel@0: rdf(ilm:genre/num(5,GenreID),rdfs:label,literal(GenreName)) <== Daniel@0: odbc_query(ilm,"select ID, name from classifications",row(GenreID,GenreName)). Daniel@0: Daniel@0: rdf(ilm:album/num(AlbumId), Pred, Obj) <== Daniel@0: include_genre(GenreId,GenreName), Daniel@0: status("Querying albums of genre ~w...",[GenreName]), Daniel@0: genre_album(GenreId,AlbumId), Daniel@0: status("Importing ILM albums, genre ~w: ~d",[GenreName, AlbumId]), Daniel@0: album_facet(AlbumId,Facet), Daniel@0: map(Facet,Pred,Obj). Daniel@0: Daniel@0: rdf(ilm:track/num(AlbumId)/num(TrackNo), Pred, Obj) <== Daniel@0: include_genre(GenreId,GenreName), Daniel@0: status("Querying tracks of genre ~w...",[GenreName]), Daniel@0: genre_track(GenreId,AlbumId-TrackNo), Daniel@0: status("Importing ILM tracks, genre ~w: ~d/~d",[GenreName, AlbumId, TrackNo]), Daniel@0: ( Facet=track_no-TrackNo Daniel@0: ; Facet=album_id-AlbumId Daniel@0: ; track_facet(AlbumId-TrackNo,Facet) Daniel@0: ), Daniel@0: map(Facet,Pred,Obj). Daniel@0: Daniel@0: map(Prop-Val,Pred,Obj) :- Daniel@0: ( map(Prop,Pred,Val,Obj) *-> true Daniel@0: ; print_message(warning,ilm_p2r:unrecognized_column(Prop,Val)), fail Daniel@0: ). Daniel@0: Daniel@0: Daniel@0: % album level Daniel@0: map(album_title , dc:title, X, literal(X)). Daniel@0: map(product_label , mo:label, X, literal(X)). Daniel@0: map(product_artist , ilm:artist, X, literal(X)). Daniel@0: map(product_upc , ilm:upc, X, literal(X)). Daniel@0: map(product_release_year, ilm:release_date, Y, literal(type(xsd:date,YA))) :- atom_number(YA,Y). Daniel@0: map(product_classifications, mo:genre, Atom, Genre) :- genre_list_member(Genre,Atom). Daniel@0: map(product_genre, ilm:genre, Id, Obj) :- uripattern:pattern_uri(ilm:genre/num(5,Id),Obj). Daniel@0: Daniel@0: % track level Daniel@0: map(genre_id, ilm:genre, Id, Obj) :- uripattern:pattern_uri(ilm:genre/num(5,Id),Obj). Daniel@0: map(album_id, ilm:album, X, Album) :- uripattern:pattern_uri(ilm:album/num(X),Album). Daniel@0: map(track_no, mo:track_number, X, literal(type(xsd:nonNegativeInteger,X))). Daniel@0: map(track_isrc, mo:isrc, X, literal(type(xsd:string,X))). Daniel@0: map(song_title, dc:title, X, literal(X)). Daniel@0: map(comment, ilm:comment, X, literal(X)). Daniel@0: map(artist_name, ilm:artist, X, literal(X)). Daniel@0: map(track_classifications, mo:genre, X, Genre) :- genre_list_member(Genre,X). Daniel@0: map(track_duration, mo:duration, X, literal(type(xsd:float,Millis))) :- Daniel@0: parse_duration_millis(X,Millis). Daniel@0: Daniel@0: map(release_year, ilm:release_date, Y, literal(type(xsd:date,YA))) :- atom_number(YA,Y). Daniel@0: map(assets_online, ilm:asset_online, Atom, literal(Type)) :- Daniel@0: parse_list_member(',',Atom,TypeS), Daniel@0: atom_string(Type,TypeS). Daniel@0: Daniel@0: % map(P,ilm:P,date(Y,M,D),literal(type(xsd:date,Date))) :- Daniel@0: % format_time(atom(Date),'%F',date(Y,M,D)). Daniel@0: % map(P,ilm:P,timestamp(YY,MM,DD,H,M,S,_),literal(type(xsd:dateTime, DateTime))) :- !, Daniel@0: % format_time(atom(DateTime),'%FT%T',date(YY,MM,DD,H,M,S,0,-,-)).