You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
10 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. #!/usr/bin/env python2
  2. """Youtubedlg module that contains util functions.
  3. Attributes:
  4. _RANDOM_OBJECT (object): Object that it's used as a default parameter.
  5. YOUTUBEDL_BIN (string): Youtube-dl binary filename.
  6. """
  7. import os
  8. import sys
  9. import subprocess
  10. from .info import __appname__
  11. _RANDOM_OBJECT = object()
  12. YOUTUBEDL_BIN = 'youtube-dl'
  13. if os.name == 'nt':
  14. YOUTUBEDL_BIN += '.exe'
  15. def remove_shortcuts(path):
  16. """Return given path after removing the shortcuts. """
  17. path = path.replace('~', os.path.expanduser('~'))
  18. return path
  19. def absolute_path(filename):
  20. """Return absolute path to the given file. """
  21. path = os.path.realpath(os.path.abspath(filename))
  22. return os.path.dirname(path)
  23. def open_dir(path):
  24. """Open path using default file navigator. """
  25. path = remove_shortcuts(path)
  26. if os.name == 'nt':
  27. os.startfile(path)
  28. else:
  29. subprocess.call(('xdg-open', path))
  30. def check_path(path):
  31. """Create path if not exist. """
  32. if not os.path.exists(path):
  33. os.makedirs(path)
  34. def get_config_path():
  35. """Return user config path.
  36. Note:
  37. Windows = %AppData%
  38. Linux = ~/.config
  39. """
  40. if os.name == 'nt':
  41. path = os.getenv('APPDATA')
  42. else:
  43. path = os.path.join(os.path.expanduser('~'), '.config')
  44. return path
  45. def shutdown_sys(password=''):
  46. """Shuts down the system.
  47. Args:
  48. password (string): SUDO password for linux.
  49. Note:
  50. On Linux you need to provide sudo password if you don't
  51. have elevated privileges.
  52. """
  53. if os.name == 'nt':
  54. subprocess.call(['shutdown', '/s', '/t', '1'])
  55. else:
  56. if not password:
  57. subprocess.call(['/sbin/shutdown', '-h', 'now'])
  58. else:
  59. subprocess.Popen(['sudo', '-S', '/sbin/shutdown', '-h', 'now'],
  60. stdin=subprocess.PIPE).communicate(password + '\n')
  61. def get_time(seconds):
  62. """Convert given seconds to days, hours, minutes and seconds.
  63. Args:
  64. seconds (float): Time in seconds.
  65. Returns:
  66. Dictionary that contains the corresponding days, hours, minutes
  67. and seconds of the given seconds.
  68. """
  69. dtime = dict(seconds=0, minutes=0, hours=0, days=0)
  70. dtime['days'] = int(seconds / 86400)
  71. dtime['hours'] = int(seconds % 86400 / 3600)
  72. dtime['minutes'] = int(seconds % 86400 % 3600 / 60)
  73. dtime['seconds'] = int(seconds % 86400 % 3600 % 60)
  74. return dtime
  75. def get_locale_file():
  76. """Search for youtube-dlg locale file.
  77. Returns:
  78. The path to youtube-dlg locale file if exists else None.
  79. Note:
  80. Paths that get_locale_file() func searches:
  81. Windows: __main__ dir.
  82. Linux: __main__ dir, /usr/share/youtube-dlg
  83. """
  84. DIR_NAME = 'locale'
  85. # __main__ dir
  86. directory = os.path.join(absolute_path(sys.argv[0]), DIR_NAME)
  87. if os.path.isdir(directory):
  88. return directory
  89. if os.name != 'nt':
  90. # /usr/share/youtube-dlg
  91. directory = os.path.join('/usr', 'share', __appname__.lower(), DIR_NAME)
  92. if os.path.isdir(directory):
  93. return directory
  94. return None
  95. def get_icon_file():
  96. """Search for youtube-dlg app icon.
  97. Returns:
  98. The path to youtube-dlg icon file if exists, else returns None.
  99. Note:
  100. Paths that get_icon_file() function searches.
  101. Windows: __main__ directory.
  102. Linux: __main__ directory, $XDG_DATA_DIRS and /usr/share/pixmaps.
  103. """
  104. SIZES = ('256x256', '128x128', '64x64', '48x48', '32x32', '16x16')
  105. ICON_NAME = 'youtube-dl-gui_%s.png'
  106. ICONS_LIST = [ICON_NAME % size for size in SIZES]
  107. # __main__ dir
  108. path = os.path.join(absolute_path(sys.argv[0]), 'icons')
  109. for icon in ICONS_LIST:
  110. icon_file = os.path.join(path, icon)
  111. if os.path.exists(icon_file):
  112. return icon_file
  113. if os.name != 'nt':
  114. # $XDG_DATA_DIRS/icons
  115. path = os.getenv('XDG_DATA_DIRS')
  116. if path is not None:
  117. for xdg_path in path.split(':'):
  118. xdg_path = os.path.join(xdg_path, 'icons', 'hicolor')
  119. for size in SIZES:
  120. icon_name = ICON_NAME % size
  121. icon_file = os.path.join(xdg_path, size, 'apps', icon_name)
  122. if os.path.exists(icon_file):
  123. return icon_file
  124. # /usr/share/pixmaps
  125. path = '/usr/share/pixmaps'
  126. for icon in ICONS_LIST:
  127. icon_file = os.path.join(path, icon)
  128. if os.path.exists(icon_file):
  129. return icon_file
  130. return None
  131. class TwoWayOrderedDict(dict):
  132. """Custom data structure which implements a two way ordrered dictionary.
  133. TwoWayOrderedDict it's a custom dictionary in which you can get the
  134. key:value relationship but you can also get the value:key relationship.
  135. It also remembers the order in which the items were inserted and supports
  136. almost all the features of the build-in dict.
  137. Note:
  138. Ways to create a new dictionary.
  139. *) d = TwoWayOrderedDict(a=1, b=2) (Unordered)
  140. *) d = TwoWayOrderedDict({'a': 1, 'b': 2}) (Unordered)
  141. *) d = TwoWayOrderedDict([('a', 1), ('b', 2)]) (Ordered)
  142. *) d = TwoWayOrderedDict(zip(['a', 'b', 'c'], [1, 2, 3])) (Ordered)
  143. Examples:
  144. >>> d = TwoWayOrderedDict(a=1, b=2)
  145. >>> d['a']
  146. 1
  147. >>> d[1]
  148. 'a'
  149. >>> print d
  150. TwoWayOrderedDict([('a', 1), ('b', 2)])
  151. """
  152. _PREV = 0
  153. _KEY = 1
  154. _NEXT = 2
  155. def __init__(self, *args, **kwargs):
  156. self._items = item = []
  157. self._items += [item, None, item] # Double linked list [prev, key, next]
  158. self._items_map = {} # Map link list items into keys to speed up lookup
  159. self._load(args, kwargs)
  160. def __setitem__(self, key, value):
  161. if key in self:
  162. # If self[key] == key for example {'b': 'b'} and we
  163. # do d['b'] = 2 then we dont want to remove the 'b'
  164. # from our linked list because we will lose the order
  165. if self[key] in self._items_map and key != self[key]:
  166. self._remove_mapped_key(self[key])
  167. dict.__delitem__(self, self[key])
  168. if value in self:
  169. # If value == key we dont have to remove the
  170. # value from the items_map because the value is
  171. # the key and we want to keep the key in our
  172. # linked list in order to keep the order.
  173. if value in self._items_map and key != value:
  174. self._remove_mapped_key(value)
  175. if self[value] in self._items_map:
  176. self._remove_mapped_key(self[value])
  177. # Check if self[value] is in the dict
  178. # for cases like {'a': 'a'} where we
  179. # have only one copy instead of {'a': 1, 1: 'a'}
  180. if self[value] in self:
  181. dict.__delitem__(self, self[value])
  182. if key not in self._items_map:
  183. last = self._items[self._PREV] # self._items prev always points to the last item
  184. last[self._NEXT] = self._items[self._PREV] = self._items_map[key] = [last, key, self._items]
  185. dict.__setitem__(self, key, value)
  186. dict.__setitem__(self, value, key)
  187. def __delitem__(self, key):
  188. if self[key] in self._items_map:
  189. self._remove_mapped_key(self[key])
  190. if key in self._items_map:
  191. self._remove_mapped_key(key)
  192. dict.__delitem__(self, self[key])
  193. # Check if key is in the dict
  194. # for cases like {'a': 'a'} where we
  195. # have only one copy instead of {'a': 1, 1: 'a'}
  196. if key in self:
  197. dict.__delitem__(self, key)
  198. def __len__(self):
  199. return len(self._items_map)
  200. def __iter__(self):
  201. curr = self._items[self._NEXT]
  202. while curr is not self._items:
  203. yield curr[self._KEY]
  204. curr = curr[self._NEXT]
  205. def __reversed__(self):
  206. curr = self._items[self._PREV]
  207. while curr is not self._items:
  208. yield curr[self._KEY]
  209. curr = curr[self._PREV]
  210. def __repr__(self):
  211. return '%s(%r)' % (self.__class__.__name__, self.items())
  212. def __eq__(self, other):
  213. if isinstance(other, self.__class__):
  214. return self.items() == other.items()
  215. return False
  216. def __ne__(self, other):
  217. return not self == other
  218. def _remove_mapped_key(self, key):
  219. """Remove the given key both from the linked list
  220. and the map dictionary. """
  221. prev, __, next = self._items_map.pop(key)
  222. prev[self._NEXT] = next
  223. next[self._PREV] = prev
  224. def _load(self, args, kwargs):
  225. """Load items into our dictionary. """
  226. for item in args:
  227. if type(item) == dict:
  228. item = item.iteritems()
  229. for key, value in item:
  230. self[key] = value
  231. for key, value in kwargs.items():
  232. self[key] = value
  233. def items(self):
  234. return [(key, self[key]) for key in self]
  235. def values(self):
  236. return [self[key] for key in self]
  237. def keys(self):
  238. return list(self)
  239. def pop(self, key, default=_RANDOM_OBJECT):
  240. try:
  241. value = self[key]
  242. del self[key]
  243. except KeyError as error:
  244. if default == _RANDOM_OBJECT:
  245. raise error
  246. value = default
  247. return value
  248. def popitem(self, last=True):
  249. """Remove and return a (key, value) pair from the dictionary.
  250. If the dictionary is empty calling popitem() raises a KeyError.
  251. Args:
  252. last (bool): When False popitem() will remove the first item
  253. from the list.
  254. Note:
  255. popitem() is useful to destructively iterate over a dictionary.
  256. Raises:
  257. KeyError
  258. """
  259. if not self:
  260. raise KeyError('popitem(): dictionary is empty')
  261. if last:
  262. __, key, __ = self._items[self._PREV]
  263. else:
  264. __, key, __ = self._items[self._NEXT]
  265. value = self.pop(key)
  266. return key, value
  267. def update(self, *args, **kwargs):
  268. self._load(args, kwargs)
  269. def setdefault(self, key, default=None):
  270. try:
  271. return self[key]
  272. except KeyError:
  273. self[key] = default
  274. return default
  275. def copy(self):
  276. return self.__class__(self.items())
  277. def clear(self):
  278. self._items = item = []
  279. self._items += [item, None, item]
  280. self._items_map = {}
  281. dict.clear(self)