I always prefer to create custom solutions for a problem rather than to rely on generic methodologies. In this specific case, the problem is quite well defined and I think that there is a quick and reliable iterative proceeding which can be defined relatively easily: basing the analysis on a sequential assignation of tasks by following the idea of "filling days" until being completed.
The algorithm would be iterating through the available (5) days, adding up the time associated with each task being assigned and comparing the resulting addition against the remaining available time for the given day. It would consist in two main parts:
Top priority assignation. Right at the start, the algorithm would be calculating the "flexibility" of the given day: it would add up all the time-slots of the tasks which have to be done on the given day. If they consume all the available time, the assignation of all these tasks would be done right away and would skip directly to the next day. In case of having available time, the algorithm would only assign the tasks with a detailed (time/day) definition; example: task to be performed on Mondays including the given slot (e.g., 9 to 9:15). After completing the assignation of all the defined-in-detail tasks, it would add up the whole time required by the remaining tasks to be done on the given day; this value is what I refer below as "remanent for the day"; the tasks belonging to this group (i.e., unassigned ones to be done on the given day) would be flagged such that the next point can deal with them properly.
Default preference rules. In case of not having assigned all the available time for the given day in the point above, a new iteration through all the tasks (not belonging to the aforementioned ones flagged for the given day) would be started by applying a system of generic preference rules (as described in the example below). Before assigning any new task, the algorithm would check whether there is still enough time to account for all the "remanent for the day". If the new-to-be-assigned task depletes the available time (i.e., avoids the "remanent for the day" to be assigned), the algorithm would keep iterating through the "preferred tasks" (the ones not belonging to the "remanent of the day") until finding one whose assignation would not deplete the available time. In case of not finding such a task, all the tasks belonging to the "remanent of the day" would be assigned right away and the algorithm would skip to the next day.
EXAMPLE OF PREFERENCE RULES FOR POINT 2: for the 9 to 9:15 slot on Monday; inspect firstly tasks allocated to the specific time independently upon the day (it wouldn't be Monday because these cases are already managed by point 1); then the biggest tasks (higher number of slots) which might be done on Mondays. It would also be possible to create a ranking for tasks in case of being in this last situation (e.g., in case of starting the last ordering by size, task X would have the maximum priority for Mondays).
The algorithm described above (or any other on these lines) represents the quickest option I can come up with for the problem you have. It focuses mainly on speed and reliability and thus the "many consecutive free slots" constraint is not fully optimised; although there is a tendency towards creating those (mainly during the last days of the week). Nonetheless, this last issue might be improved further by increasing the level of detail for the rules in point 2 (mainly the ones for tasks assigned by their time size). In summary, I do consider that an approach on these lines would deliver the best solution for the problem you propose.