To solve this problem, we need to maximize the total viewership of ads placed in three video categories: DIY videos, shopping videos, and unboxing videos. The decision variables are the number of ads placed in each category.

Let's denote:
- $x_1$ as the number of ads placed in DIY videos,
- $x_2$ as the number of ads placed in shopping videos,
- $x_3$ as the number of ads placed in unboxing videos.

The objective function is to maximize total viewership, given by:
\[10000x_1 + 4000x_2 + 9000x_3\]

The constraints are:
1. Budget constraint: The total cost of placing ads should not exceed $120000.
\[5000x_1 + 3200x_2 + 4000x_3 \leq 120000\]
2. DIY video constraint: At most 5 ads can be placed in DIY videos.
\[x_1 \leq 5\]
3. Unboxing video constraint: The number of ads placed in unboxing videos should not exceed half the total number of ads.
\[x_3 \leq 0.5(x_1 + x_2 + x_3)\]
4. Shopping video constraint: At least 20% of the total ads should be placed in shopping videos.
\[x_2 \geq 0.2(x_1 + x_2 + x_3)\]

We also know that $x_1, x_2, x_3 \geq 0$ and are integers since we cannot place a fraction of an ad.

Now, let's translate this problem into Gurobi code in Python:

```python
from gurobipy import *

# Create a model
m = Model("Ad Placement")

# Define the decision variables
x1 = m.addVar(vtype=GRB.INTEGER, name="DIY")
x2 = m.addVar(vtype=GRB.INTEGER, name="Shopping")
x3 = m.addVar(vtype=GRB.INTEGER, name="Unboxing")

# Objective function: Maximize total viewership
m.setObjective(10000*x1 + 4000*x2 + 9000*x3, GRB.MAXIMIZE)

# Budget constraint
m.addConstr(5000*x1 + 3200*x2 + 4000*x3 <= 120000, name="Budget")

# DIY video constraint
m.addConstr(x1 <= 5, name="DIY Limit")

# Unboxing video constraint
m.addConstr(x3 <= 0.5*(x1 + x2 + x3), name="Unboxing Limit")

# Shopping video constraint
m.addConstr(x2 >= 0.2*(x1 + x2 + x3), name="Shopping Minimum")

# Non-negativity constraints (not necessary here since we've set vtype=GRB.INTEGER and all coefficients are positive)

# Solve the model
m.optimize()

# Print solution
for v in m.getVars():
    print(f"{v.varName}: {v.x}")

print(f"Objective: {m.objVal}")
```