I divided my whole project work into following main parts. Each part is created separately and independently of the other part. Or in other words these could be considered as modules. In this way not only development will be easy but also the code will be easier to read and understand. Bug and cause identification will also be easy in this case. These parts are:

  • Creating and Programming the MusicBrainz GUI Dialog: As shown below is the screenshot of MusicBrainz GUI Dialog. Below URLs, links to screenshot of GUI Dialog. Buttons have their usual meaning. Moreover, there’s also a BreadCrumb like Widget above the MetadataTreeView. This will help user navigate through the results shown. Below are some keypoints regarding the implementation details of this GUI Dialog:

    • Automatic Search and Results

      https://dl.dropboxusercontent.com/s/gjc37uopumrjspj/automatic search.png?dl=1&token_hash=AAGQA0T-7fyAaFIEvZWSJNlLPzdSquorL3SmBegvu96QZg

    • Scan Selected

      https://dl.dropboxusercontent.com/s/7e40jzqpzjq7evl/scan selected.png?dl=1&token_hash=AAH1UR2WpwohJl_Nt_4HOTTtm1wYYRr-VNrnQ6jF_GUikA

    • Manual Search

      https://dl.dropboxusercontent.com/s/eepxx7zbv3ljo82/manual search.png?dl=1&token_hash=AAGAvMtX_0L4tVSIev2KWYIa6MiAv6i99-xh-vwtLbbMFw

    • Disc Lookup

      https://dl.dropboxusercontent.com/s/0jqpst67kyork6w/disc_lookup.png?dl=1&token_hash=AAG7CRxSk4LRcpqqLjm9Ki3VcWTXYD2joAWFRDMPgrLe0A

    • Functioning of GUI: Functioning of GUI will be as follows:

      • Up and Down: Through “Up” Button current selection will move up one row and through “Down” Button current selection will move one down row.

      • Invert Selection: Through “Invert Selection” Button, all the current selected rows will become unselected and current unselected row will become selected. Or in other words selection status of rows will be changed.

      • Select All and Unselect All: Through “Select All” Button, all the rows will be selected. Through “Unselect All” Button, all the rows will be unselected.

      • Refresh Entity: Through “Refresh Entity” Button, the current selected Entity’s Metadata data will be refreshed i.e. will be downloaded again from the MusicBrainz servers.

      • Breadcrumb Widget: Breadcrumb is a popular way to help in navigation. It is also used in GNOME’s Nautilus. It will be a GtkButtonBox which will contain GtkToggleButton. The ToggleButton corresponding to the current selected Entity will have the “Pressed” state. All other will have normal. Clicking on the ToggleButton, its corresponding Entity will be selected.

      • Search in Results: User can also search for information in results. Implementing search will be easy by iterating all the rows of EntityListStore.

    • EntityListView: EntityListView is a GtkTreeView displaying the data obtained from the MusicBrainz server in a fashion. Its GtkTreeModel will be a GtkListStore, lets call it EntityListStore. Each node of EntityListStore will also store a pointer to the Tree node representing Mb5Entity. When user will do a search then artist and albums of results will be displayed EntityListView. Double clicking on any row, will display all tracks of the given album with their metadata obtained from MusicBrainz. Breadcrumb widget will also be updated accordingly. Here, you can see an example of search “Backstreet Boys”. All albums of Backstreet Boys are shown, double clicking on any album will show its tracks and their metadata. Backstreet Boys Example: https://dl.dropboxusercontent.com/s/4e93pa0i9ard9mf/bsb example-1.png?dl=1&token_hash=AAG_1n8QaBKDXSXHzDC-UCDgpqRaVzT60hgYm-U_n8AMeg https://dl.dropboxusercontent.com/s/v7ydiqo4ovdq8hu/bsb example0.png?dl=1&token_hash=AAHi-ulfX0wZK27chG392R_BFLAouQQGmsweDMp6L0naCw

      • Clicking on the required album will lead to following:

      https://dl.dropboxusercontent.com/s/41fi0aj9p1qv7uv/bsb example.png?dl=1&token_hash=AAGxl9ONEwctstlelFTT_D8996dIFzu4bbjNxS4HcVnnGQ

    • Storing obtained Metadata: It is required to store all the obtained Metadata information in some way. This will reduce the internet bandwidth consumption if a user requests the Metadata for same entity. All this data could be stored in a data structure. This will save all the information about each Mb5Entity. This could be done by creating a Tree with custom type. Each node of a Tree will store a pointer to the obtained Mb5Entity. This Tree will contain Artist, ReleaseGroup, Release, Work, Label, Recordings. Any information required by above EntityListStore will be taken from Tree.

    • Asynchronous Operation: Whenever this GUI is busy in doing something, then the application may freeze. So, threads will be used in this case. All the libmusicbrainz5's get Metadata operations will be made asynchronous with the help of threads. Although, we can use GThread or pthread but a better way would be to use GTask or GSimpleAsyncResult. Both of them provide functions for running some task in another thread and providing its result in main thread. For this a new function Create_ET_Task() will be created, to create a new GTask. This GTask or will run a new thread in function get_metadata_thread_func() and when this thread will end get_metadata_thread_callback() will called in the main thread.

      • get_metadata_thread_func() is responsible for getting metadata by communicating with MusicBrainz Servers.

      • get_metadata_thread_callback() is responsible for extracting Data for Entities stored in the obtained XML representation of Metadata recieved from above function. mb5_metadata_* and mb5_<entity>_* functions will be used to get the data (by parsing) from the Metadata obtained. Here, <entity> refers to one of the artist, label, recording, release, release-group, work. Data extracted will then be stored in GtkTreeStore.

      Hence, work flow of Create_ET_Task() will be as follows:
      • Create a new GTask and supply get_metadata_thread_callback() argument for callback function.
      • Use g_task_run_in_thread() to run GTask in function get_metadata_thread_func()
      With this libmusicbrainz5's functions will run in one thread and main loop in other thread, hence there will be no GUI blocking.
    • Double Clicking Row in GtkTreeView: Whenever a row is double clicked in the EntityListView. Then application will start communicating with MusicBrainz5 servers to get the Metadata about the Entity in the selected row. Also, Metadata will be shown in the MetadataTreeView. To achieve this following procedure will be adopted:

      • From EntityListStore, get the object representing the Entity in the selected row.

      • Check if Metadata about this object has been already obtained from MusicBrainz servers.

      • If Yes, then display this obtained Metadata.
      • If No, then call Create_ET_Task().
    • Getting Query Parameters: A function get_mb5_query_params() will be used to get the values of parameters to be passed to mb5_query_query() function. get_mb5_query_params() will take one of the parameters representing the type of search i.e. Manual Search or Automatic Search or Disc Lookup or Search With Albums. It will return a pointer to the variable of type QueryParams. QueryParams will contain following members:

      • Entity, a string representing the entity to search.
      • ID, a string representing the MusicBrainz ID of the entity to search.

      • Resource, a string representing Resource.
      • NumParams, an integer representing size of the below string arrays.

      • ParamNames, a string array representing parameter names in search query.

      • ParamValues, a string array representing parameter values in search query.

  • Implementing Manual Search: Manual Search lets user search any word with any of the 6 core entities (i.e. Artist, Release Group, Release, Work, Label, Recording) selected in the MusicBrainz Database. Manual Search will be done after user clicked the Search Button. Whenever user will do Manual Search then a query will be generated containing the query string, corresponding to the search string entered in the GtkComboBoxText and the MusicBrainz5 selected in the GtkComboBox. Through Search Button's clicked handler, following procedure will be done:

    • Use gtk_combo_box_text_get_active_text() to get the string to be searched.
    • Use gtk_combo_box_get_active_text() to get the entity to be searched.
    • Call get_mb5_query_params() to get parameters for creating Mb5Query.

    • Create Mb5Query.

    • Run Create_ET_Task().
  • Implementing Disc Search: Disc Search lets user get metadata about inserted CD's content from MusicBrainz Database. Disc Search will be implemented with the help of libdiscid also. When user will click the Disc Lookup Search button, then its clicked handler will be called. This handler will do the following procedure:

    • Create discid of the inserted CD will be using discid_get_id().
    • Call get_mb5_query_params() to get parameters for creating Mb5Query.

    • Create Mb5Query.

    • Call Create_ET_Task().
  • Implementing Automatic Search: With Automatic Search, user can search for an album of selected files i.e. user will select files of an album and automatically, EasyTAG will search MusicBrainz servers based on the current selection of files. Automatic Search will start whenever user will click the Automatic Search Button. This button’s clicked handler will then get activated. Inside clicked handler following things will happen:

    • Get the common album of all the selected files in EasyTAG’s BrowserFileList.

    • Call get_mb5_query_params() to get parameters for creating Mb5Query.

    • Create a new Mb5Query.

    • Call Create_ET_Task().
  • Implementing Search Files with Albums: This feature is one step ahead of Automatic Search. This feature will group different files into their same album. Then it will search for those albums in MusicBrainz servers and will display the result accordingly. EasyTAG will start searching when Search Files with Album Button will be clicked. This button’s clicked handler will do these things:

    • Iterate through all the selected files in EastyTAG’s BrowserFileList.

    • Store all the albums of selected files in an array.
    • Call get_mb5_query_params() to get parameters for creating Mb5Query for each of the albums.

    • Create a new Mb5Query for all these albums.

    • Call Create_ET_Task() for all of the above Mb5Query.

  • Implementing Apply TAGs to Selected Files: Method of applying TAGs to file will be similar to the present one in EasyTAG's CDDB Dialog. Selected TAGs in EntityListView will be applied to the selected files in the BrowserFileList. This means ith selected TAG will be applied to the ith selected file in BrowserFileList. Whenever user will click on Apply TAGs button, then its clicked handler will be called. This handler will perform the following procedure:

    • Get the GList of selected GtkTreeIter in BrowserFileList using gtk_tree_selection_get_selected_rows(), let this GList be selected_file_iter_list.

    • Get the GList of selected GtkTreeIter in EntityGtkTreeView using gtk_tree_selection_get_selected_rows(), let this GList be selected_track_iter_list.

    • For each iter in both the list, do the following:
    • Call et_create_tag_from_iter().
    • Call et_file_add_tag_from_iter().

    Function et_create_tag_from_iter() will take a GtkTreeIter as its argument and will return a FileTag object which will be created on the basis of passed argument. Function et_file_add_tag_from_iter() will take a GtkTreeIter and a FileTag object as its arguments and will add the passed FileTag to the ETFile represented by the GtkTreeIter.

  • Creating and Programming the MusicBrainz Options GUI: Below is the screenshot of the the MusicBrainz Options GUI page. This will replace the current CDDB Options in the EasyTAG Options GUI Dialog.

    • https://dl.dropboxusercontent.com/s/f3grq2vxr6g1yo3/options.png?dl=1&token_hash=AAFLtnwYfAjy8GZtMkn5uQGS_SZBnhDZcQMjHkUINIXFvA

  • Implementing Options: Above options will be implemented with the help of different libmusicbrainz5 and libdiscid functions. For proxy options libmusicbrainz5's mb5_query_set_proxy* () functions will be used. To set MusicBrainz5's User Authentication mb5_query_set_username and mb5_query_set_password will be used. Moreover, libsecret will help to save user password securely. For setting and retrieving Device Name for Disc Lookup, libdiscid's disc_id_get_device and disc_id_set_device would be used.

  • Unit Test for Above Components: Unit Testing will be done using Glib-Testing and gtester. To add all of the these functions g_test_add_data_func()will be used. Shown below are functions responsible for unit testing different components:

    • Unit Testing for Manual Search: A function for Unit Testing Manual Search will be et_unit_test_manual_search(). Following procedure will be adopted for it:

      • For each of the entity in GtkComboBox, do:

      • Call get_mb5_query_params() with parameters including an example of each of the entity.
      • Use combination of g_assert_strcmp() for each member of the returned value obtained by calling above function.
    • Unit Testing for Automatic Search: A function for Unit Testing Automatic Search will be et_unit_test_automatic_search(). Following procedure will be adopted for it:

      • Call get_mb5_query_params() with parameters including an example of an album.
      • Use combination of g_assert_strcmp() for each member of the returned value obtained by calling above function.
    • Unit Testing for Disc Lookup: A function for Unit Testing Automatic Search will be et_unit_test_disc_lookup(). Following procedure will be adopted for it:

      • Call discid_get_id() to get the discid of insert CD.
      • Call get_mb5_query_params().
      • Use combination of g_assert_strcmp() for each member of the returned value obtained by calling above function.
    • Unit Testing for Search Files with Albums: A function for Unit Testing Automatic Search will be et_unit_test_search_files_with_albums(). Following procedure will be adopted for it:

      • Create an array of albums. This array will contain different examples of albums.
      • Call get_mb5_query_params() for each of the albums in arrays.
      • Use combination of g_assert_strcmp() for each member of the returned value obtained by calling above function.
    • Unit Testing for ApplyTAG: A function for Unit Testing Apply TAG will be et_unit_test_apply_tag(). Following procedure will be adopted for it:

      • Call gtk_tree_selection_set_selected_rows() for MetadataGtkTreeView.

      • Call gtk_tree_selection_set_selected_rows() for BrowserFileList.

      • Call et_create_tag_from_iter() for each of the selected GtkTreeRow.

      • Use combination of g_asser_strcmp() for each member of FileTag returned from the above function.

  • Functional Test: get_metadata_thread_func() should also be tested to ensure that this function works correctly for obtaining metadata about the requested entity from MusicBrainz server. But, in order to test this it is not possible that every time while testing this function internet will be used because otherwise this will lead to high internet usage. So, to test this function we can create a mocked MusicBrainz server. This server could be created by libsoup and will be of type SoupServer. A function et_get_metadata_test() will be used to do the functional testing. This function will do the following work:

    • Call soup_server_new() to create a new SoupServer.

    • Use soup_server_add_handler() to add a handler for any url.
    • Create Mb5Query with server name as “localhost” and port as the one specified earlier in Step 1.

    • Call get_metadata_thread_func().
    • Use a series of g_assert_strcmp() to compare the results obtained from Metadata with what is desired.

AbhinavJangda/GSoC14MusicBrainzTimeline (last edited 2014-05-08 09:39:18 by AbhinavJangda)