• R/O
  • SSH

Commit

Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revisãoebe378b053c5cebf9505f4656abc8988eadc90a5 (tree)
Hora2017-10-15 00:30:14
AutorJaime Marquínez Ferrándiz <jaime.marquinez.ferrandiz@fast...>
CommiterJaime Marquínez Ferrándiz

Mensagem de Log

Initial commit

Mudança Sumário

Diff

diff -r 000000000000 -r ebe378b053c5 .hgignore
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Sat Oct 14 17:30:14 2017 +0200
@@ -0,0 +1,2 @@
1+syntax: glob
2+*.pyc
diff -r 000000000000 -r ebe378b053c5 LICENSE
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE Sat Oct 14 17:30:14 2017 +0200
@@ -0,0 +1,24 @@
1+This is free and unencumbered software released into the public domain.
2+
3+Anyone is free to copy, modify, publish, use, compile, sell, or
4+distribute this software, either in source code form or as a compiled
5+binary, for any purpose, commercial or non-commercial, and by any
6+means.
7+
8+In jurisdictions that recognize copyright laws, the author or authors
9+of this software dedicate any and all copyright interest in the
10+software to the public domain. We make this dedication for the benefit
11+of the public at large and to the detriment of our heirs and
12+successors. We intend this dedication to be an overt act of
13+relinquishment in perpetuity of all present and future rights to this
14+software under copyright law.
15+
16+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+OTHER DEALINGS IN THE SOFTWARE.
23+
24+For more information, please refer to <http://unlicense.org/>
diff -r 000000000000 -r ebe378b053c5 beetsplug/__init__.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/beetsplug/__init__.py Sat Oct 14 17:30:14 2017 +0200
@@ -0,0 +1,2 @@
1+from pkgutil import extend_path
2+__path__ = extend_path(__path__, __name__)
diff -r 000000000000 -r ebe378b053c5 beetsplug/playersync.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/beetsplug/playersync.py Sat Oct 14 17:30:14 2017 +0200
@@ -0,0 +1,145 @@
1+from __future__ import unicode_literals
2+
3+import os.path
4+import os
5+import sqlite3
6+import shutil
7+import datetime
8+
9+from beets.plugins import BeetsPlugin
10+from beets.ui import Subcommand
11+from beets.util import prune_dirs, bytestring_path
12+from beets.dbcore import OrQuery
13+from beets.library import parse_query_parts, Item
14+
15+_CREATE_DATABASE_SCRIPT='''
16+CREATE TABLE song(idSong INTEGER PRIMARY KEY, filename TEXT NOT NULL, date TIMESTAMP, synced BOOL);
17+CREATE TABLE query(idQuery INTEGER PRIMARY KEY AUTOINCREMENT, query TEXT NOT NULL);
18+CREATE TABLE querysong(idQuery INT REFERENCES query, idSong INT REFERENCES song,
19+ PRIMARY KEY (idQuery, idSong)
20+ );
21+CREATE TABLE playlist(idPlaylist INTEGER PRIMARY KEY AUTOINCREMENT, playlist TEXT NOT NULL);
22+CREATE TABLE playlistsong(idPlaylist INTEGER REFERENCES playlist, idSong INTEGER REFERENCES song, listIndex INTEGER NOT NULL,
23+ PRIMARY KEY (idPlaylist, idSong, listIndex));
24+'''
25+
26+class PlayerSync(BeetsPlugin):
27+ def info(self, *args, **kwargs):
28+ return self._log.info(*args, **kwargs)
29+
30+ def error(self, *args, **kwargs):
31+ return self._log.error(*args, **kwargs)
32+
33+ def commands(self):
34+ sync_command = Subcommand('sync', help='Sync music player')
35+ sync_command.func = self.sync
36+ return [sync_command]
37+
38+ def sync(self, lib, opts, args):
39+ for device in self.config['devices']:
40+ self.sync_device(device, lib, opts, args)
41+ self.info('Done')
42+
43+ def sync_device(self, config, lib, opts, args):
44+ self.info("Syncing {0}", config['path'])
45+ path = os.path.expanduser(config['path'].get())
46+ if not os.path.exists(path):
47+ self.error('Path doesn\'t exists {0}', path)
48+ return
49+ self.info('Creating database')
50+ db_file = os.path.join(path, 'beetssync.db')
51+ db = sqlite3.connect(db_file)
52+ db.text_factory = str
53+ if not db.execute('SELECT * FROM sqlite_master WHERE name="song"').fetchall():
54+ with db:
55+ db.executescript(_CREATE_DATABASE_SCRIPT)
56+ with db:
57+ db.execute('DELETE FROM query')
58+ db.execute('DELETE FROM querysong')
59+ db.execute('DELETE FROM playlist')
60+ db.execute('DELETE FROM playlistsong')
61+
62+ for query in config['queries'].get(list):
63+ self.info('Processing query: "{0}"', query)
64+ items = lib.items(query)
65+ for item in items:
66+ self.add_item(lib, db, item)
67+ with db:
68+ db.execute('INSERT INTO query (query) VALUES (?)', (query,))
69+ query_id = db.execute('SELECT idQuery FROM query WHERE query=?', (query,)).fetchone()[0]
70+ db.executemany('INSERT INTO querysong VALUES (?, ?)', [(query_id, item['id']) for item in items])
71+
72+ for playlist in config['playlists'].get(list):
73+ self.info('Processing playlist: "{0}"', playlist)
74+ playlist_file = os.path.expanduser(playlist)
75+ with open(playlist_file, 'rt') as f:
76+ paths = [line for line in (line.strip() for line in f) if line and not line.startswith('#')]
77+ items = []
78+ for song_path in paths:
79+ query, q_sort = parse_query_parts(['path:' + song_path], Item)
80+ item = list(lib.items(OrQuery(query)))[0]
81+ self.add_item(lib, db, item)
82+ items.append(item)
83+ with db:
84+ db.execute(
85+ 'INSERT INTO playlist (playlist) VALUES (?)',
86+ (playlist,))
87+ playlist_id = db.execute(
88+ 'SELECT idPlaylist FROM playlist WHERE playlist=?',
89+ (playlist,)).fetchone()[0]
90+ db.executemany(
91+ 'INSERT INTO playlistsong VALUES (?, ?, ?)',
92+ [(playlist_id, item['id'], index) for index, item in enumerate(items)])
93+
94+ self.info('Syncing songs')
95+ for item_id, song_path in db.execute('''
96+ SELECT song.idSong, song.filename FROM song JOIN querysong ON song.idSong=querysong.idSong WHERE synced=0 or synced is NULL
97+ UNION
98+ SELECT song.idSong, song.filename FROM song JOIN playlistsong ON song.idSong=playlistsong.idSong WHERE synced=0 or synced is NULL
99+ '''):
100+ item = lib.get_item(item_id)
101+ copy_path = os.path.join(path, song_path)
102+ if not os.path.exists(item['path']):
103+ self.info('"{0}" does not exist', item['path'])
104+ continue
105+ with db:
106+ self.info('Copying "{0}"', item)
107+ if not os.path.exists(os.path.dirname(copy_path)):
108+ os.makedirs(os.path.dirname(copy_path))
109+ shutil.copyfile(item['path'], copy_path)
110+ db.execute('UPDATE song SET synced=1,date=? WHERE idSong=?', (datetime.datetime.now(), item_id))
111+
112+ for item_id, song_path in db.execute('''
113+ SELECT song.idSong, filename FROM song
114+ LEFT JOIN querysong ON song.idSong=querysong.idSong
115+ LEFT JOIN playlistsong ON song.idSong=playlistsong.idSong
116+ WHERE synced=1 and (querysong.idQuery is NULL and playlistsong.idPlaylist is NULL)
117+ '''):
118+ item = lib.get_item(item_id)
119+ copy_path = os.path.join(path, song_path)
120+ with db:
121+ self.info('Removing "{0}"', item)
122+ if os.path.exists(copy_path):
123+ os.unlink(copy_path)
124+ prune_dirs(os.path.dirname(copy_path), root=path)
125+ db.execute('DELETE FROM song WHERE idSong=?', (item_id,))
126+
127+ self.info('Creating playlists')
128+ for playlist_id, playlist_path in db.execute('SELECT * FROM playlist'):
129+ with open(os.path.join(path, os.path.basename(playlist_path)), 'wt') as f:
130+ for (filename,) in db.execute('''
131+ SELECT filename FROM song JOIN playlistsong ON song.idSong=playlistsong.idSong
132+ WHERE idPlaylist=?
133+ ORDER BY listIndex
134+ ''', (playlist_id,)):
135+ f.write(filename + '\n')
136+
137+ self.info('Finished syncing {0}', config['path'])
138+
139+ def add_item(self, lib, db, item):
140+ item_id = item['id']
141+ fullpath = item['path']
142+ copy_path = os.path.relpath(fullpath, lib.directory)
143+ if not db.execute('SELECT * FROM song WHERE idSong=?', (item_id,)).fetchall():
144+ with db:
145+ db.execute('INSERT INTO song (idSong, filename) VALUES (?,?)', (item_id, copy_path))