What you can do is combination of different events in Event System.
For example, every time your item is successfully published (transaction state changed to Success), you can schedule same item to unpublish at specific time in future based on metadata. You also must take care of the following issues:
- what if someone removes transaction from queue before its executed,
- what if item MetaData value is changed
- what if unpublish failed?
Honestly, I would do this as combination of Core Service and Windows Service. I would have one scheduled windows service which uses Core Service as connection to database, and would take care that item is INDEED UNPUBLISHED WHEN NEEDED.
Also, you can use direct database access to Tridion_cm database, if using core service is to extensive to you. Database in general shouldn't be used, but single select statements can be, if you know the structure of database and items. Also, you should take care of clogging transaction queue with transactions... etc...