prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Possibly make `thumbnail` null for audio files without artwork
  ## Description
  <!-- Concisely describe the bug. -->
  
  Currently the frontend tries to fetch thumbnails for all audio files regardless of whether the audio file in question has one or not. 
  I noticed that the API returns the thumbnail URL for all tracks. That makes sense, but could we improve this to be `null` for audio tracks without artwork? Then we could check the field in the frontend before making a network request.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `api/catalog/api/serializers/audio_serializers.py`
  Content:
  ```
  1 from rest_framework import serializers
  2 
  3 from elasticsearch_dsl.response import Hit
  4 
  5 from catalog.api.constants.field_order import field_position_map
  6 from catalog.api.constants.field_values import AUDIO_CATEGORIES, LENGTHS
  7 from catalog.api.docs.media_docs import fields_to_md
  8 from catalog.api.models import Audio, AudioReport, AudioSet
  9 from catalog.api.serializers.fields import (
  10     EnumCharField,
  11     SchemableHyperlinkedIdentityField,
  12 )
  13 from catalog.api.serializers.media_serializers import (
  14     MediaReportRequestSerializer,
  15     MediaSearchRequestSerializer,
  16     MediaSearchSerializer,
  17     MediaSerializer,
  18     get_hyperlinks_serializer,
  19     get_search_request_source_serializer,
  20 )
  21 
  22 
  23 #######################
  24 # Request serializers #
  25 #######################
  26 
  27 
  28 AudioSearchRequestSourceSerializer = get_search_request_source_serializer("audio")
  29 
  30 
  31 class AudioSearchRequestSerializer(
  32     AudioSearchRequestSourceSerializer,
  33     MediaSearchRequestSerializer,
  34 ):
  35     """Parse and validate search query string parameters."""
  36 
  37     fields_names = [
  38         *MediaSearchRequestSerializer.fields_names,
  39         *AudioSearchRequestSourceSerializer.field_names,
  40         "category",
  41         "length",
  42     ]
  43     """
  44     Keep the fields names in sync with the actual fields below as this list is
  45     used to generate Swagger documentation.
  46     """
  47 
  48     category = EnumCharField(
  49         plural="categories",
  50         enum_class=AUDIO_CATEGORIES,
  51         required=False,
  52     )
  53     length = EnumCharField(
  54         plural="lengths",
  55         enum_class=LENGTHS,
  56         required=False,
  57     )
  58 
  59 
  60 class AudioReportRequestSerializer(MediaReportRequestSerializer):
  61     class Meta(MediaReportRequestSerializer.Meta):
  62         model = AudioReport
  63 
  64 
  65 ########################
  66 # Response serializers #
  67 ########################
  68 
  69 
  70 class AudioSetSerializer(serializers.ModelSerializer):
  71     """An audio set, rendered as a part of the ``AudioSerializer`` output."""
  72 
  73     class Meta:
  74         model = AudioSet
  75         fields = [
  76             "title",
  77             "foreign_landing_url",
  78             "creator",
  79             "creator_url",
  80             "url",
  81             "filesize",
  82             "filetype",
  83         ]
  84 
  85 
  86 AudioHyperlinksSerializer = get_hyperlinks_serializer("audio")
  87 
  88 
  89 class AudioSerializer(AudioHyperlinksSerializer, MediaSerializer):
  90     """A single audio file. Used in search results."""
  91 
  92     class Meta:
  93         model = Audio
  94         fields = sorted(  # keep this list ordered logically
  95             [
  96                 *MediaSerializer.Meta.fields,
  97                 *AudioHyperlinksSerializer.field_names,
  98                 "genres",
  99                 "alt_files",
  100                 "audio_set",
  101                 "duration",
  102                 "bit_rate",
  103                 "sample_rate",
  104                 "waveform",  # hyperlink to the endpoint that generates the waveform
  105                 "peaks",  # waveform peaks, if they have already been generated
  106             ],
  107             key=lambda val: field_position_map.get(val, 999),
  108         )
  109         """
  110         Keep the fields names in sync with the actual fields below as this list is
  111         used to generate Swagger documentation.
  112         """
  113 
  114     audio_set = AudioSetSerializer(
  115         allow_null=True,
  116         help_text="Reference to set of which this track is a part.",
  117         read_only=True,
  118     )
  119 
  120     waveform = SchemableHyperlinkedIdentityField(
  121         read_only=True,
  122         view_name="audio-waveform",
  123         lookup_field="identifier",
  124         help_text="A direct link to the waveform peaks.",
  125     )
  126 
  127     # Add-on data
  128     peaks = serializers.SerializerMethodField(
  129         help_text="The list of peaks used to generate the waveform for the audio."
  130     )
  131 
  132     @staticmethod
  133     def get_peaks(obj) -> list[int]:
  134         if isinstance(obj, Hit):
  135             obj = Audio.objects.get(identifier=obj.identifier)
  136         return obj.get_waveform()
  137 
  138 
  139 class AudioSearchSerializer(MediaSearchSerializer):
  140     """
  141     The full audio search response.
  142     This serializer is purely representational and not actually used to
  143     serialize the response.
  144     """
  145 
  146     results = AudioSerializer(
  147         many=True,
  148         help_text=(
  149             "An array of audios and their details such as "
  150             f"{fields_to_md(AudioSerializer.Meta.fields)}."
  151         ),
  152     )
  153 
  154 
  155 ##########################
  156 # Additional serializers #
  157 ##########################
  158 
  159 
  160 class AudioWaveformSerializer(serializers.Serializer):
  161     len = serializers.SerializerMethodField()
  162     points = serializers.ListField(
  163         child=serializers.FloatField(min_value=0, max_value=1)
  164     )
  165 
  166     @staticmethod
  167     def get_len(obj) -> int:
  168         return len(obj.get("points", []))
  169
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/api/catalog/api/serializers/audio_serializers.py b/api/catalog/api/serializers/audio_serializers.py
  --- a/api/catalog/api/serializers/audio_serializers.py
  +++ b/api/catalog/api/serializers/audio_serializers.py
  @@ -135,6 +135,18 @@
               obj = Audio.objects.get(identifier=obj.identifier)
           return obj.get_waveform()
   
  +    def to_representation(self, instance):
  +        # Get the original representation
  +        output = super().to_representation(instance)
  +
  +        if isinstance(instance, Hit):
  +            # TODO: Remove when updating ES indexes
  +            audio = Audio.objects.get(identifier=instance.identifier)
  +            if not audio.thumbnail:
  +                output["thumbnail"] = None
  +
  +        return output
  +
   
   class AudioSearchSerializer(MediaSearchSerializer):
       """
  
verification_info: {"golden_diff": "diff --git a/api/catalog/api/serializers/audio_serializers.py b/api/catalog/api/serializers/audio_serializers.py\n--- a/api/catalog/api/serializers/audio_serializers.py\n+++ b/api/catalog/api/serializers/audio_serializers.py\n@@ -135,6 +135,18 @@\n             obj = Audio.objects.get(identifier=obj.identifier)\n         return obj.get_waveform()\n \n+    def to_representation(self, instance):\n+        # Get the original representation\n+        output = super().to_representation(instance)\n+\n+        if isinstance(instance, Hit):\n+            # TODO: Remove when updating ES indexes\n+            audio = Audio.objects.get(identifier=instance.identifier)\n+            if not audio.thumbnail:\n+                output[\"thumbnail\"] = None\n+\n+        return output\n+\n \n class AudioSearchSerializer(MediaSearchSerializer):\n     \"\"\"\n", "issue": "Possibly make `thumbnail` null for audio files without artwork\n## Description\r\n<!-- Concisely describe the bug. -->\r\n\r\nCurrently the frontend tries to fetch thumbnails for all audio files regardless of whether the audio file in question has one or not. \r\nI noticed that the API returns the thumbnail URL for all tracks. That makes sense, but could we improve this to be `null` for audio tracks without artwork? Then we could check the field in the frontend before making a network request.\n", "before_files": [{"content": "from rest_framework import serializers\n\nfrom elasticsearch_dsl.response import Hit\n\nfrom catalog.api.constants.field_order import field_position_map\nfrom catalog.api.constants.field_values import AUDIO_CATEGORIES, LENGTHS\nfrom catalog.api.docs.media_docs import fields_to_md\nfrom catalog.api.models import Audio, AudioReport, AudioSet\nfrom catalog.api.serializers.fields import (\n    EnumCharField,\n    SchemableHyperlinkedIdentityField,\n)\nfrom catalog.api.serializers.media_serializers import (\n    MediaReportRequestSerializer,\n    MediaSearchRequestSerializer,\n    MediaSearchSerializer,\n    MediaSerializer,\n    get_hyperlinks_serializer,\n    get_search_request_source_serializer,\n)\n\n\n#######################\n# Request serializers #\n#######################\n\n\nAudioSearchRequestSourceSerializer = get_search_request_source_serializer(\"audio\")\n\n\nclass AudioSearchRequestSerializer(\n    AudioSearchRequestSourceSerializer,\n    MediaSearchRequestSerializer,\n):\n    \"\"\"Parse and validate search query string parameters.\"\"\"\n\n    fields_names = [\n        *MediaSearchRequestSerializer.fields_names,\n        *AudioSearchRequestSourceSerializer.field_names,\n        \"category\",\n        \"length\",\n    ]\n    \"\"\"\n    Keep the fields names in sync with the actual fields below as this list is\n    used to generate Swagger documentation.\n    \"\"\"\n\n    category = EnumCharField(\n        plural=\"categories\",\n        enum_class=AUDIO_CATEGORIES,\n        required=False,\n    )\n    length = EnumCharField(\n        plural=\"lengths\",\n        enum_class=LENGTHS,\n        required=False,\n    )\n\n\nclass AudioReportRequestSerializer(MediaReportRequestSerializer):\n    class Meta(MediaReportRequestSerializer.Meta):\n        model = AudioReport\n\n\n########################\n# Response serializers #\n########################\n\n\nclass AudioSetSerializer(serializers.ModelSerializer):\n    \"\"\"An audio set, rendered as a part of the ``AudioSerializer`` output.\"\"\"\n\n    class Meta:\n        model = AudioSet\n        fields = [\n            \"title\",\n            \"foreign_landing_url\",\n            \"creator\",\n            \"creator_url\",\n            \"url\",\n            \"filesize\",\n            \"filetype\",\n        ]\n\n\nAudioHyperlinksSerializer = get_hyperlinks_serializer(\"audio\")\n\n\nclass AudioSerializer(AudioHyperlinksSerializer, MediaSerializer):\n    \"\"\"A single audio file. Used in search results.\"\"\"\n\n    class Meta:\n        model = Audio\n        fields = sorted(  # keep this list ordered logically\n            [\n                *MediaSerializer.Meta.fields,\n                *AudioHyperlinksSerializer.field_names,\n                \"genres\",\n                \"alt_files\",\n                \"audio_set\",\n                \"duration\",\n                \"bit_rate\",\n                \"sample_rate\",\n                \"waveform\",  # hyperlink to the endpoint that generates the waveform\n                \"peaks\",  # waveform peaks, if they have already been generated\n            ],\n            key=lambda val: field_position_map.get(val, 999),\n        )\n        \"\"\"\n        Keep the fields names in sync with the actual fields below as this list is\n        used to generate Swagger documentation.\n        \"\"\"\n\n    audio_set = AudioSetSerializer(\n        allow_null=True,\n        help_text=\"Reference to set of which this track is a part.\",\n        read_only=True,\n    )\n\n    waveform = SchemableHyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-waveform\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the waveform peaks.\",\n    )\n\n    # Add-on data\n    peaks = serializers.SerializerMethodField(\n        help_text=\"The list of peaks used to generate the waveform for the audio.\"\n    )\n\n    @staticmethod\n    def get_peaks(obj) -> list[int]:\n        if isinstance(obj, Hit):\n            obj = Audio.objects.get(identifier=obj.identifier)\n        return obj.get_waveform()\n\n\nclass AudioSearchSerializer(MediaSearchSerializer):\n    \"\"\"\n    The full audio search response.\n    This serializer is purely representational and not actually used to\n    serialize the response.\n    \"\"\"\n\n    results = AudioSerializer(\n        many=True,\n        help_text=(\n            \"An array of audios and their details such as \"\n            f\"{fields_to_md(AudioSerializer.Meta.fields)}.\"\n        ),\n    )\n\n\n##########################\n# Additional serializers #\n##########################\n\n\nclass AudioWaveformSerializer(serializers.Serializer):\n    len = serializers.SerializerMethodField()\n    points = serializers.ListField(\n        child=serializers.FloatField(min_value=0, max_value=1)\n    )\n\n    @staticmethod\n    def get_len(obj) -> int:\n        return len(obj.get(\"points\", []))\n", "path": "api/catalog/api/serializers/audio_serializers.py"}], "after_files": [{"content": "from rest_framework import serializers\n\nfrom elasticsearch_dsl.response import Hit\n\nfrom catalog.api.constants.field_order import field_position_map\nfrom catalog.api.constants.field_values import AUDIO_CATEGORIES, LENGTHS\nfrom catalog.api.docs.media_docs import fields_to_md\nfrom catalog.api.models import Audio, AudioReport, AudioSet\nfrom catalog.api.serializers.fields import (\n    EnumCharField,\n    SchemableHyperlinkedIdentityField,\n)\nfrom catalog.api.serializers.media_serializers import (\n    MediaReportRequestSerializer,\n    MediaSearchRequestSerializer,\n    MediaSearchSerializer,\n    MediaSerializer,\n    get_hyperlinks_serializer,\n    get_search_request_source_serializer,\n)\n\n\n#######################\n# Request serializers #\n#######################\n\n\nAudioSearchRequestSourceSerializer = get_search_request_source_serializer(\"audio\")\n\n\nclass AudioSearchRequestSerializer(\n    AudioSearchRequestSourceSerializer,\n    MediaSearchRequestSerializer,\n):\n    \"\"\"Parse and validate search query string parameters.\"\"\"\n\n    fields_names = [\n        *MediaSearchRequestSerializer.fields_names,\n        *AudioSearchRequestSourceSerializer.field_names,\n        \"category\",\n        \"length\",\n    ]\n    \"\"\"\n    Keep the fields names in sync with the actual fields below as this list is\n    used to generate Swagger documentation.\n    \"\"\"\n\n    category = EnumCharField(\n        plural=\"categories\",\n        enum_class=AUDIO_CATEGORIES,\n        required=False,\n    )\n    length = EnumCharField(\n        plural=\"lengths\",\n        enum_class=LENGTHS,\n        required=False,\n    )\n\n\nclass AudioReportRequestSerializer(MediaReportRequestSerializer):\n    class Meta(MediaReportRequestSerializer.Meta):\n        model = AudioReport\n\n\n########################\n# Response serializers #\n########################\n\n\nclass AudioSetSerializer(serializers.ModelSerializer):\n    \"\"\"An audio set, rendered as a part of the ``AudioSerializer`` output.\"\"\"\n\n    class Meta:\n        model = AudioSet\n        fields = [\n            \"title\",\n            \"foreign_landing_url\",\n            \"creator\",\n            \"creator_url\",\n            \"url\",\n            \"filesize\",\n            \"filetype\",\n        ]\n\n\nAudioHyperlinksSerializer = get_hyperlinks_serializer(\"audio\")\n\n\nclass AudioSerializer(AudioHyperlinksSerializer, MediaSerializer):\n    \"\"\"A single audio file. Used in search results.\"\"\"\n\n    class Meta:\n        model = Audio\n        fields = sorted(  # keep this list ordered logically\n            [\n                *MediaSerializer.Meta.fields,\n                *AudioHyperlinksSerializer.field_names,\n                \"genres\",\n                \"alt_files\",\n                \"audio_set\",\n                \"duration\",\n                \"bit_rate\",\n                \"sample_rate\",\n                \"waveform\",  # hyperlink to the endpoint that generates the waveform\n                \"peaks\",  # waveform peaks, if they have already been generated\n            ],\n            key=lambda val: field_position_map.get(val, 999),\n        )\n        \"\"\"\n        Keep the fields names in sync with the actual fields below as this list is\n        used to generate Swagger documentation.\n        \"\"\"\n\n    audio_set = AudioSetSerializer(\n        allow_null=True,\n        help_text=\"Reference to set of which this track is a part.\",\n        read_only=True,\n    )\n\n    waveform = SchemableHyperlinkedIdentityField(\n        read_only=True,\n        view_name=\"audio-waveform\",\n        lookup_field=\"identifier\",\n        help_text=\"A direct link to the waveform peaks.\",\n    )\n\n    # Add-on data\n    peaks = serializers.SerializerMethodField(\n        help_text=\"The list of peaks used to generate the waveform for the audio.\"\n    )\n\n    @staticmethod\n    def get_peaks(obj) -> list[int]:\n        if isinstance(obj, Hit):\n            obj = Audio.objects.get(identifier=obj.identifier)\n        return obj.get_waveform()\n\n    def to_representation(self, instance):\n        # Get the original representation\n        output = super().to_representation(instance)\n\n        if isinstance(instance, Hit):\n            # TODO: Remove when updating ES indexes\n            audio = Audio.objects.get(identifier=instance.identifier)\n            if not audio.thumbnail:\n                output[\"thumbnail\"] = None\n\n        return output\n\n\nclass AudioSearchSerializer(MediaSearchSerializer):\n    \"\"\"\n    The full audio search response.\n    This serializer is purely representational and not actually used to\n    serialize the response.\n    \"\"\"\n\n    results = AudioSerializer(\n        many=True,\n        help_text=(\n            \"An array of audios and their details such as \"\n            f\"{fields_to_md(AudioSerializer.Meta.fields)}.\"\n        ),\n    )\n\n\n##########################\n# Additional serializers #\n##########################\n\n\nclass AudioWaveformSerializer(serializers.Serializer):\n    len = serializers.SerializerMethodField()\n    points = serializers.ListField(\n        child=serializers.FloatField(min_value=0, max_value=1)\n    )\n\n    @staticmethod\n    def get_len(obj) -> int:\n        return len(obj.get(\"points\", []))\n", "path": "api/catalog/api/serializers/audio_serializers.py"}]}