Django Library PyGal
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

userviews.py 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. from django.shortcuts import render
  2. from django.utils.translation import gettext as _
  3. import geo
  4. import mimetypes
  5. from ..models import get_item_type, get_item_by_rel_path, TYPE_AUDIO, TYPE_FOLDER, TYPE_IMAGE, TYPE_OTHER, TYPE_VIDEO
  6. import os
  7. import pygal
  8. from ..queries import search_result_query
  9. import random
  10. import stringtools
  11. import themes
  12. ADDTAG_ENTRY = 'addtag-main'
  13. INFOVIEW_ENTRY = 'infoview-main'
  14. DOWNLOAD_ENTRY = 'download-main'
  15. DOWNLOAD_FLAT_ENTRY = 'download-flat-sub'
  16. DOWNLOAD_STRUCT_ENTRY = 'download-struct-sub'
  17. FAVOURITE_ENTRY = 'favourite-main'
  18. REPEAT_ENTRY = 'repeat-main'
  19. SHUFFLE_ENTRY = 'shuffle-main'
  20. def get_wrapper_class(full_path):
  21. return {
  22. TYPE_FOLDER: folder_view,
  23. TYPE_IMAGE: image_view,
  24. TYPE_VIDEO: video_view,
  25. TYPE_AUDIO: audio_view,
  26. TYPE_OTHER: other_view,
  27. }.get(get_item_type(full_path), base_view)
  28. def get_wrapper_instance(full_path, request, is_nxt_prv_item=False):
  29. return get_wrapper_class(full_path)(request, full_path, is_nxt_prv_item)
  30. def random_copy(request, lst):
  31. shuffle_id = pygal.get_shuffle_id(request)
  32. #
  33. rv = lst[:]
  34. if shuffle_id is not None:
  35. r = random.Random()
  36. r.seed(shuffle_id)
  37. r.shuffle(rv)
  38. return rv
  39. class base_view(object):
  40. def __init__(self, request, full_path, is_nxt_prv_item):
  41. self.request = request
  42. self.full_path = full_path
  43. self.is_nxt_prv_item = is_nxt_prv_item
  44. #
  45. self.item = get_item_by_rel_path(pygal.get_rel_path(full_path))
  46. if self.item is None:
  47. raise LookupError("Error while initialising base_view, but item for %s does not exist." % full_path)
  48. self.is_item = self.item.type != TYPE_FOLDER
  49. #
  50. self.mime_type = mimetypes.types_map.get(os.path.splitext(self.full_path)[1])
  51. self.template = 'pygal/empty.html'
  52. @property
  53. def tags(self):
  54. return self.item.tag_set.all()
  55. def may_read(self):
  56. return self.item.may_read(self.request.user)
  57. def may_modify(self):
  58. return self.item.may_modify(self.request.user)
  59. def context_adaption(self, context):
  60. context['item'] = self
  61. context['thumbnail_size'] = pygal.get_thumbnail_size(self.request)
  62. context['title'] = self.name or ''
  63. context[context.ACTIONBAR].extend(self.actionbar)
  64. @property
  65. def heading(self):
  66. return '%s' % self.item.name
  67. @property
  68. def general_information(self):
  69. rv = []
  70. full_path = pygal.get_full_path(self.item.rel_path)
  71. rv.append({'description': _('Name'), 'data': os.path.basename(full_path), 'url': None})
  72. rv.append({'description': _('Creation Time'), 'data': self.item.item_data.formatted_datetime, 'url': None})
  73. rv.append({'description': _('Path'), 'data': os.path.dirname(full_path), 'url': None})
  74. rv.append({'description': _('Size'), 'data': stringtools.physical_value_repr(self.item.item_data.size, 'B'), 'url': None})
  75. rv.append({'description': _('UID'), 'data': self.item.current_uid(), 'url': None})
  76. return rv
  77. def __actionbar__(self):
  78. b = themes.bar()
  79. if self.is_item:
  80. if self.is_my_favourite:
  81. b.append_entry(
  82. FAVOURITE_ENTRY,
  83. '',
  84. themes.color_icon_url(self.request, 'is_favourite.png'),
  85. pygal.url_favourite_unset(self.request, self.item.rel_path),
  86. True,
  87. False
  88. )
  89. else:
  90. b.append_entry(
  91. FAVOURITE_ENTRY,
  92. '',
  93. themes.color_icon_url(self.request, 'favourite.png'),
  94. pygal.url_favourite_set(self.request, self.item.rel_path),
  95. True,
  96. False
  97. )
  98. if pygal.is_infoview(self.request):
  99. b.append_entry(
  100. INFOVIEW_ENTRY,
  101. _('Info'),
  102. themes.color_icon_url(self.request, 'info.png'),
  103. pygal.url_infoview(self.request, self.item.rel_path),
  104. True,
  105. True
  106. )
  107. else:
  108. b.append_entry(
  109. INFOVIEW_ENTRY,
  110. _('Info'),
  111. themes.color_icon_url(self.request, 'info.png'),
  112. pygal.url_infoview(self.request, self.item.rel_path, search=pygal.SEARCH_KEEP),
  113. True,
  114. False
  115. )
  116. b.append_entry(
  117. DOWNLOAD_ENTRY,
  118. _('Download'),
  119. themes.color_icon_url(self.request, 'download.png'),
  120. pygal.url_download(self.request, self.item.rel_path),
  121. True,
  122. False
  123. )
  124. if type(self) is not folder_view:
  125. if pygal.is_repeatview(self.request):
  126. b.append_entry(
  127. REPEAT_ENTRY,
  128. _('Repeat'),
  129. themes.color_icon_url(self.request, 'stop.png'),
  130. pygal.url_userview(self.request, self.item.rel_path, search=pygal.SEARCH_KEEP),
  131. True,
  132. True
  133. )
  134. else:
  135. b.append_entry(
  136. REPEAT_ENTRY,
  137. _('Repeat'),
  138. themes.color_icon_url(self.request, 'play.png'),
  139. pygal.url_repeatview(self.request, self.item.rel_path),
  140. True,
  141. False
  142. )
  143. if pygal.get_shuffle_id(self.request) is None:
  144. b.append_entry(
  145. SHUFFLE_ENTRY,
  146. _('Shuffle'),
  147. themes.color_icon_url(self.request, 'shuffle.png'),
  148. pygal.url_userview(self.request, self.item.rel_path, shuffle=pygal.SHUFFLE_ENABLE, search=pygal.SEARCH_KEEP),
  149. True,
  150. False
  151. )
  152. else:
  153. b.append_entry(
  154. SHUFFLE_ENTRY,
  155. _('Shuffle'),
  156. themes.color_icon_url(self.request, 'shuffle.png'),
  157. pygal.url_userview(self.request, self.item.rel_path, shuffle=pygal.SHUFFLE_DISABLE, search=pygal.SEARCH_KEEP),
  158. True,
  159. True
  160. )
  161. if self.is_item and self.may_modify():
  162. b.append_entry(
  163. ADDTAG_ENTRY,
  164. _('Add Tag'),
  165. themes.color_icon_url(self.request, 'edit2.png'),
  166. pygal.url_addtag(self.request, self.item.rel_path),
  167. True,
  168. False
  169. )
  170. return b
  171. @property
  172. def is_my_favourite(self):
  173. return self.request.user in self.item.favourite_of.all()
  174. @property
  175. def actionbar(self):
  176. return self.__actionbar__()
  177. def __tagbar__(self):
  178. b = themes.bar(self.request)
  179. i = 0
  180. for t in self.item.tag_set.all():
  181. i += 1
  182. edit_url = pygal.url_tagedit(self.request, t.id) if self.may_modify() else None
  183. b.append_entry('tag-%d' % i, t.text, themes.color_icon_url(self.request, '%d.png' % (i % 10)), edit_url, True, False)
  184. return b
  185. @property
  186. def tagbar(self):
  187. return self.__tagbar__()
  188. @property
  189. def duration(self):
  190. return self.item.item_data.duration + 1.5
  191. @property
  192. def url_item(self):
  193. return pygal.url_item(self.request, self.item.rel_path)
  194. @property
  195. def url_repeatview(self):
  196. return pygal.url_repeatview(self.request, self.item.rel_path)
  197. @property
  198. def is_repeatview(self):
  199. return pygal.is_repeatview(self.request)
  200. @property
  201. def url_thumbnail(self):
  202. return pygal.url_thumbnail(self.request, self.item.rel_path)
  203. @property
  204. def url_userview(self):
  205. if self.is_nxt_prv_item:
  206. return pygal.url_userview(self.request, self.item.rel_path, search=pygal.SEARCH_KEEP, repeat=pygal.REPEAT_KEEP)
  207. else:
  208. return pygal.url_userview(self.request, self.item.rel_path, search=pygal.SEARCH_KEEP, repeat=pygal.REPEAT_DISABLE)
  209. @property
  210. def url_webnail(self):
  211. return pygal.url_webnail(self.request, self.item.rel_path)
  212. @property
  213. def name(self):
  214. return self.item.name
  215. @property
  216. def date_txt(self):
  217. return self.item.item_data.formatted_datetime
  218. def __parent__(self):
  219. if pygal.is_searchview(self.request) or pygal.is_favouriteview(self.request):
  220. return query_view(self.request, search_result_query(self.request))
  221. else:
  222. return get_wrapper_instance(os.path.dirname(self.full_path), self.request)
  223. def __nxt_prv__(self, direction):
  224. if direction not in [-1, 1]:
  225. raise ValueError("Parameter direction is incorrect: %s" % repr(direction))
  226. fp_il = random_copy(self.request, self.__parent__().sorted_fullpathlist())
  227. i = fp_il.index(self.full_path)
  228. lgt = len(fp_il)
  229. for i in range(i + direction, i + direction * lgt, direction):
  230. full_path = fp_il[i % lgt]
  231. if get_item_type(full_path) != TYPE_FOLDER:
  232. return get_wrapper_instance(full_path, self.request, is_nxt_prv_item=True)
  233. return self
  234. @property
  235. def nxt(self):
  236. return self.__nxt_prv__(1)
  237. @property
  238. def prv(self):
  239. return self.__nxt_prv__(-1)
  240. def render(self, context):
  241. return render(self.request, self.template, context=context)
  242. class query_view(object):
  243. def __init__(self, request, query):
  244. self.request = request
  245. self.query = query
  246. #
  247. self.template = 'pygal/overview.html'
  248. #
  249. self.__item_list__ = None
  250. def context_adaption(self, context):
  251. context['item'] = self
  252. context['thumbnail_size'] = pygal.get_thumbnail_size(self.request)
  253. context['title'] = self.name or ''
  254. context[context.ACTIONBAR].extend(self.actionbar)
  255. @property
  256. def name(self):
  257. if pygal.is_favouriteview(self.request):
  258. return _('My Favourites')
  259. elif pygal.is_searchview(self.request):
  260. return _('Search: "%s"' % pygal.get_search_query(self.request))
  261. else:
  262. return '-'
  263. def __actionbar__(self):
  264. b = themes.bar()
  265. if pygal.is_infoview(self.request):
  266. b.append_entry(
  267. INFOVIEW_ENTRY,
  268. _('Info'),
  269. themes.color_icon_url(self.request, 'info.png'),
  270. pygal.url_infoview(self.request, ''),
  271. True,
  272. True
  273. )
  274. else:
  275. b.append_entry(
  276. INFOVIEW_ENTRY,
  277. _('Info'),
  278. themes.color_icon_url(self.request, 'info.png'),
  279. pygal.url_infoview(self.request, ''),
  280. True,
  281. False
  282. )
  283. b.append_entry(
  284. DOWNLOAD_ENTRY,
  285. _('Download'),
  286. themes.color_icon_url(self.request, 'download.png'),
  287. None,
  288. True,
  289. False
  290. )
  291. b.append_entry_to_entry(
  292. DOWNLOAD_ENTRY,
  293. DOWNLOAD_STRUCT_ENTRY,
  294. _('Download (Structured)'),
  295. themes.gray_icon_url(self.request, 'download.png'),
  296. pygal.url_download(self.request, ''),
  297. True,
  298. False
  299. )
  300. b.append_entry_to_entry(
  301. DOWNLOAD_ENTRY,
  302. DOWNLOAD_FLAT_ENTRY,
  303. _('Download (Flat)'),
  304. themes.gray_icon_url(self.request, 'download.png'),
  305. pygal.url_download(self.request, '', flat=True),
  306. True,
  307. False
  308. )
  309. if pygal.get_shuffle_id(self.request) is None:
  310. b.append_entry(
  311. SHUFFLE_ENTRY,
  312. _('Shuffle'),
  313. themes.color_icon_url(self.request, 'shuffle.png'),
  314. pygal.url_userview(self.request, '', shuffle=pygal.SHUFFLE_ENABLE, search=pygal.SEARCH_KEEP),
  315. True,
  316. False
  317. )
  318. else:
  319. b.append_entry(
  320. SHUFFLE_ENTRY,
  321. _('Shuffle'),
  322. themes.color_icon_url(self.request, 'shuffle.png'),
  323. pygal.url_userview(self.request, '', shuffle=pygal.SHUFFLE_DISABLE, search=pygal.SEARCH_KEEP),
  324. True,
  325. True
  326. )
  327. return b
  328. @property
  329. def actionbar(self):
  330. return self.__actionbar__()
  331. def sorted_fullpathlist(self):
  332. il = []
  333. for item_model in self.query:
  334. if item_model.may_read(self.request.user):
  335. il.append(item_model)
  336. il.sort(key=lambda entry: entry.sort_string(), reverse=True)
  337. return [pygal.get_full_path(i.rel_path) for i in il]
  338. def __init_itemlist__(self):
  339. if self.__item_list__ is None:
  340. self.__item_list__ = []
  341. for full_path in self.sorted_fullpathlist():
  342. w = get_wrapper_instance(full_path, self.request)
  343. self.__item_list__.append(w)
  344. @property
  345. def item_list(self):
  346. self.__init_itemlist__()
  347. return random_copy(self.request, self.__item_list__)
  348. def render(self, context):
  349. return render(self.request, self.template, context=context)
  350. class folder_view(base_view):
  351. def __init__(self, *args, **kwargs):
  352. base_view.__init__(self, *args, **kwargs)
  353. #
  354. self.template = 'pygal/overview.html'
  355. #
  356. self.__item_list__ = None
  357. def __actionbar__(self):
  358. b = base_view.__actionbar__(self)
  359. b.append_entry_to_entry(
  360. DOWNLOAD_ENTRY,
  361. DOWNLOAD_STRUCT_ENTRY,
  362. _('Download (Structured)'),
  363. themes.gray_icon_url(self.request, 'download.png'),
  364. pygal.url_download(self.request, self.item.rel_path),
  365. True,
  366. False
  367. )
  368. b.append_entry_to_entry(
  369. DOWNLOAD_ENTRY,
  370. DOWNLOAD_FLAT_ENTRY,
  371. _('Download (Flat)'),
  372. themes.gray_icon_url(self.request, 'download.png'),
  373. pygal.url_download(self.request, self.item.rel_path, flat=True),
  374. True,
  375. False
  376. )
  377. return b
  378. def sorted_fullpathlist(self):
  379. return [pygal.get_full_path(i.rel_path) for i in self.item.sorted_itemlist()]
  380. def __init_fullpathlist__(self):
  381. if self.__item_list__ is None:
  382. self.__item_list__ = []
  383. for full_path in self.sorted_fullpathlist():
  384. w = get_wrapper_instance(full_path, self.request)
  385. self.__item_list__.append(w)
  386. @property
  387. def item_list(self):
  388. self.__init_fullpathlist__()
  389. return random_copy(self.request, self.__item_list__)
  390. @property
  391. def url_thumbnail(self):
  392. return pygal.url_thumbnail(self. request, self.item.thumbnail_item().rel_path)
  393. class image_view(base_view):
  394. def __init__(self, *args, **kwargs):
  395. base_view.__init__(self, *args, **kwargs)
  396. #
  397. self.template = 'pygal/image.html'
  398. def __actionbar__(self):
  399. b = base_view.__actionbar__(self)
  400. gps_data = self.item.item_data.gps
  401. if gps_data is not None:
  402. b.append_entry(
  403. 'actionbar-gpslink',
  404. _('GPS'),
  405. themes.color_icon_url(self.request, 'gps.png'),
  406. geo.osm.landmark_link(geo.gps.coordinate(**gps_data)),
  407. True,
  408. False
  409. )
  410. return b
  411. @property
  412. def width(self):
  413. if self.item.item_data.orientation in [5, 6, 7, 8]:
  414. return self.item.item_data.height
  415. else:
  416. return self.item.item_data.width
  417. @property
  418. def height(self):
  419. if self.item.item_data.orientation in [5, 6, 7, 8]:
  420. return self.item.item_data.width
  421. else:
  422. return self.item.item_data.height
  423. class video_view(base_view):
  424. def __init__(self, *args, **kwargs):
  425. base_view.__init__(self, *args, **kwargs)
  426. #
  427. self.template = 'pygal/video.html'
  428. @property
  429. def use_internal_player(self):
  430. return self.mime_type in [mimetypes.types_map.get(ext) for ext in ['.mp4', '.webm', '.ogv', '.flv', '.3gp', ]]
  431. @property
  432. def webnail_width(self):
  433. w, h = self.item.item_data.width, self.item.item_data.height
  434. return int(pygal.get_webnail_size(self.request) * w / max(w, h))
  435. @property
  436. def webnail_height(self):
  437. w, h = self.item.item_data.width, self.item.item_data.height
  438. return int(pygal.get_webnail_size(self.request) * h / max(w, h))
  439. class audio_view(base_view):
  440. def __init__(self, *args, **kwargs):
  441. base_view.__init__(self, *args, **kwargs)
  442. #
  443. self.template = 'pygal/audio.html'
  444. @property
  445. def heading(self):
  446. return '%02d - %s' % (self.item.item_data.track, self.item.item_data.title)
  447. @property
  448. def audio_information(self):
  449. rv = []
  450. entries = (
  451. (_('Artist'), self.item.artist_c),
  452. (_('Album'), self.item.album_c),
  453. (_('Year'), self.item.year_c),
  454. (_('Title'), self.item.title_c),
  455. (_('Duration'), stringtools.time_repr(self.item.duration_c)),
  456. )
  457. for description, data in entries:
  458. if data is not None:
  459. rv.append({'description': description, 'data': data, 'url': None})
  460. return rv
  461. class other_view(base_view):
  462. def __init__(self, *args, **kwargs):
  463. base_view.__init__(self, *args, **kwargs)
  464. #
  465. self.template = 'pygal/other.html'